diff options
-rw-r--r-- | .cirrus.yml | 6 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/compat.h | 33 | ||||
-rw-r--r-- | src/crypto.c | 245 | ||||
-rw-r--r-- | src/crypto.h | 94 | ||||
-rw-r--r-- | src/if_wg.c | 181 | ||||
-rw-r--r-- | src/support.h | 4 | ||||
-rw-r--r-- | src/version.h | 2 | ||||
-rw-r--r-- | src/wg_cookie.c | 2 | ||||
-rw-r--r-- | src/wg_noise.c | 67 |
11 files changed, 392 insertions, 248 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 47f05d5..b55d3d3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,6 +14,12 @@ freebsd_task: - name: freebsd12-2-amd64 freebsd_instance: image: freebsd-12-2-release-amd64 + - name: freebsd12-3-amd64 + freebsd_instance: + image: freebsd-12-3-release-amd64 - name: freebsd13-0-amd64 freebsd_instance: image: freebsd-13-0-release-amd64 + - name: freebsd13-1-amd64 + freebsd_instance: + image: freebsd-13-1-release-amd64 @@ -1,6 +1,6 @@ # WireGuard for FreeBSD -This is a kernel module for FreeBSD to support [WireGuard](https://www.wireguard.com/). It is being developed here before its eventual submission to FreeBSD 13.1 or 14. +This is a kernel module for FreeBSD to support [WireGuard](https://www.wireguard.com/). It is being developed here before its eventual submission to FreeBSD. ### Installation instructions @@ -12,7 +12,7 @@ Snapshots of this may be installed from packages: ### Building instructions -If you'd prefer to build this repo from scratch, rather than using a package, first make sure you have the latest net/wireguard-tools package installed, version ≥1.0.20210424. Then, on FreeBSD 12.1, 12.2, and 13.0: +If you'd prefer to build this repo from scratch, rather than using a package, first make sure you have the latest net/wireguard-tools package installed, version ≥1.0.20210424. Then, on FreeBSD 12.3, 13.0, 13.1, and 13.2: ``` # git clone https://git.zx2c4.com/wireguard-freebsd diff --git a/src/Makefile b/src/Makefile index e787882..392bd7f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,6 +6,6 @@ SRCS= opt_inet.h opt_inet6.h device_if.h bus_if.h ifdi_if.h SRCS+= if_wg.c wg_noise.c wg_cookie.c crypto.c -CFLAGS+= -include compat.h +CFLAGS+= -include ${.CURDIR}/compat.h .include <bsd.kmod.mk> diff --git a/src/compat.h b/src/compat.h index 575b44d..d55c628 100644 --- a/src/compat.h +++ b/src/compat.h @@ -8,7 +8,28 @@ #include <sys/param.h> -#if __FreeBSD_version < 1400000 +#if (__FreeBSD_version < 1400036 && __FreeBSD_version >= 1400000) || __FreeBSD_version < 1300519 +#define COMPAT_NEED_CHACHA20POLY1305_MBUF +#endif + +#if __FreeBSD_version < 1400048 +#define COMPAT_NEED_CHACHA20POLY1305 +#endif + +#if __FreeBSD_version < 1400049 +#define COMPAT_NEED_CURVE25519 +#endif + +#if __FreeBSD_version < 0x7fffffff /* TODO: update this when implemented */ +#define COMPAT_NEED_BLAKE2S +#endif + +#if __FreeBSD_version < 1400059 +#include <sys/sockbuf.h> +#define sbcreatecontrol(a, b, c, d, e) sbcreatecontrol(a, b, c, d) +#endif + +#if __FreeBSD_version < 1300507 #include <sys/smp.h> #include <sys/gtaskqueue.h> @@ -68,16 +89,6 @@ static inline void taskqgroup_drain_all(struct taskqgroup *tqg) #undef atomic_load_ptr #define atomic_load_ptr(p) (*(volatile __typeof(*p) *)(p)) -static inline void m_snd_tag_rele(struct m_snd_tag *mst) -{ - struct ifnet *ifp; - if (!mst) - return; - ifp = mst->ifp; - ifp->if_snd_tag_free(mst); - if_rele(ifp); -} - #endif #if __FreeBSD_version < 1202000 diff --git a/src/crypto.c b/src/crypto.c index 8e00266..ed86a8a 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -5,10 +5,16 @@ #include <sys/types.h> #include <sys/endian.h> +#include <sys/malloc.h> #include <sys/systm.h> +#include <opencrypto/cryptodev.h> #include "crypto.h" +#ifndef COMPAT_NEED_CHACHA20POLY1305_MBUF +static crypto_session_t chacha20_poly1305_sid; +#endif + #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif @@ -27,49 +33,48 @@ #define cpu_to_le32(a) htole32(a) #define cpu_to_le64(a) htole64(a) -static inline uint32_t get_unaligned_le32(const uint8_t *a) +static inline __unused uint32_t get_unaligned_le32(const uint8_t *a) { uint32_t l; __builtin_memcpy(&l, a, sizeof(l)); return le32_to_cpup(&l); } -static inline uint64_t get_unaligned_le64(const uint8_t *a) +static inline __unused uint64_t get_unaligned_le64(const uint8_t *a) { uint64_t l; __builtin_memcpy(&l, a, sizeof(l)); return le64_to_cpup(&l); } -static inline void put_unaligned_le32(uint32_t s, uint8_t *d) +static inline __unused void put_unaligned_le32(uint32_t s, uint8_t *d) { uint32_t l = cpu_to_le32(s); __builtin_memcpy(d, &l, sizeof(l)); } -static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words) +static inline __unused void cpu_to_le32_array(uint32_t *buf, unsigned int words) { while (words--) { *buf = cpu_to_le32(*buf); ++buf; } } -static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words) +static inline __unused void le32_to_cpu_array(uint32_t *buf, unsigned int words) { while (words--) { *buf = le32_to_cpup(buf); ++buf; } } - -static inline uint32_t rol32(uint32_t word, unsigned int shift) +static inline __unused uint32_t rol32(uint32_t word, unsigned int shift) { return (word << (shift & 31)) | (word >> ((-shift) & 31)); } -static inline uint32_t ror32(uint32_t word, unsigned int shift) +static inline __unused uint32_t ror32(uint32_t word, unsigned int shift) { return (word >> (shift & 31)) | (word << ((-shift) & 31)); } -static void xor_cpy(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, - size_t len) +#if defined(COMPAT_NEED_CHACHA20POLY1305) || defined(COMPAT_NEED_CHACHA20POLY1305_MBUF) +static void xor_cpy(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, size_t len) { size_t i; @@ -502,8 +507,9 @@ static void poly1305_final(struct poly1305_ctx *ctx, explicit_bzero(ctx, sizeof(*ctx)); } +#endif - +#ifdef COMPAT_NEED_CHACHA20POLY1305 static const uint8_t pad0[16] = { 0 }; void @@ -587,7 +593,45 @@ chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, return ret; } -static inline bool +void +xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, + const size_t src_len, const uint8_t *ad, + const size_t ad_len, + const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + uint32_t derived_key[CHACHA20_KEY_WORDS]; + + hchacha20(derived_key, nonce, key); + cpu_to_le32_array(derived_key, ARRAY_SIZE(derived_key)); + chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, + get_unaligned_le64(nonce + 16), + (uint8_t *)derived_key); + explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); +} + +bool +xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, + const size_t src_len, const uint8_t *ad, + const size_t ad_len, + const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + bool ret; + uint32_t derived_key[CHACHA20_KEY_WORDS]; + + hchacha20(derived_key, nonce, key); + cpu_to_le32_array(derived_key, ARRAY_SIZE(derived_key)); + ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, + get_unaligned_le64(nonce + 16), + (uint8_t *)derived_key); + explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); + return ret; +} +#endif + +#ifdef COMPAT_NEED_CHACHA20POLY1305_MBUF +static inline int chacha20poly1305_crypt_mbuf(struct mbuf *m0, uint64_t nonce, const uint8_t key[CHACHA20POLY1305_KEY_SIZE], bool encrypt) { @@ -596,7 +640,7 @@ chacha20poly1305_crypt_mbuf(struct mbuf *m0, uint64_t nonce, uint8_t *buf, mbuf_mac[POLY1305_MAC_SIZE]; size_t len, leftover = 0; struct mbuf *m; - bool ret; + int ret; union { uint32_t stream[CHACHA20_BLOCK_WORDS]; uint8_t block0[POLY1305_KEY_SIZE]; @@ -606,7 +650,7 @@ chacha20poly1305_crypt_mbuf(struct mbuf *m0, uint64_t nonce, if (!encrypt) { if (m0->m_pkthdr.len < POLY1305_MAC_SIZE) - return false; + return EMSGSIZE; m_copydata(m0, m0->m_pkthdr.len - POLY1305_MAC_SIZE, POLY1305_MAC_SIZE, mbuf_mac); m_adj(m0, -POLY1305_MAC_SIZE); } @@ -655,9 +699,9 @@ chacha20poly1305_crypt_mbuf(struct mbuf *m0, uint64_t nonce, poly1305_final(&poly1305_state, b.mac); if (encrypt) - ret = m_append(m0, POLY1305_MAC_SIZE, b.mac); + ret = m_append(m0, POLY1305_MAC_SIZE, b.mac) ? 0 : ENOMEM; else - ret = timingsafe_bcmp(b.mac, mbuf_mac, POLY1305_MAC_SIZE) == 0; + ret = timingsafe_bcmp(b.mac, mbuf_mac, POLY1305_MAC_SIZE) == 0 ? 0 : EBADMSG; explicit_bzero(&chacha20_state, sizeof(chacha20_state)); explicit_bzero(&b, sizeof(b)); @@ -665,57 +709,78 @@ chacha20poly1305_crypt_mbuf(struct mbuf *m0, uint64_t nonce, return ret; } -bool +int chacha20poly1305_encrypt_mbuf(struct mbuf *m, const uint64_t nonce, const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) { return chacha20poly1305_crypt_mbuf(m, nonce, key, true); } -bool +int chacha20poly1305_decrypt_mbuf(struct mbuf *m, const uint64_t nonce, const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) { return chacha20poly1305_crypt_mbuf(m, nonce, key, false); } - -void -xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, - const size_t src_len, const uint8_t *ad, - const size_t ad_len, - const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], - const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +#else +static int +crypto_callback(struct cryptop *crp) { - uint32_t derived_key[CHACHA20_KEY_WORDS]; - - hchacha20(derived_key, nonce, key); - cpu_to_le32_array(derived_key, ARRAY_SIZE(derived_key)); - chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, - get_unaligned_le64(nonce + 16), - (uint8_t *)derived_key); - explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); + return (0); } -bool -xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, - const size_t src_len, const uint8_t *ad, - const size_t ad_len, - const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], - const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +int +chacha20poly1305_encrypt_mbuf(struct mbuf *m, const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) { - bool ret; - uint32_t derived_key[CHACHA20_KEY_WORDS]; - - hchacha20(derived_key, nonce, key); - cpu_to_le32_array(derived_key, ARRAY_SIZE(derived_key)); - ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, - get_unaligned_le64(nonce + 16), - (uint8_t *)derived_key); - explicit_bzero(derived_key, CHACHA20POLY1305_KEY_SIZE); - return ret; + static char blank_tag[POLY1305_HASH_LEN]; + struct cryptop crp; + int ret; + + if (!m_append(m, POLY1305_HASH_LEN, blank_tag)) + return (ENOMEM); + crypto_initreq(&crp, chacha20_poly1305_sid); + crp.crp_op = CRYPTO_OP_ENCRYPT | CRYPTO_OP_COMPUTE_DIGEST; + crp.crp_flags = CRYPTO_F_IV_SEPARATE | CRYPTO_F_CBIMM; + crypto_use_mbuf(&crp, m); + crp.crp_payload_length = m->m_pkthdr.len - POLY1305_HASH_LEN; + crp.crp_digest_start = crp.crp_payload_length; + le64enc(crp.crp_iv, nonce); + crp.crp_cipher_key = key; + crp.crp_callback = crypto_callback; + ret = crypto_dispatch(&crp); + crypto_destroyreq(&crp); + return (ret); +} + +int +chacha20poly1305_decrypt_mbuf(struct mbuf *m, const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + struct cryptop crp; + int ret; + + if (m->m_pkthdr.len < POLY1305_HASH_LEN) + return (EMSGSIZE); + crypto_initreq(&crp, chacha20_poly1305_sid); + crp.crp_op = CRYPTO_OP_DECRYPT | CRYPTO_OP_VERIFY_DIGEST; + crp.crp_flags = CRYPTO_F_IV_SEPARATE | CRYPTO_F_CBIMM; + crypto_use_mbuf(&crp, m); + crp.crp_payload_length = m->m_pkthdr.len - POLY1305_HASH_LEN; + crp.crp_digest_start = crp.crp_payload_length; + le64enc(crp.crp_iv, nonce); + crp.crp_cipher_key = key; + crp.crp_callback = crypto_callback; + ret = crypto_dispatch(&crp); + crypto_destroyreq(&crp); + if (ret) + return (ret); + m_adj(m, -POLY1305_HASH_LEN); + return (0); } +#endif - +#ifdef COMPAT_NEED_BLAKE2S static const uint32_t blake2s_iv[8] = { 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL @@ -874,58 +939,9 @@ void blake2s_final(struct blake2s_state *state, uint8_t *out) memcpy(out, state->h, state->outlen); explicit_bzero(state, sizeof(*state)); } +#endif -void blake2s(uint8_t *out, const uint8_t *in, const uint8_t *key, - const size_t outlen, const size_t inlen, const size_t keylen) -{ - struct blake2s_state state; - - if (keylen) - blake2s_init_key(&state, outlen, key, keylen); - else - blake2s_init(&state, outlen); - - blake2s_update(&state, in, inlen); - blake2s_final(&state, out); -} - -void blake2s_hmac(uint8_t *out, const uint8_t *in, const uint8_t *key, const size_t outlen, - const size_t inlen, const size_t keylen) -{ - struct blake2s_state state; - uint8_t x_key[BLAKE2S_BLOCK_SIZE] __aligned(sizeof(uint32_t)) = { 0 }; - uint8_t i_hash[BLAKE2S_HASH_SIZE] __aligned(sizeof(uint32_t)); - int i; - - if (keylen > BLAKE2S_BLOCK_SIZE) { - blake2s_init(&state, BLAKE2S_HASH_SIZE); - blake2s_update(&state, key, keylen); - blake2s_final(&state, x_key); - } else - memcpy(x_key, key, keylen); - - for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) - x_key[i] ^= 0x36; - - blake2s_init(&state, BLAKE2S_HASH_SIZE); - blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); - blake2s_update(&state, in, inlen); - blake2s_final(&state, i_hash); - - for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) - x_key[i] ^= 0x5c ^ 0x36; - - blake2s_init(&state, BLAKE2S_HASH_SIZE); - blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); - blake2s_update(&state, i_hash, BLAKE2S_HASH_SIZE); - blake2s_final(&state, i_hash); - - memcpy(out, i_hash, outlen); - explicit_bzero(x_key, BLAKE2S_BLOCK_SIZE); - explicit_bzero(i_hash, BLAKE2S_HASH_SIZE); -} - - +#ifdef COMPAT_NEED_CURVE25519 /* Below here is fiat's implementation of x25519. * * Copyright (C) 2015-2016 The fiat-crypto Authors. @@ -1784,3 +1800,30 @@ bool curve25519(uint8_t out[CURVE25519_KEY_SIZE], return timingsafe_bcmp(out, curve25519_null_point, CURVE25519_KEY_SIZE) != 0; } +#endif + +int +crypto_init(void) +{ +#ifndef COMPAT_NEED_CHACHA20POLY1305_MBUF + struct crypto_session_params csp = { + .csp_mode = CSP_MODE_AEAD, + .csp_ivlen = sizeof(uint64_t), + .csp_cipher_alg = CRYPTO_CHACHA20_POLY1305, + .csp_cipher_klen = CHACHA20POLY1305_KEY_SIZE, + .csp_flags = CSP_F_SEPARATE_AAD | CSP_F_SEPARATE_OUTPUT + }; + int ret = crypto_newsession(&chacha20_poly1305_sid, &csp, CRYPTOCAP_F_SOFTWARE); + if (ret != 0) + return (ret); +#endif + return (0); +} + +void +crypto_deinit(void) +{ +#ifndef COMPAT_NEED_CHACHA20POLY1305_MBUF + crypto_freesession(chacha20_poly1305_sid); +#endif +} diff --git a/src/crypto.h b/src/crypto.h index b1a5f0e..90b27b9 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -6,15 +6,19 @@ #ifndef _WG_CRYPTO #define _WG_CRYPTO -#include <sys/types.h> +#include <sys/param.h> #include <sys/mbuf.h> +int crypto_init(void); +void crypto_deinit(void); + enum chacha20poly1305_lengths { XCHACHA20POLY1305_NONCE_SIZE = 24, CHACHA20POLY1305_KEY_SIZE = 32, CHACHA20POLY1305_AUTHTAG_SIZE = 16 }; +#ifdef COMPAT_NEED_CHACHA20POLY1305 void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, const uint8_t *ad, const size_t ad_len, @@ -27,14 +31,6 @@ chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, const uint64_t nonce, const uint8_t key[CHACHA20POLY1305_KEY_SIZE]); -bool -chacha20poly1305_encrypt_mbuf(struct mbuf *, const uint64_t nonce, - const uint8_t key[CHACHA20POLY1305_KEY_SIZE]); - -bool -chacha20poly1305_decrypt_mbuf(struct mbuf *, const uint64_t nonce, - const uint8_t key[CHACHA20POLY1305_KEY_SIZE]); - void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, const uint8_t *ad, @@ -48,6 +44,64 @@ xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, const size_t ad_len, const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], const uint8_t key[CHACHA20POLY1305_KEY_SIZE]); +#else +#include <sys/endian.h> +#include <crypto/chacha20_poly1305.h> + +static inline void +chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, + const uint8_t *ad, const size_t ad_len, + const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + uint8_t nonce_bytes[8]; + + le64enc(nonce_bytes, nonce); + chacha20_poly1305_encrypt(dst, src, src_len, ad, ad_len, + nonce_bytes, sizeof(nonce_bytes), key); +} + +static inline bool +chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, const size_t src_len, + const uint8_t *ad, const size_t ad_len, + const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + uint8_t nonce_bytes[8]; + + le64enc(nonce_bytes, nonce); + return (chacha20_poly1305_decrypt(dst, src, src_len, ad, ad_len, + nonce_bytes, sizeof(nonce_bytes), key)); +} + +static inline void +xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, + const size_t src_len, const uint8_t *ad, + const size_t ad_len, + const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + xchacha20_poly1305_encrypt(dst, src, src_len, ad, ad_len, nonce, key); +} + +static inline bool +xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, + const size_t src_len, const uint8_t *ad, + const size_t ad_len, + const uint8_t nonce[XCHACHA20POLY1305_NONCE_SIZE], + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]) +{ + return (xchacha20_poly1305_decrypt(dst, src, src_len, ad, ad_len, nonce, key)); +} +#endif + +int +chacha20poly1305_encrypt_mbuf(struct mbuf *, const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]); + +int +chacha20poly1305_decrypt_mbuf(struct mbuf *, const uint64_t nonce, + const uint8_t key[CHACHA20POLY1305_KEY_SIZE]); enum blake2s_lengths { @@ -56,6 +110,7 @@ enum blake2s_lengths { BLAKE2S_KEY_SIZE = 32 }; +#ifdef COMPAT_NEED_BLAKE2S struct blake2s_state { uint32_t h[8]; uint32_t t[2]; @@ -74,12 +129,22 @@ void blake2s_update(struct blake2s_state *state, const uint8_t *in, size_t inlen void blake2s_final(struct blake2s_state *state, uint8_t *out); -void blake2s(uint8_t *out, const uint8_t *in, const uint8_t *key, - const size_t outlen, const size_t inlen, const size_t keylen); +static inline void blake2s(uint8_t *out, const uint8_t *in, const uint8_t *key, + const size_t outlen, const size_t inlen, const size_t keylen) +{ + struct blake2s_state state; + + if (keylen) + blake2s_init_key(&state, outlen, key, keylen); + else + blake2s_init(&state, outlen); -void blake2s_hmac(uint8_t *out, const uint8_t *in, const uint8_t *key, - const size_t outlen, const size_t inlen, const size_t keylen); + blake2s_update(&state, in, inlen); + blake2s_final(&state, out); +} +#endif +#ifdef COMPAT_NEED_CURVE25519 enum curve25519_lengths { CURVE25519_KEY_SIZE = 32 }; @@ -108,5 +173,8 @@ static inline void curve25519_generate_secret(uint8_t secret[CURVE25519_KEY_SIZE arc4random_buf(secret, CURVE25519_KEY_SIZE); curve25519_clamp_secret(secret); } +#else +#include <crypto/curve25519.h> +#endif #endif diff --git a/src/if_wg.c b/src/if_wg.c index 11b8394..ac824d7 100644 --- a/src/if_wg.c +++ b/src/if_wg.c @@ -265,6 +265,8 @@ struct wg_softc { struct grouptask *sc_decrypt; struct wg_queue sc_encrypt_parallel; struct wg_queue sc_decrypt_parallel; + u_int sc_encrypt_last_cpu; + u_int sc_decrypt_last_cpu; struct sx sc_lock; }; @@ -377,7 +379,7 @@ static void wg_queue_purge(struct wg_queue *); static int wg_queue_both(struct wg_queue *, struct wg_queue *, struct wg_packet *); static struct wg_packet *wg_queue_dequeue_serial(struct wg_queue *); static struct wg_packet *wg_queue_dequeue_parallel(struct wg_queue *); -static void wg_input(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); +static bool wg_input(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); static void wg_peer_send_staged(struct wg_peer *); static int wg_clone_create(struct if_clone *, int, caddr_t); static void wg_qflush(struct ifnet *); @@ -407,18 +409,10 @@ wg_peer_alloc(struct wg_softc *sc, const uint8_t pub_key[WG_KEY_SIZE]) sx_assert(&sc->sc_lock, SX_XLOCKED); - if ((peer = malloc(sizeof(*peer), M_WG, M_NOWAIT | M_ZERO)) == NULL) - goto free_none; - - if ((peer->p_remote = noise_remote_alloc(sc->sc_local, peer, pub_key)) == NULL) - goto free_peer; - - if ((peer->p_tx_bytes = counter_u64_alloc(M_NOWAIT)) == NULL) - goto free_remote; - - if ((peer->p_rx_bytes = counter_u64_alloc(M_NOWAIT)) == NULL) - goto free_tx_bytes; - + peer = malloc(sizeof(*peer), M_WG, M_WAITOK | M_ZERO); + peer->p_remote = noise_remote_alloc(sc->sc_local, peer, pub_key); + peer->p_tx_bytes = counter_u64_alloc(M_WAITOK); + peer->p_rx_bytes = counter_u64_alloc(M_WAITOK); peer->p_id = peer_counter++; peer->p_sc = sc; @@ -452,14 +446,6 @@ wg_peer_alloc(struct wg_softc *sc, const uint8_t pub_key[WG_KEY_SIZE]) peer->p_aips_num = 0; return (peer); -free_tx_bytes: - counter_u64_free(peer->p_tx_bytes); -free_remote: - noise_remote_free(peer->p_remote, NULL); -free_peer: - free(peer, M_WG); -free_none: - return NULL; } static void @@ -558,8 +544,7 @@ wg_aip_add(struct wg_softc *sc, struct wg_peer *peer, sa_family_t af, const void struct wg_aip *aip; int i, ret = 0; - if ((aip = malloc(sizeof(*aip), M_WG, M_NOWAIT | M_ZERO)) == NULL) - return (ENOBUFS); + aip = malloc(sizeof(*aip), M_WG, M_WAITOK | M_ZERO); aip->a_peer = peer; aip->a_af = af; @@ -572,6 +557,7 @@ wg_aip_add(struct wg_softc *sc, struct wg_peer *peer, sa_family_t af, const void aip->a_addr.ip &= aip->a_mask.ip; aip->a_addr.length = aip->a_mask.length = offsetof(struct aip_addr, in) + sizeof(struct in_addr); break; +#ifdef INET6 case AF_INET6: if (cidr > 128) cidr = 128; root = sc->sc_aip6; @@ -581,6 +567,7 @@ wg_aip_add(struct wg_softc *sc, struct wg_peer *peer, sa_family_t af, const void aip->a_addr.ip6[i] &= aip->a_mask.ip6[i]; aip->a_addr.length = aip->a_mask.length = offsetof(struct aip_addr, in6) + sizeof(struct in6_addr); break; +#endif default: free(aip, M_WG); return (EAFNOSUPPORT); @@ -706,7 +693,7 @@ wg_socket_init(struct wg_softc *sc, in_port_t port) if (rc) goto out; - rc = udp_set_kernel_tunneling(so4, wg_input, NULL, sc); + rc = udp_set_kernel_tunneling(so4, (udp_tun_func_t)wg_input, NULL, sc); /* * udp_set_kernel_tunneling can only fail if there is already a tunneling function set. * This should never happen with a new socket. @@ -717,7 +704,7 @@ wg_socket_init(struct wg_softc *sc, in_port_t port) rc = socreate(AF_INET6, &so6, SOCK_DGRAM, IPPROTO_UDP, cred, td); if (rc) goto out; - rc = udp_set_kernel_tunneling(so6, wg_input, NULL, sc); + rc = udp_set_kernel_tunneling(so6, (udp_tun_func_t)wg_input, NULL, sc); MPASS(rc == 0); #endif @@ -891,13 +878,13 @@ wg_send(struct wg_softc *sc, struct wg_endpoint *e, struct mbuf *m) if (e->e_local.l_in.s_addr != INADDR_ANY) control = sbcreatecontrol((caddr_t)&e->e_local.l_in, sizeof(struct in_addr), IP_SENDSRCADDR, - IPPROTO_IP); + IPPROTO_IP, M_NOWAIT); #ifdef INET6 } else if (e->e_remote.r_sa.sa_family == AF_INET6) { if (!IN6_IS_ADDR_UNSPECIFIED(&e->e_local.l_in6)) control = sbcreatecontrol((caddr_t)&e->e_local.l_pktinfo6, sizeof(struct in6_pktinfo), IPV6_PKTINFO, - IPPROTO_IPV6); + IPPROTO_IPV6, M_NOWAIT); #endif } else { m_freem(m); @@ -1476,10 +1463,8 @@ wg_mbuf_reset(struct mbuf *m) m_tag_delete(m, t); } - if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) { - m_snd_tag_rele(m->m_pkthdr.snd_tag); - m->m_pkthdr.snd_tag = NULL; - } + KASSERT((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0, + ("%s: mbuf %p has a send tag", __func__, m)); m->m_pkthdr.csum_flags = 0; m->m_pkthdr.PH_per.sixtyfour[0] = 0; @@ -1639,21 +1624,22 @@ wg_softc_encrypt(struct wg_softc *sc) static void wg_encrypt_dispatch(struct wg_softc *sc) { - for (int i = 0; i < mp_ncpus; i++) { - if (sc->sc_encrypt[i].gt_task.ta_flags & TASK_ENQUEUED) - continue; - GROUPTASK_ENQUEUE(&sc->sc_encrypt[i]); - } + /* + * The update to encrypt_last_cpu is racey such that we may + * reschedule the task for the same CPU multiple times, but + * the race doesn't really matter. + */ + u_int cpu = (sc->sc_encrypt_last_cpu + 1) % mp_ncpus; + sc->sc_encrypt_last_cpu = cpu; + GROUPTASK_ENQUEUE(&sc->sc_encrypt[cpu]); } static void wg_decrypt_dispatch(struct wg_softc *sc) { - for (int i = 0; i < mp_ncpus; i++) { - if (sc->sc_decrypt[i].gt_task.ta_flags & TASK_ENQUEUED) - continue; - GROUPTASK_ENQUEUE(&sc->sc_decrypt[i]); - } + u_int cpu = (sc->sc_decrypt_last_cpu + 1) % mp_ncpus; + sc->sc_decrypt_last_cpu = cpu; + GROUPTASK_ENQUEUE(&sc->sc_decrypt[cpu]); } static void @@ -1676,10 +1662,10 @@ wg_deliver_out(struct wg_peer *peer) len = m->m_pkthdr.len; + wg_timers_event_any_authenticated_packet_traversal(peer); + wg_timers_event_any_authenticated_packet_sent(peer); rc = wg_send(sc, &endpoint, m); if (rc == 0) { - wg_timers_event_any_authenticated_packet_traversal(peer); - wg_timers_event_any_authenticated_packet_sent(peer); if (len > (sizeof(struct wg_pkt_data) + NOISE_AUTHTAG_LEN)) wg_timers_event_data_sent(peer); counter_u64_add(peer->p_tx_bytes, len); @@ -1802,11 +1788,7 @@ wg_queue_deinit(struct wg_queue *queue) static size_t wg_queue_len(struct wg_queue *queue) { - size_t len; - mtx_lock(&queue->q_mtx); - len = queue->q_len; - mtx_unlock(&queue->q_mtx); - return (len); + return (queue->q_len); } static int @@ -1869,9 +1851,9 @@ wg_queue_enlist_staged(struct wg_queue *staged, struct wg_packet_list *list) static void wg_queue_delist_staged(struct wg_queue *staged, struct wg_packet_list *list) { + STAILQ_INIT(list); mtx_lock(&staged->q_mtx); - *list = staged->q_queue; - STAILQ_INIT(&staged->q_queue); + STAILQ_CONCAT(list, &staged->q_queue); staged->q_len = 0; mtx_unlock(&staged->q_mtx); } @@ -1944,7 +1926,7 @@ wg_queue_dequeue_parallel(struct wg_queue *parallel) return (pkt); } -static void +static bool wg_input(struct mbuf *m, int offset, struct inpcb *inpcb, const struct sockaddr *sa, void *_sc) { @@ -1963,7 +1945,7 @@ wg_input(struct mbuf *m, int offset, struct inpcb *inpcb, m = m_unshare(m, M_NOWAIT); if (!m) { if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); - return; + return true; } /* Caller provided us with `sa`, no need for this header. */ @@ -1972,13 +1954,13 @@ wg_input(struct mbuf *m, int offset, struct inpcb *inpcb, /* Pullup enough to read packet type */ if ((m = m_pullup(m, sizeof(uint32_t))) == NULL) { if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); - return; + return true; } if ((pkt = wg_packet_alloc(m)) == NULL) { if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); m_freem(m); - return; + return true; } /* Save send/recv address and port for later. */ @@ -2025,11 +2007,11 @@ wg_input(struct mbuf *m, int offset, struct inpcb *inpcb, } else { goto error; } - return; + return true; error: if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); wg_packet_free(pkt); - return; + return true; } static void @@ -2280,10 +2262,7 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl) wg_aip_remove_all(sc, peer); } if (peer == NULL) { - if ((peer = wg_peer_alloc(sc, pub_key)) == NULL) { - err = ENOMEM; - goto out; - } + peer = wg_peer_alloc(sc, pub_key); need_insert = true; } if (nvlist_exists_binary(nvl, "endpoint")) { @@ -2380,10 +2359,8 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) if (wgd->wgd_size >= UINT32_MAX / 2) return (E2BIG); - if ((nvlpacked = malloc(wgd->wgd_size, M_TEMP, M_NOWAIT | M_ZERO)) == NULL) - return (ENOMEM); + nvlpacked = malloc(wgd->wgd_size, M_TEMP, M_WAITOK | M_ZERO); - sx_xlock(&sc->sc_lock); err = copyin(wgd->wgd_data, nvlpacked, wgd->wgd_size); if (err) goto out; @@ -2392,6 +2369,7 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) err = EBADMSG; goto out; } + sx_xlock(&sc->sc_lock); if (nvlist_exists_bool(nvl, "replace-peers") && nvlist_get_bool(nvl, "replace-peers")) wg_peer_destroy_all(sc); @@ -2399,12 +2377,12 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) uint64_t new_port = nvlist_get_number(nvl, "listen-port"); if (new_port > UINT16_MAX) { err = EINVAL; - goto out; + goto out_locked; } if (new_port != sc->sc_socket.so_port) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { if ((err = wg_socket_init(sc, new_port)) != 0) - goto out; + goto out_locked; } else sc->sc_socket.so_port = new_port; } @@ -2413,7 +2391,7 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) const void *key = nvlist_get_binary(nvl, "private-key", &size); if (size != WG_KEY_SIZE) { err = EINVAL; - goto out; + goto out_locked; } if (noise_local_keys(sc->sc_local, NULL, private) != 0 || @@ -2447,11 +2425,11 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) uint64_t user_cookie = nvlist_get_number(nvl, "user-cookie"); if (user_cookie > UINT32_MAX) { err = EINVAL; - goto out; + goto out_locked; } err = wg_socket_set_cookie(sc, user_cookie); if (err) - goto out; + goto out_locked; } if (nvlist_exists_nvlist_array(nvl, "peers")) { size_t peercount; @@ -2461,15 +2439,16 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) for (int i = 0; i < peercount; i++) { err = wg_peer_add(sc, nvl_peers[i]); if (err != 0) - goto out; + goto out_locked; } } +out_locked: + sx_xunlock(&sc->sc_lock); nvlist_destroy(nvl); out: explicit_bzero(nvlpacked, wgd->wgd_size); free(nvlpacked, M_TEMP); - sx_xunlock(&sc->sc_lock); return (err); } @@ -2505,10 +2484,7 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd) } peer_count = sc->sc_peers_num; if (peer_count) { - if ((nvl_peers = mallocarray(peer_count, sizeof(void *), M_NVLIST, M_NOWAIT | M_ZERO)) == NULL) { - err = ENOMEM; - goto err; - } + nvl_peers = mallocarray(peer_count, sizeof(void *), M_NVLIST, M_WAITOK | M_ZERO); i = 0; TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) { if (i >= peer_count) @@ -2537,10 +2513,7 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd) aip_count = peer->p_aips_num; if (aip_count) { - if ((nvl_aips = mallocarray(aip_count, sizeof(void *), M_NVLIST, M_NOWAIT | M_ZERO)) == NULL) { - err = ENOMEM; - goto err_peer; - } + nvl_aips = mallocarray(aip_count, sizeof(void *), M_NVLIST, M_WAITOK | M_ZERO); j = 0; LIST_FOREACH(aip, &peer->p_aips, a_entry) { if (j >= aip_count) @@ -2554,10 +2527,13 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd) if (aip->a_af == AF_INET) { nvlist_add_binary(nvl_aip, "ipv4", &aip->a_addr.in, sizeof(aip->a_addr.in)); nvlist_add_number(nvl_aip, "cidr", bitcount32(aip->a_mask.ip)); - } else if (aip->a_af == AF_INET6) { + } +#ifdef INET6 + else if (aip->a_af == AF_INET6) { nvlist_add_binary(nvl_aip, "ipv6", &aip->a_addr.in6, sizeof(aip->a_addr.in6)); nvlist_add_number(nvl_aip, "cidr", in6_mask2len(&aip->a_mask.in6, NULL)); } +#endif } nvlist_add_nvlist_array(nvl_peer, "allowed-ips", (const nvlist_t *const *)nvl_aips, aip_count); err_aip: @@ -2573,9 +2549,12 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd) for (i = 0; i < peer_count; ++i) nvlist_destroy(nvl_peers[i]); free(nvl_peers, M_NVLIST); - if (err) + if (err) { + sx_sunlock(&sc->sc_lock); goto err; + } } + sx_sunlock(&sc->sc_lock); packed = nvlist_pack(nvl, &size); if (!packed) { err = ENOMEM; @@ -2589,10 +2568,6 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd) err = ENOSPC; goto out; } - if (!wgd->wgd_data) { - err = EFAULT; - goto out; - } err = copyout(packed, wgd->wgd_data, size); wgd->wgd_size = size; @@ -2601,7 +2576,6 @@ out: free(packed, M_NVLIST); err: nvlist_destroy(nvl); - sx_sunlock(&sc->sc_lock); return (err); } @@ -2743,17 +2717,13 @@ wg_clone_create(struct if_clone *ifc, int unit, caddr_t params) struct wg_softc *sc; struct ifnet *ifp; - if ((sc = malloc(sizeof(*sc), M_WG, M_NOWAIT | M_ZERO)) == NULL) - goto free_none; + sc = malloc(sizeof(*sc), M_WG, M_WAITOK | M_ZERO); - if ((sc->sc_local = noise_local_alloc(sc)) == NULL) - goto free_sc; + sc->sc_local = noise_local_alloc(sc); - if ((sc->sc_encrypt = mallocarray(sizeof(struct grouptask), mp_ncpus, M_WG, M_NOWAIT | M_ZERO)) == NULL) - goto free_local; + sc->sc_encrypt = mallocarray(sizeof(struct grouptask), mp_ncpus, M_WG, M_WAITOK | M_ZERO); - if ((sc->sc_decrypt = mallocarray(sizeof(struct grouptask), mp_ncpus, M_WG, M_NOWAIT | M_ZERO)) == NULL) - goto free_encrypt; + sc->sc_decrypt = mallocarray(sizeof(struct grouptask), mp_ncpus, M_WG, M_WAITOK | M_ZERO); if (!rn_inithead((void **)&sc->sc_aip4, offsetof(struct aip_addr, in) * NBBY)) goto free_decrypt; @@ -2821,13 +2791,9 @@ free_aip4: free(sc->sc_aip4, M_RTABLE); free_decrypt: free(sc->sc_decrypt, M_WG); -free_encrypt: free(sc->sc_encrypt, M_WG); -free_local: noise_local_free(sc->sc_local, NULL); -free_sc: free(sc, M_WG); -free_none: return (ENOMEM); } @@ -3014,17 +2980,25 @@ wg_module_init(void) if ((wg_packet_zone = uma_zcreate("wg packet", sizeof(struct wg_packet), NULL, NULL, NULL, NULL, 0, 0)) == NULL) goto free_none; - if (cookie_init() != 0) + ret = crypto_init(); + if (ret != 0) goto free_zone; + if (cookie_init() != 0) + goto free_crypto; wg_osd_jail_slot = osd_jail_register(NULL, methods); ret = ENOTRECOVERABLE; if (!wg_run_selftests()) - goto free_zone; + goto free_all; return (0); +free_all: + osd_jail_deregister(wg_osd_jail_slot); + cookie_deinit(); +free_crypto: + crypto_deinit(); free_zone: uma_zdestroy(wg_packet_zone); free_none: @@ -3038,16 +3012,17 @@ wg_module_deinit(void) VNET_LIST_RLOCK(); VNET_FOREACH(vnet_iter) { struct if_clone *clone = VNET_VNET(vnet_iter, wg_cloner); - if (!clone) - continue; - if_clone_detach(clone); - VNET_VNET(vnet_iter, wg_cloner) = NULL; + if (clone) { + if_clone_detach(clone); + VNET_VNET(vnet_iter, wg_cloner) = NULL; + } } VNET_LIST_RUNLOCK(); NET_EPOCH_WAIT(); MPASS(LIST_EMPTY(&wg_list)); osd_jail_deregister(wg_osd_jail_slot); cookie_deinit(); + crypto_deinit(); uma_zdestroy(wg_packet_zone); } diff --git a/src/support.h b/src/support.h index d1c326c..ee6b03c 100644 --- a/src/support.h +++ b/src/support.h @@ -37,7 +37,11 @@ sogetsockaddr(struct socket *so, struct sockaddr **nam) int error; CURVNET_SET(so->so_vnet); +#if __FreeBSD_version < 1400066 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, nam); +#else + error = so->so_proto->pr_sockaddr(so, nam); +#endif CURVNET_RESTORE(); return (error); } diff --git a/src/version.h b/src/version.h index ffad8b6..f1a1d72 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define WIREGUARD_VERSION 20210606 +#define WIREGUARD_VERSION 20220615 diff --git a/src/wg_cookie.c b/src/wg_cookie.c index d87bfe5..fa63832 100644 --- a/src/wg_cookie.c +++ b/src/wg_cookie.c @@ -341,7 +341,7 @@ ratelimit_init(struct ratelimit *rl) { size_t i; mtx_init(&rl->rl_mtx, "ratelimit_lock", NULL, MTX_DEF); - callout_init_rw(&rl->rl_gc, &rl->rl_mtx, 0); + callout_init_mtx(&rl->rl_gc, &rl->rl_mtx, 0); arc4random_buf(rl->rl_secret, sizeof(rl->rl_secret)); for (i = 0; i < RATELIMIT_SIZE; i++) LIST_INIT(&rl->rl_table[i]); diff --git a/src/wg_noise.c b/src/wg_noise.c index f8d823c..d562ed1 100644 --- a/src/wg_noise.c +++ b/src/wg_noise.c @@ -181,9 +181,7 @@ noise_local_alloc(void *arg) struct noise_local *l; size_t i; - l = malloc(sizeof(*l), M_NOISE, M_NOWAIT | M_ZERO); - if (!l) - return (NULL); + l = malloc(sizeof(*l), M_NOISE, M_WAITOK | M_ZERO); rw_init(&l->l_identity_lock, "noise_identity"); l->l_has_identity = false; @@ -297,8 +295,7 @@ noise_remote_alloc(struct noise_local *l, void *arg, { struct noise_remote *r; - if ((r = malloc(sizeof(*r), M_NOISE, M_NOWAIT | M_ZERO)) == NULL) - return (NULL); + r = malloc(sizeof(*r), M_NOISE, M_WAITOK | M_ZERO); memcpy(r->r_public, public, NOISE_PUBLIC_KEY_LEN); rw_init(&r->r_handshake_lock, "noise_handshake"); @@ -905,8 +902,11 @@ noise_keep_key_fresh_recv(struct noise_remote *r) int noise_keypair_encrypt(struct noise_keypair *kp, uint32_t *r_idx, uint64_t nonce, struct mbuf *m) { - if (chacha20poly1305_encrypt_mbuf(m, nonce, kp->kp_send) == 0) - return (ENOMEM); + int ret; + + ret = chacha20poly1305_encrypt_mbuf(m, nonce, kp->kp_send); + if (ret) + return (ret); *r_idx = kp->kp_index.i_remote_index; return (0); @@ -916,6 +916,7 @@ int noise_keypair_decrypt(struct noise_keypair *kp, uint64_t nonce, struct mbuf *m) { uint64_t cur_nonce; + int ret; #ifdef __LP64__ cur_nonce = ck_pr_load_64(&kp->kp_nonce_recv); @@ -929,8 +930,9 @@ noise_keypair_decrypt(struct noise_keypair *kp, uint64_t nonce, struct mbuf *m) noise_timer_expired(kp->kp_birthdate, REJECT_AFTER_TIME, 0)) return (EINVAL); - if (chacha20poly1305_decrypt_mbuf(m, nonce, kp->kp_recv) == 0) - return (EINVAL); + ret = chacha20poly1305_decrypt_mbuf(m, nonce, kp->kp_recv); + if (ret) + return (ret); return (0); } @@ -1187,6 +1189,43 @@ error: return (ret); } +static void +hmac(uint8_t *out, const uint8_t *in, const uint8_t *key, const size_t outlen, + const size_t inlen, const size_t keylen) +{ + struct blake2s_state state; + uint8_t x_key[BLAKE2S_BLOCK_SIZE] __aligned(sizeof(uint32_t)) = { 0 }; + uint8_t i_hash[BLAKE2S_HASH_SIZE] __aligned(sizeof(uint32_t)); + int i; + + if (keylen > BLAKE2S_BLOCK_SIZE) { + blake2s_init(&state, BLAKE2S_HASH_SIZE); + blake2s_update(&state, key, keylen); + blake2s_final(&state, x_key); + } else + memcpy(x_key, key, keylen); + + for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) + x_key[i] ^= 0x36; + + blake2s_init(&state, BLAKE2S_HASH_SIZE); + blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); + blake2s_update(&state, in, inlen); + blake2s_final(&state, i_hash); + + for (i = 0; i < BLAKE2S_BLOCK_SIZE; ++i) + x_key[i] ^= 0x5c ^ 0x36; + + blake2s_init(&state, BLAKE2S_HASH_SIZE); + blake2s_update(&state, x_key, BLAKE2S_BLOCK_SIZE); + blake2s_update(&state, i_hash, BLAKE2S_HASH_SIZE); + blake2s_final(&state, i_hash); + + memcpy(out, i_hash, outlen); + explicit_bzero(x_key, BLAKE2S_BLOCK_SIZE); + explicit_bzero(i_hash, BLAKE2S_HASH_SIZE); +} + /* Handshake helper functions */ static void noise_kdf(uint8_t *a, uint8_t *b, uint8_t *c, const uint8_t *x, @@ -1197,14 +1236,14 @@ noise_kdf(uint8_t *a, uint8_t *b, uint8_t *c, const uint8_t *x, uint8_t sec[BLAKE2S_HASH_SIZE]; /* Extract entropy from "x" into sec */ - blake2s_hmac(sec, x, ck, BLAKE2S_HASH_SIZE, x_len, NOISE_HASH_LEN); + hmac(sec, x, ck, BLAKE2S_HASH_SIZE, x_len, NOISE_HASH_LEN); if (a == NULL || a_len == 0) goto out; /* Expand first key: key = sec, data = 0x1 */ out[0] = 1; - blake2s_hmac(out, out, sec, BLAKE2S_HASH_SIZE, 1, BLAKE2S_HASH_SIZE); + hmac(out, out, sec, BLAKE2S_HASH_SIZE, 1, BLAKE2S_HASH_SIZE); memcpy(a, out, a_len); if (b == NULL || b_len == 0) @@ -1212,8 +1251,7 @@ noise_kdf(uint8_t *a, uint8_t *b, uint8_t *c, const uint8_t *x, /* Expand second key: key = sec, data = "a" || 0x2 */ out[BLAKE2S_HASH_SIZE] = 2; - blake2s_hmac(out, out, sec, BLAKE2S_HASH_SIZE, BLAKE2S_HASH_SIZE + 1, - BLAKE2S_HASH_SIZE); + hmac(out, out, sec, BLAKE2S_HASH_SIZE, BLAKE2S_HASH_SIZE + 1, BLAKE2S_HASH_SIZE); memcpy(b, out, b_len); if (c == NULL || c_len == 0) @@ -1221,8 +1259,7 @@ noise_kdf(uint8_t *a, uint8_t *b, uint8_t *c, const uint8_t *x, /* Expand third key: key = sec, data = "b" || 0x3 */ out[BLAKE2S_HASH_SIZE] = 3; - blake2s_hmac(out, out, sec, BLAKE2S_HASH_SIZE, BLAKE2S_HASH_SIZE + 1, - BLAKE2S_HASH_SIZE); + hmac(out, out, sec, BLAKE2S_HASH_SIZE, BLAKE2S_HASH_SIZE + 1, BLAKE2S_HASH_SIZE); memcpy(c, out, c_len); out: |