xref: /openbsd-src/sys/net/wg_noise.c (revision efbb2e09ffebb712903070c7f89c2796597a6043)
1*efbb2e09Smvs /*	$OpenBSD: wg_noise.c,v 1.7 2024/03/05 17:48:01 mvs Exp $ */
258360b13Sdlg /*
358360b13Sdlg  * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
458360b13Sdlg  * Copyright (C) 2019-2020 Matt Dunwoodie <ncon@noconroy.net>
558360b13Sdlg  *
658360b13Sdlg  * Permission to use, copy, modify, and distribute this software for any
758360b13Sdlg  * purpose with or without fee is hereby granted, provided that the above
858360b13Sdlg  * copyright notice and this permission notice appear in all copies.
958360b13Sdlg  *
1058360b13Sdlg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1158360b13Sdlg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1258360b13Sdlg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1358360b13Sdlg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1458360b13Sdlg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1558360b13Sdlg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1658360b13Sdlg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1758360b13Sdlg  */
1858360b13Sdlg 
1958360b13Sdlg #include <sys/types.h>
2058360b13Sdlg #include <sys/systm.h>
2158360b13Sdlg #include <sys/param.h>
2258360b13Sdlg #include <sys/atomic.h>
23*efbb2e09Smvs #include <sys/mutex.h>
2458360b13Sdlg #include <sys/rwlock.h>
2558360b13Sdlg 
2658360b13Sdlg #include <crypto/blake2s.h>
2758360b13Sdlg #include <crypto/curve25519.h>
2858360b13Sdlg #include <crypto/chachapoly.h>
2958360b13Sdlg 
3058360b13Sdlg #include <net/wg_noise.h>
3158360b13Sdlg 
3258360b13Sdlg /* Private functions */
3358360b13Sdlg static struct noise_keypair *
3458360b13Sdlg 		noise_remote_keypair_allocate(struct noise_remote *);
3558360b13Sdlg static void
3658360b13Sdlg 		noise_remote_keypair_free(struct noise_remote *,
3758360b13Sdlg 			struct noise_keypair *);
3858360b13Sdlg static uint32_t	noise_remote_handshake_index_get(struct noise_remote *);
3958360b13Sdlg static void	noise_remote_handshake_index_drop(struct noise_remote *);
4058360b13Sdlg 
4158360b13Sdlg static uint64_t	noise_counter_send(struct noise_counter *);
4258360b13Sdlg static int	noise_counter_recv(struct noise_counter *, uint64_t);
4358360b13Sdlg 
4458360b13Sdlg static void	noise_kdf(uint8_t *, uint8_t *, uint8_t *, const uint8_t *,
4558360b13Sdlg 			size_t, size_t, size_t, size_t,
4658360b13Sdlg 			const uint8_t [NOISE_HASH_LEN]);
4758360b13Sdlg static int	noise_mix_dh(
4858360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
4958360b13Sdlg 			uint8_t [NOISE_SYMMETRIC_KEY_LEN],
5058360b13Sdlg 			const uint8_t [NOISE_PUBLIC_KEY_LEN],
5158360b13Sdlg 			const uint8_t [NOISE_PUBLIC_KEY_LEN]);
5258360b13Sdlg static int	noise_mix_ss(
5358360b13Sdlg 			uint8_t ck[NOISE_HASH_LEN],
5458360b13Sdlg 			uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
5558360b13Sdlg 			const uint8_t ss[NOISE_PUBLIC_KEY_LEN]);
5658360b13Sdlg static void	noise_mix_hash(
5758360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
5858360b13Sdlg 			const uint8_t *,
5958360b13Sdlg 			size_t);
6058360b13Sdlg static void	noise_mix_psk(
6158360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
6258360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
6358360b13Sdlg 			uint8_t [NOISE_SYMMETRIC_KEY_LEN],
6458360b13Sdlg 			const uint8_t [NOISE_SYMMETRIC_KEY_LEN]);
6558360b13Sdlg static void	noise_param_init(
6658360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
6758360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
6858360b13Sdlg 			const uint8_t [NOISE_PUBLIC_KEY_LEN]);
6958360b13Sdlg 
7058360b13Sdlg static void	noise_msg_encrypt(uint8_t *, const uint8_t *, size_t,
7158360b13Sdlg 			uint8_t [NOISE_SYMMETRIC_KEY_LEN],
7258360b13Sdlg 			uint8_t [NOISE_HASH_LEN]);
7358360b13Sdlg static int	noise_msg_decrypt(uint8_t *, const uint8_t *, size_t,
7458360b13Sdlg 			uint8_t [NOISE_SYMMETRIC_KEY_LEN],
7558360b13Sdlg 			uint8_t [NOISE_HASH_LEN]);
7658360b13Sdlg static void	noise_msg_ephemeral(
7758360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
7858360b13Sdlg 			uint8_t [NOISE_HASH_LEN],
7958360b13Sdlg 			const uint8_t src[NOISE_PUBLIC_KEY_LEN]);
8058360b13Sdlg 
8158360b13Sdlg static void	noise_tai64n_now(uint8_t [NOISE_TIMESTAMP_LEN]);
8258360b13Sdlg static int	noise_timer_expired(struct timespec *, time_t, long);
8358360b13Sdlg 
8458360b13Sdlg /* Set/Get noise parameters */
8558360b13Sdlg void
noise_local_init(struct noise_local * l,struct noise_upcall * upcall)8658360b13Sdlg noise_local_init(struct noise_local *l, struct noise_upcall *upcall)
8758360b13Sdlg {
8858360b13Sdlg 	bzero(l, sizeof(*l));
8958360b13Sdlg 	rw_init(&l->l_identity_lock, "noise_local_identity");
9058360b13Sdlg 	l->l_upcall = *upcall;
9158360b13Sdlg }
9258360b13Sdlg 
9358360b13Sdlg void
noise_local_lock_identity(struct noise_local * l)9458360b13Sdlg noise_local_lock_identity(struct noise_local *l)
9558360b13Sdlg {
9658360b13Sdlg 	rw_enter_write(&l->l_identity_lock);
9758360b13Sdlg }
9858360b13Sdlg 
9958360b13Sdlg void
noise_local_unlock_identity(struct noise_local * l)10058360b13Sdlg noise_local_unlock_identity(struct noise_local *l)
10158360b13Sdlg {
10258360b13Sdlg 	rw_exit_write(&l->l_identity_lock);
10358360b13Sdlg }
10458360b13Sdlg 
10558360b13Sdlg int
noise_local_set_private(struct noise_local * l,uint8_t private[NOISE_PUBLIC_KEY_LEN])10658360b13Sdlg noise_local_set_private(struct noise_local *l,
10758360b13Sdlg 			uint8_t private[NOISE_PUBLIC_KEY_LEN])
10858360b13Sdlg {
10958360b13Sdlg 	rw_assert_wrlock(&l->l_identity_lock);
11058360b13Sdlg 
11158360b13Sdlg 	memcpy(l->l_private, private, NOISE_PUBLIC_KEY_LEN);
11258360b13Sdlg 	curve25519_clamp_secret(l->l_private);
11358360b13Sdlg 	l->l_has_identity = curve25519_generate_public(l->l_public, private);
11458360b13Sdlg 
11558360b13Sdlg 	return l->l_has_identity ? 0 : ENXIO;
11658360b13Sdlg }
11758360b13Sdlg 
11858360b13Sdlg int
noise_local_keys(struct noise_local * l,uint8_t public[NOISE_PUBLIC_KEY_LEN],uint8_t private[NOISE_PUBLIC_KEY_LEN])11958360b13Sdlg noise_local_keys(struct noise_local *l, uint8_t public[NOISE_PUBLIC_KEY_LEN],
12058360b13Sdlg     uint8_t private[NOISE_PUBLIC_KEY_LEN])
12158360b13Sdlg {
12258360b13Sdlg 	int ret = 0;
12358360b13Sdlg 	rw_enter_read(&l->l_identity_lock);
12458360b13Sdlg 	if (l->l_has_identity) {
12558360b13Sdlg 		if (public != NULL)
12658360b13Sdlg 			memcpy(public, l->l_public, NOISE_PUBLIC_KEY_LEN);
12758360b13Sdlg 		if (private != NULL)
12858360b13Sdlg 			memcpy(private, l->l_private, NOISE_PUBLIC_KEY_LEN);
12958360b13Sdlg 	} else {
13058360b13Sdlg 		ret = ENXIO;
13158360b13Sdlg 	}
13258360b13Sdlg 	rw_exit_read(&l->l_identity_lock);
13358360b13Sdlg 	return ret;
13458360b13Sdlg }
13558360b13Sdlg 
13658360b13Sdlg void
noise_remote_init(struct noise_remote * r,uint8_t public[NOISE_PUBLIC_KEY_LEN],struct noise_local * l)13758360b13Sdlg noise_remote_init(struct noise_remote *r, uint8_t public[NOISE_PUBLIC_KEY_LEN],
13858360b13Sdlg     struct noise_local *l)
13958360b13Sdlg {
14058360b13Sdlg 	bzero(r, sizeof(*r));
14158360b13Sdlg 	memcpy(r->r_public, public, NOISE_PUBLIC_KEY_LEN);
14258360b13Sdlg 	rw_init(&r->r_handshake_lock, "noise_handshake");
143*efbb2e09Smvs 	mtx_init_flags(&r->r_keypair_mtx, IPL_NET, "noise_keypair", 0);
14458360b13Sdlg 
14558360b13Sdlg 	SLIST_INSERT_HEAD(&r->r_unused_keypairs, &r->r_keypair[0], kp_entry);
14658360b13Sdlg 	SLIST_INSERT_HEAD(&r->r_unused_keypairs, &r->r_keypair[1], kp_entry);
14758360b13Sdlg 	SLIST_INSERT_HEAD(&r->r_unused_keypairs, &r->r_keypair[2], kp_entry);
14858360b13Sdlg 
14958360b13Sdlg 	KASSERT(l != NULL);
15058360b13Sdlg 	r->r_local = l;
15158360b13Sdlg 
15258360b13Sdlg 	rw_enter_write(&l->l_identity_lock);
15358360b13Sdlg 	noise_remote_precompute(r);
15458360b13Sdlg 	rw_exit_write(&l->l_identity_lock);
15558360b13Sdlg }
15658360b13Sdlg 
15758360b13Sdlg int
noise_remote_set_psk(struct noise_remote * r,uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])15858360b13Sdlg noise_remote_set_psk(struct noise_remote *r,
15958360b13Sdlg     uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
16058360b13Sdlg {
16158360b13Sdlg 	int same;
16258360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
16358360b13Sdlg 	same = !timingsafe_bcmp(r->r_psk, psk, NOISE_SYMMETRIC_KEY_LEN);
16458360b13Sdlg 	if (!same) {
16558360b13Sdlg 		memcpy(r->r_psk, psk, NOISE_SYMMETRIC_KEY_LEN);
16658360b13Sdlg 	}
16758360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
16858360b13Sdlg 	return same ? EEXIST : 0;
16958360b13Sdlg }
17058360b13Sdlg 
17158360b13Sdlg int
noise_remote_keys(struct noise_remote * r,uint8_t public[NOISE_PUBLIC_KEY_LEN],uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])17258360b13Sdlg noise_remote_keys(struct noise_remote *r, uint8_t public[NOISE_PUBLIC_KEY_LEN],
17358360b13Sdlg     uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
17458360b13Sdlg {
17558360b13Sdlg 	static uint8_t null_psk[NOISE_SYMMETRIC_KEY_LEN];
17658360b13Sdlg 	int ret;
17758360b13Sdlg 
17858360b13Sdlg 	if (public != NULL)
17958360b13Sdlg 		memcpy(public, r->r_public, NOISE_PUBLIC_KEY_LEN);
18058360b13Sdlg 
18158360b13Sdlg 	rw_enter_read(&r->r_handshake_lock);
18258360b13Sdlg 	if (psk != NULL)
18358360b13Sdlg 		memcpy(psk, r->r_psk, NOISE_SYMMETRIC_KEY_LEN);
18458360b13Sdlg 	ret = timingsafe_bcmp(r->r_psk, null_psk, NOISE_SYMMETRIC_KEY_LEN);
18558360b13Sdlg 	rw_exit_read(&r->r_handshake_lock);
18658360b13Sdlg 
18758360b13Sdlg 	/* If r_psk != null_psk return 0, else ENOENT (no psk) */
18858360b13Sdlg 	return ret ? 0 : ENOENT;
18958360b13Sdlg }
19058360b13Sdlg 
19158360b13Sdlg void
noise_remote_precompute(struct noise_remote * r)19258360b13Sdlg noise_remote_precompute(struct noise_remote *r)
19358360b13Sdlg {
19458360b13Sdlg 	struct noise_local *l = r->r_local;
19558360b13Sdlg 	rw_assert_wrlock(&l->l_identity_lock);
19658360b13Sdlg 	if (!l->l_has_identity)
19758360b13Sdlg 		bzero(r->r_ss, NOISE_PUBLIC_KEY_LEN);
19858360b13Sdlg 	else if (!curve25519(r->r_ss, l->l_private, r->r_public))
19958360b13Sdlg 		bzero(r->r_ss, NOISE_PUBLIC_KEY_LEN);
20058360b13Sdlg 
20158360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
20258360b13Sdlg 	noise_remote_handshake_index_drop(r);
20358360b13Sdlg 	explicit_bzero(&r->r_handshake, sizeof(r->r_handshake));
20458360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
20558360b13Sdlg }
20658360b13Sdlg 
20758360b13Sdlg /* Handshake functions */
20858360b13Sdlg int
noise_create_initiation(struct noise_remote * r,uint32_t * s_idx,uint8_t ue[NOISE_PUBLIC_KEY_LEN],uint8_t es[NOISE_PUBLIC_KEY_LEN+NOISE_AUTHTAG_LEN],uint8_t ets[NOISE_TIMESTAMP_LEN+NOISE_AUTHTAG_LEN])20958360b13Sdlg noise_create_initiation(struct noise_remote *r, uint32_t *s_idx,
21058360b13Sdlg     uint8_t ue[NOISE_PUBLIC_KEY_LEN],
21158360b13Sdlg     uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN],
21258360b13Sdlg     uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN])
21358360b13Sdlg {
21458360b13Sdlg 	struct noise_handshake *hs = &r->r_handshake;
21558360b13Sdlg 	struct noise_local *l = r->r_local;
21658360b13Sdlg 	uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
21758360b13Sdlg 	int ret = EINVAL;
21858360b13Sdlg 
21958360b13Sdlg 	rw_enter_read(&l->l_identity_lock);
22058360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
22158360b13Sdlg 	if (!l->l_has_identity)
22258360b13Sdlg 		goto error;
22358360b13Sdlg 	noise_param_init(hs->hs_ck, hs->hs_hash, r->r_public);
22458360b13Sdlg 
22558360b13Sdlg 	/* e */
22658360b13Sdlg 	curve25519_generate_secret(hs->hs_e);
22758360b13Sdlg 	if (curve25519_generate_public(ue, hs->hs_e) == 0)
22858360b13Sdlg 		goto error;
22958360b13Sdlg 	noise_msg_ephemeral(hs->hs_ck, hs->hs_hash, ue);
23058360b13Sdlg 
23158360b13Sdlg 	/* es */
23258360b13Sdlg 	if (noise_mix_dh(hs->hs_ck, key, hs->hs_e, r->r_public) != 0)
23358360b13Sdlg 		goto error;
23458360b13Sdlg 
23558360b13Sdlg 	/* s */
23658360b13Sdlg 	noise_msg_encrypt(es, l->l_public,
23758360b13Sdlg 	    NOISE_PUBLIC_KEY_LEN, key, hs->hs_hash);
23858360b13Sdlg 
23958360b13Sdlg 	/* ss */
24058360b13Sdlg 	if (noise_mix_ss(hs->hs_ck, key, r->r_ss) != 0)
24158360b13Sdlg 		goto error;
24258360b13Sdlg 
24358360b13Sdlg 	/* {t} */
24458360b13Sdlg 	noise_tai64n_now(ets);
24558360b13Sdlg 	noise_msg_encrypt(ets, ets,
24658360b13Sdlg 	    NOISE_TIMESTAMP_LEN, key, hs->hs_hash);
24758360b13Sdlg 
24858360b13Sdlg 	noise_remote_handshake_index_drop(r);
24958360b13Sdlg 	hs->hs_state = CREATED_INITIATION;
25058360b13Sdlg 	hs->hs_local_index = noise_remote_handshake_index_get(r);
25158360b13Sdlg 	*s_idx = hs->hs_local_index;
25258360b13Sdlg 	ret = 0;
25358360b13Sdlg error:
25458360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
25558360b13Sdlg 	rw_exit_read(&l->l_identity_lock);
25658360b13Sdlg 	explicit_bzero(key, NOISE_SYMMETRIC_KEY_LEN);
25758360b13Sdlg 	return ret;
25858360b13Sdlg }
25958360b13Sdlg 
26058360b13Sdlg int
noise_consume_initiation(struct noise_local * l,struct noise_remote ** rp,uint32_t s_idx,uint8_t ue[NOISE_PUBLIC_KEY_LEN],uint8_t es[NOISE_PUBLIC_KEY_LEN+NOISE_AUTHTAG_LEN],uint8_t ets[NOISE_TIMESTAMP_LEN+NOISE_AUTHTAG_LEN])26158360b13Sdlg noise_consume_initiation(struct noise_local *l, struct noise_remote **rp,
26258360b13Sdlg     uint32_t s_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN],
26358360b13Sdlg     uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN],
26458360b13Sdlg     uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN])
26558360b13Sdlg {
26658360b13Sdlg 	struct noise_remote *r;
26758360b13Sdlg 	struct noise_handshake hs;
26858360b13Sdlg 	uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
26958360b13Sdlg 	uint8_t r_public[NOISE_PUBLIC_KEY_LEN];
27058360b13Sdlg 	uint8_t	timestamp[NOISE_TIMESTAMP_LEN];
27158360b13Sdlg 	int ret = EINVAL;
27258360b13Sdlg 
27358360b13Sdlg 	rw_enter_read(&l->l_identity_lock);
27458360b13Sdlg 	if (!l->l_has_identity)
27558360b13Sdlg 		goto error;
27658360b13Sdlg 	noise_param_init(hs.hs_ck, hs.hs_hash, l->l_public);
27758360b13Sdlg 
27858360b13Sdlg 	/* e */
27958360b13Sdlg 	noise_msg_ephemeral(hs.hs_ck, hs.hs_hash, ue);
28058360b13Sdlg 
28158360b13Sdlg 	/* es */
28258360b13Sdlg 	if (noise_mix_dh(hs.hs_ck, key, l->l_private, ue) != 0)
28358360b13Sdlg 		goto error;
28458360b13Sdlg 
28558360b13Sdlg 	/* s */
28658360b13Sdlg 	if (noise_msg_decrypt(r_public, es,
28758360b13Sdlg 	    NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN, key, hs.hs_hash) != 0)
28858360b13Sdlg 		goto error;
28958360b13Sdlg 
29058360b13Sdlg 	/* Lookup the remote we received from */
29158360b13Sdlg 	if ((r = l->l_upcall.u_remote_get(l->l_upcall.u_arg, r_public)) == NULL)
29258360b13Sdlg 		goto error;
29358360b13Sdlg 
29458360b13Sdlg 	/* ss */
29558360b13Sdlg 	if (noise_mix_ss(hs.hs_ck, key, r->r_ss) != 0)
29658360b13Sdlg 		goto error;
29758360b13Sdlg 
29858360b13Sdlg 	/* {t} */
29958360b13Sdlg 	if (noise_msg_decrypt(timestamp, ets,
30058360b13Sdlg 	    NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN, key, hs.hs_hash) != 0)
30158360b13Sdlg 		goto error;
30258360b13Sdlg 
30358360b13Sdlg 	memcpy(hs.hs_e, ue, NOISE_PUBLIC_KEY_LEN);
30458360b13Sdlg 
30558360b13Sdlg 	/* We have successfully computed the same results, now we ensure that
30658360b13Sdlg 	 * this is not an initiation replay, or a flood attack */
30758360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
30858360b13Sdlg 
30958360b13Sdlg 	/* Replay */
31058360b13Sdlg 	if (memcmp(timestamp, r->r_timestamp, NOISE_TIMESTAMP_LEN) > 0)
31158360b13Sdlg 		memcpy(r->r_timestamp, timestamp, NOISE_TIMESTAMP_LEN);
31258360b13Sdlg 	else
31358360b13Sdlg 		goto error_set;
31458360b13Sdlg 	/* Flood attack */
31558360b13Sdlg 	if (noise_timer_expired(&r->r_last_init, 0, REJECT_INTERVAL))
31658360b13Sdlg 		getnanouptime(&r->r_last_init);
31758360b13Sdlg 	else
31858360b13Sdlg 		goto error_set;
31958360b13Sdlg 
32058360b13Sdlg 	/* Ok, we're happy to accept this initiation now */
32158360b13Sdlg 	noise_remote_handshake_index_drop(r);
3221507f907Ssthen 	hs.hs_state = CONSUMED_INITIATION;
3231507f907Ssthen 	hs.hs_local_index = noise_remote_handshake_index_get(r);
3241507f907Ssthen 	hs.hs_remote_index = s_idx;
32558360b13Sdlg 	r->r_handshake = hs;
32658360b13Sdlg 	*rp = r;
32758360b13Sdlg 	ret = 0;
32858360b13Sdlg error_set:
32958360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
33058360b13Sdlg error:
33158360b13Sdlg 	rw_exit_read(&l->l_identity_lock);
33258360b13Sdlg 	explicit_bzero(key, NOISE_SYMMETRIC_KEY_LEN);
33358360b13Sdlg 	explicit_bzero(&hs, sizeof(hs));
33458360b13Sdlg 	return ret;
33558360b13Sdlg }
33658360b13Sdlg 
33758360b13Sdlg int
noise_create_response(struct noise_remote * r,uint32_t * s_idx,uint32_t * r_idx,uint8_t ue[NOISE_PUBLIC_KEY_LEN],uint8_t en[0+NOISE_AUTHTAG_LEN])33858360b13Sdlg noise_create_response(struct noise_remote *r, uint32_t *s_idx, uint32_t *r_idx,
33958360b13Sdlg     uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t en[0 + NOISE_AUTHTAG_LEN])
34058360b13Sdlg {
34158360b13Sdlg 	struct noise_handshake *hs = &r->r_handshake;
34258360b13Sdlg 	uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
34358360b13Sdlg 	uint8_t e[NOISE_PUBLIC_KEY_LEN];
34458360b13Sdlg 	int ret = EINVAL;
34558360b13Sdlg 
34658360b13Sdlg 	rw_enter_read(&r->r_local->l_identity_lock);
34758360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
34858360b13Sdlg 
34958360b13Sdlg 	if (hs->hs_state != CONSUMED_INITIATION)
35058360b13Sdlg 		goto error;
35158360b13Sdlg 
35258360b13Sdlg 	/* e */
35358360b13Sdlg 	curve25519_generate_secret(e);
35458360b13Sdlg 	if (curve25519_generate_public(ue, e) == 0)
35558360b13Sdlg 		goto error;
35658360b13Sdlg 	noise_msg_ephemeral(hs->hs_ck, hs->hs_hash, ue);
35758360b13Sdlg 
35858360b13Sdlg 	/* ee */
35958360b13Sdlg 	if (noise_mix_dh(hs->hs_ck, NULL, e, hs->hs_e) != 0)
36058360b13Sdlg 		goto error;
36158360b13Sdlg 
36258360b13Sdlg 	/* se */
36358360b13Sdlg 	if (noise_mix_dh(hs->hs_ck, NULL, e, r->r_public) != 0)
36458360b13Sdlg 		goto error;
36558360b13Sdlg 
36658360b13Sdlg 	/* psk */
36758360b13Sdlg 	noise_mix_psk(hs->hs_ck, hs->hs_hash, key, r->r_psk);
36858360b13Sdlg 
36958360b13Sdlg 	/* {} */
37058360b13Sdlg 	noise_msg_encrypt(en, NULL, 0, key, hs->hs_hash);
37158360b13Sdlg 
37258360b13Sdlg 	hs->hs_state = CREATED_RESPONSE;
37358360b13Sdlg 	*r_idx = hs->hs_remote_index;
37458360b13Sdlg 	*s_idx = hs->hs_local_index;
37558360b13Sdlg 	ret = 0;
37658360b13Sdlg error:
37758360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
37858360b13Sdlg 	rw_exit_read(&r->r_local->l_identity_lock);
37958360b13Sdlg 	explicit_bzero(key, NOISE_SYMMETRIC_KEY_LEN);
38058360b13Sdlg 	explicit_bzero(e, NOISE_PUBLIC_KEY_LEN);
38158360b13Sdlg 	return ret;
38258360b13Sdlg }
38358360b13Sdlg 
38458360b13Sdlg int
noise_consume_response(struct noise_remote * r,uint32_t s_idx,uint32_t r_idx,uint8_t ue[NOISE_PUBLIC_KEY_LEN],uint8_t en[0+NOISE_AUTHTAG_LEN])38558360b13Sdlg noise_consume_response(struct noise_remote *r, uint32_t s_idx, uint32_t r_idx,
38658360b13Sdlg     uint8_t ue[NOISE_PUBLIC_KEY_LEN], uint8_t en[0 + NOISE_AUTHTAG_LEN])
38758360b13Sdlg {
38858360b13Sdlg 	struct noise_local *l = r->r_local;
38958360b13Sdlg 	struct noise_handshake hs;
39058360b13Sdlg 	uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
39158360b13Sdlg 	uint8_t preshared_key[NOISE_PUBLIC_KEY_LEN];
39258360b13Sdlg 	int ret = EINVAL;
39358360b13Sdlg 
39458360b13Sdlg 	rw_enter_read(&l->l_identity_lock);
39558360b13Sdlg 	if (!l->l_has_identity)
39658360b13Sdlg 		goto error;
39758360b13Sdlg 
39858360b13Sdlg 	rw_enter_read(&r->r_handshake_lock);
39958360b13Sdlg 	hs = r->r_handshake;
40058360b13Sdlg 	memcpy(preshared_key, r->r_psk, NOISE_SYMMETRIC_KEY_LEN);
40158360b13Sdlg 	rw_exit_read(&r->r_handshake_lock);
40258360b13Sdlg 
40358360b13Sdlg 	if (hs.hs_state != CREATED_INITIATION ||
40458360b13Sdlg 	    hs.hs_local_index != r_idx)
40558360b13Sdlg 		goto error;
40658360b13Sdlg 
40758360b13Sdlg 	/* e */
40858360b13Sdlg 	noise_msg_ephemeral(hs.hs_ck, hs.hs_hash, ue);
40958360b13Sdlg 
41058360b13Sdlg 	/* ee */
41158360b13Sdlg 	if (noise_mix_dh(hs.hs_ck, NULL, hs.hs_e, ue) != 0)
41258360b13Sdlg 		goto error;
41358360b13Sdlg 
41458360b13Sdlg 	/* se */
41558360b13Sdlg 	if (noise_mix_dh(hs.hs_ck, NULL, l->l_private, ue) != 0)
41658360b13Sdlg 		goto error;
41758360b13Sdlg 
41858360b13Sdlg 	/* psk */
41958360b13Sdlg 	noise_mix_psk(hs.hs_ck, hs.hs_hash, key, preshared_key);
42058360b13Sdlg 
42158360b13Sdlg 	/* {} */
42258360b13Sdlg 	if (noise_msg_decrypt(NULL, en,
42358360b13Sdlg 	    0 + NOISE_AUTHTAG_LEN, key, hs.hs_hash) != 0)
42458360b13Sdlg 		goto error;
42558360b13Sdlg 
42658360b13Sdlg 	hs.hs_remote_index = s_idx;
42758360b13Sdlg 
42858360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
42958360b13Sdlg 	if (r->r_handshake.hs_state == hs.hs_state &&
43058360b13Sdlg 	    r->r_handshake.hs_local_index == hs.hs_local_index) {
43158360b13Sdlg 		r->r_handshake = hs;
43258360b13Sdlg 		r->r_handshake.hs_state = CONSUMED_RESPONSE;
43358360b13Sdlg 		ret = 0;
43458360b13Sdlg 	}
43558360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
43658360b13Sdlg error:
43758360b13Sdlg 	rw_exit_read(&l->l_identity_lock);
43858360b13Sdlg 	explicit_bzero(&hs, sizeof(hs));
43958360b13Sdlg 	explicit_bzero(key, NOISE_SYMMETRIC_KEY_LEN);
44058360b13Sdlg 	return ret;
44158360b13Sdlg }
44258360b13Sdlg 
44358360b13Sdlg int
noise_remote_begin_session(struct noise_remote * r)44458360b13Sdlg noise_remote_begin_session(struct noise_remote *r)
44558360b13Sdlg {
44658360b13Sdlg 	struct noise_handshake *hs = &r->r_handshake;
44758360b13Sdlg 	struct noise_keypair kp, *next, *current, *previous;
44858360b13Sdlg 
44958360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
45058360b13Sdlg 
45158360b13Sdlg 	/* We now derive the keypair from the handshake */
45258360b13Sdlg 	if (hs->hs_state == CONSUMED_RESPONSE) {
45358360b13Sdlg 		kp.kp_is_initiator = 1;
45458360b13Sdlg 		noise_kdf(kp.kp_send, kp.kp_recv, NULL, NULL,
45558360b13Sdlg 		    NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
45658360b13Sdlg 		    hs->hs_ck);
45758360b13Sdlg 	} else if (hs->hs_state == CREATED_RESPONSE) {
45858360b13Sdlg 		kp.kp_is_initiator = 0;
45958360b13Sdlg 		noise_kdf(kp.kp_recv, kp.kp_send, NULL, NULL,
46058360b13Sdlg 		    NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
46158360b13Sdlg 		    hs->hs_ck);
46258360b13Sdlg 	} else {
463af1b164dSjasper 		rw_exit_write(&r->r_handshake_lock);
46458360b13Sdlg 		return EINVAL;
46558360b13Sdlg 	}
46658360b13Sdlg 
46758360b13Sdlg 	kp.kp_valid = 1;
46858360b13Sdlg 	kp.kp_local_index = hs->hs_local_index;
46958360b13Sdlg 	kp.kp_remote_index = hs->hs_remote_index;
47058360b13Sdlg 	getnanouptime(&kp.kp_birthdate);
47158360b13Sdlg 	bzero(&kp.kp_ctr, sizeof(kp.kp_ctr));
472*efbb2e09Smvs 	mtx_init_flags(&kp.kp_ctr.c_mtx, IPL_NET, "noise_counter", 0);
47358360b13Sdlg 
47458360b13Sdlg 	/* Now we need to add_new_keypair */
475*efbb2e09Smvs 	mtx_enter(&r->r_keypair_mtx);
47658360b13Sdlg 	next = r->r_next;
47758360b13Sdlg 	current = r->r_current;
47858360b13Sdlg 	previous = r->r_previous;
47958360b13Sdlg 
48058360b13Sdlg 	if (kp.kp_is_initiator) {
48158360b13Sdlg 		if (next != NULL) {
48258360b13Sdlg 			r->r_next = NULL;
48358360b13Sdlg 			r->r_previous = next;
48458360b13Sdlg 			noise_remote_keypair_free(r, current);
48558360b13Sdlg 		} else {
48658360b13Sdlg 			r->r_previous = current;
48758360b13Sdlg 		}
48858360b13Sdlg 
48958360b13Sdlg 		noise_remote_keypair_free(r, previous);
49058360b13Sdlg 
49158360b13Sdlg 		r->r_current = noise_remote_keypair_allocate(r);
49258360b13Sdlg 		*r->r_current = kp;
49358360b13Sdlg 	} else {
49458360b13Sdlg 		noise_remote_keypair_free(r, next);
49558360b13Sdlg 		r->r_previous = NULL;
49658360b13Sdlg 		noise_remote_keypair_free(r, previous);
49758360b13Sdlg 
49858360b13Sdlg 		r->r_next = noise_remote_keypair_allocate(r);
49958360b13Sdlg 		*r->r_next = kp;
50058360b13Sdlg 	}
501*efbb2e09Smvs 	mtx_leave(&r->r_keypair_mtx);
50258360b13Sdlg 
50358360b13Sdlg 	explicit_bzero(&r->r_handshake, sizeof(r->r_handshake));
50458360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
50558360b13Sdlg 
50658360b13Sdlg 	explicit_bzero(&kp, sizeof(kp));
50758360b13Sdlg 	return 0;
50858360b13Sdlg }
50958360b13Sdlg 
51058360b13Sdlg void
noise_remote_clear(struct noise_remote * r)51158360b13Sdlg noise_remote_clear(struct noise_remote *r)
51258360b13Sdlg {
51358360b13Sdlg 	rw_enter_write(&r->r_handshake_lock);
51458360b13Sdlg 	noise_remote_handshake_index_drop(r);
51558360b13Sdlg 	explicit_bzero(&r->r_handshake, sizeof(r->r_handshake));
51658360b13Sdlg 	rw_exit_write(&r->r_handshake_lock);
51758360b13Sdlg 
518*efbb2e09Smvs 	mtx_enter(&r->r_keypair_mtx);
51958360b13Sdlg 	noise_remote_keypair_free(r, r->r_next);
52058360b13Sdlg 	noise_remote_keypair_free(r, r->r_current);
52158360b13Sdlg 	noise_remote_keypair_free(r, r->r_previous);
52258360b13Sdlg 	r->r_next = NULL;
52358360b13Sdlg 	r->r_current = NULL;
52458360b13Sdlg 	r->r_previous = NULL;
525*efbb2e09Smvs 	mtx_leave(&r->r_keypair_mtx);
52658360b13Sdlg }
52758360b13Sdlg 
52858360b13Sdlg void
noise_remote_expire_current(struct noise_remote * r)52958360b13Sdlg noise_remote_expire_current(struct noise_remote *r)
53058360b13Sdlg {
531*efbb2e09Smvs 	mtx_enter(&r->r_keypair_mtx);
53258360b13Sdlg 	if (r->r_next != NULL)
53358360b13Sdlg 		r->r_next->kp_valid = 0;
53458360b13Sdlg 	if (r->r_current != NULL)
53558360b13Sdlg 		r->r_current->kp_valid = 0;
536*efbb2e09Smvs 	mtx_leave(&r->r_keypair_mtx);
53758360b13Sdlg }
53858360b13Sdlg 
53958360b13Sdlg int
noise_remote_ready(struct noise_remote * r)54058360b13Sdlg noise_remote_ready(struct noise_remote *r)
54158360b13Sdlg {
54258360b13Sdlg 	struct noise_keypair *kp;
54358360b13Sdlg 	int ret;
54458360b13Sdlg 
545*efbb2e09Smvs 	mtx_enter(&r->r_keypair_mtx);
54658360b13Sdlg 	/* kp_ctr isn't locked here, we're happy to accept a racy read. */
54758360b13Sdlg 	if ((kp = r->r_current) == NULL ||
54858360b13Sdlg 	    !kp->kp_valid ||
54958360b13Sdlg 	    noise_timer_expired(&kp->kp_birthdate, REJECT_AFTER_TIME, 0) ||
55058360b13Sdlg 	    kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES ||
55158360b13Sdlg 	    kp->kp_ctr.c_send >= REJECT_AFTER_MESSAGES)
55258360b13Sdlg 		ret = EINVAL;
55358360b13Sdlg 	else
55458360b13Sdlg 		ret = 0;
555*efbb2e09Smvs 	mtx_leave(&r->r_keypair_mtx);
55658360b13Sdlg 	return ret;
55758360b13Sdlg }
55858360b13Sdlg 
55958360b13Sdlg int
noise_remote_encrypt(struct noise_remote * r,uint32_t * r_idx,uint64_t * nonce,uint8_t * buf,size_t buflen)56058360b13Sdlg noise_remote_encrypt(struct noise_remote *r, uint32_t *r_idx, uint64_t *nonce,
56158360b13Sdlg     uint8_t *buf, size_t buflen)
56258360b13Sdlg {
56358360b13Sdlg 	struct noise_keypair *kp;
56458360b13Sdlg 	int ret = EINVAL;
56558360b13Sdlg 
566*efbb2e09Smvs 	mtx_enter(&r->r_keypair_mtx);
56758360b13Sdlg 	if ((kp = r->r_current) == NULL)
56858360b13Sdlg 		goto error;
56958360b13Sdlg 
57058360b13Sdlg 	/* We confirm that our values are within our tolerances. We want:
57158360b13Sdlg 	 *  - a valid keypair
57258360b13Sdlg 	 *  - our keypair to be less than REJECT_AFTER_TIME seconds old
57358360b13Sdlg 	 *  - our receive counter to be less than REJECT_AFTER_MESSAGES
57458360b13Sdlg 	 *  - our send counter to be less than REJECT_AFTER_MESSAGES
57558360b13Sdlg 	 *
57658360b13Sdlg 	 * kp_ctr isn't locked here, we're happy to accept a racy read. */
57758360b13Sdlg 	if (!kp->kp_valid ||
57858360b13Sdlg 	    noise_timer_expired(&kp->kp_birthdate, REJECT_AFTER_TIME, 0) ||
57958360b13Sdlg 	    kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES ||
58058360b13Sdlg 	    ((*nonce = noise_counter_send(&kp->kp_ctr)) > REJECT_AFTER_MESSAGES))
58158360b13Sdlg 		goto error;
58258360b13Sdlg 
58358360b13Sdlg 	/* We encrypt into the same buffer, so the caller must ensure that buf
58458360b13Sdlg 	 * has NOISE_AUTHTAG_LEN bytes to store the MAC. The nonce and index
58558360b13Sdlg 	 * are passed back out to the caller through the provided data pointer. */
58658360b13Sdlg 	*r_idx = kp->kp_remote_index;
58758360b13Sdlg 	chacha20poly1305_encrypt(buf, buf, buflen,
58858360b13Sdlg 	    NULL, 0, *nonce, kp->kp_send);
58958360b13Sdlg 
59058360b13Sdlg 	/* If our values are still within tolerances, but we are approaching
59158360b13Sdlg 	 * the tolerances, we notify the caller with ESTALE that they should
59258360b13Sdlg 	 * establish a new keypair. The current keypair can continue to be used
59358360b13Sdlg 	 * until the tolerances are hit. We notify if:
59458360b13Sdlg 	 *  - our send counter is valid and not less than REKEY_AFTER_MESSAGES
59558360b13Sdlg 	 *  - we're the initiator and our keypair is older than
59658360b13Sdlg 	 *    REKEY_AFTER_TIME seconds */
59758360b13Sdlg 	ret = ESTALE;
59858360b13Sdlg 	if ((kp->kp_valid && *nonce >= REKEY_AFTER_MESSAGES) ||
59958360b13Sdlg 	    (kp->kp_is_initiator &&
60058360b13Sdlg 	    noise_timer_expired(&kp->kp_birthdate, REKEY_AFTER_TIME, 0)))
60158360b13Sdlg 		goto error;
60258360b13Sdlg 
60358360b13Sdlg 	ret = 0;
60458360b13Sdlg error:
605*efbb2e09Smvs 	mtx_leave(&r->r_keypair_mtx);
60658360b13Sdlg 	return ret;
60758360b13Sdlg }
60858360b13Sdlg 
60958360b13Sdlg int
noise_remote_decrypt(struct noise_remote * r,uint32_t r_idx,uint64_t nonce,uint8_t * buf,size_t buflen)61058360b13Sdlg noise_remote_decrypt(struct noise_remote *r, uint32_t r_idx, uint64_t nonce,
61158360b13Sdlg     uint8_t *buf, size_t buflen)
61258360b13Sdlg {
61358360b13Sdlg 	struct noise_keypair *kp;
61458360b13Sdlg 	int ret = EINVAL;
61558360b13Sdlg 
61658360b13Sdlg 	/* We retrieve the keypair corresponding to the provided index. We
61758360b13Sdlg 	 * attempt the current keypair first as that is most likely. We also
61858360b13Sdlg 	 * want to make sure that the keypair is valid as it would be
61958360b13Sdlg 	 * catastrophic to decrypt against a zero'ed keypair. */
620*efbb2e09Smvs 	mtx_enter(&r->r_keypair_mtx);
62158360b13Sdlg 
62258360b13Sdlg 	if (r->r_current != NULL && r->r_current->kp_local_index == r_idx) {
62358360b13Sdlg 		kp = r->r_current;
62458360b13Sdlg 	} else if (r->r_previous != NULL && r->r_previous->kp_local_index == r_idx) {
62558360b13Sdlg 		kp = r->r_previous;
62658360b13Sdlg 	} else if (r->r_next != NULL && r->r_next->kp_local_index == r_idx) {
62758360b13Sdlg 		kp = r->r_next;
62858360b13Sdlg 	} else {
62958360b13Sdlg 		goto error;
63058360b13Sdlg 	}
63158360b13Sdlg 
63258360b13Sdlg 	/* We confirm that our values are within our tolerances. These values
63358360b13Sdlg 	 * are the same as the encrypt routine.
63458360b13Sdlg 	 *
63558360b13Sdlg 	 * kp_ctr isn't locked here, we're happy to accept a racy read. */
63658360b13Sdlg 	if (noise_timer_expired(&kp->kp_birthdate, REJECT_AFTER_TIME, 0) ||
63758360b13Sdlg 	    kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES)
63858360b13Sdlg 		goto error;
63958360b13Sdlg 
64058360b13Sdlg 	/* Decrypt, then validate the counter. We don't want to validate the
64158360b13Sdlg 	 * counter before decrypting as we do not know the message is authentic
64258360b13Sdlg 	 * prior to decryption. */
64358360b13Sdlg 	if (chacha20poly1305_decrypt(buf, buf, buflen,
64458360b13Sdlg 	    NULL, 0, nonce, kp->kp_recv) == 0)
64558360b13Sdlg 		goto error;
64658360b13Sdlg 
64758360b13Sdlg 	if (noise_counter_recv(&kp->kp_ctr, nonce) != 0)
64858360b13Sdlg 		goto error;
64958360b13Sdlg 
65058360b13Sdlg 	/* If we've received the handshake confirming data packet then move the
65158360b13Sdlg 	 * next keypair into current. If we do slide the next keypair in, then
65258360b13Sdlg 	 * we skip the REKEY_AFTER_TIME_RECV check. This is safe to do as a
65358360b13Sdlg 	 * data packet can't confirm a session that we are an INITIATOR of. */
65458360b13Sdlg 	if (kp == r->r_next) {
65558360b13Sdlg 		if (kp == r->r_next && kp->kp_local_index == r_idx) {
65658360b13Sdlg 			noise_remote_keypair_free(r, r->r_previous);
65758360b13Sdlg 			r->r_previous = r->r_current;
65858360b13Sdlg 			r->r_current = r->r_next;
65958360b13Sdlg 			r->r_next = NULL;
66058360b13Sdlg 
66158360b13Sdlg 			ret = ECONNRESET;
66258360b13Sdlg 			goto error;
66358360b13Sdlg 		}
66458360b13Sdlg 	}
66558360b13Sdlg 
66658360b13Sdlg 	/* Similar to when we encrypt, we want to notify the caller when we
66758360b13Sdlg 	 * are approaching our tolerances. We notify if:
66858360b13Sdlg 	 *  - we're the initiator and the current keypair is older than
66958360b13Sdlg 	 *    REKEY_AFTER_TIME_RECV seconds. */
67058360b13Sdlg 	ret = ESTALE;
67158360b13Sdlg 	kp = r->r_current;
67258360b13Sdlg 	if (kp != NULL &&
67358360b13Sdlg 	    kp->kp_valid &&
67458360b13Sdlg 	    kp->kp_is_initiator &&
67558360b13Sdlg 	    noise_timer_expired(&kp->kp_birthdate, REKEY_AFTER_TIME_RECV, 0))
67658360b13Sdlg 		goto error;
67758360b13Sdlg 
67858360b13Sdlg 	ret = 0;
67958360b13Sdlg 
68058360b13Sdlg error:
681*efbb2e09Smvs 	mtx_leave(&r->r_keypair_mtx);
68258360b13Sdlg 	return ret;
68358360b13Sdlg }
68458360b13Sdlg 
68558360b13Sdlg /* Private functions - these should not be called outside this file under any
68658360b13Sdlg  * circumstances. */
68758360b13Sdlg static struct noise_keypair *
noise_remote_keypair_allocate(struct noise_remote * r)68858360b13Sdlg noise_remote_keypair_allocate(struct noise_remote *r)
68958360b13Sdlg {
69058360b13Sdlg 	struct noise_keypair *kp;
69158360b13Sdlg 	kp = SLIST_FIRST(&r->r_unused_keypairs);
69258360b13Sdlg 	SLIST_REMOVE_HEAD(&r->r_unused_keypairs, kp_entry);
69358360b13Sdlg 	return kp;
69458360b13Sdlg }
69558360b13Sdlg 
69658360b13Sdlg static void
noise_remote_keypair_free(struct noise_remote * r,struct noise_keypair * kp)69758360b13Sdlg noise_remote_keypair_free(struct noise_remote *r, struct noise_keypair *kp)
69858360b13Sdlg {
69958360b13Sdlg 	struct noise_upcall *u = &r->r_local->l_upcall;
70058360b13Sdlg 	if (kp != NULL) {
70158360b13Sdlg 		SLIST_INSERT_HEAD(&r->r_unused_keypairs, kp, kp_entry);
70258360b13Sdlg 		u->u_index_drop(u->u_arg, kp->kp_local_index);
70358360b13Sdlg 		bzero(kp->kp_send, sizeof(kp->kp_send));
70458360b13Sdlg 		bzero(kp->kp_recv, sizeof(kp->kp_recv));
70558360b13Sdlg 	}
70658360b13Sdlg }
70758360b13Sdlg 
70858360b13Sdlg static uint32_t
noise_remote_handshake_index_get(struct noise_remote * r)70958360b13Sdlg noise_remote_handshake_index_get(struct noise_remote *r)
71058360b13Sdlg {
71158360b13Sdlg 	struct noise_upcall *u = &r->r_local->l_upcall;
71258360b13Sdlg 	return u->u_index_set(u->u_arg, r);
71358360b13Sdlg }
71458360b13Sdlg 
71558360b13Sdlg static void
noise_remote_handshake_index_drop(struct noise_remote * r)71658360b13Sdlg noise_remote_handshake_index_drop(struct noise_remote *r)
71758360b13Sdlg {
71858360b13Sdlg 	struct noise_handshake *hs = &r->r_handshake;
71958360b13Sdlg 	struct noise_upcall *u = &r->r_local->l_upcall;
72058360b13Sdlg 	rw_assert_wrlock(&r->r_handshake_lock);
72158360b13Sdlg 	if (hs->hs_state != HS_ZEROED)
72258360b13Sdlg 		u->u_index_drop(u->u_arg, hs->hs_local_index);
72358360b13Sdlg }
72458360b13Sdlg 
72558360b13Sdlg static uint64_t
noise_counter_send(struct noise_counter * ctr)72658360b13Sdlg noise_counter_send(struct noise_counter *ctr)
72758360b13Sdlg {
72858360b13Sdlg #ifdef __LP64__
72958360b13Sdlg 	return atomic_inc_long_nv((u_long *)&ctr->c_send) - 1;
73058360b13Sdlg #else
73158360b13Sdlg 	uint64_t ret;
732*efbb2e09Smvs 	mtx_enter(&ctr->c_mtx);
73358360b13Sdlg 	ret = ctr->c_send++;
734*efbb2e09Smvs 	mtx_leave(&ctr->c_mtx);
73558360b13Sdlg 	return ret;
73658360b13Sdlg #endif
73758360b13Sdlg }
73858360b13Sdlg 
73958360b13Sdlg static int
noise_counter_recv(struct noise_counter * ctr,uint64_t recv)74058360b13Sdlg noise_counter_recv(struct noise_counter *ctr, uint64_t recv)
74158360b13Sdlg {
74258360b13Sdlg 	uint64_t i, top, index_recv, index_ctr;
74358360b13Sdlg 	unsigned long bit;
74458360b13Sdlg 	int ret = EEXIST;
74558360b13Sdlg 
746*efbb2e09Smvs 	mtx_enter(&ctr->c_mtx);
74758360b13Sdlg 
74858360b13Sdlg 	/* Check that the recv counter is valid */
74958360b13Sdlg 	if (ctr->c_recv >= REJECT_AFTER_MESSAGES ||
75058360b13Sdlg 	    recv >= REJECT_AFTER_MESSAGES)
75158360b13Sdlg 		goto error;
75258360b13Sdlg 
75358360b13Sdlg 	/* If the packet is out of the window, invalid */
75458360b13Sdlg 	if (recv + COUNTER_WINDOW_SIZE < ctr->c_recv)
75558360b13Sdlg 		goto error;
75658360b13Sdlg 
75758360b13Sdlg 	/* If the new counter is ahead of the current counter, we'll need to
75858360b13Sdlg 	 * zero out the bitmap that has previously been used */
75958360b13Sdlg 	index_recv = recv / COUNTER_BITS;
76058360b13Sdlg 	index_ctr = ctr->c_recv / COUNTER_BITS;
76158360b13Sdlg 
76258360b13Sdlg 	if (recv > ctr->c_recv) {
76358360b13Sdlg 		top = MIN(index_recv - index_ctr, COUNTER_NUM);
76458360b13Sdlg 		for (i = 1; i <= top; i++)
76558360b13Sdlg 			ctr->c_backtrack[
76658360b13Sdlg 			    (i + index_ctr) & (COUNTER_NUM - 1)] = 0;
76758360b13Sdlg 		ctr->c_recv = recv;
76858360b13Sdlg 	}
76958360b13Sdlg 
77058360b13Sdlg 	index_recv %= COUNTER_NUM;
77158360b13Sdlg 	bit = 1ul << (recv % COUNTER_BITS);
77258360b13Sdlg 
77358360b13Sdlg 	if (ctr->c_backtrack[index_recv] & bit)
77458360b13Sdlg 		goto error;
77558360b13Sdlg 
77658360b13Sdlg 	ctr->c_backtrack[index_recv] |= bit;
77758360b13Sdlg 
77858360b13Sdlg 	ret = 0;
77958360b13Sdlg error:
780*efbb2e09Smvs 	mtx_leave(&ctr->c_mtx);
78158360b13Sdlg 	return ret;
78258360b13Sdlg }
78358360b13Sdlg 
78458360b13Sdlg static void
noise_kdf(uint8_t * a,uint8_t * b,uint8_t * c,const uint8_t * x,size_t a_len,size_t b_len,size_t c_len,size_t x_len,const uint8_t ck[NOISE_HASH_LEN])78558360b13Sdlg noise_kdf(uint8_t *a, uint8_t *b, uint8_t *c, const uint8_t *x,
78658360b13Sdlg     size_t a_len, size_t b_len, size_t c_len, size_t x_len,
78758360b13Sdlg     const uint8_t ck[NOISE_HASH_LEN])
78858360b13Sdlg {
78958360b13Sdlg 	uint8_t out[BLAKE2S_HASH_SIZE + 1];
79058360b13Sdlg 	uint8_t sec[BLAKE2S_HASH_SIZE];
79158360b13Sdlg 
79258360b13Sdlg 	KASSERT(a_len <= BLAKE2S_HASH_SIZE && b_len <= BLAKE2S_HASH_SIZE &&
79358360b13Sdlg 			c_len <= BLAKE2S_HASH_SIZE);
79458360b13Sdlg 	KASSERT(!(b || b_len || c || c_len) || (a && a_len));
79558360b13Sdlg 	KASSERT(!(c || c_len) || (b && b_len));
79658360b13Sdlg 
79758360b13Sdlg 	/* Extract entropy from "x" into sec */
79858360b13Sdlg 	blake2s_hmac(sec, x, ck, BLAKE2S_HASH_SIZE, x_len, NOISE_HASH_LEN);
79958360b13Sdlg 
80058360b13Sdlg 	if (a == NULL || a_len == 0)
80158360b13Sdlg 		goto out;
80258360b13Sdlg 
80358360b13Sdlg 	/* Expand first key: key = sec, data = 0x1 */
80458360b13Sdlg 	out[0] = 1;
80558360b13Sdlg 	blake2s_hmac(out, out, sec, BLAKE2S_HASH_SIZE, 1, BLAKE2S_HASH_SIZE);
80658360b13Sdlg 	memcpy(a, out, a_len);
80758360b13Sdlg 
80858360b13Sdlg 	if (b == NULL || b_len == 0)
80958360b13Sdlg 		goto out;
81058360b13Sdlg 
81158360b13Sdlg 	/* Expand second key: key = sec, data = "a" || 0x2 */
81258360b13Sdlg 	out[BLAKE2S_HASH_SIZE] = 2;
81358360b13Sdlg 	blake2s_hmac(out, out, sec, BLAKE2S_HASH_SIZE, BLAKE2S_HASH_SIZE + 1,
81458360b13Sdlg 			BLAKE2S_HASH_SIZE);
81558360b13Sdlg 	memcpy(b, out, b_len);
81658360b13Sdlg 
81758360b13Sdlg 	if (c == NULL || c_len == 0)
81858360b13Sdlg 		goto out;
81958360b13Sdlg 
82058360b13Sdlg 	/* Expand third key: key = sec, data = "b" || 0x3 */
82158360b13Sdlg 	out[BLAKE2S_HASH_SIZE] = 3;
82258360b13Sdlg 	blake2s_hmac(out, out, sec, BLAKE2S_HASH_SIZE, BLAKE2S_HASH_SIZE + 1,
82358360b13Sdlg 			BLAKE2S_HASH_SIZE);
82458360b13Sdlg 	memcpy(c, out, c_len);
82558360b13Sdlg 
82658360b13Sdlg out:
82758360b13Sdlg 	/* Clear sensitive data from stack */
82858360b13Sdlg 	explicit_bzero(sec, BLAKE2S_HASH_SIZE);
82958360b13Sdlg 	explicit_bzero(out, BLAKE2S_HASH_SIZE + 1);
83058360b13Sdlg }
83158360b13Sdlg 
83258360b13Sdlg static int
noise_mix_dh(uint8_t ck[NOISE_HASH_LEN],uint8_t key[NOISE_SYMMETRIC_KEY_LEN],const uint8_t private[NOISE_PUBLIC_KEY_LEN],const uint8_t public[NOISE_PUBLIC_KEY_LEN])83358360b13Sdlg noise_mix_dh(uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
83458360b13Sdlg     const uint8_t private[NOISE_PUBLIC_KEY_LEN],
83558360b13Sdlg     const uint8_t public[NOISE_PUBLIC_KEY_LEN])
83658360b13Sdlg {
83758360b13Sdlg 	uint8_t dh[NOISE_PUBLIC_KEY_LEN];
83858360b13Sdlg 
83958360b13Sdlg 	if (!curve25519(dh, private, public))
84058360b13Sdlg 		return EINVAL;
84158360b13Sdlg 	noise_kdf(ck, key, NULL, dh,
84258360b13Sdlg 	    NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ck);
84358360b13Sdlg 	explicit_bzero(dh, NOISE_PUBLIC_KEY_LEN);
84458360b13Sdlg 	return 0;
84558360b13Sdlg }
84658360b13Sdlg 
84758360b13Sdlg static int
noise_mix_ss(uint8_t ck[NOISE_HASH_LEN],uint8_t key[NOISE_SYMMETRIC_KEY_LEN],const uint8_t ss[NOISE_PUBLIC_KEY_LEN])84858360b13Sdlg noise_mix_ss(uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
84958360b13Sdlg     const uint8_t ss[NOISE_PUBLIC_KEY_LEN])
85058360b13Sdlg {
85158360b13Sdlg 	static uint8_t null_point[NOISE_PUBLIC_KEY_LEN];
85258360b13Sdlg 	if (timingsafe_bcmp(ss, null_point, NOISE_PUBLIC_KEY_LEN) == 0)
85358360b13Sdlg 		return ENOENT;
85458360b13Sdlg 	noise_kdf(ck, key, NULL, ss,
85558360b13Sdlg 	    NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN, ck);
85658360b13Sdlg 	return 0;
85758360b13Sdlg }
85858360b13Sdlg 
85958360b13Sdlg static void
noise_mix_hash(uint8_t hash[NOISE_HASH_LEN],const uint8_t * src,size_t src_len)86058360b13Sdlg noise_mix_hash(uint8_t hash[NOISE_HASH_LEN], const uint8_t *src,
86158360b13Sdlg     size_t src_len)
86258360b13Sdlg {
86358360b13Sdlg 	struct blake2s_state blake;
86458360b13Sdlg 
86558360b13Sdlg 	blake2s_init(&blake, NOISE_HASH_LEN);
86658360b13Sdlg 	blake2s_update(&blake, hash, NOISE_HASH_LEN);
86758360b13Sdlg 	blake2s_update(&blake, src, src_len);
86858360b13Sdlg 	blake2s_final(&blake, hash);
86958360b13Sdlg }
87058360b13Sdlg 
87158360b13Sdlg static void
noise_mix_psk(uint8_t ck[NOISE_HASH_LEN],uint8_t hash[NOISE_HASH_LEN],uint8_t key[NOISE_SYMMETRIC_KEY_LEN],const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])87258360b13Sdlg noise_mix_psk(uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
87358360b13Sdlg     uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
87458360b13Sdlg     const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
87558360b13Sdlg {
87658360b13Sdlg 	uint8_t tmp[NOISE_HASH_LEN];
87758360b13Sdlg 
87858360b13Sdlg 	noise_kdf(ck, tmp, key, psk,
87958360b13Sdlg 	    NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN,
88058360b13Sdlg 	    NOISE_SYMMETRIC_KEY_LEN, ck);
88158360b13Sdlg 	noise_mix_hash(hash, tmp, NOISE_HASH_LEN);
88258360b13Sdlg 	explicit_bzero(tmp, NOISE_HASH_LEN);
88358360b13Sdlg }
88458360b13Sdlg 
88558360b13Sdlg static void
noise_param_init(uint8_t ck[NOISE_HASH_LEN],uint8_t hash[NOISE_HASH_LEN],const uint8_t s[NOISE_PUBLIC_KEY_LEN])88658360b13Sdlg noise_param_init(uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
88758360b13Sdlg     const uint8_t s[NOISE_PUBLIC_KEY_LEN])
88858360b13Sdlg {
88958360b13Sdlg 	struct blake2s_state blake;
89058360b13Sdlg 
89158360b13Sdlg 	blake2s(ck, (uint8_t *)NOISE_HANDSHAKE_NAME, NULL,
89258360b13Sdlg 	    NOISE_HASH_LEN, strlen(NOISE_HANDSHAKE_NAME), 0);
89358360b13Sdlg 	blake2s_init(&blake, NOISE_HASH_LEN);
89458360b13Sdlg 	blake2s_update(&blake, ck, NOISE_HASH_LEN);
89558360b13Sdlg 	blake2s_update(&blake, (uint8_t *)NOISE_IDENTIFIER_NAME,
89658360b13Sdlg 	    strlen(NOISE_IDENTIFIER_NAME));
89758360b13Sdlg 	blake2s_final(&blake, hash);
89858360b13Sdlg 
89958360b13Sdlg 	noise_mix_hash(hash, s, NOISE_PUBLIC_KEY_LEN);
90058360b13Sdlg }
90158360b13Sdlg 
90258360b13Sdlg static void
noise_msg_encrypt(uint8_t * dst,const uint8_t * src,size_t src_len,uint8_t key[NOISE_SYMMETRIC_KEY_LEN],uint8_t hash[NOISE_HASH_LEN])90358360b13Sdlg noise_msg_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
90458360b13Sdlg     uint8_t key[NOISE_SYMMETRIC_KEY_LEN], uint8_t hash[NOISE_HASH_LEN])
90558360b13Sdlg {
90658360b13Sdlg 	/* Nonce always zero for Noise_IK */
90758360b13Sdlg 	chacha20poly1305_encrypt(dst, src, src_len,
90858360b13Sdlg 	    hash, NOISE_HASH_LEN, 0, key);
90958360b13Sdlg 	noise_mix_hash(hash, dst, src_len + NOISE_AUTHTAG_LEN);
91058360b13Sdlg }
91158360b13Sdlg 
91258360b13Sdlg static int
noise_msg_decrypt(uint8_t * dst,const uint8_t * src,size_t src_len,uint8_t key[NOISE_SYMMETRIC_KEY_LEN],uint8_t hash[NOISE_HASH_LEN])91358360b13Sdlg noise_msg_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
91458360b13Sdlg     uint8_t key[NOISE_SYMMETRIC_KEY_LEN], uint8_t hash[NOISE_HASH_LEN])
91558360b13Sdlg {
91658360b13Sdlg 	/* Nonce always zero for Noise_IK */
91758360b13Sdlg 	if (!chacha20poly1305_decrypt(dst, src, src_len,
91858360b13Sdlg 	    hash, NOISE_HASH_LEN, 0, key))
91958360b13Sdlg 		return EINVAL;
92058360b13Sdlg 	noise_mix_hash(hash, src, src_len);
92158360b13Sdlg 	return 0;
92258360b13Sdlg }
92358360b13Sdlg 
92458360b13Sdlg static void
noise_msg_ephemeral(uint8_t ck[NOISE_HASH_LEN],uint8_t hash[NOISE_HASH_LEN],const uint8_t src[NOISE_PUBLIC_KEY_LEN])92558360b13Sdlg noise_msg_ephemeral(uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
92658360b13Sdlg     const uint8_t src[NOISE_PUBLIC_KEY_LEN])
92758360b13Sdlg {
92858360b13Sdlg 	noise_mix_hash(hash, src, NOISE_PUBLIC_KEY_LEN);
92958360b13Sdlg 	noise_kdf(ck, NULL, NULL, src, NOISE_HASH_LEN, 0, 0,
93058360b13Sdlg 		  NOISE_PUBLIC_KEY_LEN, ck);
93158360b13Sdlg }
93258360b13Sdlg 
93358360b13Sdlg static void
noise_tai64n_now(uint8_t output[NOISE_TIMESTAMP_LEN])93458360b13Sdlg noise_tai64n_now(uint8_t output[NOISE_TIMESTAMP_LEN])
93558360b13Sdlg {
93658360b13Sdlg 	struct timespec time;
93758360b13Sdlg 	uint64_t sec;
93858360b13Sdlg 	uint32_t nsec;
93958360b13Sdlg 
94058360b13Sdlg 	getnanotime(&time);
94158360b13Sdlg 
94258360b13Sdlg 	/* Round down the nsec counter to limit precise timing leak. */
94358360b13Sdlg 	time.tv_nsec &= REJECT_INTERVAL_MASK;
94458360b13Sdlg 
94558360b13Sdlg 	/* https://cr.yp.to/libtai/tai64.html */
94658360b13Sdlg 	sec = htobe64(0x400000000000000aULL + time.tv_sec);
94758360b13Sdlg 	nsec = htobe32(time.tv_nsec);
94858360b13Sdlg 
94958360b13Sdlg 	/* memcpy to output buffer, assuming output could be unaligned. */
95058360b13Sdlg 	memcpy(output, &sec, sizeof(sec));
95158360b13Sdlg 	memcpy(output + sizeof(sec), &nsec, sizeof(nsec));
95258360b13Sdlg }
95358360b13Sdlg 
95458360b13Sdlg static int
noise_timer_expired(struct timespec * birthdate,time_t sec,long nsec)95558360b13Sdlg noise_timer_expired(struct timespec *birthdate, time_t sec, long nsec)
95658360b13Sdlg {
95758360b13Sdlg 	struct timespec uptime;
95858360b13Sdlg 	struct timespec expire = { .tv_sec = sec, .tv_nsec = nsec };
95958360b13Sdlg 
96058360b13Sdlg 	/* We don't really worry about a zeroed birthdate, to avoid the extra
96158360b13Sdlg 	 * check on every encrypt/decrypt. This does mean that r_last_init
96258360b13Sdlg 	 * check may fail if getnanouptime is < REJECT_INTERVAL from 0. */
96358360b13Sdlg 
96458360b13Sdlg 	getnanouptime(&uptime);
96558360b13Sdlg 	timespecadd(birthdate, &expire, &expire);
96658360b13Sdlg 	return timespeccmp(&uptime, &expire, >) ? ETIMEDOUT : 0;
96758360b13Sdlg }
96858360b13Sdlg 
96958360b13Sdlg #ifdef WGTEST
97058360b13Sdlg 
97158360b13Sdlg #define MESSAGE_LEN 64
97258360b13Sdlg #define LARGE_MESSAGE_LEN 1420
97358360b13Sdlg 
97458360b13Sdlg #define T_LIM (COUNTER_WINDOW_SIZE + 1)
97558360b13Sdlg #define T_INIT do {				\
97658360b13Sdlg 	bzero(&ctr, sizeof(ctr));		\
977*efbb2e09Smvs 	mtx_init_flags(&ctr.c_mtx, IPL_NET, "counter", 0);	\
97858360b13Sdlg } while (0)
97958360b13Sdlg #define T(num, v, e) do {						\
98058360b13Sdlg 	if (noise_counter_recv(&ctr, v) != e) {				\
98158360b13Sdlg 		printf("%s, test %d: failed.\n", __func__, num);	\
98258360b13Sdlg 		return;							\
98358360b13Sdlg 	}								\
98458360b13Sdlg } while (0)
98558360b13Sdlg #define T_FAILED(test) do {				\
98658360b13Sdlg 	printf("%s %s: failed\n", __func__, test);	\
98758360b13Sdlg 	return;						\
98858360b13Sdlg } while (0)
98958360b13Sdlg #define T_PASSED printf("%s: passed.\n", __func__)
99058360b13Sdlg 
99158360b13Sdlg static struct noise_local	al, bl;
99258360b13Sdlg static struct noise_remote	ar, br;
99358360b13Sdlg 
99458360b13Sdlg static struct noise_initiation {
99558360b13Sdlg 	uint32_t s_idx;
99658360b13Sdlg 	uint8_t ue[NOISE_PUBLIC_KEY_LEN];
99758360b13Sdlg 	uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN];
99858360b13Sdlg 	uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN];
99958360b13Sdlg } init;
100058360b13Sdlg 
100158360b13Sdlg static struct noise_response {
100258360b13Sdlg 	uint32_t s_idx;
100358360b13Sdlg 	uint32_t r_idx;
100458360b13Sdlg 	uint8_t ue[NOISE_PUBLIC_KEY_LEN];
100558360b13Sdlg 	uint8_t en[0 + NOISE_AUTHTAG_LEN];
100658360b13Sdlg } resp;
100758360b13Sdlg 
100858360b13Sdlg static uint64_t nonce;
100958360b13Sdlg static uint32_t index;
101058360b13Sdlg static uint8_t data[MESSAGE_LEN + NOISE_AUTHTAG_LEN];
101158360b13Sdlg static uint8_t largedata[LARGE_MESSAGE_LEN + NOISE_AUTHTAG_LEN];
101258360b13Sdlg 
101358360b13Sdlg static struct noise_remote *
upcall_get(void * x0,uint8_t * x1)101458360b13Sdlg upcall_get(void *x0, uint8_t *x1) { return x0; }
101558360b13Sdlg static uint32_t
upcall_set(void * x0,struct noise_remote * x1)101658360b13Sdlg upcall_set(void *x0, struct noise_remote *x1) { return 5; }
101758360b13Sdlg static void
upcall_drop(void * x0,uint32_t x1)101858360b13Sdlg upcall_drop(void *x0, uint32_t x1) { }
101958360b13Sdlg 
102058360b13Sdlg static void
noise_counter_test()102158360b13Sdlg noise_counter_test()
102258360b13Sdlg {
102358360b13Sdlg 	struct noise_counter ctr;
102458360b13Sdlg 	int i;
102558360b13Sdlg 
102658360b13Sdlg 	T_INIT;
102758360b13Sdlg 	/* T(test number, nonce, expected_response) */
102858360b13Sdlg 	T( 1, 0, 0);
102958360b13Sdlg 	T( 2, 1, 0);
103058360b13Sdlg 	T( 3, 1, EEXIST);
103158360b13Sdlg 	T( 4, 9, 0);
103258360b13Sdlg 	T( 5, 8, 0);
103358360b13Sdlg 	T( 6, 7, 0);
103458360b13Sdlg 	T( 7, 7, EEXIST);
103558360b13Sdlg 	T( 8, T_LIM, 0);
103658360b13Sdlg 	T( 9, T_LIM - 1, 0);
103758360b13Sdlg 	T(10, T_LIM - 1, EEXIST);
103858360b13Sdlg 	T(11, T_LIM - 2, 0);
103958360b13Sdlg 	T(12, 2, 0);
104058360b13Sdlg 	T(13, 2, EEXIST);
104158360b13Sdlg 	T(14, T_LIM + 16, 0);
104258360b13Sdlg 	T(15, 3, EEXIST);
104358360b13Sdlg 	T(16, T_LIM + 16, EEXIST);
104458360b13Sdlg 	T(17, T_LIM * 4, 0);
104558360b13Sdlg 	T(18, T_LIM * 4 - (T_LIM - 1), 0);
104658360b13Sdlg 	T(19, 10, EEXIST);
104758360b13Sdlg 	T(20, T_LIM * 4 - T_LIM, EEXIST);
104858360b13Sdlg 	T(21, T_LIM * 4 - (T_LIM + 1), EEXIST);
104958360b13Sdlg 	T(22, T_LIM * 4 - (T_LIM - 2), 0);
105058360b13Sdlg 	T(23, T_LIM * 4 + 1 - T_LIM, EEXIST);
105158360b13Sdlg 	T(24, 0, EEXIST);
105258360b13Sdlg 	T(25, REJECT_AFTER_MESSAGES, EEXIST);
105358360b13Sdlg 	T(26, REJECT_AFTER_MESSAGES - 1, 0);
105458360b13Sdlg 	T(27, REJECT_AFTER_MESSAGES, EEXIST);
105558360b13Sdlg 	T(28, REJECT_AFTER_MESSAGES - 1, EEXIST);
105658360b13Sdlg 	T(29, REJECT_AFTER_MESSAGES - 2, 0);
105758360b13Sdlg 	T(30, REJECT_AFTER_MESSAGES + 1, EEXIST);
105858360b13Sdlg 	T(31, REJECT_AFTER_MESSAGES + 2, EEXIST);
105958360b13Sdlg 	T(32, REJECT_AFTER_MESSAGES - 2, EEXIST);
106058360b13Sdlg 	T(33, REJECT_AFTER_MESSAGES - 3, 0);
106158360b13Sdlg 	T(34, 0, EEXIST);
106258360b13Sdlg 
106358360b13Sdlg 	T_INIT;
106458360b13Sdlg 	for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i)
106558360b13Sdlg 		T(35, i, 0);
106658360b13Sdlg 	T(36, 0, 0);
106758360b13Sdlg 	T(37, 0, EEXIST);
106858360b13Sdlg 
106958360b13Sdlg 	T_INIT;
107058360b13Sdlg 	for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i)
107158360b13Sdlg 		T(38, i, 0);
107258360b13Sdlg 	T(39, 1, 0);
107358360b13Sdlg 	T(40, 0, EEXIST);
107458360b13Sdlg 
107558360b13Sdlg 	T_INIT;
107658360b13Sdlg 	for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0;)
107758360b13Sdlg 		T(41, i, 0);
107858360b13Sdlg 
107958360b13Sdlg 	T_INIT;
108058360b13Sdlg 	for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1;)
108158360b13Sdlg 		T(42, i, 0);
108258360b13Sdlg 	T(43, 0, EEXIST);
108358360b13Sdlg 
108458360b13Sdlg 	T_INIT;
108558360b13Sdlg 	for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;)
108658360b13Sdlg 		T(44, i, 0);
108758360b13Sdlg 	T(45, COUNTER_WINDOW_SIZE + 1, 0);
108858360b13Sdlg 	T(46, 0, EEXIST);
108958360b13Sdlg 
109058360b13Sdlg 	T_INIT;
109158360b13Sdlg 	for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1;)
109258360b13Sdlg 		T(47, i, 0);
109358360b13Sdlg 	T(48, 0, 0);
109458360b13Sdlg 	T(49, COUNTER_WINDOW_SIZE + 1, 0);
109558360b13Sdlg 
109658360b13Sdlg 	T_PASSED;
109758360b13Sdlg }
109858360b13Sdlg 
109958360b13Sdlg static void
noise_handshake_init(struct noise_local * al,struct noise_remote * ar,struct noise_local * bl,struct noise_remote * br)110058360b13Sdlg noise_handshake_init(struct noise_local *al, struct noise_remote *ar,
110158360b13Sdlg     struct noise_local *bl, struct noise_remote *br)
110258360b13Sdlg {
110358360b13Sdlg 	uint8_t apriv[NOISE_PUBLIC_KEY_LEN], bpriv[NOISE_PUBLIC_KEY_LEN];
110458360b13Sdlg 	uint8_t apub[NOISE_PUBLIC_KEY_LEN], bpub[NOISE_PUBLIC_KEY_LEN];
110558360b13Sdlg 	uint8_t psk[NOISE_SYMMETRIC_KEY_LEN];
110658360b13Sdlg 
110758360b13Sdlg 	struct noise_upcall upcall = {
110858360b13Sdlg 		.u_arg = NULL,
110958360b13Sdlg 		.u_remote_get = upcall_get,
111058360b13Sdlg 		.u_index_set = upcall_set,
111158360b13Sdlg 		.u_index_drop = upcall_drop,
111258360b13Sdlg 	};
111358360b13Sdlg 
111458360b13Sdlg 	upcall.u_arg = ar;
111558360b13Sdlg 	noise_local_init(al, &upcall);
111658360b13Sdlg 	upcall.u_arg = br;
111758360b13Sdlg 	noise_local_init(bl, &upcall);
111858360b13Sdlg 
111958360b13Sdlg 	arc4random_buf(apriv, NOISE_PUBLIC_KEY_LEN);
112058360b13Sdlg 	arc4random_buf(bpriv, NOISE_PUBLIC_KEY_LEN);
112158360b13Sdlg 
112258360b13Sdlg 	noise_local_lock_identity(al);
112358360b13Sdlg 	noise_local_set_private(al, apriv);
112458360b13Sdlg 	noise_local_unlock_identity(al);
112558360b13Sdlg 
112658360b13Sdlg 	noise_local_lock_identity(bl);
112758360b13Sdlg 	noise_local_set_private(bl, bpriv);
112858360b13Sdlg 	noise_local_unlock_identity(bl);
112958360b13Sdlg 
113058360b13Sdlg 	noise_local_keys(al, apub, NULL);
113158360b13Sdlg 	noise_local_keys(bl, bpub, NULL);
113258360b13Sdlg 
113358360b13Sdlg 	noise_remote_init(ar, bpub, al);
113458360b13Sdlg 	noise_remote_init(br, apub, bl);
113558360b13Sdlg 
113658360b13Sdlg 	arc4random_buf(psk, NOISE_SYMMETRIC_KEY_LEN);
113758360b13Sdlg 	noise_remote_set_psk(ar, psk);
113858360b13Sdlg 	noise_remote_set_psk(br, psk);
113958360b13Sdlg }
114058360b13Sdlg 
114158360b13Sdlg static void
noise_handshake_test()114258360b13Sdlg noise_handshake_test()
114358360b13Sdlg {
114458360b13Sdlg 	struct noise_remote *r;
114558360b13Sdlg 	int i;
114658360b13Sdlg 
114758360b13Sdlg 	noise_handshake_init(&al, &ar, &bl, &br);
114858360b13Sdlg 
114958360b13Sdlg 	/* Create initiation */
115058360b13Sdlg 	if (noise_create_initiation(&ar, &init.s_idx,
115158360b13Sdlg 	    init.ue, init.es, init.ets) != 0)
115258360b13Sdlg 		T_FAILED("create_initiation");
115358360b13Sdlg 
115458360b13Sdlg 	/* Check encrypted (es) validation */
115558360b13Sdlg 	for (i = 0; i < sizeof(init.es); i++) {
115658360b13Sdlg 		init.es[i] = ~init.es[i];
115758360b13Sdlg 		if (noise_consume_initiation(&bl, &r, init.s_idx,
115858360b13Sdlg 		    init.ue, init.es, init.ets) != EINVAL)
115958360b13Sdlg 			T_FAILED("consume_initiation_es");
116058360b13Sdlg 		init.es[i] = ~init.es[i];
116158360b13Sdlg 	}
116258360b13Sdlg 
116358360b13Sdlg 	/* Check encrypted (ets) validation */
116458360b13Sdlg 	for (i = 0; i < sizeof(init.ets); i++) {
116558360b13Sdlg 		init.ets[i] = ~init.ets[i];
116658360b13Sdlg 		if (noise_consume_initiation(&bl, &r, init.s_idx,
116758360b13Sdlg 		    init.ue, init.es, init.ets) != EINVAL)
116858360b13Sdlg 			T_FAILED("consume_initiation_ets");
116958360b13Sdlg 		init.ets[i] = ~init.ets[i];
117058360b13Sdlg 	}
117158360b13Sdlg 
117258360b13Sdlg 	/* Consume initiation properly */
117358360b13Sdlg 	if (noise_consume_initiation(&bl, &r, init.s_idx,
117458360b13Sdlg 	    init.ue, init.es, init.ets) != 0)
117558360b13Sdlg 		T_FAILED("consume_initiation");
117658360b13Sdlg 	if (r != &br)
117758360b13Sdlg 		T_FAILED("remote_lookup");
117858360b13Sdlg 
117958360b13Sdlg 	/* Replay initiation */
118058360b13Sdlg 	if (noise_consume_initiation(&bl, &r, init.s_idx,
118158360b13Sdlg 	    init.ue, init.es, init.ets) != EINVAL)
118258360b13Sdlg 		T_FAILED("consume_initiation_replay");
118358360b13Sdlg 	if (r != &br)
118458360b13Sdlg 		T_FAILED("remote_lookup_r_unchanged");
118558360b13Sdlg 
118658360b13Sdlg 	/* Create response */
118758360b13Sdlg 	if (noise_create_response(&br, &resp.s_idx,
118858360b13Sdlg 	    &resp.r_idx, resp.ue, resp.en) != 0)
118958360b13Sdlg 		T_FAILED("create_response");
119058360b13Sdlg 
119158360b13Sdlg 	/* Check encrypted (en) validation */
119258360b13Sdlg 	for (i = 0; i < sizeof(resp.en); i++) {
119358360b13Sdlg 		resp.en[i] = ~resp.en[i];
119458360b13Sdlg 		if (noise_consume_response(&ar, resp.s_idx,
119558360b13Sdlg 		    resp.r_idx, resp.ue, resp.en) != EINVAL)
119658360b13Sdlg 			T_FAILED("consume_response_en");
119758360b13Sdlg 		resp.en[i] = ~resp.en[i];
119858360b13Sdlg 	}
119958360b13Sdlg 
120058360b13Sdlg 	/* Consume response properly */
120158360b13Sdlg 	if (noise_consume_response(&ar, resp.s_idx,
120258360b13Sdlg 	    resp.r_idx, resp.ue, resp.en) != 0)
120358360b13Sdlg 		T_FAILED("consume_response");
120458360b13Sdlg 
120558360b13Sdlg 	/* Derive keys on both sides */
120658360b13Sdlg 	if (noise_remote_begin_session(&ar) != 0)
120758360b13Sdlg 		T_FAILED("promote_ar");
120858360b13Sdlg 	if (noise_remote_begin_session(&br) != 0)
120958360b13Sdlg 		T_FAILED("promote_br");
121058360b13Sdlg 
121158360b13Sdlg 	for (i = 0; i < MESSAGE_LEN; i++)
121258360b13Sdlg 		data[i] = i;
121358360b13Sdlg 
121458360b13Sdlg 	/* Since bob is responder, he must not encrypt until confirmed */
121558360b13Sdlg 	if (noise_remote_encrypt(&br, &index, &nonce,
121658360b13Sdlg 	    data, MESSAGE_LEN) != EINVAL)
121758360b13Sdlg 		T_FAILED("encrypt_kci_wait");
121858360b13Sdlg 
121958360b13Sdlg 	/* Alice now encrypt and gets bob to decrypt */
122058360b13Sdlg 	if (noise_remote_encrypt(&ar, &index, &nonce,
122158360b13Sdlg 	    data, MESSAGE_LEN) != 0)
122258360b13Sdlg 		T_FAILED("encrypt_akp");
122358360b13Sdlg 	if (noise_remote_decrypt(&br, index, nonce,
122458360b13Sdlg 	    data, MESSAGE_LEN + NOISE_AUTHTAG_LEN) != ECONNRESET)
122558360b13Sdlg 		T_FAILED("decrypt_bkp");
122658360b13Sdlg 
122758360b13Sdlg 	for (i = 0; i < MESSAGE_LEN; i++)
122858360b13Sdlg 		if (data[i] != i)
122958360b13Sdlg 			T_FAILED("decrypt_message_akp_bkp");
123058360b13Sdlg 
123158360b13Sdlg 	/* Now bob has received confirmation, he can encrypt */
123258360b13Sdlg 	if (noise_remote_encrypt(&br, &index, &nonce,
123358360b13Sdlg 	    data, MESSAGE_LEN) != 0)
123458360b13Sdlg 		T_FAILED("encrypt_kci_ready");
123558360b13Sdlg 	if (noise_remote_decrypt(&ar, index, nonce,
123658360b13Sdlg 	    data, MESSAGE_LEN + NOISE_AUTHTAG_LEN) != 0)
123758360b13Sdlg 		T_FAILED("decrypt_akp");
123858360b13Sdlg 
123958360b13Sdlg 	for (i = 0; i < MESSAGE_LEN; i++)
124058360b13Sdlg 		if (data[i] != i)
124158360b13Sdlg 			T_FAILED("decrypt_message_bkp_akp");
124258360b13Sdlg 
124358360b13Sdlg 	T_PASSED;
124458360b13Sdlg }
124558360b13Sdlg 
124658360b13Sdlg static void
noise_speed_test()124758360b13Sdlg noise_speed_test()
124858360b13Sdlg {
124958360b13Sdlg #define SPEED_ITER (1<<16)
125058360b13Sdlg 	struct timespec start, end;
125158360b13Sdlg 	struct noise_remote *r;
125258360b13Sdlg 	int nsec, i;
125358360b13Sdlg 
125458360b13Sdlg #define NSEC 1000000000
125558360b13Sdlg #define T_TIME_START(iter, size) do {					\
125658360b13Sdlg 	printf("%s %d %d byte encryptions\n", __func__, iter, size);	\
125758360b13Sdlg 	nanouptime(&start);						\
125858360b13Sdlg } while (0)
125958360b13Sdlg #define T_TIME_END(iter, size) do {					\
126058360b13Sdlg 	nanouptime(&end);						\
126158360b13Sdlg 	timespecsub(&end, &start, &end);				\
126258360b13Sdlg 	nsec = (end.tv_sec * NSEC + end.tv_nsec) / iter;		\
126358360b13Sdlg 	printf("%s %d nsec/iter, %d iter/sec, %d byte/sec\n",		\
126458360b13Sdlg 	    __func__, nsec, NSEC / nsec, NSEC / nsec * size);		\
126558360b13Sdlg } while (0)
126658360b13Sdlg #define T_TIME_START_SINGLE(name) do {		\
126758360b13Sdlg 	printf("%s %s\n", __func__, name);	\
126858360b13Sdlg 	nanouptime(&start);			\
126958360b13Sdlg } while (0)
127058360b13Sdlg #define T_TIME_END_SINGLE() do {					\
127158360b13Sdlg 	nanouptime(&end);						\
127258360b13Sdlg 	timespecsub(&end, &start, &end);				\
127358360b13Sdlg 	nsec = (end.tv_sec * NSEC + end.tv_nsec);			\
127458360b13Sdlg 	printf("%s %d nsec/iter, %d iter/sec\n",			\
127558360b13Sdlg 	    __func__, nsec, NSEC / nsec);				\
127658360b13Sdlg } while (0)
127758360b13Sdlg 
127858360b13Sdlg 	noise_handshake_init(&al, &ar, &bl, &br);
127958360b13Sdlg 
128058360b13Sdlg 	T_TIME_START_SINGLE("create_initiation");
128158360b13Sdlg 	if (noise_create_initiation(&ar, &init.s_idx,
128258360b13Sdlg 	    init.ue, init.es, init.ets) != 0)
128358360b13Sdlg 		T_FAILED("create_initiation");
128458360b13Sdlg 	T_TIME_END_SINGLE();
128558360b13Sdlg 
128658360b13Sdlg 	T_TIME_START_SINGLE("consume_initiation");
128758360b13Sdlg 	if (noise_consume_initiation(&bl, &r, init.s_idx,
128858360b13Sdlg 	    init.ue, init.es, init.ets) != 0)
128958360b13Sdlg 		T_FAILED("consume_initiation");
129058360b13Sdlg 	T_TIME_END_SINGLE();
129158360b13Sdlg 
129258360b13Sdlg 	T_TIME_START_SINGLE("create_response");
129358360b13Sdlg 	if (noise_create_response(&br, &resp.s_idx,
129458360b13Sdlg 	    &resp.r_idx, resp.ue, resp.en) != 0)
129558360b13Sdlg 		T_FAILED("create_response");
129658360b13Sdlg 	T_TIME_END_SINGLE();
129758360b13Sdlg 
129858360b13Sdlg 	T_TIME_START_SINGLE("consume_response");
129958360b13Sdlg 	if (noise_consume_response(&ar, resp.s_idx,
130058360b13Sdlg 	    resp.r_idx, resp.ue, resp.en) != 0)
130158360b13Sdlg 		T_FAILED("consume_response");
130258360b13Sdlg 	T_TIME_END_SINGLE();
130358360b13Sdlg 
130458360b13Sdlg 	/* Derive keys on both sides */
130558360b13Sdlg 	T_TIME_START_SINGLE("derive_keys");
130658360b13Sdlg 	if (noise_remote_begin_session(&ar) != 0)
130758360b13Sdlg 		T_FAILED("begin_ar");
130858360b13Sdlg 	T_TIME_END_SINGLE();
130958360b13Sdlg 	if (noise_remote_begin_session(&br) != 0)
131058360b13Sdlg 		T_FAILED("begin_br");
131158360b13Sdlg 
131258360b13Sdlg 	/* Small data encryptions */
131358360b13Sdlg 	T_TIME_START(SPEED_ITER, MESSAGE_LEN);
131458360b13Sdlg 	for (i = 0; i < SPEED_ITER; i++) {
131558360b13Sdlg 		if (noise_remote_encrypt(&ar, &index, &nonce,
131658360b13Sdlg 		    data, MESSAGE_LEN) != 0)
131758360b13Sdlg 			T_FAILED("encrypt_akp");
131858360b13Sdlg 	}
131958360b13Sdlg 	T_TIME_END(SPEED_ITER, MESSAGE_LEN);
132058360b13Sdlg 
132158360b13Sdlg 
132258360b13Sdlg 	/* Large data encryptions */
132358360b13Sdlg 	T_TIME_START(SPEED_ITER, LARGE_MESSAGE_LEN);
132458360b13Sdlg 	for (i = 0; i < SPEED_ITER; i++) {
132558360b13Sdlg 		if (noise_remote_encrypt(&ar, &index, &nonce,
132658360b13Sdlg 		    largedata, LARGE_MESSAGE_LEN) != 0)
132758360b13Sdlg 			T_FAILED("encrypt_akp");
132858360b13Sdlg 	}
132958360b13Sdlg 	T_TIME_END(SPEED_ITER, LARGE_MESSAGE_LEN);
133058360b13Sdlg }
133158360b13Sdlg 
133258360b13Sdlg void
noise_test()133358360b13Sdlg noise_test()
133458360b13Sdlg {
133558360b13Sdlg 	noise_counter_test();
133658360b13Sdlg 	noise_handshake_test();
133758360b13Sdlg 	noise_speed_test();
133858360b13Sdlg }
133958360b13Sdlg 
134058360b13Sdlg #endif /* WGTEST */
1341