1a364ee04SAaron LI /*-
2a364ee04SAaron LI * SPDX-License-Identifier: ISC
3a6bca3d2SAaron LI *
4a6bca3d2SAaron LI * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
5a6bca3d2SAaron LI * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
6a6bca3d2SAaron LI * Copyright (c) 2022 The FreeBSD Foundation
7a364ee04SAaron LI * Copyright (c) 2023-2024 Aaron LI <aly@aaronly.me>
8a364ee04SAaron LI *
9a364ee04SAaron LI * Permission to use, copy, modify, and distribute this software for any
10a364ee04SAaron LI * purpose with or without fee is hereby granted, provided that the above
11a364ee04SAaron LI * copyright notice and this permission notice appear in all copies.
12a364ee04SAaron LI *
13a364ee04SAaron LI * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14a364ee04SAaron LI * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15a364ee04SAaron LI * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16a364ee04SAaron LI * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17a364ee04SAaron LI * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18a364ee04SAaron LI * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19a364ee04SAaron LI * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20a6bca3d2SAaron LI */
21a7f975c0SAaron LI /*
22a7f975c0SAaron LI * This implements Noise_IKpsk2:
23a7f975c0SAaron LI * <- s
24a7f975c0SAaron LI * ******
25a7f975c0SAaron LI * -> e, es, s, ss, {t}
26a7f975c0SAaron LI * <- e, ee, se, psk, {}
27a7f975c0SAaron LI */
28a6bca3d2SAaron LI
29a6bca3d2SAaron LI #include <sys/param.h>
30a6bca3d2SAaron LI #include <sys/systm.h>
31fa8f7fdbSAaron LI #include <sys/bitops.h> /* ilog2() */
32a6bca3d2SAaron LI #include <sys/endian.h>
33a6bca3d2SAaron LI #include <sys/kernel.h>
34a6bca3d2SAaron LI #include <sys/lock.h>
35a6bca3d2SAaron LI #include <sys/malloc.h>
361fdfe5a9SAaron LI #include <sys/queue.h>
37a6bca3d2SAaron LI #include <sys/refcount.h>
382bed72b3SAaron LI #include <sys/time.h>
39d94868ddSAaron LI
40a7f975c0SAaron LI #include <machine/atomic.h>
41a7f975c0SAaron LI
42cfdd69bcSAaron LI #include <crypto/chachapoly.h>
43d94868ddSAaron LI #include <crypto/blake2/blake2s.h>
44d94868ddSAaron LI #include <crypto/curve25519/curve25519.h>
45a6bca3d2SAaron LI #include <crypto/siphash/siphash.h>
46a6bca3d2SAaron LI
47a6bca3d2SAaron LI #include "wg_noise.h"
48a6bca3d2SAaron LI
49a6bca3d2SAaron LI /* Protocol string constants */
50a6bca3d2SAaron LI #define NOISE_HANDSHAKE_NAME "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
51a6bca3d2SAaron LI #define NOISE_IDENTIFIER_NAME "WireGuard v1 zx2c4 Jason@zx2c4.com"
52a6bca3d2SAaron LI
53a6bca3d2SAaron LI /* Constants for the counter */
54a6bca3d2SAaron LI #define COUNTER_BITS_TOTAL 8192
55fa8f7fdbSAaron LI #define COUNTER_BITS (sizeof(unsigned long) * 8)
56fa8f7fdbSAaron LI #define COUNTER_ORDER ilog2(COUNTER_BITS)
57fa8f7fdbSAaron LI #define COUNTER_WINDOW_SIZE (COUNTER_BITS_TOTAL - COUNTER_BITS)
58fa8f7fdbSAaron LI #define COUNTER_NUM (COUNTER_BITS_TOTAL / COUNTER_BITS)
59fa8f7fdbSAaron LI #define COUNTER_MASK (COUNTER_NUM - 1)
60a6bca3d2SAaron LI
61a6bca3d2SAaron LI /* Constants for the keypair */
62a7f975c0SAaron LI #define REKEY_AFTER_MESSAGES (1ULL << 60)
63a6bca3d2SAaron LI #define REJECT_AFTER_MESSAGES (UINT64_MAX - COUNTER_WINDOW_SIZE - 1)
64a6bca3d2SAaron LI #define REKEY_AFTER_TIME 120
65a6bca3d2SAaron LI #define REKEY_AFTER_TIME_RECV 165
66a6bca3d2SAaron LI #define REJECT_INTERVAL (1000000000 / 50) /* fifty times per sec */
67fa8f7fdbSAaron LI #define REJECT_INTERVAL_MASK (~((1ULL << ilog2(REJECT_INTERVAL)) - 1))
68a6bca3d2SAaron LI
69a7f975c0SAaron LI /* Constants for the hashtable */
70a6bca3d2SAaron LI #define HT_INDEX_SIZE (1 << 13)
71a6bca3d2SAaron LI #define HT_INDEX_MASK (HT_INDEX_SIZE - 1)
72a6bca3d2SAaron LI #define HT_REMOTE_SIZE (1 << 11)
73a6bca3d2SAaron LI #define HT_REMOTE_MASK (HT_REMOTE_SIZE - 1)
74a6bca3d2SAaron LI #define MAX_REMOTE_PER_LOCAL (1 << 20)
75a6bca3d2SAaron LI
76a6bca3d2SAaron LI struct noise_index {
771fdfe5a9SAaron LI LIST_ENTRY(noise_index) i_entry;
78a6bca3d2SAaron LI uint32_t i_local_index;
79a6bca3d2SAaron LI uint32_t i_remote_index;
80a7f975c0SAaron LI bool i_is_keypair;
81a6bca3d2SAaron LI };
82a6bca3d2SAaron LI
83a6bca3d2SAaron LI struct noise_keypair {
84a6bca3d2SAaron LI struct noise_index kp_index;
85a7f975c0SAaron LI
86a6bca3d2SAaron LI u_int kp_refcnt;
87a6bca3d2SAaron LI bool kp_can_send;
88a6bca3d2SAaron LI bool kp_is_initiator;
892bed72b3SAaron LI struct timespec kp_birthdate; /* nanouptime */
90a6bca3d2SAaron LI struct noise_remote *kp_remote;
91a6bca3d2SAaron LI
92a6bca3d2SAaron LI uint8_t kp_send[NOISE_SYMMETRIC_KEY_LEN];
93a6bca3d2SAaron LI uint8_t kp_recv[NOISE_SYMMETRIC_KEY_LEN];
94a6bca3d2SAaron LI
95cfdd69bcSAaron LI struct lock kp_counter_lock;
96f82bb155SAaron LI uint64_t kp_counter_send; /* next counter available */
97f82bb155SAaron LI uint64_t kp_counter_recv; /* max counter received */
98fa8f7fdbSAaron LI unsigned long kp_backtrack[COUNTER_NUM];
9941fc5cd7SAaron LI
10041fc5cd7SAaron LI #ifdef INVARIANTS
10141fc5cd7SAaron LI LIST_ENTRY(noise_keypair) _kp_entry;
10241fc5cd7SAaron LI #endif
103a6bca3d2SAaron LI };
104a6bca3d2SAaron LI
105a6bca3d2SAaron LI struct noise_handshake {
106a6bca3d2SAaron LI uint8_t hs_e[NOISE_PUBLIC_KEY_LEN];
107a6bca3d2SAaron LI uint8_t hs_hash[NOISE_HASH_LEN];
108a6bca3d2SAaron LI uint8_t hs_ck[NOISE_HASH_LEN];
109a6bca3d2SAaron LI };
110a6bca3d2SAaron LI
111a7f975c0SAaron LI /* Handshake states of the remote/peer side. */
112a6bca3d2SAaron LI enum noise_handshake_state {
113a6bca3d2SAaron LI HANDSHAKE_DEAD,
114a6bca3d2SAaron LI HANDSHAKE_INITIATOR,
115a6bca3d2SAaron LI HANDSHAKE_RESPONDER,
116a6bca3d2SAaron LI };
117a6bca3d2SAaron LI
118a6bca3d2SAaron LI struct noise_remote {
119a6bca3d2SAaron LI struct noise_index r_index;
120a6bca3d2SAaron LI
1211fdfe5a9SAaron LI LIST_ENTRY(noise_remote) r_entry;
122a6bca3d2SAaron LI bool r_entry_inserted;
123a6bca3d2SAaron LI uint8_t r_public[NOISE_PUBLIC_KEY_LEN];
124a6bca3d2SAaron LI
1257ef217feSAaron LI struct lock r_handshake_lock;
126a6bca3d2SAaron LI struct noise_handshake r_handshake;
127a6bca3d2SAaron LI enum noise_handshake_state r_handshake_state;
1282bed72b3SAaron LI struct timespec r_last_sent; /* nanouptime */
1292bed72b3SAaron LI struct timespec r_last_init_recv; /* nanouptime */
130a6bca3d2SAaron LI uint8_t r_timestamp[NOISE_TIMESTAMP_LEN];
131a6bca3d2SAaron LI uint8_t r_psk[NOISE_SYMMETRIC_KEY_LEN];
132a6bca3d2SAaron LI uint8_t r_ss[NOISE_PUBLIC_KEY_LEN];
133a6bca3d2SAaron LI
134a6bca3d2SAaron LI u_int r_refcnt;
135a6bca3d2SAaron LI struct noise_local *r_local;
136a6bca3d2SAaron LI void *r_arg;
137a6bca3d2SAaron LI
13813a64e4bSAaron LI struct lock r_keypair_lock;
139461ea786SAaron LI struct noise_keypair *r_keypair_next;
140461ea786SAaron LI struct noise_keypair *r_keypair_current;
141461ea786SAaron LI struct noise_keypair *r_keypair_previous;
14241fc5cd7SAaron LI
14341fc5cd7SAaron LI #ifdef INVARIANTS
14441fc5cd7SAaron LI LIST_ENTRY(noise_remote) _r_entry;
14541fc5cd7SAaron LI #endif
146a6bca3d2SAaron LI };
147a6bca3d2SAaron LI
148a6bca3d2SAaron LI struct noise_local {
1497ef217feSAaron LI struct lock l_identity_lock;
150a6bca3d2SAaron LI bool l_has_identity;
151a6bca3d2SAaron LI uint8_t l_public[NOISE_PUBLIC_KEY_LEN];
152a6bca3d2SAaron LI uint8_t l_private[NOISE_PUBLIC_KEY_LEN];
153a6bca3d2SAaron LI
154a6bca3d2SAaron LI u_int l_refcnt;
155a6bca3d2SAaron LI uint8_t l_hash_key[SIPHASH_KEY_LENGTH];
156a6bca3d2SAaron LI
157a7f975c0SAaron LI /* Hash table to lookup the remote from its public key. */
158ef7d48a7SAaron LI struct lock l_remote_lock;
159a6bca3d2SAaron LI size_t l_remote_num;
1601fdfe5a9SAaron LI LIST_HEAD(, noise_remote) l_remote_hash[HT_REMOTE_SIZE];
161a6bca3d2SAaron LI
162a7f975c0SAaron LI /* Hash table to lookup the remote/keypair from its index. */
163ef7d48a7SAaron LI struct lock l_index_lock;
1641fdfe5a9SAaron LI LIST_HEAD(, noise_index) l_index_hash[HT_INDEX_SIZE];
16541fc5cd7SAaron LI
16641fc5cd7SAaron LI #ifdef INVARIANTS
16741fc5cd7SAaron LI LIST_ENTRY(noise_local) _l_entry;
16841fc5cd7SAaron LI #endif
169a6bca3d2SAaron LI };
170a6bca3d2SAaron LI
17141fc5cd7SAaron LI
17241fc5cd7SAaron LI static MALLOC_DEFINE(M_NOISE, "NOISE", "wgnoise");
17341fc5cd7SAaron LI
17441fc5cd7SAaron LI #ifdef INVARIANTS
17541fc5cd7SAaron LI static struct lock noise_mtx;
17641fc5cd7SAaron LI static LIST_HEAD(, noise_local) noise_locals;
17741fc5cd7SAaron LI static LIST_HEAD(, noise_remote) noise_remotes;
17841fc5cd7SAaron LI static LIST_HEAD(, noise_keypair) noise_keypairs;
17941fc5cd7SAaron LI #endif
18041fc5cd7SAaron LI
18141fc5cd7SAaron LI
182a7f975c0SAaron LI static void noise_precompute_ss(struct noise_local *,
183a7f975c0SAaron LI struct noise_remote *);
184a6bca3d2SAaron LI
1859bb9f522SAaron LI static struct noise_local *
1869bb9f522SAaron LI noise_local_ref(struct noise_local *);
1879bb9f522SAaron LI static void noise_local_put(struct noise_local *);
1889bb9f522SAaron LI
189313ebe4eSAaron LI static uint32_t noise_remote_index_insert(struct noise_local *,
190a7f975c0SAaron LI struct noise_remote *);
191a6bca3d2SAaron LI static struct noise_remote *
192a7f975c0SAaron LI noise_remote_index_lookup(struct noise_local *,
193a7f975c0SAaron LI uint32_t, bool);
194a7f975c0SAaron LI static bool noise_remote_index_remove(struct noise_local *,
195a7f975c0SAaron LI struct noise_remote *);
196a6bca3d2SAaron LI static void noise_remote_expire_current(struct noise_remote *);
197a6bca3d2SAaron LI
198f0424a0dSAaron LI static bool noise_begin_session(struct noise_remote *);
199a6bca3d2SAaron LI static void noise_keypair_drop(struct noise_keypair *);
200a6bca3d2SAaron LI
201*979e91edSAaron LI static void noise_hmac(uint8_t *, const uint8_t *, const uint8_t *,
202*979e91edSAaron LI size_t, size_t, size_t);
203a6bca3d2SAaron LI static void noise_kdf(uint8_t *, uint8_t *, uint8_t *, const uint8_t *,
204a6bca3d2SAaron LI size_t, size_t, size_t, size_t,
205a6bca3d2SAaron LI const uint8_t [NOISE_HASH_LEN]);
206c222eea3SAaron LI static bool noise_mix_dh(uint8_t [NOISE_HASH_LEN],
207a7f975c0SAaron LI uint8_t [NOISE_SYMMETRIC_KEY_LEN],
208a6bca3d2SAaron LI const uint8_t [NOISE_PUBLIC_KEY_LEN],
209a6bca3d2SAaron LI const uint8_t [NOISE_PUBLIC_KEY_LEN]);
210c222eea3SAaron LI static bool noise_mix_ss(uint8_t ck[NOISE_HASH_LEN],
211a7f975c0SAaron LI uint8_t [NOISE_SYMMETRIC_KEY_LEN],
212a6bca3d2SAaron LI const uint8_t [NOISE_PUBLIC_KEY_LEN]);
213a7f975c0SAaron LI static void noise_mix_hash(uint8_t [NOISE_HASH_LEN],
214a7f975c0SAaron LI const uint8_t *, size_t);
215a7f975c0SAaron LI static void noise_mix_psk(uint8_t [NOISE_HASH_LEN],
216a7f975c0SAaron LI uint8_t [NOISE_HASH_LEN],
217a7f975c0SAaron LI uint8_t [NOISE_SYMMETRIC_KEY_LEN],
218a7f975c0SAaron LI const uint8_t [NOISE_SYMMETRIC_KEY_LEN]);
219a7f975c0SAaron LI
220a7f975c0SAaron LI static void noise_param_init(uint8_t [NOISE_HASH_LEN],
221a7f975c0SAaron LI uint8_t [NOISE_HASH_LEN],
222a6bca3d2SAaron LI const uint8_t [NOISE_PUBLIC_KEY_LEN]);
223a6bca3d2SAaron LI static void noise_msg_encrypt(uint8_t *, const uint8_t *, size_t,
224a7f975c0SAaron LI uint8_t [NOISE_SYMMETRIC_KEY_LEN],
225a7f975c0SAaron LI uint8_t [NOISE_HASH_LEN]);
226c222eea3SAaron LI static bool noise_msg_decrypt(uint8_t *, const uint8_t *, size_t,
227a7f975c0SAaron LI uint8_t [NOISE_SYMMETRIC_KEY_LEN],
228a7f975c0SAaron LI uint8_t [NOISE_HASH_LEN]);
229a7f975c0SAaron LI static void noise_msg_ephemeral(uint8_t [NOISE_HASH_LEN],
230a7f975c0SAaron LI uint8_t [NOISE_HASH_LEN],
231a6bca3d2SAaron LI const uint8_t [NOISE_PUBLIC_KEY_LEN]);
232a7f975c0SAaron LI
233a6bca3d2SAaron LI static void noise_tai64n_now(uint8_t [NOISE_TIMESTAMP_LEN]);
234a6bca3d2SAaron LI
235a7f975c0SAaron LI
236a7f975c0SAaron LI static inline uint64_t
siphash24(const uint8_t key[SIPHASH_KEY_LENGTH],const void * src,size_t len)237a7f975c0SAaron LI siphash24(const uint8_t key[SIPHASH_KEY_LENGTH], const void *src, size_t len)
238a7f975c0SAaron LI {
239a7f975c0SAaron LI SIPHASH_CTX ctx;
240a7f975c0SAaron LI return SipHashX(&ctx, 2, 4, key, src, len);
241a7f975c0SAaron LI }
242a7f975c0SAaron LI
243a7f975c0SAaron LI static inline bool
timer_expired(const struct timespec * birthdate,time_t sec,long nsec)244a7f975c0SAaron LI timer_expired(const struct timespec *birthdate, time_t sec, long nsec)
245a7f975c0SAaron LI {
246a7f975c0SAaron LI struct timespec uptime;
247a7f975c0SAaron LI struct timespec expire = { .tv_sec = sec, .tv_nsec = nsec };
248a7f975c0SAaron LI
24974210119SAaron LI if (__predict_false(!timespecisset(birthdate)))
25074210119SAaron LI return (true);
251a7f975c0SAaron LI
252a7f975c0SAaron LI getnanouptime(&uptime);
253a7f975c0SAaron LI timespecadd(birthdate, &expire, &expire);
254a7f975c0SAaron LI return timespeccmp(&uptime, &expire, >);
255a7f975c0SAaron LI }
256a7f975c0SAaron LI
25741fc5cd7SAaron LI /*----------------------------------------------------------------------------*/
25841fc5cd7SAaron LI
25941fc5cd7SAaron LI int
noise_init(void)26041fc5cd7SAaron LI noise_init(void)
26141fc5cd7SAaron LI {
26241fc5cd7SAaron LI #ifdef INVARIANTS
26341fc5cd7SAaron LI lockinit(&noise_mtx, "noise mtx lock", 0, 0);
26441fc5cd7SAaron LI
26541fc5cd7SAaron LI LIST_INIT(&noise_locals);
26641fc5cd7SAaron LI LIST_INIT(&noise_remotes);
26741fc5cd7SAaron LI LIST_INIT(&noise_keypairs);
26841fc5cd7SAaron LI #endif
26941fc5cd7SAaron LI
27041fc5cd7SAaron LI return (0);
27141fc5cd7SAaron LI }
27241fc5cd7SAaron LI
27341fc5cd7SAaron LI void
noise_deinit(void)27441fc5cd7SAaron LI noise_deinit(void)
27541fc5cd7SAaron LI {
27641fc5cd7SAaron LI #ifdef INVARIANTS
27741fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
27841fc5cd7SAaron LI
27941fc5cd7SAaron LI if (!LIST_EMPTY(&noise_locals))
28041fc5cd7SAaron LI panic("%s: noise_local leaked", __func__);
28141fc5cd7SAaron LI if (!LIST_EMPTY(&noise_remotes))
28241fc5cd7SAaron LI panic("%s: noise_remote leaked", __func__);
28341fc5cd7SAaron LI if (!LIST_EMPTY(&noise_keypairs))
28441fc5cd7SAaron LI panic("%s: noise_keypair leaked", __func__);
28541fc5cd7SAaron LI
28641fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
28741fc5cd7SAaron LI lockuninit(&noise_mtx);
28841fc5cd7SAaron LI #endif
28941fc5cd7SAaron LI }
290a7f975c0SAaron LI
291a7f975c0SAaron LI /*----------------------------------------------------------------------------*/
292a6bca3d2SAaron LI /* Local configuration */
293a7f975c0SAaron LI
294a6bca3d2SAaron LI struct noise_local *
noise_local_alloc(void)29529a085f5SAaron LI noise_local_alloc(void)
296a6bca3d2SAaron LI {
297a6bca3d2SAaron LI struct noise_local *l;
298a6bca3d2SAaron LI size_t i;
299a6bca3d2SAaron LI
300db846948SAaron LI l = kmalloc(sizeof(*l), M_NOISE, M_WAITOK | M_ZERO);
301a6bca3d2SAaron LI
3027ef217feSAaron LI lockinit(&l->l_identity_lock, "noise_identity", 0, 0);
303a6bca3d2SAaron LI refcount_init(&l->l_refcnt, 1);
304a9b5f3fdSAaron LI karc4random_buf(l->l_hash_key, sizeof(l->l_hash_key));
305a6bca3d2SAaron LI
306ef7d48a7SAaron LI lockinit(&l->l_remote_lock, "noise_remote", 0, 0);
307a6bca3d2SAaron LI for (i = 0; i < HT_REMOTE_SIZE; i++)
3081fdfe5a9SAaron LI LIST_INIT(&l->l_remote_hash[i]);
309a6bca3d2SAaron LI
310ef7d48a7SAaron LI lockinit(&l->l_index_lock, "noise_index", 0, 0);
311a6bca3d2SAaron LI for (i = 0; i < HT_INDEX_SIZE; i++)
3121fdfe5a9SAaron LI LIST_INIT(&l->l_index_hash[i]);
313a6bca3d2SAaron LI
31441fc5cd7SAaron LI #ifdef INVARIANTS
31541fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
31641fc5cd7SAaron LI LIST_INSERT_HEAD(&noise_locals, l, _l_entry);
31741fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
31841fc5cd7SAaron LI #endif
31941fc5cd7SAaron LI
320a6bca3d2SAaron LI return (l);
321a6bca3d2SAaron LI }
322a6bca3d2SAaron LI
3239bb9f522SAaron LI static struct noise_local *
noise_local_ref(struct noise_local * l)324a6bca3d2SAaron LI noise_local_ref(struct noise_local *l)
325a6bca3d2SAaron LI {
326a6bca3d2SAaron LI refcount_acquire(&l->l_refcnt);
327a6bca3d2SAaron LI return (l);
328a6bca3d2SAaron LI }
329a6bca3d2SAaron LI
3309bb9f522SAaron LI static void
noise_local_put(struct noise_local * l)331a6bca3d2SAaron LI noise_local_put(struct noise_local *l)
332a6bca3d2SAaron LI {
333a6bca3d2SAaron LI if (refcount_release(&l->l_refcnt)) {
33441fc5cd7SAaron LI #ifdef INVARIANTS
33541fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
33641fc5cd7SAaron LI LIST_REMOVE(l, _l_entry);
33741fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
33841fc5cd7SAaron LI #endif
33941fc5cd7SAaron LI
3407ef217feSAaron LI lockuninit(&l->l_identity_lock);
341ef7d48a7SAaron LI lockuninit(&l->l_remote_lock);
342ef7d48a7SAaron LI lockuninit(&l->l_index_lock);
343db846948SAaron LI explicit_bzero(l, sizeof(*l));
344db846948SAaron LI kfree(l, M_NOISE);
345a6bca3d2SAaron LI }
346a6bca3d2SAaron LI }
347a6bca3d2SAaron LI
348a6bca3d2SAaron LI void
noise_local_free(struct noise_local * l)34929a085f5SAaron LI noise_local_free(struct noise_local *l)
350a6bca3d2SAaron LI {
351a6bca3d2SAaron LI noise_local_put(l);
352a6bca3d2SAaron LI }
353a6bca3d2SAaron LI
354682f87c9SAaron LI bool
noise_local_set_private(struct noise_local * l,const uint8_t private[NOISE_PUBLIC_KEY_LEN])355279da17aSAaron LI noise_local_set_private(struct noise_local *l,
356279da17aSAaron LI const uint8_t private[NOISE_PUBLIC_KEY_LEN])
357a6bca3d2SAaron LI {
358a6bca3d2SAaron LI struct noise_remote *r;
359a6bca3d2SAaron LI size_t i;
360682f87c9SAaron LI bool has_identity;
361a6bca3d2SAaron LI
3627ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_EXCLUSIVE);
363279da17aSAaron LI
364682f87c9SAaron LI /* Note: we might be removing the private key. */
365a6bca3d2SAaron LI memcpy(l->l_private, private, NOISE_PUBLIC_KEY_LEN);
366a6bca3d2SAaron LI curve25519_clamp_secret(l->l_private);
367682f87c9SAaron LI has_identity = l->l_has_identity =
368279da17aSAaron LI curve25519_generate_public(l->l_public, l->l_private);
369a6bca3d2SAaron LI
370279da17aSAaron LI /* Invalidate all existing handshakes. */
371ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_SHARED);
372a6bca3d2SAaron LI for (i = 0; i < HT_REMOTE_SIZE; i++) {
3731fdfe5a9SAaron LI LIST_FOREACH(r, &l->l_remote_hash[i], r_entry) {
374a6bca3d2SAaron LI noise_precompute_ss(l, r);
375a6bca3d2SAaron LI noise_remote_expire_current(r);
376a6bca3d2SAaron LI }
377a6bca3d2SAaron LI }
378ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_RELEASE);
379279da17aSAaron LI
3807ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
381682f87c9SAaron LI return (has_identity);
382a6bca3d2SAaron LI }
383a6bca3d2SAaron LI
384682f87c9SAaron LI bool
noise_local_keys(struct noise_local * l,uint8_t public[NOISE_PUBLIC_KEY_LEN],uint8_t private[NOISE_PUBLIC_KEY_LEN])385a6bca3d2SAaron LI noise_local_keys(struct noise_local *l, uint8_t public[NOISE_PUBLIC_KEY_LEN],
386a6bca3d2SAaron LI uint8_t private[NOISE_PUBLIC_KEY_LEN])
387a6bca3d2SAaron LI {
388682f87c9SAaron LI bool has_identity;
389682f87c9SAaron LI
3907ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_SHARED);
391682f87c9SAaron LI has_identity = l->l_has_identity;
392682f87c9SAaron LI if (has_identity) {
393a6bca3d2SAaron LI if (public != NULL)
394a6bca3d2SAaron LI memcpy(public, l->l_public, NOISE_PUBLIC_KEY_LEN);
395a6bca3d2SAaron LI if (private != NULL)
396a6bca3d2SAaron LI memcpy(private, l->l_private, NOISE_PUBLIC_KEY_LEN);
397a6bca3d2SAaron LI }
3987ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
399682f87c9SAaron LI
400682f87c9SAaron LI return (has_identity);
401a6bca3d2SAaron LI }
402a6bca3d2SAaron LI
403a6bca3d2SAaron LI static void
noise_precompute_ss(struct noise_local * l,struct noise_remote * r)404a6bca3d2SAaron LI noise_precompute_ss(struct noise_local *l, struct noise_remote *r)
405a6bca3d2SAaron LI {
406c69b9a26SAaron LI KKASSERT(lockstatus(&l->l_identity_lock, curthread) != 0);
407c69b9a26SAaron LI
4087ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
409a6bca3d2SAaron LI if (!l->l_has_identity ||
410a6bca3d2SAaron LI !curve25519(r->r_ss, l->l_private, r->r_public))
411a6bca3d2SAaron LI bzero(r->r_ss, NOISE_PUBLIC_KEY_LEN);
4127ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
413a6bca3d2SAaron LI }
414a6bca3d2SAaron LI
415a7f975c0SAaron LI /*----------------------------------------------------------------------------*/
416a6bca3d2SAaron LI /* Remote configuration */
417a7f975c0SAaron LI
418a6bca3d2SAaron LI struct noise_remote *
noise_remote_alloc(struct noise_local * l,const uint8_t public[NOISE_PUBLIC_KEY_LEN],void * arg)419a7f975c0SAaron LI noise_remote_alloc(struct noise_local *l,
420a7f975c0SAaron LI const uint8_t public[NOISE_PUBLIC_KEY_LEN], void *arg)
421a6bca3d2SAaron LI {
422a6bca3d2SAaron LI struct noise_remote *r;
423a6bca3d2SAaron LI
424db846948SAaron LI r = kmalloc(sizeof(*r), M_NOISE, M_WAITOK | M_ZERO);
425a7f975c0SAaron LI
426a6bca3d2SAaron LI memcpy(r->r_public, public, NOISE_PUBLIC_KEY_LEN);
427a6bca3d2SAaron LI
4287ef217feSAaron LI lockinit(&r->r_handshake_lock, "noise_handshake", 0, 0);
429a6bca3d2SAaron LI r->r_handshake_state = HANDSHAKE_DEAD;
430a6bca3d2SAaron LI
431a6bca3d2SAaron LI refcount_init(&r->r_refcnt, 1);
432a6bca3d2SAaron LI r->r_local = noise_local_ref(l);
433a6bca3d2SAaron LI r->r_arg = arg;
434a6bca3d2SAaron LI
43513a64e4bSAaron LI lockinit(&r->r_keypair_lock, "noise_keypair", 0, 0);
436a6bca3d2SAaron LI
437c69b9a26SAaron LI lockmgr(&l->l_identity_lock, LK_SHARED);
438c69b9a26SAaron LI noise_precompute_ss(l, r);
439c69b9a26SAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
440c69b9a26SAaron LI
44141fc5cd7SAaron LI #ifdef INVARIANTS
44241fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
44341fc5cd7SAaron LI LIST_INSERT_HEAD(&noise_remotes, r, _r_entry);
44441fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
44541fc5cd7SAaron LI #endif
44641fc5cd7SAaron LI
447a6bca3d2SAaron LI return (r);
448a6bca3d2SAaron LI }
449a6bca3d2SAaron LI
450a6bca3d2SAaron LI int
noise_remote_enable(struct noise_remote * r)451a6bca3d2SAaron LI noise_remote_enable(struct noise_remote *r)
452a6bca3d2SAaron LI {
453a6bca3d2SAaron LI struct noise_local *l = r->r_local;
454a6bca3d2SAaron LI uint64_t idx;
455a6bca3d2SAaron LI int ret = 0;
456a6bca3d2SAaron LI
457a7f975c0SAaron LI idx = siphash24(l->l_hash_key, r->r_public, NOISE_PUBLIC_KEY_LEN);
458a7f975c0SAaron LI idx &= HT_REMOTE_MASK;
459a6bca3d2SAaron LI
460ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_EXCLUSIVE);
461a6bca3d2SAaron LI if (!r->r_entry_inserted) {
462ef7d48a7SAaron LI /* Insert to hashtable */
463a6bca3d2SAaron LI if (l->l_remote_num < MAX_REMOTE_PER_LOCAL) {
464a6bca3d2SAaron LI r->r_entry_inserted = true;
465a6bca3d2SAaron LI l->l_remote_num++;
4661fdfe5a9SAaron LI LIST_INSERT_HEAD(&l->l_remote_hash[idx], r, r_entry);
467a6bca3d2SAaron LI } else {
468a6bca3d2SAaron LI ret = ENOSPC;
469a6bca3d2SAaron LI }
470a6bca3d2SAaron LI }
471ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_RELEASE);
472a6bca3d2SAaron LI
473a7f975c0SAaron LI return (ret);
474a6bca3d2SAaron LI }
475a6bca3d2SAaron LI
476a6bca3d2SAaron LI void
noise_remote_disable(struct noise_remote * r)477a6bca3d2SAaron LI noise_remote_disable(struct noise_remote *r)
478a6bca3d2SAaron LI {
479a6bca3d2SAaron LI struct noise_local *l = r->r_local;
480ef7d48a7SAaron LI
481ef7d48a7SAaron LI /* Remove from hashtable */
482ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_EXCLUSIVE);
483a6bca3d2SAaron LI if (r->r_entry_inserted) {
484a6bca3d2SAaron LI r->r_entry_inserted = false;
4851fdfe5a9SAaron LI LIST_REMOVE(r, r_entry);
486a6bca3d2SAaron LI l->l_remote_num--;
487a6bca3d2SAaron LI };
488ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_RELEASE);
489a6bca3d2SAaron LI }
490a6bca3d2SAaron LI
491a6bca3d2SAaron LI struct noise_remote *
noise_remote_lookup(struct noise_local * l,const uint8_t public[NOISE_PUBLIC_KEY_LEN])492a7f975c0SAaron LI noise_remote_lookup(struct noise_local *l,
493a7f975c0SAaron LI const uint8_t public[NOISE_PUBLIC_KEY_LEN])
494a6bca3d2SAaron LI {
495a6bca3d2SAaron LI struct noise_remote *r, *ret = NULL;
496a6bca3d2SAaron LI uint64_t idx;
497a6bca3d2SAaron LI
498a7f975c0SAaron LI idx = siphash24(l->l_hash_key, public, NOISE_PUBLIC_KEY_LEN);
499a7f975c0SAaron LI idx &= HT_REMOTE_MASK;
500a6bca3d2SAaron LI
501ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_SHARED);
5021fdfe5a9SAaron LI LIST_FOREACH(r, &l->l_remote_hash[idx], r_entry) {
503ef7d48a7SAaron LI if (timingsafe_bcmp(r->r_public, public, NOISE_PUBLIC_KEY_LEN)
504ef7d48a7SAaron LI == 0) {
505ef7d48a7SAaron LI ret = noise_remote_ref(r);
506a6bca3d2SAaron LI break;
507a6bca3d2SAaron LI }
508a6bca3d2SAaron LI }
509ef7d48a7SAaron LI lockmgr(&l->l_remote_lock, LK_RELEASE);
510ef7d48a7SAaron LI
511a6bca3d2SAaron LI return (ret);
512a6bca3d2SAaron LI }
513a6bca3d2SAaron LI
514313ebe4eSAaron LI static uint32_t
noise_remote_index_insert(struct noise_local * l,struct noise_remote * r)515a6bca3d2SAaron LI noise_remote_index_insert(struct noise_local *l, struct noise_remote *r)
516a6bca3d2SAaron LI {
517a6bca3d2SAaron LI struct noise_index *i, *r_i = &r->r_index;
518a6bca3d2SAaron LI uint32_t idx;
519a6bca3d2SAaron LI
520a6bca3d2SAaron LI noise_remote_index_remove(l, r);
521a6bca3d2SAaron LI
522ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_EXCLUSIVE);
523ef7d48a7SAaron LI retry:
524a9b5f3fdSAaron LI r_i->i_local_index = karc4random();
525a6bca3d2SAaron LI idx = r_i->i_local_index & HT_INDEX_MASK;
5261fdfe5a9SAaron LI LIST_FOREACH(i, &l->l_index_hash[idx], i_entry) {
527a6bca3d2SAaron LI if (i->i_local_index == r_i->i_local_index)
528ef7d48a7SAaron LI goto retry;
529a6bca3d2SAaron LI }
5301fdfe5a9SAaron LI LIST_INSERT_HEAD(&l->l_index_hash[idx], r_i, i_entry);
531ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_RELEASE);
532313ebe4eSAaron LI
533313ebe4eSAaron LI return (r_i->i_local_index);
534a6bca3d2SAaron LI }
535a6bca3d2SAaron LI
536a6bca3d2SAaron LI static struct noise_remote *
noise_remote_index_lookup(struct noise_local * l,uint32_t idx0,bool lookup_keypair)537a7f975c0SAaron LI noise_remote_index_lookup(struct noise_local *l, uint32_t idx0,
538a7f975c0SAaron LI bool lookup_keypair)
539a6bca3d2SAaron LI {
540a6bca3d2SAaron LI struct noise_index *i;
541a6bca3d2SAaron LI struct noise_keypair *kp;
542a6bca3d2SAaron LI struct noise_remote *r, *ret = NULL;
543a6bca3d2SAaron LI uint32_t idx = idx0 & HT_INDEX_MASK;
544a6bca3d2SAaron LI
545ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_SHARED);
5461fdfe5a9SAaron LI LIST_FOREACH(i, &l->l_index_hash[idx], i_entry) {
547a6bca3d2SAaron LI if (i->i_local_index == idx0) {
548a6bca3d2SAaron LI if (!i->i_is_keypair) {
549a6bca3d2SAaron LI r = (struct noise_remote *) i;
550a6bca3d2SAaron LI } else if (lookup_keypair) {
551a7f975c0SAaron LI /* Also include keypair entries. */
552a6bca3d2SAaron LI kp = (struct noise_keypair *) i;
553a6bca3d2SAaron LI r = kp->kp_remote;
554a6bca3d2SAaron LI } else {
555a6bca3d2SAaron LI break;
556a6bca3d2SAaron LI }
557ef7d48a7SAaron LI ret = noise_remote_ref(r);
558a6bca3d2SAaron LI break;
559a6bca3d2SAaron LI }
560a6bca3d2SAaron LI }
561ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_RELEASE);
562ef7d48a7SAaron LI
563a6bca3d2SAaron LI return (ret);
564a6bca3d2SAaron LI }
565a6bca3d2SAaron LI
566a6bca3d2SAaron LI struct noise_remote *
noise_remote_index(struct noise_local * l,uint32_t idx)567a6bca3d2SAaron LI noise_remote_index(struct noise_local *l, uint32_t idx)
568a6bca3d2SAaron LI {
569a6bca3d2SAaron LI return noise_remote_index_lookup(l, idx, true);
570a6bca3d2SAaron LI }
571a6bca3d2SAaron LI
572682f87c9SAaron LI static bool
noise_remote_index_remove(struct noise_local * l,struct noise_remote * r)573a6bca3d2SAaron LI noise_remote_index_remove(struct noise_local *l, struct noise_remote *r)
574a6bca3d2SAaron LI {
5757ef217feSAaron LI KKASSERT(lockstatus(&r->r_handshake_lock, curthread) == LK_EXCLUSIVE);
576a7f975c0SAaron LI
577a6bca3d2SAaron LI if (r->r_handshake_state != HANDSHAKE_DEAD) {
578ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_EXCLUSIVE);
579a6bca3d2SAaron LI r->r_handshake_state = HANDSHAKE_DEAD;
5801fdfe5a9SAaron LI LIST_REMOVE(&r->r_index, i_entry);
581ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_RELEASE);
582682f87c9SAaron LI return (true);
583a6bca3d2SAaron LI }
584682f87c9SAaron LI
585682f87c9SAaron LI return (false);
586a6bca3d2SAaron LI }
587a6bca3d2SAaron LI
588a6bca3d2SAaron LI struct noise_remote *
noise_remote_ref(struct noise_remote * r)589a6bca3d2SAaron LI noise_remote_ref(struct noise_remote *r)
590a6bca3d2SAaron LI {
591a6bca3d2SAaron LI refcount_acquire(&r->r_refcnt);
592a6bca3d2SAaron LI return (r);
593a6bca3d2SAaron LI }
594a6bca3d2SAaron LI
595ef7d48a7SAaron LI void
noise_remote_put(struct noise_remote * r)596ef7d48a7SAaron LI noise_remote_put(struct noise_remote *r)
597a6bca3d2SAaron LI {
598ef7d48a7SAaron LI if (refcount_release(&r->r_refcnt)) {
59941fc5cd7SAaron LI #ifdef INVARIANTS
60041fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
60141fc5cd7SAaron LI LIST_REMOVE(r, _r_entry);
60241fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
60341fc5cd7SAaron LI #endif
60441fc5cd7SAaron LI
605a6bca3d2SAaron LI noise_local_put(r->r_local);
6067ef217feSAaron LI lockuninit(&r->r_handshake_lock);
60713a64e4bSAaron LI lockuninit(&r->r_keypair_lock);
608db846948SAaron LI explicit_bzero(r, sizeof(*r));
609db846948SAaron LI kfree(r, M_NOISE);
610a6bca3d2SAaron LI }
611a6bca3d2SAaron LI }
612a6bca3d2SAaron LI
613a6bca3d2SAaron LI void
noise_remote_free(struct noise_remote * r)614ef7d48a7SAaron LI noise_remote_free(struct noise_remote *r)
615a6bca3d2SAaron LI {
616a6bca3d2SAaron LI noise_remote_disable(r);
617a6bca3d2SAaron LI noise_remote_handshake_clear(r);
618a6bca3d2SAaron LI noise_remote_keypairs_clear(r);
619a6bca3d2SAaron LI noise_remote_put(r);
620a6bca3d2SAaron LI }
621a6bca3d2SAaron LI
622a6bca3d2SAaron LI void *
noise_remote_arg(struct noise_remote * r)623a6bca3d2SAaron LI noise_remote_arg(struct noise_remote *r)
624a6bca3d2SAaron LI {
625a6bca3d2SAaron LI return (r->r_arg);
626a6bca3d2SAaron LI }
627a6bca3d2SAaron LI
628a6bca3d2SAaron LI void
noise_remote_set_psk(struct noise_remote * r,const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])629a6bca3d2SAaron LI noise_remote_set_psk(struct noise_remote *r,
630a6bca3d2SAaron LI const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
631a6bca3d2SAaron LI {
6327ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
633a6bca3d2SAaron LI if (psk == NULL)
634a6bca3d2SAaron LI bzero(r->r_psk, NOISE_SYMMETRIC_KEY_LEN);
635a6bca3d2SAaron LI else
636a6bca3d2SAaron LI memcpy(r->r_psk, psk, NOISE_SYMMETRIC_KEY_LEN);
6377ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
638a6bca3d2SAaron LI }
639a6bca3d2SAaron LI
640682f87c9SAaron LI bool
noise_remote_keys(struct noise_remote * r,uint8_t public[NOISE_PUBLIC_KEY_LEN],uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])641a6bca3d2SAaron LI noise_remote_keys(struct noise_remote *r, uint8_t public[NOISE_PUBLIC_KEY_LEN],
642a6bca3d2SAaron LI uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
643a6bca3d2SAaron LI {
644a6bca3d2SAaron LI static uint8_t null_psk[NOISE_SYMMETRIC_KEY_LEN];
645682f87c9SAaron LI bool has_psk = false;
646a6bca3d2SAaron LI
647a6bca3d2SAaron LI if (public != NULL)
648a6bca3d2SAaron LI memcpy(public, r->r_public, NOISE_PUBLIC_KEY_LEN);
649a6bca3d2SAaron LI
6507ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_SHARED);
651682f87c9SAaron LI if (timingsafe_bcmp(r->r_psk, null_psk, NOISE_SYMMETRIC_KEY_LEN) != 0) {
652682f87c9SAaron LI has_psk = true;
653a6bca3d2SAaron LI if (psk != NULL)
654a6bca3d2SAaron LI memcpy(psk, r->r_psk, NOISE_SYMMETRIC_KEY_LEN);
65531551e01SAaron LI }
6567ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
657a6bca3d2SAaron LI
658682f87c9SAaron LI return (has_psk);
659a6bca3d2SAaron LI }
660a6bca3d2SAaron LI
661682f87c9SAaron LI bool
noise_remote_initiation_expired(struct noise_remote * r)662a6bca3d2SAaron LI noise_remote_initiation_expired(struct noise_remote *r)
663a6bca3d2SAaron LI {
664682f87c9SAaron LI bool expired;
665a7f975c0SAaron LI
6667ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_SHARED);
667a7f975c0SAaron LI expired = timer_expired(&r->r_last_sent, REKEY_TIMEOUT, 0);
6687ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
669a7f975c0SAaron LI
670a6bca3d2SAaron LI return (expired);
671a6bca3d2SAaron LI }
672a6bca3d2SAaron LI
673a6bca3d2SAaron LI void
noise_remote_handshake_clear(struct noise_remote * r)674a6bca3d2SAaron LI noise_remote_handshake_clear(struct noise_remote *r)
675a6bca3d2SAaron LI {
6767ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
677a6bca3d2SAaron LI if (noise_remote_index_remove(r->r_local, r))
678a6bca3d2SAaron LI bzero(&r->r_handshake, sizeof(r->r_handshake));
6792bed72b3SAaron LI bzero(&r->r_last_sent, sizeof(r->r_last_sent));
6807ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
681a6bca3d2SAaron LI }
682a6bca3d2SAaron LI
683a6bca3d2SAaron LI void
noise_remote_keypairs_clear(struct noise_remote * r)684a6bca3d2SAaron LI noise_remote_keypairs_clear(struct noise_remote *r)
685a6bca3d2SAaron LI {
686a6bca3d2SAaron LI struct noise_keypair *kp;
687a6bca3d2SAaron LI
68813a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_EXCLUSIVE);
68913a64e4bSAaron LI
690015567cbSAaron LI /*
691015567cbSAaron LI * We zero the "next" keypair before zeroing the others, so that
692015567cbSAaron LI * noise_keypair_received_with() returns early before subsequent
693015567cbSAaron LI * ones are zeroed.
694015567cbSAaron LI */
695461ea786SAaron LI kp = atomic_load_ptr(&r->r_keypair_next);
696461ea786SAaron LI atomic_store_ptr(&r->r_keypair_next, NULL);
697a6bca3d2SAaron LI noise_keypair_drop(kp);
698a6bca3d2SAaron LI
699461ea786SAaron LI kp = atomic_load_ptr(&r->r_keypair_current);
700461ea786SAaron LI atomic_store_ptr(&r->r_keypair_current, NULL);
701a6bca3d2SAaron LI noise_keypair_drop(kp);
702a6bca3d2SAaron LI
703461ea786SAaron LI kp = atomic_load_ptr(&r->r_keypair_previous);
704461ea786SAaron LI atomic_store_ptr(&r->r_keypair_previous, NULL);
705a6bca3d2SAaron LI noise_keypair_drop(kp);
70613a64e4bSAaron LI
70713a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
708a6bca3d2SAaron LI }
709a6bca3d2SAaron LI
710a6bca3d2SAaron LI static void
noise_remote_expire_current(struct noise_remote * r)711a6bca3d2SAaron LI noise_remote_expire_current(struct noise_remote *r)
712a6bca3d2SAaron LI {
713a6bca3d2SAaron LI struct noise_keypair *kp;
714a6bca3d2SAaron LI
715a6bca3d2SAaron LI noise_remote_handshake_clear(r);
716a6bca3d2SAaron LI
71713a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_SHARED);
718461ea786SAaron LI kp = atomic_load_ptr(&r->r_keypair_next);
719a6bca3d2SAaron LI if (kp != NULL)
720a6bca3d2SAaron LI atomic_store_bool(&kp->kp_can_send, false);
721461ea786SAaron LI kp = atomic_load_ptr(&r->r_keypair_current);
722a6bca3d2SAaron LI if (kp != NULL)
723a6bca3d2SAaron LI atomic_store_bool(&kp->kp_can_send, false);
72413a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
725a6bca3d2SAaron LI }
726a6bca3d2SAaron LI
727a7f975c0SAaron LI /*----------------------------------------------------------------------------*/
728a6bca3d2SAaron LI /* Keypair functions */
729a7f975c0SAaron LI
730a6bca3d2SAaron LI struct noise_keypair *
noise_keypair_lookup(struct noise_local * l,uint32_t idx0)731a6bca3d2SAaron LI noise_keypair_lookup(struct noise_local *l, uint32_t idx0)
732a6bca3d2SAaron LI {
733a6bca3d2SAaron LI struct noise_index *i;
734a6bca3d2SAaron LI struct noise_keypair *kp, *ret = NULL;
735ef7d48a7SAaron LI uint32_t idx;
736a6bca3d2SAaron LI
737ef7d48a7SAaron LI idx = idx0 & HT_INDEX_MASK;
738ef7d48a7SAaron LI
739ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_SHARED);
7401fdfe5a9SAaron LI LIST_FOREACH(i, &l->l_index_hash[idx], i_entry) {
741a6bca3d2SAaron LI if (i->i_local_index == idx0 && i->i_is_keypair) {
742a6bca3d2SAaron LI kp = (struct noise_keypair *) i;
743ef7d48a7SAaron LI ret = noise_keypair_ref(kp);
744a6bca3d2SAaron LI break;
745a6bca3d2SAaron LI }
746a6bca3d2SAaron LI }
747ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_RELEASE);
748ef7d48a7SAaron LI
749a6bca3d2SAaron LI return (ret);
750a6bca3d2SAaron LI }
751a6bca3d2SAaron LI
752a6bca3d2SAaron LI struct noise_keypair *
noise_keypair_current(struct noise_remote * r)753a6bca3d2SAaron LI noise_keypair_current(struct noise_remote *r)
754a6bca3d2SAaron LI {
755a6bca3d2SAaron LI struct noise_keypair *kp, *ret = NULL;
756a6bca3d2SAaron LI
75713a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_SHARED);
758461ea786SAaron LI kp = atomic_load_ptr(&r->r_keypair_current);
759a6bca3d2SAaron LI if (kp != NULL && atomic_load_bool(&kp->kp_can_send)) {
760a7f975c0SAaron LI if (timer_expired(&kp->kp_birthdate, REJECT_AFTER_TIME, 0))
761a6bca3d2SAaron LI atomic_store_bool(&kp->kp_can_send, false);
76213a64e4bSAaron LI else
76313a64e4bSAaron LI ret = noise_keypair_ref(kp);
764a6bca3d2SAaron LI }
76513a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
766a6bca3d2SAaron LI
76713a64e4bSAaron LI return (ret);
768a6bca3d2SAaron LI }
769a6bca3d2SAaron LI
770f0fd05c3SAaron LI /*
771f0fd05c3SAaron LI * Check whether the keypair <kp> associated with the received packet
772f0fd05c3SAaron LI * is the "next" keypair of the remote peer. If true, it means the
773f0fd05c3SAaron LI * keypair has received the confirmation from the initiator and thus
774f0fd05c3SAaron LI * becomes the "current".
775f0fd05c3SAaron LI */
776682f87c9SAaron LI bool
noise_keypair_received_with(struct noise_keypair * kp)777a6bca3d2SAaron LI noise_keypair_received_with(struct noise_keypair *kp)
778a6bca3d2SAaron LI {
779a6bca3d2SAaron LI struct noise_keypair *old;
780a6bca3d2SAaron LI struct noise_remote *r = kp->kp_remote;
781a6bca3d2SAaron LI
782f0fd05c3SAaron LI if (kp->kp_is_initiator)
783f0fd05c3SAaron LI return (false);
784461ea786SAaron LI if (kp != atomic_load_ptr(&r->r_keypair_next))
785682f87c9SAaron LI return (false);
786a6bca3d2SAaron LI
78713a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_EXCLUSIVE);
78813a64e4bSAaron LI
78913a64e4bSAaron LI /* Double check after locking. */
790461ea786SAaron LI if (kp != atomic_load_ptr(&r->r_keypair_next)) {
79113a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
792682f87c9SAaron LI return (false);
793a6bca3d2SAaron LI }
794a6bca3d2SAaron LI
795f0fd05c3SAaron LI /*
796f0fd05c3SAaron LI * Received the confirming data packet, so move the keypair from
797f0fd05c3SAaron LI * the "next" slot to the "current".
798f0fd05c3SAaron LI */
799461ea786SAaron LI old = atomic_load_ptr(&r->r_keypair_previous);
800461ea786SAaron LI atomic_store_ptr(&r->r_keypair_previous,
801461ea786SAaron LI atomic_load_ptr(&r->r_keypair_current));
802a6bca3d2SAaron LI noise_keypair_drop(old);
803461ea786SAaron LI atomic_store_ptr(&r->r_keypair_current, kp);
804461ea786SAaron LI atomic_store_ptr(&r->r_keypair_next, NULL);
80513a64e4bSAaron LI
80613a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
807a6bca3d2SAaron LI
808682f87c9SAaron LI return (true);
809a6bca3d2SAaron LI }
810a6bca3d2SAaron LI
81113a64e4bSAaron LI struct noise_keypair *
noise_keypair_ref(struct noise_keypair * kp)81213a64e4bSAaron LI noise_keypair_ref(struct noise_keypair *kp)
813a6bca3d2SAaron LI {
81413a64e4bSAaron LI refcount_acquire(&kp->kp_refcnt);
81513a64e4bSAaron LI return (kp);
816a6bca3d2SAaron LI }
817a6bca3d2SAaron LI
818a6bca3d2SAaron LI void
noise_keypair_put(struct noise_keypair * kp)819a6bca3d2SAaron LI noise_keypair_put(struct noise_keypair *kp)
820a6bca3d2SAaron LI {
82113a64e4bSAaron LI if (refcount_release(&kp->kp_refcnt)) {
82241fc5cd7SAaron LI #ifdef INVARIANTS
82341fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
82441fc5cd7SAaron LI LIST_REMOVE(kp, _kp_entry);
82541fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
82641fc5cd7SAaron LI #endif
82741fc5cd7SAaron LI
82813a64e4bSAaron LI noise_remote_put(kp->kp_remote);
82913a64e4bSAaron LI lockuninit(&kp->kp_counter_lock);
83013a64e4bSAaron LI explicit_bzero(kp, sizeof(*kp));
83113a64e4bSAaron LI kfree(kp, M_NOISE);
83213a64e4bSAaron LI }
833a6bca3d2SAaron LI }
834a6bca3d2SAaron LI
835a6bca3d2SAaron LI static void
noise_keypair_drop(struct noise_keypair * kp)836a6bca3d2SAaron LI noise_keypair_drop(struct noise_keypair *kp)
837a6bca3d2SAaron LI {
838a6bca3d2SAaron LI struct noise_remote *r;
839a6bca3d2SAaron LI struct noise_local *l;
840a6bca3d2SAaron LI
841a6bca3d2SAaron LI if (kp == NULL)
842a6bca3d2SAaron LI return;
843a6bca3d2SAaron LI
844a6bca3d2SAaron LI r = kp->kp_remote;
845a6bca3d2SAaron LI l = r->r_local;
846a6bca3d2SAaron LI
847ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_EXCLUSIVE);
8481fdfe5a9SAaron LI LIST_REMOVE(&kp->kp_index, i_entry);
849ef7d48a7SAaron LI lockmgr(&l->l_index_lock, LK_RELEASE);
850a6bca3d2SAaron LI
85113a64e4bSAaron LI KKASSERT(lockstatus(&r->r_keypair_lock, curthread) == LK_EXCLUSIVE);
852a6bca3d2SAaron LI noise_keypair_put(kp);
853a6bca3d2SAaron LI }
854a6bca3d2SAaron LI
855a6bca3d2SAaron LI struct noise_remote *
noise_keypair_remote(struct noise_keypair * kp)856a6bca3d2SAaron LI noise_keypair_remote(struct noise_keypair *kp)
857a6bca3d2SAaron LI {
858a6bca3d2SAaron LI return (noise_remote_ref(kp->kp_remote));
859a6bca3d2SAaron LI }
860a6bca3d2SAaron LI
861682f87c9SAaron LI bool
noise_keypair_counter_next(struct noise_keypair * kp,uint64_t * send)862cfdd69bcSAaron LI noise_keypair_counter_next(struct noise_keypair *kp, uint64_t *send)
863a6bca3d2SAaron LI {
864a6bca3d2SAaron LI if (!atomic_load_bool(&kp->kp_can_send))
865682f87c9SAaron LI return (false);
866a6bca3d2SAaron LI
867a6bca3d2SAaron LI #ifdef __LP64__
868cfdd69bcSAaron LI *send = atomic_fetchadd_64(&kp->kp_counter_send, 1);
869a6bca3d2SAaron LI #else
870cfdd69bcSAaron LI lockmgr(&kp->kp_counter_lock, LK_EXCLUSIVE);
871cfdd69bcSAaron LI *send = kp->kp_counter_send++;
872cfdd69bcSAaron LI lockmgr(&kp->kp_counter_lock, LK_RELEASE);
873a6bca3d2SAaron LI #endif
874015567cbSAaron LI if (*send >= REJECT_AFTER_MESSAGES) {
875a6bca3d2SAaron LI atomic_store_bool(&kp->kp_can_send, false);
876682f87c9SAaron LI return (false);
877a6bca3d2SAaron LI }
878a6bca3d2SAaron LI
879015567cbSAaron LI return (true);
880015567cbSAaron LI }
881015567cbSAaron LI
88279d60aa0SAaron LI /*
88379d60aa0SAaron LI * Validate the received counter to avoid replay attacks. A sliding window
88479d60aa0SAaron LI * is used to keep track of the received counters, since the UDP messages
88579d60aa0SAaron LI * can arrive out of order.
88679d60aa0SAaron LI *
88779d60aa0SAaron LI * NOTE: Validate the counter only *after* successful decryption, which
88879d60aa0SAaron LI * ensures that the message and counter is authentic.
88979d60aa0SAaron LI *
89079d60aa0SAaron LI * This implements the algorithm from RFC 6479:
89179d60aa0SAaron LI * "IPsec Anti-Replay Algorithm without Bit Shifting"
89279d60aa0SAaron LI */
89379d60aa0SAaron LI int
noise_keypair_counter_check(struct noise_keypair * kp,uint64_t recv)894cfdd69bcSAaron LI noise_keypair_counter_check(struct noise_keypair *kp, uint64_t recv)
895a6bca3d2SAaron LI {
896a6bca3d2SAaron LI unsigned long index, index_current, top, i, bit;
89779d60aa0SAaron LI int ret;
898a6bca3d2SAaron LI
899cfdd69bcSAaron LI lockmgr(&kp->kp_counter_lock, LK_EXCLUSIVE);
900a6bca3d2SAaron LI
901f82bb155SAaron LI if (__predict_false(kp->kp_counter_recv >= REJECT_AFTER_MESSAGES ||
90279d60aa0SAaron LI recv >= REJECT_AFTER_MESSAGES)) {
90379d60aa0SAaron LI ret = EINVAL;
90479d60aa0SAaron LI goto out;
90579d60aa0SAaron LI }
906a6bca3d2SAaron LI
90779d60aa0SAaron LI if (__predict_false(recv + COUNTER_WINDOW_SIZE < kp->kp_counter_recv)) {
90879d60aa0SAaron LI ret = ESTALE;
90979d60aa0SAaron LI goto out;
91079d60aa0SAaron LI }
911a6bca3d2SAaron LI
912a6bca3d2SAaron LI index = recv >> COUNTER_ORDER;
913a6bca3d2SAaron LI
914cfdd69bcSAaron LI if (__predict_true(recv > kp->kp_counter_recv)) {
91579d60aa0SAaron LI /*
91679d60aa0SAaron LI * The new counter is ahead of the current counter, so need
91779d60aa0SAaron LI * to zero out the bitmap that has previously been used.
91879d60aa0SAaron LI */
919cfdd69bcSAaron LI index_current = kp->kp_counter_recv >> COUNTER_ORDER;
920fa8f7fdbSAaron LI top = MIN(index - index_current, COUNTER_NUM);
921a6bca3d2SAaron LI for (i = 1; i <= top; i++)
922fa8f7fdbSAaron LI kp->kp_backtrack[(i+index_current) & COUNTER_MASK] = 0;
923a6bca3d2SAaron LI #ifdef __LP64__
924cfdd69bcSAaron LI atomic_store_64(&kp->kp_counter_recv, recv);
925a6bca3d2SAaron LI #else
926cfdd69bcSAaron LI kp->kp_counter_recv = recv;
927a6bca3d2SAaron LI #endif
928a6bca3d2SAaron LI }
929a6bca3d2SAaron LI
930fa8f7fdbSAaron LI index &= COUNTER_MASK;
931fa8f7fdbSAaron LI bit = 1UL << (recv & (COUNTER_BITS - 1));
93279d60aa0SAaron LI if (kp->kp_backtrack[index] & bit) {
93379d60aa0SAaron LI ret = EEXIST;
93479d60aa0SAaron LI goto out;
93579d60aa0SAaron LI }
936a6bca3d2SAaron LI
937a6bca3d2SAaron LI kp->kp_backtrack[index] |= bit;
93879d60aa0SAaron LI ret = 0;
939682f87c9SAaron LI
94079d60aa0SAaron LI out:
941cfdd69bcSAaron LI lockmgr(&kp->kp_counter_lock, LK_RELEASE);
94279d60aa0SAaron LI return (ret);
943a6bca3d2SAaron LI }
944a6bca3d2SAaron LI
94570a0d19bSAaron LI /*
94670a0d19bSAaron LI * Check whether the current keypair of the given remote <r> is expiring soon
94770a0d19bSAaron LI * or already expired, and thus should do a refreshing.
94870a0d19bSAaron LI */
949682f87c9SAaron LI bool
noise_keypair_should_refresh(struct noise_remote * r,bool sending)95070a0d19bSAaron LI noise_keypair_should_refresh(struct noise_remote *r, bool sending)
951a6bca3d2SAaron LI {
95270a0d19bSAaron LI struct noise_keypair *kp;
953cfdd69bcSAaron LI uint64_t counter;
95470a0d19bSAaron LI bool refresh;
955a6bca3d2SAaron LI
95613a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_SHARED);
95713a64e4bSAaron LI
95870a0d19bSAaron LI kp = atomic_load_ptr(&r->r_keypair_current);
95970a0d19bSAaron LI refresh = (kp != NULL && atomic_load_bool(&kp->kp_can_send));
96070a0d19bSAaron LI if (__predict_false(!refresh))
961a6bca3d2SAaron LI goto out;
962a7f975c0SAaron LI
96370a0d19bSAaron LI if (sending) {
96470a0d19bSAaron LI /* sending path */
96570a0d19bSAaron LI #ifdef __LP64__
96670a0d19bSAaron LI counter = atomic_load_64(&kp->kp_counter_send);
96770a0d19bSAaron LI #else
96870a0d19bSAaron LI lockmgr(&kp->kp_counter_lock, LK_SHARED);
96970a0d19bSAaron LI counter = kp->kp_counter_send;
97070a0d19bSAaron LI lockmgr(&kp->kp_counter_lock, LK_RELEASE);
97170a0d19bSAaron LI #endif
97270a0d19bSAaron LI refresh = (counter > REKEY_AFTER_MESSAGES ||
97370a0d19bSAaron LI (kp->kp_is_initiator &&
97470a0d19bSAaron LI timer_expired(&kp->kp_birthdate,
97570a0d19bSAaron LI REKEY_AFTER_TIME, 0)));
97670a0d19bSAaron LI } else {
97770a0d19bSAaron LI /* receiving path */
97870a0d19bSAaron LI refresh = (kp->kp_is_initiator &&
97970a0d19bSAaron LI timer_expired(&kp->kp_birthdate, REJECT_AFTER_TIME -
98070a0d19bSAaron LI KEEPALIVE_TIMEOUT - REKEY_TIMEOUT, 0));
98170a0d19bSAaron LI }
982a6bca3d2SAaron LI
983a6bca3d2SAaron LI out:
98413a64e4bSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
98570a0d19bSAaron LI return (refresh);
986a6bca3d2SAaron LI }
987a6bca3d2SAaron LI
988a6bca3d2SAaron LI int
noise_keypair_encrypt(struct noise_keypair * kp,uint32_t * r_idx,uint64_t counter,struct mbuf * m)989cfdd69bcSAaron LI noise_keypair_encrypt(struct noise_keypair *kp, uint32_t *r_idx,
990cfdd69bcSAaron LI uint64_t counter, struct mbuf *m)
991a6bca3d2SAaron LI {
992cfdd69bcSAaron LI uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE];
993a6bca3d2SAaron LI int ret;
994a6bca3d2SAaron LI
995cfdd69bcSAaron LI /* 32 bits of zeros + 64-bit little-endian value of the counter */
996cfdd69bcSAaron LI *(uint32_t *)nonce = 0;
997cfdd69bcSAaron LI *(uint64_t *)(nonce + 4) = htole64(counter);
998cfdd69bcSAaron LI
999cfdd69bcSAaron LI ret = chacha20poly1305_encrypt_mbuf(m, NULL, 0, nonce, kp->kp_send);
1000a7f975c0SAaron LI if (ret == 0)
1001a6bca3d2SAaron LI *r_idx = kp->kp_index.i_remote_index;
1002a7f975c0SAaron LI
1003a7f975c0SAaron LI return (ret);
1004a6bca3d2SAaron LI }
1005a6bca3d2SAaron LI
1006a6bca3d2SAaron LI int
noise_keypair_decrypt(struct noise_keypair * kp,uint64_t counter,struct mbuf * m)1007cfdd69bcSAaron LI noise_keypair_decrypt(struct noise_keypair *kp, uint64_t counter,
1008cfdd69bcSAaron LI struct mbuf *m)
1009a6bca3d2SAaron LI {
1010cfdd69bcSAaron LI uint64_t cur_counter;
1011cfdd69bcSAaron LI uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE];
1012a6bca3d2SAaron LI
1013a6bca3d2SAaron LI #ifdef __LP64__
1014cfdd69bcSAaron LI cur_counter = atomic_load_64(&kp->kp_counter_recv);
1015a6bca3d2SAaron LI #else
1016cfdd69bcSAaron LI lockmgr(&kp->kp_counter_lock, LK_SHARED);
1017cfdd69bcSAaron LI cur_counter = kp->kp_counter_recv;
1018cfdd69bcSAaron LI lockmgr(&kp->kp_counter_lock, LK_RELEASE);
1019a6bca3d2SAaron LI #endif
1020cfdd69bcSAaron LI if (cur_counter >= REJECT_AFTER_MESSAGES ||
1021a7f975c0SAaron LI timer_expired(&kp->kp_birthdate, REJECT_AFTER_TIME, 0))
1022a6bca3d2SAaron LI return (EINVAL);
1023a6bca3d2SAaron LI
1024cfdd69bcSAaron LI *(uint32_t *)nonce = 0;
1025cfdd69bcSAaron LI *(uint64_t *)(nonce + 4) = htole64(counter);
1026a6bca3d2SAaron LI
1027a7f975c0SAaron LI return chacha20poly1305_decrypt_mbuf(m, NULL, 0, nonce, kp->kp_recv);
1028a6bca3d2SAaron LI }
1029a6bca3d2SAaron LI
1030a7f975c0SAaron LI /*----------------------------------------------------------------------------*/
1031a6bca3d2SAaron LI /* Handshake functions */
1032a7f975c0SAaron LI
1033e44138a7SAaron LI bool
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])1034a7f975c0SAaron LI noise_create_initiation(struct noise_remote *r, uint32_t *s_idx,
1035a6bca3d2SAaron LI uint8_t ue[NOISE_PUBLIC_KEY_LEN],
1036a6bca3d2SAaron LI uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN],
1037a6bca3d2SAaron LI uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN])
1038a6bca3d2SAaron LI {
1039a6bca3d2SAaron LI struct noise_handshake *hs = &r->r_handshake;
1040a6bca3d2SAaron LI struct noise_local *l = r->r_local;
1041a6bca3d2SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
1042e44138a7SAaron LI bool ok = false;
1043a6bca3d2SAaron LI
10447ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_SHARED);
10457ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
1046a7f975c0SAaron LI
1047a6bca3d2SAaron LI if (!l->l_has_identity)
1048a6bca3d2SAaron LI goto error;
1049a7f975c0SAaron LI if (!timer_expired(&r->r_last_sent, REKEY_TIMEOUT, 0))
1050a6bca3d2SAaron LI goto error;
1051a7f975c0SAaron LI
1052a6bca3d2SAaron LI noise_param_init(hs->hs_ck, hs->hs_hash, r->r_public);
1053a6bca3d2SAaron LI
1054a6bca3d2SAaron LI /* e */
1055a6bca3d2SAaron LI curve25519_generate_secret(hs->hs_e);
1056a6bca3d2SAaron LI if (curve25519_generate_public(ue, hs->hs_e) == 0)
1057a6bca3d2SAaron LI goto error;
1058a6bca3d2SAaron LI noise_msg_ephemeral(hs->hs_ck, hs->hs_hash, ue);
1059a6bca3d2SAaron LI
1060a6bca3d2SAaron LI /* es */
1061c222eea3SAaron LI if (!noise_mix_dh(hs->hs_ck, key, hs->hs_e, r->r_public))
1062a6bca3d2SAaron LI goto error;
1063a6bca3d2SAaron LI
1064a6bca3d2SAaron LI /* s */
1065a7f975c0SAaron LI noise_msg_encrypt(es, l->l_public, NOISE_PUBLIC_KEY_LEN,
1066a7f975c0SAaron LI key, hs->hs_hash);
1067a6bca3d2SAaron LI
1068a6bca3d2SAaron LI /* ss */
1069c222eea3SAaron LI if (!noise_mix_ss(hs->hs_ck, key, r->r_ss))
1070a6bca3d2SAaron LI goto error;
1071a6bca3d2SAaron LI
1072a6bca3d2SAaron LI /* {t} */
1073a6bca3d2SAaron LI noise_tai64n_now(ets);
1074a7f975c0SAaron LI noise_msg_encrypt(ets, ets, NOISE_TIMESTAMP_LEN, key, hs->hs_hash);
1075a6bca3d2SAaron LI
1076313ebe4eSAaron LI *s_idx = noise_remote_index_insert(l, r);
1077a6bca3d2SAaron LI r->r_handshake_state = HANDSHAKE_INITIATOR;
10782bed72b3SAaron LI getnanouptime(&r->r_last_sent);
1079e44138a7SAaron LI ok = true;
1080a7f975c0SAaron LI
1081a6bca3d2SAaron LI error:
10827ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
10837ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
1084a7f975c0SAaron LI explicit_bzero(key, sizeof(key));
1085e44138a7SAaron LI return (ok);
1086a6bca3d2SAaron LI }
1087a6bca3d2SAaron LI
1088e44138a7SAaron LI struct noise_remote *
noise_consume_initiation(struct noise_local * l,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])1089e44138a7SAaron LI noise_consume_initiation(struct noise_local *l, uint32_t s_idx,
1090e44138a7SAaron LI uint8_t ue[NOISE_PUBLIC_KEY_LEN],
1091a6bca3d2SAaron LI uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN],
1092a6bca3d2SAaron LI uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN])
1093a6bca3d2SAaron LI {
1094e44138a7SAaron LI struct noise_remote *r, *ret = NULL;
1095a6bca3d2SAaron LI struct noise_handshake hs;
1096a6bca3d2SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
1097a6bca3d2SAaron LI uint8_t r_public[NOISE_PUBLIC_KEY_LEN];
1098a6bca3d2SAaron LI uint8_t timestamp[NOISE_TIMESTAMP_LEN];
1099a6bca3d2SAaron LI
11007ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_SHARED);
1101a7f975c0SAaron LI
1102a6bca3d2SAaron LI if (!l->l_has_identity)
1103a6bca3d2SAaron LI goto error;
1104a7f975c0SAaron LI
1105a6bca3d2SAaron LI noise_param_init(hs.hs_ck, hs.hs_hash, l->l_public);
1106a6bca3d2SAaron LI
1107a6bca3d2SAaron LI /* e */
1108a6bca3d2SAaron LI noise_msg_ephemeral(hs.hs_ck, hs.hs_hash, ue);
1109a6bca3d2SAaron LI
1110a6bca3d2SAaron LI /* es */
1111c222eea3SAaron LI if (!noise_mix_dh(hs.hs_ck, key, l->l_private, ue))
1112a6bca3d2SAaron LI goto error;
1113a6bca3d2SAaron LI
1114a6bca3d2SAaron LI /* s */
1115c222eea3SAaron LI if (!noise_msg_decrypt(r_public, es,
1116a7f975c0SAaron LI NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN,
1117c222eea3SAaron LI key, hs.hs_hash))
1118a6bca3d2SAaron LI goto error;
1119a6bca3d2SAaron LI
1120a6bca3d2SAaron LI /* Lookup the remote we received from */
1121a6bca3d2SAaron LI if ((r = noise_remote_lookup(l, r_public)) == NULL)
1122a6bca3d2SAaron LI goto error;
1123a6bca3d2SAaron LI
1124a6bca3d2SAaron LI /* ss */
1125c222eea3SAaron LI if (!noise_mix_ss(hs.hs_ck, key, r->r_ss))
1126a6bca3d2SAaron LI goto error_put;
1127a6bca3d2SAaron LI
1128a6bca3d2SAaron LI /* {t} */
1129c222eea3SAaron LI if (!noise_msg_decrypt(timestamp, ets,
1130a7f975c0SAaron LI NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN,
1131c222eea3SAaron LI key, hs.hs_hash))
1132a6bca3d2SAaron LI goto error_put;
1133a6bca3d2SAaron LI
1134a6bca3d2SAaron LI memcpy(hs.hs_e, ue, NOISE_PUBLIC_KEY_LEN);
1135a6bca3d2SAaron LI
1136a7f975c0SAaron LI /*
1137a7f975c0SAaron LI * We have successfully computed the same results, now we ensure that
1138a7f975c0SAaron LI * this is not an initiation replay, or a flood attack.
1139a7f975c0SAaron LI */
11407ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
1141a6bca3d2SAaron LI
1142a6bca3d2SAaron LI /* Replay */
1143a6bca3d2SAaron LI if (memcmp(timestamp, r->r_timestamp, NOISE_TIMESTAMP_LEN) > 0)
1144a6bca3d2SAaron LI memcpy(r->r_timestamp, timestamp, NOISE_TIMESTAMP_LEN);
1145a6bca3d2SAaron LI else
1146a6bca3d2SAaron LI goto error_set;
1147a6bca3d2SAaron LI /* Flood attack */
1148a7f975c0SAaron LI if (timer_expired(&r->r_last_init_recv, 0, REJECT_INTERVAL))
11492bed72b3SAaron LI getnanouptime(&r->r_last_init_recv);
1150a6bca3d2SAaron LI else
1151a6bca3d2SAaron LI goto error_set;
1152a6bca3d2SAaron LI
1153a6bca3d2SAaron LI /* Ok, we're happy to accept this initiation now */
1154a6bca3d2SAaron LI noise_remote_index_insert(l, r);
1155a6bca3d2SAaron LI r->r_index.i_remote_index = s_idx;
1156a6bca3d2SAaron LI r->r_handshake_state = HANDSHAKE_RESPONDER;
1157a6bca3d2SAaron LI r->r_handshake = hs;
1158e44138a7SAaron LI ret = noise_remote_ref(r);
1159a7f975c0SAaron LI
1160a6bca3d2SAaron LI error_set:
11617ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
1162a6bca3d2SAaron LI error_put:
1163a6bca3d2SAaron LI noise_remote_put(r);
1164a6bca3d2SAaron LI error:
11657ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
1166a7f975c0SAaron LI explicit_bzero(key, sizeof(key));
1167a6bca3d2SAaron LI explicit_bzero(&hs, sizeof(hs));
1168a6bca3d2SAaron LI return (ret);
1169a6bca3d2SAaron LI }
1170a6bca3d2SAaron LI
1171e44138a7SAaron LI bool
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])1172a7f975c0SAaron LI noise_create_response(struct noise_remote *r, uint32_t *s_idx,
1173a7f975c0SAaron LI uint32_t *r_idx, uint8_t ue[NOISE_PUBLIC_KEY_LEN],
1174a6bca3d2SAaron LI uint8_t en[0 + NOISE_AUTHTAG_LEN])
1175a6bca3d2SAaron LI {
1176a6bca3d2SAaron LI struct noise_handshake *hs = &r->r_handshake;
1177a6bca3d2SAaron LI struct noise_local *l = r->r_local;
1178a6bca3d2SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
1179a6bca3d2SAaron LI uint8_t e[NOISE_PUBLIC_KEY_LEN];
1180e44138a7SAaron LI bool ok = false;
1181a6bca3d2SAaron LI
11827ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_SHARED);
11837ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
1184a6bca3d2SAaron LI
1185a6bca3d2SAaron LI if (r->r_handshake_state != HANDSHAKE_RESPONDER)
1186a6bca3d2SAaron LI goto error;
1187a6bca3d2SAaron LI
1188a6bca3d2SAaron LI /* e */
1189a6bca3d2SAaron LI curve25519_generate_secret(e);
1190a6bca3d2SAaron LI if (curve25519_generate_public(ue, e) == 0)
1191a6bca3d2SAaron LI goto error;
1192a6bca3d2SAaron LI noise_msg_ephemeral(hs->hs_ck, hs->hs_hash, ue);
1193a6bca3d2SAaron LI
1194a6bca3d2SAaron LI /* ee */
1195c222eea3SAaron LI if (!noise_mix_dh(hs->hs_ck, NULL, e, hs->hs_e))
1196a6bca3d2SAaron LI goto error;
1197a6bca3d2SAaron LI
1198a6bca3d2SAaron LI /* se */
1199c222eea3SAaron LI if (!noise_mix_dh(hs->hs_ck, NULL, e, r->r_public))
1200a6bca3d2SAaron LI goto error;
1201a6bca3d2SAaron LI
1202a6bca3d2SAaron LI /* psk */
1203a6bca3d2SAaron LI noise_mix_psk(hs->hs_ck, hs->hs_hash, key, r->r_psk);
1204a6bca3d2SAaron LI
1205a6bca3d2SAaron LI /* {} */
1206a6bca3d2SAaron LI noise_msg_encrypt(en, NULL, 0, key, hs->hs_hash);
1207a6bca3d2SAaron LI
1208f0424a0dSAaron LI if (noise_begin_session(r)) {
12092bed72b3SAaron LI getnanouptime(&r->r_last_sent);
1210a6bca3d2SAaron LI *s_idx = r->r_index.i_local_index;
1211a6bca3d2SAaron LI *r_idx = r->r_index.i_remote_index;
1212e44138a7SAaron LI ok = true;
1213a6bca3d2SAaron LI }
1214a7f975c0SAaron LI
1215a6bca3d2SAaron LI error:
12167ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
12177ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
1218a7f975c0SAaron LI explicit_bzero(key, sizeof(key));
1219a7f975c0SAaron LI explicit_bzero(e, sizeof(e));
1220e44138a7SAaron LI return (ok);
1221a6bca3d2SAaron LI }
1222a6bca3d2SAaron LI
1223e44138a7SAaron LI struct noise_remote *
noise_consume_response(struct noise_local * l,uint32_t s_idx,uint32_t r_idx,uint8_t ue[NOISE_PUBLIC_KEY_LEN],uint8_t en[0+NOISE_AUTHTAG_LEN])1224e44138a7SAaron LI noise_consume_response(struct noise_local *l, uint32_t s_idx, uint32_t r_idx,
1225a6bca3d2SAaron LI uint8_t ue[NOISE_PUBLIC_KEY_LEN],
1226a6bca3d2SAaron LI uint8_t en[0 + NOISE_AUTHTAG_LEN])
1227a6bca3d2SAaron LI {
1228e44138a7SAaron LI struct noise_remote *r, *ret = NULL;
1229e44138a7SAaron LI struct noise_handshake hs;
1230a6bca3d2SAaron LI uint8_t preshared_key[NOISE_SYMMETRIC_KEY_LEN];
1231a6bca3d2SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN];
1232a6bca3d2SAaron LI
1233e44138a7SAaron LI r = noise_remote_index_lookup(l, r_idx, false);
1234e44138a7SAaron LI if (r == NULL)
1235e44138a7SAaron LI return (NULL);
1236a6bca3d2SAaron LI
12377ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_SHARED);
1238a6bca3d2SAaron LI if (!l->l_has_identity)
1239a6bca3d2SAaron LI goto error;
1240a6bca3d2SAaron LI
12417ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_SHARED);
1242a6bca3d2SAaron LI if (r->r_handshake_state != HANDSHAKE_INITIATOR) {
12437ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
1244a6bca3d2SAaron LI goto error;
1245a6bca3d2SAaron LI }
1246a6bca3d2SAaron LI memcpy(preshared_key, r->r_psk, NOISE_SYMMETRIC_KEY_LEN);
1247a6bca3d2SAaron LI hs = r->r_handshake;
12487ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
1249a6bca3d2SAaron LI
1250a6bca3d2SAaron LI /* e */
1251a6bca3d2SAaron LI noise_msg_ephemeral(hs.hs_ck, hs.hs_hash, ue);
1252a6bca3d2SAaron LI
1253a6bca3d2SAaron LI /* ee */
1254c222eea3SAaron LI if (!noise_mix_dh(hs.hs_ck, NULL, hs.hs_e, ue))
1255a6bca3d2SAaron LI goto error_zero;
1256a6bca3d2SAaron LI
1257a6bca3d2SAaron LI /* se */
1258c222eea3SAaron LI if (!noise_mix_dh(hs.hs_ck, NULL, l->l_private, ue))
1259a6bca3d2SAaron LI goto error_zero;
1260a6bca3d2SAaron LI
1261a6bca3d2SAaron LI /* psk */
1262a6bca3d2SAaron LI noise_mix_psk(hs.hs_ck, hs.hs_hash, key, preshared_key);
1263a6bca3d2SAaron LI
1264a6bca3d2SAaron LI /* {} */
1265c222eea3SAaron LI if (!noise_msg_decrypt(NULL, en, 0 + NOISE_AUTHTAG_LEN, key,
1266c222eea3SAaron LI hs.hs_hash))
1267a6bca3d2SAaron LI goto error_zero;
1268a6bca3d2SAaron LI
12697ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_EXCLUSIVE);
1270a6bca3d2SAaron LI if (r->r_handshake_state == HANDSHAKE_INITIATOR &&
1271a6bca3d2SAaron LI r->r_index.i_local_index == r_idx) {
1272a6bca3d2SAaron LI r->r_handshake = hs;
1273a6bca3d2SAaron LI r->r_index.i_remote_index = s_idx;
1274f0424a0dSAaron LI if (noise_begin_session(r))
1275e44138a7SAaron LI ret = noise_remote_ref(r);
1276a6bca3d2SAaron LI }
12777ef217feSAaron LI lockmgr(&r->r_handshake_lock, LK_RELEASE);
1278a7f975c0SAaron LI
1279a6bca3d2SAaron LI error_zero:
1280a7f975c0SAaron LI explicit_bzero(preshared_key, sizeof(preshared_key));
1281a7f975c0SAaron LI explicit_bzero(key, sizeof(key));
1282a6bca3d2SAaron LI explicit_bzero(&hs, sizeof(hs));
1283a6bca3d2SAaron LI error:
12847ef217feSAaron LI lockmgr(&l->l_identity_lock, LK_RELEASE);
1285a6bca3d2SAaron LI noise_remote_put(r);
1286a6bca3d2SAaron LI return (ret);
1287a6bca3d2SAaron LI }
1288a6bca3d2SAaron LI
1289a7f975c0SAaron LI /*----------------------------------------------------------------------------*/
1290a6bca3d2SAaron LI /* Handshake helper functions */
1291a7f975c0SAaron LI
1292f0424a0dSAaron LI static bool
noise_begin_session(struct noise_remote * r)1293f0424a0dSAaron LI noise_begin_session(struct noise_remote *r)
1294f0424a0dSAaron LI {
1295f0424a0dSAaron LI struct noise_local *l = r->r_local;
1296f0424a0dSAaron LI struct noise_keypair *kp, *next, *current, *previous;
1297f0424a0dSAaron LI struct noise_index *r_i;
1298f0424a0dSAaron LI
1299f0424a0dSAaron LI KKASSERT(lockstatus(&r->r_handshake_lock, curthread) == LK_EXCLUSIVE);
1300f0424a0dSAaron LI
1301f0424a0dSAaron LI kp = kmalloc(sizeof(*kp), M_NOISE, M_NOWAIT | M_ZERO);
1302f0424a0dSAaron LI if (kp == NULL)
1303f0424a0dSAaron LI return (false);
1304f0424a0dSAaron LI
1305f0424a0dSAaron LI /*
1306f0424a0dSAaron LI * Initialize the new keypair.
1307f0424a0dSAaron LI */
1308f0424a0dSAaron LI refcount_init(&kp->kp_refcnt, 1);
1309f0424a0dSAaron LI kp->kp_can_send = true;
1310f0424a0dSAaron LI kp->kp_is_initiator = (r->r_handshake_state == HANDSHAKE_INITIATOR);
1311f0424a0dSAaron LI kp->kp_remote = noise_remote_ref(r);
1312f0424a0dSAaron LI getnanouptime(&kp->kp_birthdate);
1313f0424a0dSAaron LI lockinit(&kp->kp_counter_lock, "noise_counter", 0, 0);
1314f0424a0dSAaron LI
1315f0424a0dSAaron LI noise_kdf((kp->kp_is_initiator ? kp->kp_send : kp->kp_recv),
1316f0424a0dSAaron LI (kp->kp_is_initiator ? kp->kp_recv : kp->kp_send),
1317f0424a0dSAaron LI NULL, NULL,
1318f0424a0dSAaron LI NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
1319f0424a0dSAaron LI r->r_handshake.hs_ck);
1320f0424a0dSAaron LI
1321f0424a0dSAaron LI /*
1322f0424a0dSAaron LI * Rotate existing keypairs and load the new one.
1323f0424a0dSAaron LI */
1324f0424a0dSAaron LI lockmgr(&r->r_keypair_lock, LK_EXCLUSIVE);
1325f0424a0dSAaron LI next = atomic_load_ptr(&r->r_keypair_next);
1326f0424a0dSAaron LI current = atomic_load_ptr(&r->r_keypair_current);
1327f0424a0dSAaron LI previous = atomic_load_ptr(&r->r_keypair_previous);
1328f0424a0dSAaron LI if (kp->kp_is_initiator) {
1329f0424a0dSAaron LI /*
1330f0424a0dSAaron LI * Received a confirmation response, which means this new
1331f0424a0dSAaron LI * keypair can now be used.
1332f0424a0dSAaron LI *
1333f0424a0dSAaron LI * Rotate the existing keypair ("current" or "next" slot)
1334f0424a0dSAaron LI * to the "previous" slot, and load the new keypair to the
1335f0424a0dSAaron LI * "current" slot.
1336f0424a0dSAaron LI */
1337f0424a0dSAaron LI if (next != NULL) {
1338f0424a0dSAaron LI atomic_store_ptr(&r->r_keypair_next, NULL);
1339f0424a0dSAaron LI atomic_store_ptr(&r->r_keypair_previous, next);
1340f0424a0dSAaron LI noise_keypair_drop(current);
1341f0424a0dSAaron LI } else {
1342f0424a0dSAaron LI atomic_store_ptr(&r->r_keypair_previous, current);
1343f0424a0dSAaron LI }
1344f0424a0dSAaron LI noise_keypair_drop(previous);
1345f0424a0dSAaron LI atomic_store_ptr(&r->r_keypair_current, kp);
1346f0424a0dSAaron LI } else {
1347f0424a0dSAaron LI /*
1348f0424a0dSAaron LI * This new keypair cannot be used until we receive a
1349f0424a0dSAaron LI * confirmation via the first data packet.
1350f0424a0dSAaron LI *
1351f0424a0dSAaron LI * So drop the "previous" keypair, the possibly existing
1352f0424a0dSAaron LI * "next" one, and load the new keypair to the "next" slot.
1353f0424a0dSAaron LI */
1354f0424a0dSAaron LI atomic_store_ptr(&r->r_keypair_next, kp);
1355f0424a0dSAaron LI noise_keypair_drop(next);
1356f0424a0dSAaron LI atomic_store_ptr(&r->r_keypair_previous, NULL);
1357f0424a0dSAaron LI noise_keypair_drop(previous);
1358f0424a0dSAaron LI }
1359f0424a0dSAaron LI lockmgr(&r->r_keypair_lock, LK_RELEASE);
1360f0424a0dSAaron LI
1361f0424a0dSAaron LI /*
1362f0424a0dSAaron LI * Insert into index hashtable, replacing the existing remote index
1363f0424a0dSAaron LI * (added with handshake initiation creation/consumption).
1364f0424a0dSAaron LI */
1365f0424a0dSAaron LI r_i = &r->r_index;
1366f0424a0dSAaron LI kp->kp_index.i_is_keypair = true;
1367f0424a0dSAaron LI kp->kp_index.i_local_index = r_i->i_local_index;
1368f0424a0dSAaron LI kp->kp_index.i_remote_index = r_i->i_remote_index;
1369f0424a0dSAaron LI
1370f0424a0dSAaron LI KKASSERT(lockstatus(&r->r_handshake_lock, curthread) == LK_EXCLUSIVE);
1371f0424a0dSAaron LI lockmgr(&l->l_index_lock, LK_EXCLUSIVE);
1372f0424a0dSAaron LI LIST_INSERT_BEFORE(r_i, &kp->kp_index, i_entry);
1373f0424a0dSAaron LI r->r_handshake_state = HANDSHAKE_DEAD;
1374f0424a0dSAaron LI LIST_REMOVE(r_i, i_entry);
1375f0424a0dSAaron LI lockmgr(&l->l_index_lock, LK_RELEASE);
1376f0424a0dSAaron LI
137741fc5cd7SAaron LI #ifdef INVARIANTS
137841fc5cd7SAaron LI lockmgr(&noise_mtx, LK_EXCLUSIVE);
137941fc5cd7SAaron LI LIST_INSERT_HEAD(&noise_keypairs, kp, _kp_entry);
138041fc5cd7SAaron LI lockmgr(&noise_mtx, LK_RELEASE);
138141fc5cd7SAaron LI #endif
138241fc5cd7SAaron LI
1383f0424a0dSAaron LI explicit_bzero(&r->r_handshake, sizeof(r->r_handshake));
1384f0424a0dSAaron LI return (true);
1385f0424a0dSAaron LI }
1386f0424a0dSAaron LI
1387a6bca3d2SAaron LI static void
noise_hmac(uint8_t * out,const uint8_t * in,const uint8_t * key,size_t outlen,size_t inlen,size_t keylen)1388*979e91edSAaron LI noise_hmac(uint8_t *out, const uint8_t *in, const uint8_t *key,
1389*979e91edSAaron LI size_t outlen, size_t inlen, size_t keylen)
1390*979e91edSAaron LI {
1391*979e91edSAaron LI struct blake2s_state blake;
1392*979e91edSAaron LI uint8_t x_key[BLAKE2S_BLOCK_SIZE] __aligned(__alignof__(uint32_t));
1393*979e91edSAaron LI uint8_t i_hash[BLAKE2S_HASH_SIZE] __aligned(__alignof__(uint32_t));
1394*979e91edSAaron LI int i;
1395*979e91edSAaron LI
1396*979e91edSAaron LI KKASSERT(out != NULL && outlen <= BLAKE2S_HASH_SIZE &&
1397*979e91edSAaron LI key != NULL && keylen > 0);
1398*979e91edSAaron LI
1399*979e91edSAaron LI memset(x_key, 0, BLAKE2S_BLOCK_SIZE);
1400*979e91edSAaron LI if (keylen > BLAKE2S_BLOCK_SIZE) {
1401*979e91edSAaron LI blake2s_init(&blake, BLAKE2S_HASH_SIZE);
1402*979e91edSAaron LI blake2s_update(&blake, key, keylen);
1403*979e91edSAaron LI blake2s_final(&blake, x_key);
1404*979e91edSAaron LI } else {
1405*979e91edSAaron LI memcpy(x_key, key, keylen);
1406*979e91edSAaron LI }
1407*979e91edSAaron LI
1408*979e91edSAaron LI for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i)
1409*979e91edSAaron LI x_key[i] ^= 0x36;
1410*979e91edSAaron LI
1411*979e91edSAaron LI blake2s_init(&blake, BLAKE2S_HASH_SIZE);
1412*979e91edSAaron LI blake2s_update(&blake, x_key, BLAKE2S_BLOCK_SIZE);
1413*979e91edSAaron LI blake2s_update(&blake, in, inlen);
1414*979e91edSAaron LI blake2s_final(&blake, i_hash);
1415*979e91edSAaron LI
1416*979e91edSAaron LI for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i)
1417*979e91edSAaron LI x_key[i] ^= 0x5c ^ 0x36;
1418*979e91edSAaron LI
1419*979e91edSAaron LI blake2s_init(&blake, BLAKE2S_HASH_SIZE);
1420*979e91edSAaron LI blake2s_update(&blake, x_key, BLAKE2S_BLOCK_SIZE);
1421*979e91edSAaron LI blake2s_update(&blake, i_hash, BLAKE2S_HASH_SIZE);
1422*979e91edSAaron LI blake2s_final(&blake, i_hash);
1423*979e91edSAaron LI
1424*979e91edSAaron LI memcpy(out, i_hash, outlen);
1425*979e91edSAaron LI explicit_bzero(x_key, BLAKE2S_BLOCK_SIZE);
1426*979e91edSAaron LI explicit_bzero(i_hash, BLAKE2S_HASH_SIZE);
1427*979e91edSAaron LI }
1428*979e91edSAaron LI
1429*979e91edSAaron LI 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])1430a6bca3d2SAaron LI noise_kdf(uint8_t *a, uint8_t *b, uint8_t *c, const uint8_t *x,
1431a6bca3d2SAaron LI size_t a_len, size_t b_len, size_t c_len, size_t x_len,
1432a6bca3d2SAaron LI const uint8_t ck[NOISE_HASH_LEN])
1433a6bca3d2SAaron LI {
1434a6bca3d2SAaron LI uint8_t out[BLAKE2S_HASH_SIZE + 1];
1435a6bca3d2SAaron LI uint8_t sec[BLAKE2S_HASH_SIZE];
1436a6bca3d2SAaron LI
1437a7f975c0SAaron LI KKASSERT(a != NULL && a_len > 0);
1438a7f975c0SAaron LI KKASSERT(a_len <= BLAKE2S_HASH_SIZE &&
1439a7f975c0SAaron LI b_len <= BLAKE2S_HASH_SIZE &&
1440a7f975c0SAaron LI c_len <= BLAKE2S_HASH_SIZE);
1441a6bca3d2SAaron LI
1442a7f975c0SAaron LI /* Extract entropy from "x" into sec */
1443*979e91edSAaron LI noise_hmac(sec, x, ck, BLAKE2S_HASH_SIZE /* outlen */,
1444a7f975c0SAaron LI x_len /* inlen */, NOISE_HASH_LEN);
1445a6bca3d2SAaron LI
1446a6bca3d2SAaron LI /* Expand first key: key = sec, data = 0x1 */
1447a6bca3d2SAaron LI out[0] = 1;
1448*979e91edSAaron LI noise_hmac(out, out, sec, BLAKE2S_HASH_SIZE /* outlen */,
1449a7f975c0SAaron LI 1 /* inlen */, BLAKE2S_HASH_SIZE);
1450a6bca3d2SAaron LI memcpy(a, out, a_len);
1451a6bca3d2SAaron LI
1452a6bca3d2SAaron LI if (b == NULL || b_len == 0)
1453a6bca3d2SAaron LI goto out;
1454a6bca3d2SAaron LI
1455a6bca3d2SAaron LI /* Expand second key: key = sec, data = "a" || 0x2 */
1456a6bca3d2SAaron LI out[BLAKE2S_HASH_SIZE] = 2;
1457*979e91edSAaron LI noise_hmac(out, out, sec, BLAKE2S_HASH_SIZE /* outlen */,
1458a7f975c0SAaron LI BLAKE2S_HASH_SIZE + 1 /* inlen */, BLAKE2S_HASH_SIZE);
1459a6bca3d2SAaron LI memcpy(b, out, b_len);
1460a6bca3d2SAaron LI
1461a6bca3d2SAaron LI if (c == NULL || c_len == 0)
1462a6bca3d2SAaron LI goto out;
1463a6bca3d2SAaron LI
1464a6bca3d2SAaron LI /* Expand third key: key = sec, data = "b" || 0x3 */
1465a6bca3d2SAaron LI out[BLAKE2S_HASH_SIZE] = 3;
1466*979e91edSAaron LI noise_hmac(out, out, sec, BLAKE2S_HASH_SIZE /* outlen */,
1467a7f975c0SAaron LI BLAKE2S_HASH_SIZE + 1 /* inlen */, BLAKE2S_HASH_SIZE);
1468a6bca3d2SAaron LI memcpy(c, out, c_len);
1469a6bca3d2SAaron LI
1470a6bca3d2SAaron LI out:
1471a6bca3d2SAaron LI /* Clear sensitive data from stack */
1472a7f975c0SAaron LI explicit_bzero(sec, sizeof(sec));
1473a7f975c0SAaron LI explicit_bzero(out, sizeof(out));
1474a6bca3d2SAaron LI }
1475a6bca3d2SAaron LI
1476c222eea3SAaron LI static bool
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])1477a6bca3d2SAaron LI noise_mix_dh(uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
1478a6bca3d2SAaron LI const uint8_t private[NOISE_PUBLIC_KEY_LEN],
1479a6bca3d2SAaron LI const uint8_t public[NOISE_PUBLIC_KEY_LEN])
1480a6bca3d2SAaron LI {
1481a6bca3d2SAaron LI uint8_t dh[NOISE_PUBLIC_KEY_LEN];
1482a6bca3d2SAaron LI
1483a6bca3d2SAaron LI if (!curve25519(dh, private, public))
1484c222eea3SAaron LI return (false);
1485c222eea3SAaron LI
1486a6bca3d2SAaron LI noise_kdf(ck, key, NULL, dh,
1487a7f975c0SAaron LI NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0,
1488a7f975c0SAaron LI NOISE_PUBLIC_KEY_LEN, ck);
1489a6bca3d2SAaron LI explicit_bzero(dh, NOISE_PUBLIC_KEY_LEN);
1490c222eea3SAaron LI return (true);
1491a6bca3d2SAaron LI }
1492a6bca3d2SAaron LI
1493c222eea3SAaron LI static bool
noise_mix_ss(uint8_t ck[NOISE_HASH_LEN],uint8_t key[NOISE_SYMMETRIC_KEY_LEN],const uint8_t ss[NOISE_PUBLIC_KEY_LEN])1494a6bca3d2SAaron LI noise_mix_ss(uint8_t ck[NOISE_HASH_LEN], uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
1495a6bca3d2SAaron LI const uint8_t ss[NOISE_PUBLIC_KEY_LEN])
1496a6bca3d2SAaron LI {
1497a6bca3d2SAaron LI static uint8_t null_point[NOISE_PUBLIC_KEY_LEN];
1498a7f975c0SAaron LI
1499a6bca3d2SAaron LI if (timingsafe_bcmp(ss, null_point, NOISE_PUBLIC_KEY_LEN) == 0)
1500c222eea3SAaron LI return (false);
1501c222eea3SAaron LI
1502a6bca3d2SAaron LI noise_kdf(ck, key, NULL, ss,
1503a7f975c0SAaron LI NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN,
1504a7f975c0SAaron LI 0, NOISE_PUBLIC_KEY_LEN, ck);
1505c222eea3SAaron LI return (true);
1506a6bca3d2SAaron LI }
1507a6bca3d2SAaron LI
1508a6bca3d2SAaron LI static void
noise_mix_hash(uint8_t hash[NOISE_HASH_LEN],const uint8_t * src,size_t src_len)1509a6bca3d2SAaron LI noise_mix_hash(uint8_t hash[NOISE_HASH_LEN], const uint8_t *src,
1510a6bca3d2SAaron LI size_t src_len)
1511a6bca3d2SAaron LI {
1512a6bca3d2SAaron LI struct blake2s_state blake;
1513a6bca3d2SAaron LI
1514a6bca3d2SAaron LI blake2s_init(&blake, NOISE_HASH_LEN);
1515a6bca3d2SAaron LI blake2s_update(&blake, hash, NOISE_HASH_LEN);
1516a6bca3d2SAaron LI blake2s_update(&blake, src, src_len);
1517a6bca3d2SAaron LI blake2s_final(&blake, hash);
1518a6bca3d2SAaron LI }
1519a6bca3d2SAaron LI
1520a6bca3d2SAaron LI 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])1521a6bca3d2SAaron LI noise_mix_psk(uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
1522a6bca3d2SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
1523a6bca3d2SAaron LI const uint8_t psk[NOISE_SYMMETRIC_KEY_LEN])
1524a6bca3d2SAaron LI {
1525a6bca3d2SAaron LI uint8_t tmp[NOISE_HASH_LEN];
1526a6bca3d2SAaron LI
1527a6bca3d2SAaron LI noise_kdf(ck, tmp, key, psk,
1528a6bca3d2SAaron LI NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN,
1529a6bca3d2SAaron LI NOISE_SYMMETRIC_KEY_LEN, ck);
1530a6bca3d2SAaron LI noise_mix_hash(hash, tmp, NOISE_HASH_LEN);
1531a6bca3d2SAaron LI explicit_bzero(tmp, NOISE_HASH_LEN);
1532a6bca3d2SAaron LI }
1533a6bca3d2SAaron LI
1534a6bca3d2SAaron LI 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])1535a6bca3d2SAaron LI noise_param_init(uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
1536a6bca3d2SAaron LI const uint8_t s[NOISE_PUBLIC_KEY_LEN])
1537a6bca3d2SAaron LI {
1538a6bca3d2SAaron LI struct blake2s_state blake;
1539a6bca3d2SAaron LI
1540a7f975c0SAaron LI blake2s(ck, NOISE_HANDSHAKE_NAME, NULL,
1541c3668ed7SAaron LI NOISE_HASH_LEN, sizeof(NOISE_HANDSHAKE_NAME) - 1, 0);
1542a6bca3d2SAaron LI blake2s_init(&blake, NOISE_HASH_LEN);
1543a6bca3d2SAaron LI blake2s_update(&blake, ck, NOISE_HASH_LEN);
1544a7f975c0SAaron LI blake2s_update(&blake, NOISE_IDENTIFIER_NAME,
1545c3668ed7SAaron LI sizeof(NOISE_IDENTIFIER_NAME) - 1);
1546a6bca3d2SAaron LI blake2s_final(&blake, hash);
1547a6bca3d2SAaron LI
1548a6bca3d2SAaron LI noise_mix_hash(hash, s, NOISE_PUBLIC_KEY_LEN);
1549a6bca3d2SAaron LI }
1550a6bca3d2SAaron LI
1551a6bca3d2SAaron LI 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])1552a6bca3d2SAaron LI noise_msg_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
1553a7f975c0SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
1554a7f975c0SAaron LI uint8_t hash[NOISE_HASH_LEN])
1555a6bca3d2SAaron LI {
1556a6bca3d2SAaron LI /* Nonce always zero for Noise_IK */
1557cfdd69bcSAaron LI static const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE] = { 0 };
1558cfdd69bcSAaron LI
1559a7f975c0SAaron LI chacha20poly1305_encrypt(dst, src, src_len, hash, NOISE_HASH_LEN,
1560a7f975c0SAaron LI nonce, key);
1561a6bca3d2SAaron LI noise_mix_hash(hash, dst, src_len + NOISE_AUTHTAG_LEN);
1562a6bca3d2SAaron LI }
1563a6bca3d2SAaron LI
1564c222eea3SAaron LI static bool
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])1565a6bca3d2SAaron LI noise_msg_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len,
1566a7f975c0SAaron LI uint8_t key[NOISE_SYMMETRIC_KEY_LEN],
1567a7f975c0SAaron LI uint8_t hash[NOISE_HASH_LEN])
1568a6bca3d2SAaron LI {
1569a6bca3d2SAaron LI /* Nonce always zero for Noise_IK */
1570cfdd69bcSAaron LI static const uint8_t nonce[CHACHA20POLY1305_NONCE_SIZE] = { 0 };
1571cfdd69bcSAaron LI
1572a6bca3d2SAaron LI if (!chacha20poly1305_decrypt(dst, src, src_len,
1573cfdd69bcSAaron LI hash, NOISE_HASH_LEN, nonce, key))
1574c222eea3SAaron LI return (false);
1575c222eea3SAaron LI
1576a6bca3d2SAaron LI noise_mix_hash(hash, src, src_len);
1577c222eea3SAaron LI return (true);
1578a6bca3d2SAaron LI }
1579a6bca3d2SAaron LI
1580a6bca3d2SAaron LI 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])1581a6bca3d2SAaron LI noise_msg_ephemeral(uint8_t ck[NOISE_HASH_LEN], uint8_t hash[NOISE_HASH_LEN],
1582a6bca3d2SAaron LI const uint8_t src[NOISE_PUBLIC_KEY_LEN])
1583a6bca3d2SAaron LI {
1584a6bca3d2SAaron LI noise_mix_hash(hash, src, NOISE_PUBLIC_KEY_LEN);
1585a6bca3d2SAaron LI noise_kdf(ck, NULL, NULL, src, NOISE_HASH_LEN, 0, 0,
1586a6bca3d2SAaron LI NOISE_PUBLIC_KEY_LEN, ck);
1587a6bca3d2SAaron LI }
1588a6bca3d2SAaron LI
1589a6bca3d2SAaron LI static void
noise_tai64n_now(uint8_t output[NOISE_TIMESTAMP_LEN])1590a6bca3d2SAaron LI noise_tai64n_now(uint8_t output[NOISE_TIMESTAMP_LEN])
1591a6bca3d2SAaron LI {
1592a6bca3d2SAaron LI struct timespec time;
1593a6bca3d2SAaron LI uint64_t sec;
1594a6bca3d2SAaron LI uint32_t nsec;
1595a6bca3d2SAaron LI
1596a6bca3d2SAaron LI getnanotime(&time);
1597a6bca3d2SAaron LI
1598a6bca3d2SAaron LI /* Round down the nsec counter to limit precise timing leak. */
1599a6bca3d2SAaron LI time.tv_nsec &= REJECT_INTERVAL_MASK;
1600a6bca3d2SAaron LI
1601a6bca3d2SAaron LI /* https://cr.yp.to/libtai/tai64.html */
1602a6bca3d2SAaron LI sec = htobe64(0x400000000000000aULL + time.tv_sec);
1603a6bca3d2SAaron LI nsec = htobe32(time.tv_nsec);
1604a6bca3d2SAaron LI
1605a6bca3d2SAaron LI /* memcpy to output buffer, assuming output could be unaligned. */
1606a6bca3d2SAaron LI memcpy(output, &sec, sizeof(sec));
1607a6bca3d2SAaron LI memcpy(output + sizeof(sec), &nsec, sizeof(nsec));
1608a6bca3d2SAaron LI }
1609a6bca3d2SAaron LI
1610e6c44b2eSAaron LI #ifdef WG_SELFTESTS
1611a6bca3d2SAaron LI #include "selftest/counter.c"
1612e6c44b2eSAaron LI #endif /* WG_SELFTESTS */
1613