1/*	$OpenBSD: wg_cookie.c,v 1.5 2023/08/18 08:11:47 jsg Exp $ */
2/*
3 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4 * Copyright (C) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/types.h>
20#include <sys/systm.h>
21#include <sys/param.h>
22#include <sys/rwlock.h>
23#include <sys/malloc.h> /* Because systm doesn't include M_NOWAIT, M_DEVBUF */
24#include <sys/pool.h>
25#include <sys/socket.h>
26
27#include <crypto/chachapoly.h>
28
29#include <net/wg_cookie.h>
30
31static void	cookie_precompute_key(uint8_t *,
32			const uint8_t[COOKIE_INPUT_SIZE], const char *);
33static void	cookie_macs_mac1(struct cookie_macs *, const void *, size_t,
34			const uint8_t[COOKIE_KEY_SIZE]);
35static void	cookie_macs_mac2(struct cookie_macs *, const void *, size_t,
36			const uint8_t[COOKIE_COOKIE_SIZE]);
37static int	cookie_timer_expired(struct timespec *, time_t, long);
38static void	cookie_checker_make_cookie(struct cookie_checker *,
39			uint8_t[COOKIE_COOKIE_SIZE], struct sockaddr *);
40static int	ratelimit_init(struct ratelimit *, struct pool *);
41static void	ratelimit_deinit(struct ratelimit *);
42static void	ratelimit_gc(struct ratelimit *, int);
43static int	ratelimit_allow(struct ratelimit *, struct sockaddr *);
44
45/* Public Functions */
46void
47cookie_maker_init(struct cookie_maker *cp, uint8_t key[COOKIE_INPUT_SIZE])
48{
49	bzero(cp, sizeof(*cp));
50	cookie_precompute_key(cp->cp_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
51	cookie_precompute_key(cp->cp_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
52	rw_init(&cp->cp_lock, "cookie_maker");
53}
54
55int
56cookie_checker_init(struct cookie_checker *cc, struct pool *pool)
57{
58	int res;
59	bzero(cc, sizeof(*cc));
60
61	rw_init(&cc->cc_key_lock, "cookie_checker_key");
62	rw_init(&cc->cc_secret_lock, "cookie_checker_secret");
63
64	if ((res = ratelimit_init(&cc->cc_ratelimit_v4, pool)) != 0)
65		return res;
66#ifdef INET6
67	if ((res = ratelimit_init(&cc->cc_ratelimit_v6, pool)) != 0) {
68		ratelimit_deinit(&cc->cc_ratelimit_v4);
69		return res;
70	}
71#endif
72	return 0;
73}
74
75void
76cookie_checker_update(struct cookie_checker *cc,
77    uint8_t key[COOKIE_INPUT_SIZE])
78{
79	rw_enter_write(&cc->cc_key_lock);
80	if (key) {
81		cookie_precompute_key(cc->cc_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
82		cookie_precompute_key(cc->cc_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
83	} else {
84		bzero(cc->cc_mac1_key, sizeof(cc->cc_mac1_key));
85		bzero(cc->cc_cookie_key, sizeof(cc->cc_cookie_key));
86	}
87	rw_exit_write(&cc->cc_key_lock);
88}
89
90void
91cookie_checker_deinit(struct cookie_checker *cc)
92{
93	ratelimit_deinit(&cc->cc_ratelimit_v4);
94#ifdef INET6
95	ratelimit_deinit(&cc->cc_ratelimit_v6);
96#endif
97}
98
99void
100cookie_checker_create_payload(struct cookie_checker *cc,
101    struct cookie_macs *cm, uint8_t nonce[COOKIE_NONCE_SIZE],
102    uint8_t ecookie[COOKIE_ENCRYPTED_SIZE], struct sockaddr *sa)
103{
104	uint8_t cookie[COOKIE_COOKIE_SIZE];
105
106	cookie_checker_make_cookie(cc, cookie, sa);
107	arc4random_buf(nonce, COOKIE_NONCE_SIZE);
108
109	rw_enter_read(&cc->cc_key_lock);
110	xchacha20poly1305_encrypt(ecookie, cookie, COOKIE_COOKIE_SIZE,
111	    cm->mac1, COOKIE_MAC_SIZE, nonce, cc->cc_cookie_key);
112	rw_exit_read(&cc->cc_key_lock);
113
114	explicit_bzero(cookie, sizeof(cookie));
115}
116
117int
118cookie_maker_consume_payload(struct cookie_maker *cp,
119    uint8_t nonce[COOKIE_NONCE_SIZE], uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])
120{
121	int ret = 0;
122	uint8_t cookie[COOKIE_COOKIE_SIZE];
123
124	rw_enter_write(&cp->cp_lock);
125
126	if (cp->cp_mac1_valid == 0) {
127		ret = ETIMEDOUT;
128		goto error;
129	}
130
131	if (xchacha20poly1305_decrypt(cookie, ecookie, COOKIE_ENCRYPTED_SIZE,
132	    cp->cp_mac1_last, COOKIE_MAC_SIZE, nonce, cp->cp_cookie_key) == 0) {
133		ret = EINVAL;
134		goto error;
135	}
136
137	memcpy(cp->cp_cookie, cookie, COOKIE_COOKIE_SIZE);
138	getnanouptime(&cp->cp_birthdate);
139	cp->cp_mac1_valid = 0;
140
141error:
142	rw_exit_write(&cp->cp_lock);
143	return ret;
144}
145
146void
147cookie_maker_mac(struct cookie_maker *cp, struct cookie_macs *cm, void *buf,
148		size_t len)
149{
150	rw_enter_read(&cp->cp_lock);
151
152	cookie_macs_mac1(cm, buf, len, cp->cp_mac1_key);
153
154	memcpy(cp->cp_mac1_last, cm->mac1, COOKIE_MAC_SIZE);
155	cp->cp_mac1_valid = 1;
156
157	if (!cookie_timer_expired(&cp->cp_birthdate,
158	    COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY, 0))
159		cookie_macs_mac2(cm, buf, len, cp->cp_cookie);
160	else
161		bzero(cm->mac2, COOKIE_MAC_SIZE);
162
163	rw_exit_read(&cp->cp_lock);
164}
165
166int
167cookie_checker_validate_macs(struct cookie_checker *cc, struct cookie_macs *cm,
168		void *buf, size_t len, int busy, struct sockaddr *sa)
169{
170	struct cookie_macs our_cm;
171	uint8_t cookie[COOKIE_COOKIE_SIZE];
172
173	/* Validate incoming MACs */
174	rw_enter_read(&cc->cc_key_lock);
175	cookie_macs_mac1(&our_cm, buf, len, cc->cc_mac1_key);
176	rw_exit_read(&cc->cc_key_lock);
177
178	/* If mac1 is invalid, we want to drop the packet */
179	if (timingsafe_bcmp(our_cm.mac1, cm->mac1, COOKIE_MAC_SIZE) != 0)
180		return EINVAL;
181
182	if (busy != 0) {
183		cookie_checker_make_cookie(cc, cookie, sa);
184		cookie_macs_mac2(&our_cm, buf, len, cookie);
185
186		/* If the mac2 is invalid, we want to send a cookie response */
187		if (timingsafe_bcmp(our_cm.mac2, cm->mac2, COOKIE_MAC_SIZE) != 0)
188			return EAGAIN;
189
190		/* If the mac2 is valid, we may want rate limit the peer.
191		 * ratelimit_allow will return either 0 or ECONNREFUSED,
192		 * implying there is no ratelimiting, or we should ratelimit
193		 * (refuse) respectively. */
194		if (sa->sa_family == AF_INET)
195			return ratelimit_allow(&cc->cc_ratelimit_v4, sa);
196#ifdef INET6
197		else if (sa->sa_family == AF_INET6)
198			return ratelimit_allow(&cc->cc_ratelimit_v6, sa);
199#endif
200		else
201			return EAFNOSUPPORT;
202	}
203	return 0;
204}
205
206/* Private functions */
207static void
208cookie_precompute_key(uint8_t *key, const uint8_t input[COOKIE_INPUT_SIZE],
209    const char *label)
210{
211	struct blake2s_state blake;
212
213	blake2s_init(&blake, COOKIE_KEY_SIZE);
214	blake2s_update(&blake, label, strlen(label));
215	blake2s_update(&blake, input, COOKIE_INPUT_SIZE);
216	blake2s_final(&blake, key);
217}
218
219static void
220cookie_macs_mac1(struct cookie_macs *cm, const void *buf, size_t len,
221    const uint8_t key[COOKIE_KEY_SIZE])
222{
223	struct blake2s_state state;
224	blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_KEY_SIZE);
225	blake2s_update(&state, buf, len);
226	blake2s_final(&state, cm->mac1);
227}
228
229static void
230cookie_macs_mac2(struct cookie_macs *cm, const void *buf, size_t len,
231		const uint8_t key[COOKIE_COOKIE_SIZE])
232{
233	struct blake2s_state state;
234	blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_COOKIE_SIZE);
235	blake2s_update(&state, buf, len);
236	blake2s_update(&state, cm->mac1, COOKIE_MAC_SIZE);
237	blake2s_final(&state, cm->mac2);
238}
239
240static int
241cookie_timer_expired(struct timespec *birthdate, time_t sec, long nsec)
242{
243	struct timespec	uptime;
244	struct timespec	expire = { .tv_sec = sec, .tv_nsec = nsec };
245
246	if (birthdate->tv_sec == 0 && birthdate->tv_nsec == 0)
247		return ETIMEDOUT;
248
249	getnanouptime(&uptime);
250	timespecadd(birthdate, &expire, &expire);
251	return timespeccmp(&uptime, &expire, >) ? ETIMEDOUT : 0;
252}
253
254static void
255cookie_checker_make_cookie(struct cookie_checker *cc,
256		uint8_t cookie[COOKIE_COOKIE_SIZE], struct sockaddr *sa)
257{
258	struct blake2s_state state;
259
260	rw_enter_write(&cc->cc_secret_lock);
261	if (cookie_timer_expired(&cc->cc_secret_birthdate,
262	    COOKIE_SECRET_MAX_AGE, 0)) {
263		arc4random_buf(cc->cc_secret, COOKIE_SECRET_SIZE);
264		getnanouptime(&cc->cc_secret_birthdate);
265	}
266	blake2s_init_key(&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
267	    COOKIE_SECRET_SIZE);
268	rw_exit_write(&cc->cc_secret_lock);
269
270	if (sa->sa_family == AF_INET) {
271		blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_addr,
272				sizeof(struct in_addr));
273		blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_port,
274				sizeof(in_port_t));
275		blake2s_final(&state, cookie);
276#ifdef INET6
277	} else if (sa->sa_family == AF_INET6) {
278		blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_addr,
279				sizeof(struct in6_addr));
280		blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_port,
281				sizeof(in_port_t));
282		blake2s_final(&state, cookie);
283#endif
284	} else {
285		arc4random_buf(cookie, COOKIE_COOKIE_SIZE);
286	}
287}
288
289static int
290ratelimit_init(struct ratelimit *rl, struct pool *pool)
291{
292	rw_init(&rl->rl_lock, "ratelimit_lock");
293	arc4random_buf(&rl->rl_secret, sizeof(rl->rl_secret));
294	rl->rl_table = hashinit(RATELIMIT_SIZE, M_DEVBUF, M_NOWAIT,
295	    &rl->rl_table_mask);
296	rl->rl_pool = pool;
297	rl->rl_table_num = 0;
298	return rl->rl_table == NULL ? ENOBUFS : 0;
299}
300
301static void
302ratelimit_deinit(struct ratelimit *rl)
303{
304	rw_enter_write(&rl->rl_lock);
305	ratelimit_gc(rl, 1);
306	hashfree(rl->rl_table, RATELIMIT_SIZE, M_DEVBUF);
307	rw_exit_write(&rl->rl_lock);
308}
309
310static void
311ratelimit_gc(struct ratelimit *rl, int force)
312{
313	size_t i;
314	struct ratelimit_entry *r, *tr;
315	struct timespec expiry;
316
317	rw_assert_wrlock(&rl->rl_lock);
318
319	if (force) {
320		for (i = 0; i < RATELIMIT_SIZE; i++) {
321			LIST_FOREACH_SAFE(r, &rl->rl_table[i], r_entry, tr) {
322				rl->rl_table_num--;
323				LIST_REMOVE(r, r_entry);
324				pool_put(rl->rl_pool, r);
325			}
326		}
327		return;
328	}
329
330	if ((cookie_timer_expired(&rl->rl_last_gc, ELEMENT_TIMEOUT, 0) &&
331	    rl->rl_table_num > 0)) {
332		getnanouptime(&rl->rl_last_gc);
333		getnanouptime(&expiry);
334		expiry.tv_sec -= ELEMENT_TIMEOUT;
335
336		for (i = 0; i < RATELIMIT_SIZE; i++) {
337			LIST_FOREACH_SAFE(r, &rl->rl_table[i], r_entry, tr) {
338				if (timespeccmp(&r->r_last_time, &expiry, <)) {
339					rl->rl_table_num--;
340					LIST_REMOVE(r, r_entry);
341					pool_put(rl->rl_pool, r);
342				}
343			}
344		}
345	}
346}
347
348static int
349ratelimit_allow(struct ratelimit *rl, struct sockaddr *sa)
350{
351	uint64_t key, tokens;
352	struct timespec diff;
353	struct ratelimit_entry *r;
354	int ret = ECONNREFUSED;
355
356	if (sa->sa_family == AF_INET)
357		key = SipHash24(&rl->rl_secret, &satosin(sa)->sin_addr,
358				IPV4_MASK_SIZE);
359#ifdef INET6
360	else if (sa->sa_family == AF_INET6)
361		key = SipHash24(&rl->rl_secret, &satosin6(sa)->sin6_addr,
362				IPV6_MASK_SIZE);
363#endif
364	else
365		return ret;
366
367	rw_enter_write(&rl->rl_lock);
368
369	LIST_FOREACH(r, &rl->rl_table[key & rl->rl_table_mask], r_entry) {
370		if (r->r_af != sa->sa_family)
371			continue;
372
373		if (r->r_af == AF_INET && bcmp(&r->r_in,
374		    &satosin(sa)->sin_addr, IPV4_MASK_SIZE) != 0)
375			continue;
376
377#ifdef INET6
378		if (r->r_af == AF_INET6 && bcmp(&r->r_in6,
379		    &satosin6(sa)->sin6_addr, IPV6_MASK_SIZE) != 0)
380			continue;
381#endif
382
383		/* If we get to here, we've found an entry for the endpoint.
384		 * We apply standard token bucket, by calculating the time
385		 * lapsed since our last_time, adding that, ensuring that we
386		 * cap the tokens at TOKEN_MAX. If the endpoint has no tokens
387		 * left (that is tokens <= INITIATION_COST) then we block the
388		 * request, otherwise we subtract the INITIATION_COST and
389		 * return OK. */
390		diff = r->r_last_time;
391		getnanouptime(&r->r_last_time);
392		timespecsub(&r->r_last_time, &diff, &diff);
393
394		tokens = r->r_tokens + diff.tv_sec * NSEC_PER_SEC + diff.tv_nsec;
395
396		if (tokens > TOKEN_MAX)
397			tokens = TOKEN_MAX;
398
399		if (tokens >= INITIATION_COST) {
400			r->r_tokens = tokens - INITIATION_COST;
401			goto ok;
402		} else {
403			r->r_tokens = tokens;
404			goto error;
405		}
406	}
407
408	/* If we get to here, we didn't have an entry for the endpoint. */
409	ratelimit_gc(rl, 0);
410
411	/* Hard limit on number of entries */
412	if (rl->rl_table_num >= RATELIMIT_SIZE_MAX)
413		goto error;
414
415	/* Goto error if out of memory */
416	if ((r = pool_get(rl->rl_pool, PR_NOWAIT)) == NULL)
417		goto error;
418
419	rl->rl_table_num++;
420
421	/* Insert entry into the hashtable and ensure it's initialised */
422	LIST_INSERT_HEAD(&rl->rl_table[key & rl->rl_table_mask], r, r_entry);
423	r->r_af = sa->sa_family;
424	if (r->r_af == AF_INET)
425		memcpy(&r->r_in, &satosin(sa)->sin_addr, IPV4_MASK_SIZE);
426#ifdef INET6
427	else if (r->r_af == AF_INET6)
428		memcpy(&r->r_in6, &satosin6(sa)->sin6_addr, IPV6_MASK_SIZE);
429#endif
430
431	getnanouptime(&r->r_last_time);
432	r->r_tokens = TOKEN_MAX - INITIATION_COST;
433ok:
434	ret = 0;
435error:
436	rw_exit_write(&rl->rl_lock);
437	return ret;
438}
439
440#ifdef WGTEST
441
442#define MESSAGE_LEN 64
443#define T_FAILED_ITER(test) do {				\
444	printf("%s %s: failed. iter: %d\n", __func__, test, i);	\
445	goto cleanup;						\
446} while (0)
447#define T_FAILED(test) do {				\
448	printf("%s %s: failed.\n", __func__, test);	\
449	goto cleanup;					\
450} while (0)
451#define T_PASSED printf("%s: passed.\n", __func__)
452
453static const struct expected_results {
454	int result;
455	int sleep_time;
456} rl_expected[] = {
457	[0 ... INITIATIONS_BURSTABLE - 1] = { 0, 0 },
458	[INITIATIONS_BURSTABLE] = { ECONNREFUSED, 0 },
459	[INITIATIONS_BURSTABLE + 1] = { 0, NSEC_PER_SEC / INITIATIONS_PER_SECOND },
460	[INITIATIONS_BURSTABLE + 2] = { ECONNREFUSED, 0 },
461	[INITIATIONS_BURSTABLE + 3] = { 0, (NSEC_PER_SEC / INITIATIONS_PER_SECOND) * 2 },
462	[INITIATIONS_BURSTABLE + 4] = { 0, 0 },
463	[INITIATIONS_BURSTABLE + 5] = { ECONNREFUSED, 0 }
464};
465
466static void
467cookie_ratelimit_timings_test()
468{
469	struct ratelimit rl;
470	struct pool rl_pool;
471	struct sockaddr_in sin;
472#ifdef INET6
473	struct sockaddr_in6 sin6;
474#endif
475	int i;
476
477	pool_init(&rl_pool, sizeof(struct ratelimit_entry), 0,
478	    IPL_NONE, 0, "rl", NULL);
479	ratelimit_init(&rl, &rl_pool);
480
481	sin.sin_family = AF_INET;
482#ifdef INET6
483	sin6.sin6_family = AF_INET6;
484#endif
485
486	for (i = 0; i < sizeof(rl_expected)/sizeof(*rl_expected); i++) {
487		if (rl_expected[i].sleep_time != 0)
488			tsleep_nsec(&rl, PWAIT, "rl", rl_expected[i].sleep_time);
489
490		/* The first v4 ratelimit_allow is against a constant address,
491		 * and should be indifferent to the port. */
492		sin.sin_addr.s_addr = 0x01020304;
493		sin.sin_port = arc4random();
494
495		if (ratelimit_allow(&rl, sintosa(&sin)) != rl_expected[i].result)
496			T_FAILED_ITER("malicious v4");
497
498		/* The second ratelimit_allow is to test that an arbitrary
499		 * address is still allowed. */
500		sin.sin_addr.s_addr += i + 1;
501		sin.sin_port = arc4random();
502
503		if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
504			T_FAILED_ITER("non-malicious v4");
505
506#ifdef INET6
507		/* The first v6 ratelimit_allow is against a constant address,
508		 * and should be indifferent to the port. We also mutate the
509		 * lower 64 bits of the address as we want to ensure ratelimit
510		 * occurs against the higher 64 bits (/64 network). */
511		sin6.sin6_addr.s6_addr32[0] = 0x01020304;
512		sin6.sin6_addr.s6_addr32[1] = 0x05060708;
513		sin6.sin6_addr.s6_addr32[2] = i;
514		sin6.sin6_addr.s6_addr32[3] = i;
515		sin6.sin6_port = arc4random();
516
517		if (ratelimit_allow(&rl, sin6tosa(&sin6)) != rl_expected[i].result)
518			T_FAILED_ITER("malicious v6");
519
520		/* Again, test that an address different to above is still
521		 * allowed. */
522		sin6.sin6_addr.s6_addr32[0] += i + 1;
523		sin6.sin6_port = arc4random();
524
525		if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
526			T_FAILED_ITER("non-malicious v6");
527#endif
528	}
529	T_PASSED;
530cleanup:
531	ratelimit_deinit(&rl);
532	pool_destroy(&rl_pool);
533}
534
535static void
536cookie_ratelimit_capacity_test()
537{
538	struct ratelimit rl;
539	struct pool rl_pool;
540	struct sockaddr_in sin;
541	int i;
542
543	pool_init(&rl_pool, sizeof(struct ratelimit_entry), 0,
544	    IPL_NONE, 0, "rl", NULL);
545	ratelimit_init(&rl, &rl_pool);
546
547	sin.sin_family = AF_INET;
548	sin.sin_port = 1234;
549
550	/* Here we test that the ratelimiter has an upper bound on the number
551	 * of addresses to be limited */
552	for (i = 0; i <= RATELIMIT_SIZE_MAX; i++) {
553		sin.sin_addr.s_addr = i;
554		if (i == RATELIMIT_SIZE_MAX) {
555			if (ratelimit_allow(&rl, sintosa(&sin)) != ECONNREFUSED)
556				T_FAILED_ITER("reject");
557		} else {
558			if (ratelimit_allow(&rl, sintosa(&sin)) != 0)
559				T_FAILED_ITER("allow");
560		}
561	}
562	T_PASSED;
563cleanup:
564	ratelimit_deinit(&rl);
565	pool_destroy(&rl_pool);
566}
567
568static void
569cookie_mac_test()
570{
571	struct pool rl_pool;
572	struct cookie_checker checker;
573	struct cookie_maker maker;
574	struct cookie_macs cm;
575	struct sockaddr_in sin;
576	int res, i;
577
578	uint8_t	nonce[COOKIE_NONCE_SIZE];
579	uint8_t	cookie[COOKIE_ENCRYPTED_SIZE];
580	uint8_t	shared[COOKIE_INPUT_SIZE];
581	uint8_t message[MESSAGE_LEN];
582
583	arc4random_buf(shared, COOKIE_INPUT_SIZE);
584	arc4random_buf(message, MESSAGE_LEN);
585
586	/* Init cookie_maker. */
587	cookie_maker_init(&maker, shared);
588
589	/* Init cookie_checker. */
590	pool_init(&rl_pool, sizeof(struct ratelimit_entry), 0,
591	    IPL_NONE, 0, "rl", NULL);
592
593	if (cookie_checker_init(&checker, &rl_pool) != 0)
594		T_FAILED("cookie_checker_allocate");
595	cookie_checker_update(&checker, shared);
596
597	/* Create dummy sockaddr */
598	sin.sin_family = AF_INET;
599	sin.sin_len = sizeof(sin);
600	sin.sin_addr.s_addr = 1;
601	sin.sin_port = 51820;
602
603	/* MAC message */
604	cookie_maker_mac(&maker, &cm, message, MESSAGE_LEN);
605
606	/* Check we have a null mac2 */
607	for (i = 0; i < sizeof(cm.mac2); i++)
608		if (cm.mac2[i] != 0)
609			T_FAILED("validate_macs_noload_mac2_zeroed");
610
611	/* Validate all bytes are checked in mac1 */
612	for (i = 0; i < sizeof(cm.mac1); i++) {
613		cm.mac1[i] = ~cm.mac1[i];
614		if (cookie_checker_validate_macs(&checker, &cm, message,
615		    MESSAGE_LEN, 0, sintosa(&sin)) != EINVAL)
616			T_FAILED("validate_macs_noload_munge");
617		cm.mac1[i] = ~cm.mac1[i];
618	}
619
620	/* Check mac2 is zeroed */
621	res = 0;
622	for (i = 0; i < sizeof(cm.mac2); i++)
623		res |= cm.mac2[i];
624	if (res != 0)
625		T_FAILED("validate_macs_mac2_checkzero");
626
627
628	/* Check we can successfully validate the MAC */
629	if (cookie_checker_validate_macs(&checker, &cm, message,
630	    MESSAGE_LEN, 0, sintosa(&sin)) != 0)
631		T_FAILED("validate_macs_noload_normal");
632
633	/* Check we get a EAGAIN if no mac2 and under load */
634	if (cookie_checker_validate_macs(&checker, &cm, message,
635	    MESSAGE_LEN, 1, sintosa(&sin)) != EAGAIN)
636		T_FAILED("validate_macs_load_normal");
637
638	/* Simulate a cookie message */
639	cookie_checker_create_payload(&checker, &cm, nonce, cookie, sintosa(&sin));
640
641	/* Validate all bytes are checked in cookie */
642	for (i = 0; i < sizeof(cookie); i++) {
643		cookie[i] = ~cookie[i];
644		if (cookie_maker_consume_payload(&maker, nonce, cookie) != EINVAL)
645			T_FAILED("consume_payload_munge");
646		cookie[i] = ~cookie[i];
647	}
648
649	/* Check we can actually consume the payload */
650	if (cookie_maker_consume_payload(&maker, nonce, cookie) != 0)
651		T_FAILED("consume_payload_normal");
652
653	/* Check replay isn't allowed */
654	if (cookie_maker_consume_payload(&maker, nonce, cookie) != ETIMEDOUT)
655		T_FAILED("consume_payload_normal_replay");
656
657	/* MAC message again, with MAC2 */
658	cookie_maker_mac(&maker, &cm, message, MESSAGE_LEN);
659
660	/* Check we added a mac2 */
661	res = 0;
662	for (i = 0; i < sizeof(cm.mac2); i++)
663		res |= cm.mac2[i];
664	if (res == 0)
665		T_FAILED("validate_macs_make_mac2");
666
667	/* Check we get OK if mac2 and under load */
668	if (cookie_checker_validate_macs(&checker, &cm, message,
669	    MESSAGE_LEN, 1, sintosa(&sin)) != 0)
670		T_FAILED("validate_macs_load_normal_mac2");
671
672	sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
673	/* Check we get EAGAIN if we munge the source IP */
674	if (cookie_checker_validate_macs(&checker, &cm, message,
675	    MESSAGE_LEN, 1, sintosa(&sin)) != EAGAIN)
676		T_FAILED("validate_macs_load_spoofip_mac2");
677	sin.sin_addr.s_addr = ~sin.sin_addr.s_addr;
678
679	/* Check we get OK if mac2 and under load */
680	if (cookie_checker_validate_macs(&checker, &cm, message,
681	    MESSAGE_LEN, 1, sintosa(&sin)) != 0)
682		T_FAILED("validate_macs_load_normal_mac2_retry");
683
684	printf("cookie_mac: passed.\n");
685cleanup:
686	cookie_checker_deinit(&checker);
687	pool_destroy(&rl_pool);
688}
689
690void
691cookie_test()
692{
693	cookie_ratelimit_timings_test();
694	cookie_ratelimit_capacity_test();
695	cookie_mac_test();
696}
697
698#endif /* WGTEST */
699