aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2021-10-11 11:27:16 -0700
committerJason A. Donenfeld <Jason@zx2c4.com>2022-06-14 00:54:55 +0200
commita6354a1436fb19e96156fdaa9c71ebbe4ea3e45a (patch)
tree71bfb1bfb4d1ac02357f00ded160f1ad4881b3e4
parentif_wg: wg_peer_alloc and wg_aip_add: Use M_WAITOK with malloc (diff)
downloadwireguard-freebsd-a6354a1436fb19e96156fdaa9c71ebbe4ea3e45a.tar.xz
wireguard-freebsd-a6354a1436fb19e96156fdaa9c71ebbe4ea3e45a.zip
crypto: use OCF to encrypt/decrypt packets when supported
This requires the the recent changes in FreeBSD to support the Chacha20-Poly1305 AEAD cipher with support for an 8 byte nonce (vs the 12 byte nonce used by TLS and IPsec). Signed-off-by: John Baldwin <jhb@FreeBSD.org>
-rw-r--r--src/crypto.c93
-rw-r--r--src/crypto.h10
-rw-r--r--src/if_wg.c8
3 files changed, 109 insertions, 2 deletions
diff --git a/src/crypto.c b/src/crypto.c
index 7316f2d..fb8290d 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"
+#ifdef OCF_CHACHA20_POLY1305
+static crypto_session_t chacha20_poly1305_sid;
+#endif
+
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
@@ -587,6 +593,63 @@ chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, const size_t src_len,
return ret;
}
+#ifdef OCF_CHACHA20_POLY1305
+static int
+crypto_callback(struct cryptop *crp)
+{
+ return (0);
+}
+
+int
+chacha20poly1305_encrypt_mbuf(struct mbuf *m, const uint64_t nonce,
+ const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
+{
+ static char blank_tag[POLY1305_HASH_LEN];
+ struct cryptop crp;
+ int error;
+
+ 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;
+ error = crypto_dispatch(&crp);
+ crypto_destroyreq(&crp);
+ return (error);
+}
+
+int
+chacha20poly1305_decrypt_mbuf(struct mbuf *m, const uint64_t nonce,
+ const uint8_t key[CHACHA20POLY1305_KEY_SIZE])
+{
+ struct cryptop crp;
+ int error;
+
+ 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;
+ error = crypto_dispatch(&crp);
+ crypto_destroyreq(&crp);
+ if (error != 0)
+ return (error);
+ m_adj(m, -POLY1305_HASH_LEN);
+ return (0);
+}
+#else
static inline int
chacha20poly1305_crypt_mbuf(struct mbuf *m0, uint64_t nonce,
const uint8_t key[CHACHA20POLY1305_KEY_SIZE], bool encrypt)
@@ -678,6 +741,7 @@ chacha20poly1305_decrypt_mbuf(struct mbuf *m, const uint64_t nonce,
{
return chacha20poly1305_crypt_mbuf(m, nonce, key, false);
}
+#endif
void
xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src,
@@ -1784,3 +1848,32 @@ bool curve25519(uint8_t out[CURVE25519_KEY_SIZE],
return timingsafe_bcmp(out, curve25519_null_point, CURVE25519_KEY_SIZE) != 0;
}
+
+int
+crypto_init(void)
+{
+#ifdef OCF_CHACHA20_POLY1305
+ struct crypto_session_params csp;
+ int error;
+
+ memset(&csp, 0, sizeof(csp));
+ csp.csp_mode = CSP_MODE_AEAD;
+ csp.csp_ivlen = sizeof(uint64_t);
+ csp.csp_cipher_alg = CRYPTO_CHACHA20_POLY1305;
+ csp.csp_cipher_klen = CHACHA20POLY1305_KEY_SIZE;
+ csp.csp_flags = CSP_F_SEPARATE_AAD | CSP_F_SEPARATE_OUTPUT;
+ error = crypto_newsession(&chacha20_poly1305_sid, &csp,
+ CRYPTOCAP_F_SOFTWARE);
+ if (error != 0)
+ return (error);
+#endif
+ return (0);
+}
+
+void
+crypto_deinit(void)
+{
+#ifdef OCF_CHACHA20_POLY1305
+ crypto_freesession(chacha20_poly1305_sid);
+#endif
+}
diff --git a/src/crypto.h b/src/crypto.h
index ad06066..01b4dee 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -6,9 +6,14 @@
#ifndef _WG_CRYPTO
#define _WG_CRYPTO
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/mbuf.h>
+#if __FreeBSD_version >= 1400036 || \
+ (__FreeBSD_version < 1400000 && __FreeBSD_version >= 1300519)
+#define OCF_CHACHA20_POLY1305
+#endif
+
enum chacha20poly1305_lengths {
XCHACHA20POLY1305_NONCE_SIZE = 24,
CHACHA20POLY1305_KEY_SIZE = 32,
@@ -109,4 +114,7 @@ static inline void curve25519_generate_secret(uint8_t secret[CURVE25519_KEY_SIZE
curve25519_clamp_secret(secret);
}
+int crypto_init(void);
+void crypto_deinit(void);
+
#endif
diff --git a/src/if_wg.c b/src/if_wg.c
index a368d15..ac824d7 100644
--- a/src/if_wg.c
+++ b/src/if_wg.c
@@ -2980,8 +2980,11 @@ 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);
@@ -2994,6 +2997,8 @@ wg_module_init(void)
free_all:
osd_jail_deregister(wg_osd_jail_slot);
cookie_deinit();
+free_crypto:
+ crypto_deinit();
free_zone:
uma_zdestroy(wg_packet_zone);
free_none:
@@ -3017,6 +3022,7 @@ wg_module_deinit(void)
MPASS(LIST_EMPTY(&wg_list));
osd_jail_deregister(wg_osd_jail_slot);
cookie_deinit();
+ crypto_deinit();
uma_zdestroy(wg_packet_zone);
}