diff --git a/kernel-src/noise.c b/kernel-src/noise.c index 29e63fc..79bc75f 100644 --- a/kernel-src/noise.c +++ b/kernel-src/noise.c @@ -533,6 +533,10 @@ static int __must_check message_encrypt(u8 *dst_ciphertext, size_t dst_ciphertex size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN]) { + /* For Noise_IK, an all-zeros IV is used, and the key itself guarantees + * uniqueness of the { key, iv } tuple, via wc_ecc_make_keypair_exim(), + * mix_dh(), mix_precomputed_dh(), and mix_psk(). + */ int ret = wc_AesGcm_oneshot_encrypt(dst_ciphertext, dst_ciphertext_space, key, NOISE_SYMMETRIC_KEY_LEN, src_plaintext, src_len, NULL /* iv */, 0, hash, NOISE_HASH_LEN, NOISE_AUTHTAG_LEN); @@ -721,7 +725,7 @@ wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src, goto out; } - /* Get an exclusive lock here, even though initially we only need a read + /* Get an exclusive lock here, even though initially we only need a read * lock -- this avoids a race window after the defensive tests and * before storing the new ephemeral key. The attack tests have a * negligible CPU footprint, so the atomic ops (identically expensive diff --git a/kernel-src/receive.c b/kernel-src/receive.c index 72f7536..07e76a8 100644 --- a/kernel-src/receive.c +++ b/kernel-src/receive.c @@ -208,8 +208,10 @@ static int wg_receive_handshake_packet(struct wg_device *wg, wg_packet_send_keepalive(peer); ret = 0; } - else + else { + WC_DEBUG_PR_CODEPOINT(); ret = -ECANCELED; + } break; } } diff --git a/kernel-src/selftest/allowedips.c b/kernel-src/selftest/allowedips.c index 5d6c9d7..023c100 100644 --- a/kernel-src/selftest/allowedips.c +++ b/kernel-src/selftest/allowedips.c @@ -324,7 +324,7 @@ static __init bool randomized_test(void) mutate_mask[k] = 0xff; mutate_mask[k] = 0xff << ((8 - (mutate_amount % 8)) % 8); - for (k = mutate_amount/8 + 1; k < 4; ++k) + for (k = mutate_amount / 8 + 1; k < 4; ++k) mutate_mask[k] = 0; for (k = 0; k < 4; ++k) mutated[k] = (mutated[k] & mutate_mask[k]) | @@ -369,7 +369,7 @@ static __init bool randomized_test(void) mutate_mask[k] = 0xff << ((8 - (mutate_amount % 8)) % 8); /* 16 bytes of IPv6 address */ - for (k = mutate_amount/8 + 1; k < 16; ++k) + for (k = mutate_amount / 8 + 1; k < 16; ++k) mutate_mask[k] = 0; for (k = 0; k < 16; ++k) mutated[k] = (mutated[k] & mutate_mask[k]) | diff --git a/kernel-src/send.c b/kernel-src/send.c index c7705bf..c8c6af3 100644 --- a/kernel-src/send.c +++ b/kernel-src/send.c @@ -48,13 +48,19 @@ static int __must_check wg_packet_send_handshake_initiation(struct wg_peer *peer wg_timers_any_authenticated_packet_traversal(peer); wg_timers_any_authenticated_packet_sent(peer); } + else + WC_DEBUG_PR_CODEPOINT_VAL(ret); } + else + WC_DEBUG_PR_CODEPOINT_VAL(ret); wg_timers_handshake_initiated(peer); /* restart retry timer even * if send failed. */ } - else + else { + WC_DEBUG_PR_CODEPOINT(); ret = -ECANCELED; + } if (ret != 0) (void)atomic64_cmpxchg_relaxed(&peer->last_sent_handshake, @@ -132,7 +138,10 @@ int __must_check wg_packet_send_handshake_response(struct wg_peer *peer) if (ret == 0) { if (! wg_noise_handshake_begin_session(&peer->handshake, &peer->keypairs)) + { + WC_DEBUG_PR_CODEPOINT(); ret = -ECANCELED; + } } if (ret == 0) { wg_timers_session_derived(peer); @@ -145,8 +154,10 @@ int __must_check wg_packet_send_handshake_response(struct wg_peer *peer) HANDSHAKE_DSCP); } } - else + else { + WC_DEBUG_PR_CODEPOINT(); ret = -ECANCELED; + } memzero_explicit(&packet, sizeof packet); diff --git a/kernel-src/wolfcrypt_glue.c b/kernel-src/wolfcrypt_glue.c index 40a4e65..5aa5860 100644 --- a/kernel-src/wolfcrypt_glue.c +++ b/kernel-src/wolfcrypt_glue.c @@ -72,7 +72,7 @@ int wc_hmac_oneshot(const int type, byte *out, const size_t out_space, const byt static const byte ZeroNonce[AES_IV_SIZE] = {}; -int wc_AesGcm_Appended_Tag_Encrypt(Aes* aes, byte* out, word32 out_space, +static int wc_AesGcm_Appended_Tag_Encrypt(Aes* aes, byte* out, word32 out_space, const byte* in, word32 in_sz, const byte* iv, word32 iv_sz, const byte* authIn, word32 authIn_sz, @@ -88,12 +88,40 @@ int wc_AesGcm_Appended_Tag_Encrypt(Aes* aes, byte* out, word32 out_space, iv_sz = sizeof(ZeroNonce); } +#ifdef WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED WC_DEBUG_PR_NEG_RET(wc_AesGcmEncrypt(aes, out, in, in_sz, iv, iv_sz, - out + in_sz, authTag_len, - authIn, authIn_sz)); + out + in_sz, authTag_len, + authIn, authIn_sz)); +#else /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ + /* avoid wc_AesGcmEncrypt(), to stay in-boundary for FIPS. */ + #ifdef WOLFSSL_AESGCM_STREAM + { + int ret = wc_AesGcmInit(aes, NULL /* key */, 0 /* len */, iv, iv_sz); + if (ret < 0) + WC_DEBUG_PR_NEG_RET(ret); + ret = wc_AesGcmEncryptUpdate(aes, out, in, in_sz, authIn, authIn_sz); + if (ret < 0) + WC_DEBUG_PR_NEG_RET(ret); + WC_DEBUG_PR_NEG_RET(wc_AesGcmEncryptFinal(aes, out + in_sz, authTag_len)); + } + #else + { + byte ivOut[GCM_NONCE_MAX_SZ]; + int ret; + if (iv_sz > GCM_NONCE_MAX_SZ) + WC_DEBUG_PR_NEG_RET(BAD_LENGTH_E); + ret = wc_AesGcmSetExtIV(aes, iv, iv_sz); + if (ret < 0) + WC_DEBUG_PR_NEG_RET(ret); + WC_DEBUG_PR_NEG_RET(wc_AesGcmEncrypt_ex(aes, out, in, in_sz, ivOut, iv_sz, + out + in_sz, authTag_len, + authIn, authIn_sz)); + } + #endif +#endif /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ } -int wc_AesGcm_Appended_Tag_Decrypt(Aes* aes, byte* out, word32 out_space, +static int wc_AesGcm_Appended_Tag_Decrypt(Aes* aes, byte* out, word32 out_space, const byte* in, word32 in_sz, const byte* iv, word32 iv_sz, const byte* authIn, word32 authIn_sz, @@ -176,6 +204,17 @@ int wc_AesGcm_oneshot_decrypt(byte* out, size_t out_space, const byte* key, size #ifdef WOLFSSL_AESGCM_STREAM +/* Don't incur the FIPS check overhead inside the loop -- the Final() call + * below will check and error if the module entered degraded state during + * the loop. + */ +#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) + #undef wc_AesGcmDecryptUpdate + #undef wc_AesGcmEncryptUpdate + typeof(wc_AesGcmDecryptUpdate_fips) wc_AesGcmDecryptUpdate; + typeof(wc_AesGcmEncryptUpdate_fips) wc_AesGcmEncryptUpdate; +#endif + static __always_inline bool wc_AesGcm_crypt_sg_inplace(struct scatterlist *src, const size_t src_len, const u8 *ad, const size_t ad_len, u64 nonce, @@ -319,6 +358,11 @@ static __always_inline bool wc_AesGcm_crypt_sg_inplace(struct scatterlist *src, return ret == 0; } +#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) + #define wc_AesGcmDecryptUpdate wc_AesGcmDecryptUpdate_fips + #define wc_AesGcmEncryptUpdate wc_AesGcmEncryptUpdate_fips +#endif + #else /* !WOLFSSL_AESGCM_STREAM */ static __always_inline bool wc_AesGcm_crypt_sg_inplace(struct scatterlist *src, const size_t src_len, @@ -400,13 +444,36 @@ static __always_inline bool wc_AesGcm_crypt_sg_inplace(struct scatterlist *src, full_nonce, (word32)sizeof(full_nonce), miter.addr + length, WC_AES_BLOCK_SIZE, ad, (word32)ad_len); + if (ret < 0) + WC_DEBUG_PR_CODEPOINT_VAL(ret); } else { +#ifdef WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED ret = wc_AesGcmEncrypt(aes, miter.addr, miter.addr, (word32)length, full_nonce, (word32)sizeof(full_nonce), miter.addr + length, WC_AES_BLOCK_SIZE, ad, (word32)ad_len); + if (ret < 0) + WC_DEBUG_PR_CODEPOINT_VAL(ret); +#else /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ + /* Use wc_AesGcmSetExtIV() and wc_AesGcmEncrypt_ex(), not + * wc_AesGcmEncrypt(), to stay in-boundary for FIPS. + */ + byte ivOut[GCM_NONCE_MAX_SZ]; + ret = wc_AesGcmSetExtIV(aes, full_nonce, (word32)sizeof(full_nonce)); + if (ret == 0) { + ret = wc_AesGcmEncrypt_ex(aes, miter.addr, + miter.addr, (word32)length, + ivOut, (word32)sizeof(full_nonce), + miter.addr + length, WC_AES_BLOCK_SIZE, + ad, (word32)ad_len); + if (ret < 0) + WC_DEBUG_PR_CODEPOINT_VAL(ret); + } + else + WC_DEBUG_PR_CODEPOINT_VAL(ret); +#endif /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ } sg_miter_stop(&miter); @@ -437,11 +504,32 @@ static __always_inline bool wc_AesGcm_crypt_sg_inplace(struct scatterlist *src, } else { scatterwalk_map_and_copy(buf, src, 0, src_len, 0); +#ifdef WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED ret = wc_AesGcmEncrypt(aes, buf, buf, (word32)src_len, full_nonce, (word32)sizeof(full_nonce), buf + src_len, WC_AES_BLOCK_SIZE, ad, (word32)ad_len); + if (ret < 0) + WC_DEBUG_PR_CODEPOINT_VAL(ret); +#else /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ + { + /* Avoid wc_AesGcmEncrypt() to stay in-boundary for FIPS. */ + byte ivOut[GCM_NONCE_MAX_SZ]; + ret = wc_AesGcmSetExtIV(aes, full_nonce, (word32)sizeof(full_nonce)); + if (ret == 0) { + ret = wc_AesGcmEncrypt_ex(aes, buf, + buf, (word32)src_len, + ivOut, (word32)sizeof(full_nonce), + buf + src_len, WC_AES_BLOCK_SIZE, + ad, (word32)ad_len); + if (ret < 0) + WC_DEBUG_PR_CODEPOINT_VAL(ret); + } + else + WC_DEBUG_PR_CODEPOINT_VAL(ret); + } +#endif /* !WC_FIPS_AESGCM_ONE_SHOT_EXT_IV_ALLOWED */ if (ret == 0) scatterwalk_map_and_copy(buf, src, 0, src_len + WC_AES_BLOCK_SIZE, 1); else @@ -889,6 +977,8 @@ int wc_linuxkm_drbg_init_ctx(struct wc_rng_bank **ctx) { WC_DUMP_BACKTRACE_NONDEBUG; } } + else + WC_DEBUG_PR_CODEPOINT_VAL(ret); return (ret == 0) ? ret : -ECANCELED; } diff --git a/kernel-src/wolfcrypt_glue.h b/kernel-src/wolfcrypt_glue.h index 9b737e6..3d9fb9f 100644 --- a/kernel-src/wolfcrypt_glue.h +++ b/kernel-src/wolfcrypt_glue.h @@ -7,9 +7,10 @@ #define WOLFCRYPTO_SHIM_H #include +#include #if !defined(HAVE_AESGCM) || (!defined(HAVE_AESGCM_DECRYPT) && defined(NO_AES_DECRYPT)) - #error libwolfssl missing AES-GCM with streaming + #error libwolfssl missing AES-GCM #endif #if defined(NO_SHA256) #error libwolfssl missing SHA256 @@ -69,6 +70,7 @@ #define WC_DEBUG_PR_NULL_RET(x) do { typeof(x) _ret = (x); if (! _ret) { pr_notice("value is NULL at %s %s L %d\n", __FILE__, __FUNCTION__, __LINE__); dump_stack(); } return _ret; } while (0) #define WC_DEBUG_PR_VOID_RET do { pr_notice("return at %s %s L %d\n", __FILE__, __FUNCTION__, __LINE__); dump_stack(); return; } while (0) #define WC_DEBUG_PR_CODEPOINT() pr_notice("codepoint at %s %s L %d\n", __FILE__, __FUNCTION__, __LINE__) +#define WC_DEBUG_PR_CODEPOINT_VAL(val) pr_notice("codepoint at %s %s L %d, val %d\n", __FILE__, __FUNCTION__, __LINE__, val) #define WC_DEBUG_PR(fmt, ...) pr_notice("%s %s L %d: " fmt, __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__) #else @@ -79,6 +81,7 @@ #define WC_DEBUG_PR_NULL_RET(x) return(x) #define WC_DEBUG_PR_VOID_RET return #define WC_DEBUG_PR_CODEPOINT() WC_DO_NOTHING +#define WC_DEBUG_PR_CODEPOINT_VAL(val) WC_DO_NOTHING #define WC_DEBUG_PR(fmt, ...) WC_DO_NOTHING #endif @@ -183,18 +186,6 @@ static inline u32 wc_3u32_keyed_hash(const byte *key, const size_t key_len, u32 return wc_u32_keyed_hash(key, key_len, (byte *)&ubuf, sizeof(ubuf)); } -extern int wc_AesGcm_Appended_Tag_Encrypt(Aes* aes, byte* out, word32 out_space, - const byte* in, word32 in_sz, - const byte* iv, word32 iv_sz, - const byte* authIn, word32 authIn_sz, - const word32 authtag_len); - -extern int wc_AesGcm_Appended_Tag_Decrypt(Aes* aes, byte* out, word32 out_space, - const byte* in, word32 in_sz, - const byte* iv, word32 iv_sz, - const byte* authIn, word32 authIn_sz, - const word32 authtag_len); - extern int wc_AesGcm_oneshot_encrypt(byte* out, size_t out_space, const byte* key, size_t keySz, const byte* in, size_t inSz, const byte* iv, size_t ivSz, const byte* authIn, size_t authInSz, size_t authTagSz);