diff options
author | John Baldwin <jhb@FreeBSD.org> | 2021-10-11 11:27:16 -0700 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2022-06-14 00:54:55 +0200 |
commit | a6354a1436fb19e96156fdaa9c71ebbe4ea3e45a (patch) | |
tree | 71bfb1bfb4d1ac02357f00ded160f1ad4881b3e4 | |
parent | if_wg: wg_peer_alloc and wg_aip_add: Use M_WAITOK with malloc (diff) | |
download | wireguard-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.c | 93 | ||||
-rw-r--r-- | src/crypto.h | 10 | ||||
-rw-r--r-- | src/if_wg.c | 8 |
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); } |