]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/if_wg/module/wg_cookie.c
service(8): use an environment more consistent with init(8)
[FreeBSD/FreeBSD.git] / sys / dev / if_wg / module / wg_cookie.c
1 /*
2  * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
3  * Copyright (C) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <sys/cdefs.h>
19 __FBSDID("$FreeBSD$");
20
21 #include <sys/types.h>
22 #include <sys/systm.h>
23 #include <sys/param.h>
24 #include <sys/rwlock.h>
25 #include <sys/malloc.h> /* Because systm doesn't include M_NOWAIT, M_DEVBUF */
26 #include <sys/socket.h>
27
28 #include <sys/wg_cookie.h>
29 #include <zinc/chacha20poly1305.h>
30
31 static void     cookie_precompute_key(uint8_t *,
32                         const uint8_t[COOKIE_INPUT_SIZE], const char *);
33 static void     cookie_macs_mac1(struct cookie_macs *, const void *, size_t,
34                         const uint8_t[COOKIE_KEY_SIZE]);
35 static void     cookie_macs_mac2(struct cookie_macs *, const void *, size_t,
36                         const uint8_t[COOKIE_COOKIE_SIZE]);
37 static int      cookie_timer_expired(struct timespec *, time_t, long);
38 static void     cookie_checker_make_cookie(struct cookie_checker *,
39                         uint8_t[COOKIE_COOKIE_SIZE], struct sockaddr *);
40 static void     ratelimit_gc(struct ratelimit *, int);
41 static int      ratelimit_allow(struct ratelimit *, struct sockaddr *);
42
43 /* Public Functions */
44 void
45 cookie_maker_init(struct cookie_maker *cp, const uint8_t key[COOKIE_INPUT_SIZE])
46 {
47         bzero(cp, sizeof(*cp));
48         cookie_precompute_key(cp->cp_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
49         cookie_precompute_key(cp->cp_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
50         rw_init(&cp->cp_lock, "cookie_maker");
51 }
52
53 int
54 cookie_checker_init(struct cookie_checker *cc, uma_zone_t zone)
55 {
56         struct ratelimit *rl = &cc->cc_ratelimit;
57         bzero(cc, sizeof(*cc));
58
59         rw_init(&cc->cc_key_lock, "cookie_checker_key");
60         rw_init(&cc->cc_secret_lock, "cookie_checker_secret");
61
62         rw_init(&rl->rl_lock, "ratelimit_lock");
63         arc4random_buf(&rl->rl_secret, sizeof(rl->rl_secret));
64         rl->rl_table = hashinit(RATELIMIT_SIZE, M_DEVBUF, &rl->rl_table_mask);
65         rl->rl_zone = zone;
66
67         return (0);
68 }
69
70 void
71 cookie_checker_update(struct cookie_checker *cc,
72     uint8_t key[COOKIE_INPUT_SIZE])
73 {
74         rw_enter_write(&cc->cc_key_lock);
75         if (key) {
76                 cookie_precompute_key(cc->cc_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
77                 cookie_precompute_key(cc->cc_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
78         } else {
79                 bzero(cc->cc_mac1_key, sizeof(cc->cc_mac1_key));
80                 bzero(cc->cc_cookie_key, sizeof(cc->cc_cookie_key));
81         }
82         rw_exit_write(&cc->cc_key_lock);
83 }
84
85 void
86 cookie_checker_deinit(struct cookie_checker *cc)
87 {
88         struct ratelimit *rl = &cc->cc_ratelimit;
89
90         rw_enter_write(&rl->rl_lock);
91         ratelimit_gc(rl, 1);
92         hashdestroy(rl->rl_table, M_DEVBUF, rl->rl_table_mask);
93         rw_exit_write(&rl->rl_lock);
94 }
95
96 void
97 cookie_checker_create_payload(struct cookie_checker *cc,
98     struct cookie_macs *cm, uint8_t nonce[COOKIE_XNONCE_SIZE],
99     uint8_t ecookie[COOKIE_ENCRYPTED_SIZE], struct sockaddr *sa)
100 {
101         uint8_t cookie[COOKIE_COOKIE_SIZE];
102
103         cookie_checker_make_cookie(cc, cookie, sa);
104         arc4random_buf(nonce, COOKIE_XNONCE_SIZE);
105
106         rw_enter_read(&cc->cc_key_lock);
107         xchacha20poly1305_encrypt(ecookie, cookie, COOKIE_COOKIE_SIZE,
108             cm->mac1, COOKIE_MAC_SIZE, nonce, cc->cc_cookie_key);
109         rw_exit_read(&cc->cc_key_lock);
110
111         explicit_bzero(cookie, sizeof(cookie));
112 }
113
114 int
115 cookie_maker_consume_payload(struct cookie_maker *cp,
116     uint8_t nonce[COOKIE_XNONCE_SIZE], uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])
117 {
118         int ret = 0;
119         uint8_t cookie[COOKIE_COOKIE_SIZE];
120
121         rw_enter_write(&cp->cp_lock);
122
123         if (cp->cp_mac1_valid == 0) {
124                 ret = ETIMEDOUT;
125                 goto error;
126         }
127
128         if (xchacha20poly1305_decrypt(cookie, ecookie, COOKIE_ENCRYPTED_SIZE,
129             cp->cp_mac1_last, COOKIE_MAC_SIZE, nonce, cp->cp_cookie_key) == 0) {
130                 ret = EINVAL;
131                 goto error;
132         }
133
134         memcpy(cp->cp_cookie, cookie, COOKIE_COOKIE_SIZE);
135         getnanouptime(&cp->cp_birthdate);
136         cp->cp_mac1_valid = 0;
137
138 error:
139         rw_exit_write(&cp->cp_lock);
140         return ret;
141 }
142
143 void
144 cookie_maker_mac(struct cookie_maker *cp, struct cookie_macs *cm, void *buf,
145                 size_t len)
146 {
147         rw_enter_read(&cp->cp_lock);
148
149         cookie_macs_mac1(cm, buf, len, cp->cp_mac1_key);
150
151         memcpy(cp->cp_mac1_last, cm->mac1, COOKIE_MAC_SIZE);
152         cp->cp_mac1_valid = 1;
153
154         if (!cookie_timer_expired(&cp->cp_birthdate,
155             COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY, 0))
156                 cookie_macs_mac2(cm, buf, len, cp->cp_cookie);
157         else
158                 bzero(cm->mac2, COOKIE_MAC_SIZE);
159
160         rw_exit_read(&cp->cp_lock);
161 }
162
163 int
164 cookie_checker_validate_macs(struct cookie_checker *cc, struct cookie_macs *cm,
165                 void *buf, size_t len, int busy, struct sockaddr *sa)
166 {
167         struct cookie_macs our_cm;
168         uint8_t cookie[COOKIE_COOKIE_SIZE];
169
170         /* Validate incoming MACs */
171         rw_enter_read(&cc->cc_key_lock);
172         cookie_macs_mac1(&our_cm, buf, len, cc->cc_mac1_key);
173         rw_exit_read(&cc->cc_key_lock);
174
175         /* If mac1 is invald, we want to drop the packet */
176         if (timingsafe_bcmp(our_cm.mac1, cm->mac1, COOKIE_MAC_SIZE) != 0)
177                 return EINVAL;
178
179         if (busy != 0) {
180                 cookie_checker_make_cookie(cc, cookie, sa);
181                 cookie_macs_mac2(&our_cm, buf, len, cookie);
182
183                 /* If the mac2 is invalid, we want to send a cookie response */
184                 if (timingsafe_bcmp(our_cm.mac2, cm->mac2, COOKIE_MAC_SIZE) != 0)
185                         return EAGAIN;
186
187                 /* If the mac2 is valid, we may want rate limit the peer. 
188                  * ratelimit_allow will return either 0 or ECONNREFUSED,
189                  * implying there is no ratelimiting, or we should ratelimit
190                  * (refuse) respectively. */
191                 return ratelimit_allow(&cc->cc_ratelimit, sa);
192         }
193         return 0;
194 }
195
196 /* Private functions */
197 static void
198 cookie_precompute_key(uint8_t *key, const uint8_t input[COOKIE_INPUT_SIZE],
199     const char *label)
200 {
201         struct blake2s_state blake;
202
203         blake2s_init(&blake, COOKIE_KEY_SIZE);
204         blake2s_update(&blake, label, strlen(label));
205         blake2s_update(&blake, input, COOKIE_INPUT_SIZE);
206         blake2s_final(&blake, key, COOKIE_KEY_SIZE);
207 }
208
209 static void
210 cookie_macs_mac1(struct cookie_macs *cm, const void *buf, size_t len,
211     const uint8_t key[COOKIE_KEY_SIZE])
212 {
213         struct blake2s_state state;
214         blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_KEY_SIZE);
215         blake2s_update(&state, buf, len);
216         blake2s_final(&state, cm->mac1, COOKIE_MAC_SIZE);
217 }
218
219 static void
220 cookie_macs_mac2(struct cookie_macs *cm, const void *buf, size_t len,
221                 const uint8_t key[COOKIE_COOKIE_SIZE])
222 {
223         struct blake2s_state state;
224         blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_COOKIE_SIZE);
225         blake2s_update(&state, buf, len);
226         blake2s_update(&state, cm->mac1, COOKIE_MAC_SIZE);
227         blake2s_final(&state, cm->mac2, COOKIE_MAC_SIZE);
228 }
229
230 static int
231 cookie_timer_expired(struct timespec *birthdate, time_t sec, long nsec)
232 {
233         struct timespec uptime;
234         struct timespec expire = { .tv_sec = sec, .tv_nsec = nsec };
235
236         if (birthdate->tv_sec == 0 && birthdate->tv_nsec == 0)
237                 return ETIMEDOUT;
238
239         getnanouptime(&uptime);
240         timespecadd(birthdate, &expire, &expire);
241         return timespeccmp(&uptime, &expire, >) ? ETIMEDOUT : 0;
242 }
243
244 static void
245 cookie_checker_make_cookie(struct cookie_checker *cc,
246                 uint8_t cookie[COOKIE_COOKIE_SIZE], struct sockaddr *sa)
247 {
248         struct blake2s_state state;
249
250         rw_enter_write(&cc->cc_secret_lock);
251         if (cookie_timer_expired(&cc->cc_secret_birthdate,
252             COOKIE_SECRET_MAX_AGE, 0)) {
253                 arc4random_buf(cc->cc_secret, COOKIE_SECRET_SIZE);
254                 getnanouptime(&cc->cc_secret_birthdate);
255         }
256         blake2s_init_key(&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
257             COOKIE_SECRET_SIZE);
258         rw_exit_write(&cc->cc_secret_lock);
259
260         if (sa->sa_family == AF_INET) {
261                 blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_addr,
262                                 sizeof(struct in_addr));
263                 blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_port, 
264                                 sizeof(in_port_t));
265                 blake2s_final(&state, cookie, COOKIE_COOKIE_SIZE);
266         } else if (sa->sa_family == AF_INET6) {
267                 blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_addr,
268                                 sizeof(struct in6_addr));
269                 blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_port,
270                                 sizeof(in_port_t));
271                 blake2s_final(&state, cookie, COOKIE_COOKIE_SIZE);
272         } else {
273                 arc4random_buf(cookie, COOKIE_COOKIE_SIZE);
274         }
275 }
276
277 static void
278 ratelimit_gc(struct ratelimit *rl, int force)
279 {
280         size_t i;
281         struct ratelimit_entry *r, *tr;
282         struct timespec expiry;
283
284         rw_assert(&rl->rl_lock, RA_WLOCKED);
285
286         if (force) {
287                 for (i = 0; i < RATELIMIT_SIZE; i++) {
288                         LIST_FOREACH_SAFE(r, &rl->rl_table[i], r_entry, tr) {
289                                 rl->rl_table_num--;
290                                 LIST_REMOVE(r, r_entry);
291                                 uma_zfree(rl->rl_zone, r);
292                         }
293                 }
294                 return;
295         }
296
297         if ((cookie_timer_expired(&rl->rl_last_gc, ELEMENT_TIMEOUT, 0) &&
298             rl->rl_table_num > 0)) {
299                 getnanouptime(&rl->rl_last_gc);
300                 getnanouptime(&expiry);
301                 expiry.tv_sec -= ELEMENT_TIMEOUT;
302
303                 for (i = 0; i < RATELIMIT_SIZE; i++) {
304                         LIST_FOREACH_SAFE(r, &rl->rl_table[i], r_entry, tr) {
305                                 if (timespeccmp(&r->r_last_time, &expiry, <)) {
306                                         rl->rl_table_num--;
307                                         LIST_REMOVE(r, r_entry);
308                                         uma_zfree(rl->rl_zone, r);
309                                 }
310                         }
311                 }
312         }
313 }
314
315 static int
316 ratelimit_allow(struct ratelimit *rl, struct sockaddr *sa)
317 {
318         uint64_t key, tokens;
319         struct timespec diff;
320         struct ratelimit_entry *r;
321         int ret = ECONNREFUSED;
322
323         if (sa->sa_family == AF_INET)
324                 key = siphash24(&rl->rl_secret, &satosin(sa)->sin_addr,
325                                 IPV4_MASK_SIZE);
326         else if (sa->sa_family == AF_INET6)
327                 key = siphash24(&rl->rl_secret, &satosin6(sa)->sin6_addr,
328                                 IPV6_MASK_SIZE);
329         else
330                 return ret;
331
332         rw_enter_write(&rl->rl_lock);
333
334         LIST_FOREACH(r, &rl->rl_table[key & rl->rl_table_mask], r_entry) {
335                 if (r->r_af != sa->sa_family)
336                         continue;
337
338                 if (r->r_af == AF_INET && bcmp(&r->r_in,
339                     &satosin(sa)->sin_addr, IPV4_MASK_SIZE) != 0)
340                         continue;
341
342                 if (r->r_af == AF_INET6 && bcmp(&r->r_in6,
343                     &satosin6(sa)->sin6_addr, IPV6_MASK_SIZE) != 0)
344                         continue;
345
346                 /* If we get to here, we've found an entry for the endpoint.
347                  * We apply standard token bucket, by calculating the time
348                  * lapsed since our last_time, adding that, ensuring that we
349                  * cap the tokens at TOKEN_MAX. If the endpoint has no tokens
350                  * left (that is tokens <= INITIATION_COST) then we block the
351                  * request, otherwise we subtract the INITITIATION_COST and
352                  * return OK. */
353                 diff = r->r_last_time;
354                 getnanouptime(&r->r_last_time);
355                 timespecsub(&r->r_last_time, &diff, &diff);
356
357                 tokens = r->r_tokens + diff.tv_sec * NSEC_PER_SEC + diff.tv_nsec;
358
359                 if (tokens > TOKEN_MAX)
360                         tokens = TOKEN_MAX;
361
362                 if (tokens > INITIATION_COST) {
363                         r->r_tokens = tokens - INITIATION_COST;
364                         goto ok;
365                 } else {
366                         r->r_tokens = tokens;
367                         goto error;
368                 }
369         }
370
371         /* If we get to here, we didn't have an entry for the endpoint. */
372         ratelimit_gc(rl, 0);
373
374         /* Hard limit on number of entries */
375         if (rl->rl_table_num >= RATELIMIT_SIZE_MAX * 8)
376                 goto error;
377
378         /* Goto error if out of memory */
379         if ((r = uma_zalloc(rl->rl_zone, M_NOWAIT)) == NULL)
380                 goto error;
381
382         rl->rl_table_num++;
383
384         /* Insert entry into the hashtable and ensure it's initialised */
385         LIST_INSERT_HEAD(&rl->rl_table[key & rl->rl_table_mask], r, r_entry);
386         r->r_af = sa->sa_family;
387         if (r->r_af == AF_INET)
388                 memcpy(&r->r_in, &satosin(sa)->sin_addr, IPV4_MASK_SIZE);
389         else if (r->r_af == AF_INET6)
390                 memcpy(&r->r_in6, &satosin6(sa)->sin6_addr, IPV6_MASK_SIZE);
391
392         getnanouptime(&r->r_last_time);
393         r->r_tokens = TOKEN_MAX - INITIATION_COST;
394 ok:
395         ret = 0;
396 error:
397         rw_exit_write(&rl->rl_lock);
398         return ret;
399 }