Line data Source code
1 : /*
2 : * Copyright (c) 2020 Doc.ai and/or its affiliates.
3 : * Copyright (c) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>.
4 : * Copyright (c) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>.
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at:
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include <stddef.h>
19 : #include <openssl/rand.h>
20 : #include <vlib/vlib.h>
21 :
22 : #include <wireguard/wireguard_cookie.h>
23 : #include <wireguard/wireguard_chachapoly.h>
24 : #include <wireguard/wireguard.h>
25 :
26 : static void cookie_precompute_key (uint8_t *,
27 : const uint8_t[COOKIE_INPUT_SIZE],
28 : const char *);
29 : static void cookie_macs_mac1 (message_macs_t *, const void *, size_t,
30 : const uint8_t[COOKIE_KEY_SIZE]);
31 : static void cookie_macs_mac2 (message_macs_t *, const void *, size_t,
32 : const uint8_t[COOKIE_COOKIE_SIZE]);
33 : static void cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *,
34 : uint8_t[COOKIE_COOKIE_SIZE],
35 : ip46_address_t *ip, u16 udp_port);
36 :
37 : static void ratelimit_init (ratelimit_t *, ratelimit_entry_t *);
38 : static void ratelimit_deinit (ratelimit_t *);
39 : static void ratelimit_gc (ratelimit_t *, bool);
40 : static bool ratelimit_allow (ratelimit_t *, ip46_address_t *);
41 :
42 : /* Public Functions */
43 : void
44 146 : cookie_maker_init (cookie_maker_t * cp, const uint8_t key[COOKIE_INPUT_SIZE])
45 : {
46 146 : clib_memset (cp, 0, sizeof (*cp));
47 146 : cookie_precompute_key (cp->cp_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
48 146 : cookie_precompute_key (cp->cp_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
49 146 : }
50 :
51 : void
52 82 : cookie_checker_init (cookie_checker_t *cc, ratelimit_entry_t *pool)
53 : {
54 82 : clib_memset (cc, 0, sizeof (*cc));
55 82 : ratelimit_init (&cc->cc_ratelimit_v4, pool);
56 82 : ratelimit_init (&cc->cc_ratelimit_v6, pool);
57 82 : }
58 :
59 : void
60 82 : cookie_checker_update (cookie_checker_t * cc, uint8_t key[COOKIE_INPUT_SIZE])
61 : {
62 82 : if (key)
63 : {
64 82 : cookie_precompute_key (cc->cc_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
65 82 : cookie_precompute_key (cc->cc_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
66 : }
67 : else
68 : {
69 0 : clib_memset (cc->cc_mac1_key, 0, sizeof (cc->cc_mac1_key));
70 0 : clib_memset (cc->cc_cookie_key, 0, sizeof (cc->cc_cookie_key));
71 : }
72 82 : }
73 :
74 : void
75 82 : cookie_checker_deinit (cookie_checker_t *cc)
76 : {
77 82 : ratelimit_deinit (&cc->cc_ratelimit_v4);
78 82 : ratelimit_deinit (&cc->cc_ratelimit_v6);
79 82 : }
80 :
81 : void
82 28 : cookie_checker_create_payload (vlib_main_t *vm, cookie_checker_t *cc,
83 : message_macs_t *cm,
84 : uint8_t nonce[COOKIE_NONCE_SIZE],
85 : uint8_t ecookie[COOKIE_ENCRYPTED_SIZE],
86 : ip46_address_t *ip, u16 udp_port)
87 : {
88 : uint8_t cookie[COOKIE_COOKIE_SIZE];
89 :
90 28 : cookie_checker_make_cookie (vm, cc, cookie, ip, udp_port);
91 28 : RAND_bytes (nonce, COOKIE_NONCE_SIZE);
92 :
93 28 : wg_xchacha20poly1305_encrypt (vm, cookie, COOKIE_COOKIE_SIZE, ecookie,
94 28 : cm->mac1, COOKIE_MAC_SIZE, nonce,
95 28 : cc->cc_cookie_key);
96 :
97 28 : wg_secure_zero_memory (cookie, sizeof (cookie));
98 28 : }
99 :
100 : bool
101 16 : cookie_maker_consume_payload (vlib_main_t *vm, cookie_maker_t *cp,
102 : uint8_t nonce[COOKIE_NONCE_SIZE],
103 : uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])
104 : {
105 : uint8_t cookie[COOKIE_COOKIE_SIZE];
106 :
107 16 : if (cp->cp_mac1_valid == 0)
108 : {
109 0 : return false;
110 : }
111 :
112 16 : if (!wg_xchacha20poly1305_decrypt (vm, ecookie, COOKIE_ENCRYPTED_SIZE,
113 16 : cookie, cp->cp_mac1_last, COOKIE_MAC_SIZE,
114 16 : nonce, cp->cp_cookie_key))
115 : {
116 8 : return false;
117 : }
118 :
119 8 : clib_memcpy (cp->cp_cookie, cookie, COOKIE_COOKIE_SIZE);
120 8 : cp->cp_birthdate = vlib_time_now (vm);
121 8 : cp->cp_mac1_valid = 0;
122 :
123 8 : return true;
124 : }
125 :
126 : void
127 214 : cookie_maker_mac (cookie_maker_t * cp, message_macs_t * cm, void *buf,
128 : size_t len)
129 : {
130 214 : len = len - sizeof (message_macs_t);
131 214 : cookie_macs_mac1 (cm, buf, len, cp->cp_mac1_key);
132 :
133 214 : clib_memcpy (cp->cp_mac1_last, cm->mac1, COOKIE_MAC_SIZE);
134 214 : cp->cp_mac1_valid = 1;
135 :
136 214 : if (!wg_birthdate_has_expired (cp->cp_birthdate,
137 : COOKIE_SECRET_MAX_AGE -
138 : COOKIE_SECRET_LATENCY))
139 8 : cookie_macs_mac2 (cm, buf, len, cp->cp_cookie);
140 : else
141 206 : clib_memset (cm->mac2, 0, COOKIE_MAC_SIZE);
142 214 : }
143 :
144 : enum cookie_mac_state
145 918 : cookie_checker_validate_macs (vlib_main_t *vm, cookie_checker_t *cc,
146 : message_macs_t *cm, void *buf, size_t len,
147 : bool busy, ip46_address_t *ip, u16 udp_port)
148 : {
149 : message_macs_t our_cm;
150 : uint8_t cookie[COOKIE_COOKIE_SIZE];
151 :
152 918 : len = len - sizeof (message_macs_t);
153 918 : cookie_macs_mac1 (&our_cm, buf, len, cc->cc_mac1_key);
154 :
155 : /* If mac1 is invalid, we want to drop the packet */
156 918 : if (clib_memcmp (our_cm.mac1, cm->mac1, COOKIE_MAC_SIZE) != 0)
157 14 : return INVALID_MAC;
158 :
159 904 : if (!busy)
160 774 : return VALID_MAC_BUT_NO_COOKIE;
161 :
162 130 : cookie_checker_make_cookie (vm, cc, cookie, ip, udp_port);
163 130 : cookie_macs_mac2 (&our_cm, buf, len, cookie);
164 :
165 : /* If the mac2 is invalid, we want to send a cookie response */
166 130 : if (clib_memcmp (our_cm.mac2, cm->mac2, COOKIE_MAC_SIZE) != 0)
167 28 : return VALID_MAC_BUT_NO_COOKIE;
168 :
169 : /* If the mac2 is valid, we may want to rate limit the peer */
170 : ratelimit_t *rl;
171 102 : rl = ip46_address_is_ip4 (ip) ? &cc->cc_ratelimit_v4 : &cc->cc_ratelimit_v6;
172 :
173 102 : if (!ratelimit_allow (rl, ip))
174 54 : return VALID_MAC_WITH_COOKIE_BUT_RATELIMITED;
175 :
176 48 : return VALID_MAC_WITH_COOKIE;
177 : }
178 :
179 : /* Private functions */
180 : static void
181 456 : cookie_precompute_key (uint8_t * key, const uint8_t input[COOKIE_INPUT_SIZE],
182 : const char *label)
183 : {
184 : blake2s_state_t blake;
185 :
186 456 : blake2s_init (&blake, COOKIE_KEY_SIZE);
187 456 : blake2s_update (&blake, (const uint8_t *) label, strlen (label));
188 456 : blake2s_update (&blake, input, COOKIE_INPUT_SIZE);
189 456 : blake2s_final (&blake, key, COOKIE_KEY_SIZE);
190 456 : }
191 :
192 : static void
193 1132 : cookie_macs_mac1 (message_macs_t * cm, const void *buf, size_t len,
194 : const uint8_t key[COOKIE_KEY_SIZE])
195 : {
196 : blake2s_state_t state;
197 1132 : blake2s_init_key (&state, COOKIE_MAC_SIZE, key, COOKIE_KEY_SIZE);
198 1132 : blake2s_update (&state, buf, len);
199 1132 : blake2s_final (&state, cm->mac1, COOKIE_MAC_SIZE);
200 :
201 1132 : }
202 :
203 : static void
204 138 : cookie_macs_mac2 (message_macs_t * cm, const void *buf, size_t len,
205 : const uint8_t key[COOKIE_COOKIE_SIZE])
206 : {
207 : blake2s_state_t state;
208 138 : blake2s_init_key (&state, COOKIE_MAC_SIZE, key, COOKIE_COOKIE_SIZE);
209 138 : blake2s_update (&state, buf, len);
210 138 : blake2s_update (&state, cm->mac1, COOKIE_MAC_SIZE);
211 138 : blake2s_final (&state, cm->mac2, COOKIE_MAC_SIZE);
212 138 : }
213 :
214 : static void
215 158 : cookie_checker_make_cookie (vlib_main_t *vm, cookie_checker_t *cc,
216 : uint8_t cookie[COOKIE_COOKIE_SIZE],
217 : ip46_address_t *ip, u16 udp_port)
218 : {
219 : blake2s_state_t state;
220 :
221 158 : if (wg_birthdate_has_expired (cc->cc_secret_birthdate,
222 : COOKIE_SECRET_MAX_AGE))
223 : {
224 16 : cc->cc_secret_birthdate = vlib_time_now (vm);
225 16 : RAND_bytes (cc->cc_secret, COOKIE_SECRET_SIZE);
226 : }
227 :
228 158 : blake2s_init_key (&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
229 : COOKIE_SECRET_SIZE);
230 :
231 158 : if (ip46_address_is_ip4 (ip))
232 : {
233 104 : blake2s_update (&state, ip->ip4.as_u8, sizeof (ip4_address_t));
234 : }
235 : else
236 : {
237 54 : blake2s_update (&state, ip->ip6.as_u8, sizeof (ip6_address_t));
238 : }
239 158 : blake2s_update (&state, (u8 *) & udp_port, sizeof (u16));
240 158 : blake2s_final (&state, cookie, COOKIE_COOKIE_SIZE);
241 158 : }
242 :
243 : static void
244 164 : ratelimit_init (ratelimit_t *rl, ratelimit_entry_t *pool)
245 : {
246 164 : rl->rl_pool = pool;
247 164 : }
248 :
249 : static void
250 164 : ratelimit_deinit (ratelimit_t *rl)
251 : {
252 164 : ratelimit_gc (rl, /* force */ true);
253 164 : hash_free (rl->rl_table);
254 164 : }
255 :
256 : static void
257 180 : ratelimit_gc (ratelimit_t *rl, bool force)
258 : {
259 : u32 r_key;
260 : u32 r_idx;
261 : ratelimit_entry_t *r;
262 :
263 180 : if (force)
264 : {
265 : /* clang-format off */
266 1076 : hash_foreach (r_key, r_idx, rl->rl_table, {
267 : r = pool_elt_at_index (rl->rl_pool, r_idx);
268 : pool_put (rl->rl_pool, r);
269 : });
270 : /* clang-format on */
271 164 : return;
272 : }
273 :
274 16 : f64 now = vlib_time_now (vlib_get_main ());
275 :
276 16 : if ((rl->rl_last_gc + ELEMENT_TIMEOUT) < now)
277 : {
278 14 : u32 *r_key_to_del = NULL;
279 : u32 *pr_key;
280 :
281 14 : rl->rl_last_gc = now;
282 :
283 : /* clang-format off */
284 14 : hash_foreach (r_key, r_idx, rl->rl_table, {
285 : r = pool_elt_at_index (rl->rl_pool, r_idx);
286 : if ((r->r_last_time + ELEMENT_TIMEOUT) < now)
287 : {
288 : vec_add1 (r_key_to_del, r_key);
289 : pool_put (rl->rl_pool, r);
290 : }
291 : });
292 : /* clang-format on */
293 :
294 14 : vec_foreach (pr_key, r_key_to_del)
295 : {
296 0 : hash_unset (rl->rl_table, *pr_key);
297 : }
298 :
299 14 : vec_free (r_key_to_del);
300 : }
301 : }
302 :
303 : static bool
304 102 : ratelimit_allow (ratelimit_t *rl, ip46_address_t *ip)
305 : {
306 : u32 r_key;
307 : uword *p;
308 : u32 r_idx;
309 : ratelimit_entry_t *r;
310 102 : f64 now = vlib_time_now (vlib_get_main ());
311 :
312 102 : if (ip46_address_is_ip4 (ip))
313 : /* Use all 4 bytes of IPv4 address */
314 68 : r_key = ip->ip4.as_u32;
315 : else
316 : /* Use top 8 bytes (/64) of IPv6 address */
317 34 : r_key = ip->ip6.as_u32[0] ^ ip->ip6.as_u32[1];
318 :
319 : /* Check if there is already an entry for the IP address */
320 102 : p = hash_get (rl->rl_table, r_key);
321 102 : if (p)
322 : {
323 : u64 tokens;
324 : f64 diff;
325 :
326 86 : r_idx = p[0];
327 86 : r = pool_elt_at_index (rl->rl_pool, r_idx);
328 :
329 86 : diff = now - r->r_last_time;
330 86 : r->r_last_time = now;
331 :
332 86 : tokens = r->r_tokens + diff * NSEC_PER_SEC;
333 :
334 86 : if (tokens > TOKEN_MAX)
335 0 : tokens = TOKEN_MAX;
336 :
337 86 : if (tokens >= INITIATION_COST)
338 : {
339 32 : r->r_tokens = tokens - INITIATION_COST;
340 32 : return true;
341 : }
342 :
343 54 : r->r_tokens = tokens;
344 54 : return false;
345 : }
346 :
347 : /* No entry for the IP address */
348 16 : ratelimit_gc (rl, /* force */ false);
349 :
350 16 : if (hash_elts (rl->rl_table) >= RATELIMIT_SIZE_MAX)
351 0 : return false;
352 :
353 16 : pool_get (rl->rl_pool, r);
354 16 : r_idx = r - rl->rl_pool;
355 16 : hash_set (rl->rl_table, r_key, r_idx);
356 :
357 16 : r->r_last_time = now;
358 16 : r->r_tokens = TOKEN_MAX - INITIATION_COST;
359 :
360 16 : return true;
361 : }
362 :
363 : /*
364 : * fd.io coding-style-patch-verification: ON
365 : *
366 : * Local Variables:
367 : * eval: (c-set-style "gnu")
368 : * End:
369 : */
|