aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml6
-rw-r--r--README.md4
-rw-r--r--src/Makefile2
-rw-r--r--src/compat.h33
-rw-r--r--src/crypto.c245
-rw-r--r--src/crypto.h94
-rw-r--r--src/if_wg.c181
-rw-r--r--src/support.h4
-rw-r--r--src/version.h2
-rw-r--r--src/wg_cookie.c2
-rw-r--r--src/wg_noise.c67
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
diff --git a/README.md b/README.md
index 273803f..a59fa6b 100644
--- a/README.md
+++ b/README.md
@@ -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: