diff --git a/scripts/openssl.test b/scripts/openssl.test index 49140c19aca..71b36386eb5 100755 --- a/scripts/openssl.test +++ b/scripts/openssl.test @@ -387,6 +387,13 @@ do_openssl_client() { openssl_caCert1="-CAfile" openssl_caCert2="$caCert" fi + # Integrity-only cipher suites require SECLEVEL=0 to allow NULL encryption + openssl_seclevel="" + if [ "$tls13_integrity_only" = "yes" ] + then + openssl_seclevel="-cipher ALL:@SECLEVEL=0" + fi + if [ "$tls13_cipher" = "" ] then echo "#" @@ -394,8 +401,8 @@ do_openssl_client() { echo "Hello" | eval "$OPENSSL s_client -connect localhost:$port -reconnect -legacy_renegotiation -cipher $cmpSuite $openssl_version $openssl_psk $openssl_cert1 \"$openssl_cert2\" $openssl_key1 \"$openssl_key2\" $openssl_caCert1 \"$openssl_caCert2\"" else echo "#" - echo "# $OPENSSL s_client -connect localhost:$port -reconnect -legacy_renegotiation -ciphersuites=$cmpSuite $openssl_version $openssl_psk $openssl_cert1 \"$openssl_cert2\" $openssl_key1 \"$openssl_key2\" $openssl_caCert1 \"$openssl_caCert2\"" - echo "Hello" | eval "$OPENSSL s_client -connect localhost:$port -reconnect -legacy_renegotiation -ciphersuites=$cmpSuite $openssl_version $openssl_psk $openssl_cert1 \"$openssl_cert2\" $openssl_key1 \"$openssl_key2\" $openssl_caCert1 \"$openssl_caCert2\"" + echo "# $OPENSSL s_client -connect localhost:$port -reconnect -legacy_renegotiation -ciphersuites=$cmpSuite $openssl_seclevel $openssl_version $openssl_psk $openssl_cert1 \"$openssl_cert2\" $openssl_key1 \"$openssl_key2\" $openssl_caCert1 \"$openssl_caCert2\"" + echo "Hello" | eval "$OPENSSL s_client -connect localhost:$port -reconnect -legacy_renegotiation -ciphersuites=$cmpSuite $openssl_seclevel $openssl_version $openssl_psk $openssl_cert1 \"$openssl_cert2\" $openssl_key1 \"$openssl_key2\" $openssl_caCert1 \"$openssl_caCert2\"" fi client_result=$? @@ -941,8 +948,9 @@ do echo -e "trying wolfSSL cipher suite $wolfSuite" wolf_temp_cases_total=$((wolf_temp_cases_total + 1)) open_temp_cases_total=$((open_temp_cases_total + 1)) - matchSuite=0; + matchSuite=0 tls13_suite= + tls13_integrity_only= case $wolfSuite in "TLS13-AES128-GCM-SHA256") @@ -966,10 +974,22 @@ do tls13_suite="yes" ;; "TLS13-SHA256-SHA256") - continue + cmpSuite="TLS_SHA256_SHA256" + tls13_suite="yes" + tls13_integrity_only="yes" + # OpenSSL does not enable TLS_SHA256_SHA256 in openssl ciphers + # output by default, but it can be specified with -ciphersuite as + # done in do_openssl_client() + matchSuite=1 ;; "TLS13-SHA384-SHA384") - continue + cmpSuite="TLS_SHA384_SHA384" + tls13_suite="yes" + tls13_integrity_only="yes" + # OpenSSL does not enable TLS_SHA256_SHA256 in openssl ciphers + # output by default, but it can be specified with -ciphersuite as + # done in do_openssl_client() + matchSuite=1 ;; "TLS13-"*) echo -e "Suite = $wolfSuite not recognized!" @@ -982,35 +1002,38 @@ do ;; esac - case ":$openssl_ciphers:" in *":$cmpSuite:"*) # add extra : for edge cases - case "$cmpSuite" in - "TLS_"*) - if [ "$version" != "4" -a "$version" != "d" ] - then - echo -e "TLS 1.3 cipher suite but not TLS 1.3 protocol" - matchSuite=0 - else - echo -e "Matched to OpenSSL suite support" - matchSuite=1 - fi - ;; - *) - if [ "$version" = "d" -a "$wolfdowngrade" = "4" ] - then - echo -e "Not TLS 1.3 cipher suite but TLS 1.3 downgrade" - matchSuite=0 - elif [ "$version" != "4" ] - then - echo -e "Matched to OpenSSL suite support" - matchSuite=1 - else - echo -e "Not TLS 1.3 cipher suite but TLS 1.3 protocol" - matchSuite=0 - fi + if [ $matchSuite = 0 ] + then + case ":$openssl_ciphers:" in *":$cmpSuite:"*) # add extra : for edge cases + case "$cmpSuite" in + "TLS_"*) + if [ "$version" != "4" -a "$version" != "d" ] + then + echo -e "TLS 1.3 cipher suite but not TLS 1.3 protocol" + matchSuite=0 + else + echo -e "Matched to OpenSSL suite support" + matchSuite=1 + fi + ;; + *) + if [ "$version" = "d" -a "$wolfdowngrade" = "4" ] + then + echo -e "Not TLS 1.3 cipher suite but TLS 1.3 downgrade" + matchSuite=0 + elif [ "$version" != "4" ] + then + echo -e "Matched to OpenSSL suite support" + matchSuite=1 + else + echo -e "Not TLS 1.3 cipher suite but TLS 1.3 protocol" + matchSuite=0 + fi + ;; + esac ;; esac - ;; - esac + fi if [ $matchSuite = 0 ] then @@ -1130,6 +1153,80 @@ do continue fi tls13_cipher=yes + # Integrity-only cipher suites (NULL encryption) + if [ "$tls13_integrity_only" = "yes" ] + then + # Only run integrity-only tests with TLS 1.3 (version 4) + if [ "$version" != "4" ] + then + tls13_cipher= + tls13_integrity_only= + continue + fi + + # Integrity-only cipher suites require OpenSSL 3.4 or later + $OPENSSL version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 | \ + awk -F. '{if ($1 > 3 || ($1 == 3 && $2 >= 4)) exit 1; else exit 0;}' + if [ $? -eq 0 ] + then + echo -e "OpenSSL version too old for integrity-only ciphers, skipping" + tls13_cipher= + tls13_integrity_only= + continue + fi + + # Test with RSA certs if available + if [ $openssl_pid != $no_pid -a "$wolf_rsa" != "" ] + then + cert="${CERT_DIR}/client-cert.pem" + key="${CERT_DIR}/client-key.pem" + caCert="${CERT_DIR}/ca-cert.pem" + + # Start a dedicated OpenSSL server for integrity-only tests + generate_port + integrity_openssl_port=$port + $OPENSSL s_server -accept $integrity_openssl_port -cert "${CERT_DIR}/server-cert.pem" -key "${CERT_DIR}/server-key.pem" -quiet -CAfile "${CERT_DIR}/client-cert.pem" -www -cipher "ALL:eNULL:@SECLEVEL=0" -ciphersuites "$cmpSuite" -verify 10 -verify_return_error & + integrity_openssl_pid=$! + sleep 0.1 + + port=$integrity_openssl_port + do_wolfssl_client + + # Kill the dedicated server + kill $integrity_openssl_pid 2>/dev/null + + port=$wolfssl_port + do_openssl_client + fi + # Test with ECC certs if available + if [ $ecdsa_openssl_pid != $no_pid -a "$wolf_ecc" != "" ] + then + cert="${CERT_DIR}/client-ecc-cert.pem" + key="${CERT_DIR}/ecc-client-key.pem" + caCert="${CERT_DIR}/ca-ecc-cert.pem" + + # Start a dedicated OpenSSL server for integrity-only tests (ECC) + generate_port + integrity_openssl_port=$port + $OPENSSL s_server -accept $integrity_openssl_port -cert "${CERT_DIR}/server-ecc.pem" -key "${CERT_DIR}/ecc-key.pem" -quiet -CAfile "${CERT_DIR}/client-ecc-cert.pem" -www -cipher "ALL:eNULL:@SECLEVEL=0" -ciphersuites "$cmpSuite" -verify 10 -verify_return_error & + integrity_openssl_pid=$! + sleep 0.1 + + wolf_temp_cases_total=$((wolf_temp_cases_total + 1)) + port=$integrity_openssl_port + do_wolfssl_client + + # Kill the dedicated server + kill $integrity_openssl_pid 2>/dev/null + + open_temp_cases_total=$((open_temp_cases_total + 1)) + port=$ecdsa_wolfssl_port + do_openssl_client + fi + tls13_cipher= + tls13_integrity_only= + continue + fi # RSA if [ $openssl_pid != $no_pid -a "$ecdhe_avail" = "yes" ] then diff --git a/src/internal.c b/src/internal.c index 9b8736cac1f..d9758200e2f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -938,7 +938,7 @@ static int ExportKeyState(WOLFSSL* ssl, byte* exp, word32 len, byte ver, XMEMCPY(exp + idx, keys->aead_exp_IV, AEAD_MAX_EXP_SZ); idx += AEAD_MAX_EXP_SZ; - sz = (small)? 0: AEAD_MAX_IMP_SZ; + sz = (small)? 0: ssl->specs.iv_size; if (idx + (sz * 2) + OPAQUE8_LEN > len) { WOLFSSL_MSG("Buffer not large enough for imp IVs"); return BUFFER_E; diff --git a/src/keys.c b/src/keys.c index fbe32514737..ed5f709372d 100644 --- a/src/keys.c +++ b/src/keys.c @@ -1239,7 +1239,7 @@ int GetCipherSpec(word16 side, byte cipherSuite0, byte cipherSuite, specs->static_ecdh = 0; specs->key_size = WC_SHA256_DIGEST_SIZE; specs->block_size = 0; - specs->iv_size = HMAC_NONCE_SZ; + specs->iv_size = WC_SHA256_DIGEST_SIZE; specs->aead_mac_size = WC_SHA256_DIGEST_SIZE; break; @@ -1257,7 +1257,7 @@ int GetCipherSpec(word16 side, byte cipherSuite0, byte cipherSuite, specs->static_ecdh = 0; specs->key_size = WC_SHA384_DIGEST_SIZE; specs->block_size = 0; - specs->iv_size = HMAC_NONCE_SZ; + specs->iv_size = WC_SHA384_DIGEST_SIZE; specs->aead_mac_size = WC_SHA384_DIGEST_SIZE; break; @@ -2827,7 +2827,7 @@ int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) if (!tls13) { CcmRet = wc_AesCcmSetNonce(enc->aes, keys->client_write_IV, - AEAD_MAX_IMP_SZ); + AEAD_NONCE_SZ); if (CcmRet != 0) return CcmRet; } #endif @@ -2856,7 +2856,7 @@ int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2))) if (!tls13) { CcmRet = wc_AesCcmSetNonce(enc->aes, keys->server_write_IV, - AEAD_MAX_IMP_SZ); + AEAD_NONCE_SZ); if (CcmRet != 0) return CcmRet; } #endif @@ -3357,14 +3357,14 @@ int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, if (side == WOLFSSL_CLIENT_END) { if (enc) { XMEMCPY(keys->aead_enc_imp_IV, keys->client_write_IV, - HMAC_NONCE_SZ); + specs->iv_size); hmacRet = wc_HmacSetKey(enc->hmac, hashType, keys->client_write_key, specs->key_size); if (hmacRet != 0) return hmacRet; } if (dec) { XMEMCPY(keys->aead_dec_imp_IV, keys->server_write_IV, - HMAC_NONCE_SZ); + specs->iv_size); hmacRet = wc_HmacSetKey(dec->hmac, hashType, keys->server_write_key, specs->key_size); if (hmacRet != 0) return hmacRet; @@ -3373,14 +3373,14 @@ int SetKeys(Ciphers* enc, Ciphers* dec, Keys* keys, CipherSpecs* specs, else { if (enc) { XMEMCPY(keys->aead_enc_imp_IV, keys->server_write_IV, - HMAC_NONCE_SZ); + specs->iv_size); hmacRet = wc_HmacSetKey(enc->hmac, hashType, keys->server_write_key, specs->key_size); if (hmacRet != 0) return hmacRet; } if (dec) { XMEMCPY(keys->aead_dec_imp_IV, keys->client_write_IV, - HMAC_NONCE_SZ); + specs->iv_size); hmacRet = wc_HmacSetKey(dec->hmac, hashType, keys->client_write_key, specs->key_size); if (hmacRet != 0) return hmacRet; diff --git a/src/tls13.c b/src/tls13.c index 50cae9e577d..15e37133612 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -2426,9 +2426,13 @@ static WC_INLINE void WriteSEQTls13(WOLFSSL* ssl, int verifyOrder, byte* out) * order The side on which the message is to be or was sent. */ static WC_INLINE void BuildTls13Nonce(WOLFSSL* ssl, byte* nonce, const byte* iv, - int order) + int ivSz, int order) { - int seq_offset = AEAD_NONCE_SZ - SEQ_SZ; + int seq_offset; + /* Ensure minimum nonce size for standard AEAD ciphers */ + if (ivSz < AEAD_NONCE_SZ) + ivSz = AEAD_NONCE_SZ; + seq_offset = ivSz - SEQ_SZ; /* The nonce is the IV with the sequence XORed into the last bytes. */ WriteSEQTls13(ssl, order, nonce + seq_offset); XMEMCPY(nonce, iv, seq_offset); @@ -2521,7 +2525,7 @@ static int Tls13IntegrityOnly_Encrypt(WOLFSSL* ssl, byte* output, int ret; /* HMAC: nonce | aad | input */ - ret = wc_HmacUpdate(ssl->encrypt.hmac, nonce, HMAC_NONCE_SZ); + ret = wc_HmacUpdate(ssl->encrypt.hmac, nonce, ssl->specs.iv_size); if (ret == 0) ret = wc_HmacUpdate(ssl->encrypt.hmac, aad, aadSz); if (ret == 0) @@ -2604,12 +2608,12 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #ifdef CIPHER_NONCE if (ssl->encrypt.nonce == NULL) { - ssl->encrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->encrypt.nonce = (byte*)XMALLOC(AEAD_MAX_IMP_SZ, ssl->heap, DYNAMIC_TYPE_CIPHER); #ifdef WOLFSSL_CHECK_MEM_ZERO if (ssl->encrypt.nonce != NULL) { wc_MemZero_Add("EncryptTls13 nonce", ssl->encrypt.nonce, - AEAD_NONCE_SZ); + ssl->specs.iv_size); } #endif } @@ -2617,7 +2621,7 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, return MEMORY_E; BuildTls13Nonce(ssl, ssl->encrypt.nonce, ssl->keys.aead_enc_imp_IV, - CUR_ORDER); + ssl->specs.iv_size, CUR_ORDER); #endif /* Advance state and proceed */ @@ -2799,7 +2803,7 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, #endif #ifdef CIPHER_NONCE - ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); + ForceZero(ssl->encrypt.nonce, ssl->specs.iv_size); #endif break; @@ -2913,7 +2917,7 @@ static int Tls13IntegrityOnly_Decrypt(WOLFSSL* ssl, byte* output, byte hmac[WC_MAX_DIGEST_SIZE]; /* HMAC: nonce | aad | input */ - ret = wc_HmacUpdate(ssl->decrypt.hmac, nonce, HMAC_NONCE_SZ); + ret = wc_HmacUpdate(ssl->decrypt.hmac, nonce, ssl->specs.iv_size); if (ret == 0) ret = wc_HmacUpdate(ssl->decrypt.hmac, aad, aadSz); if (ret == 0) @@ -3005,12 +3009,12 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz, #ifdef CIPHER_NONCE if (ssl->decrypt.nonce == NULL) { - ssl->decrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->decrypt.nonce = (byte*)XMALLOC(AEAD_MAX_IMP_SZ, ssl->heap, DYNAMIC_TYPE_CIPHER); #ifdef WOLFSSL_CHECK_MEM_ZERO if (ssl->decrypt.nonce != NULL) { wc_MemZero_Add("DecryptTls13 nonce", ssl->decrypt.nonce, - AEAD_NONCE_SZ); + ssl->specs.iv_size); } #endif } @@ -3018,7 +3022,7 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz, return MEMORY_E; BuildTls13Nonce(ssl, ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV, - PEER_ORDER); + ssl->specs.iv_size, PEER_ORDER); #endif /* Advance state and proceed */ @@ -3171,7 +3175,7 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz, #endif #ifdef CIPHER_NONCE - ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); + ForceZero(ssl->decrypt.nonce, ssl->specs.iv_size); #endif break; diff --git a/wolfcrypt/src/port/Renesas/renesas_fspsm_util.c b/wolfcrypt/src/port/Renesas/renesas_fspsm_util.c index 885f8bb190f..c7fadb08085 100644 --- a/wolfcrypt/src/port/Renesas/renesas_fspsm_util.c +++ b/wolfcrypt/src/port/Renesas/renesas_fspsm_util.c @@ -853,8 +853,8 @@ int wc_fspsm_generateSessionKey(WOLFSSL *ssl, SCE_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 || cbInfo->internal->cipher == SCE_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) { - enc->aes->nonceSz = AEAD_MAX_IMP_SZ; - dec->aes->nonceSz = AEAD_MAX_IMP_SZ; + enc->aes->nonceSz = AEAD_NONCE_SZ; + dec->aes->nonceSz = AEAD_NONCE_SZ; } enc->aes->devId = devId; dec->aes->devId = devId; diff --git a/wolfcrypt/src/port/Renesas/renesas_tsip_util.c b/wolfcrypt/src/port/Renesas/renesas_tsip_util.c index 33fa22a9b75..c3b791acd34 100644 --- a/wolfcrypt/src/port/Renesas/renesas_tsip_util.c +++ b/wolfcrypt/src/port/Renesas/renesas_tsip_util.c @@ -3276,8 +3276,8 @@ int wc_tsip_generateSessionKey( R_TSIP_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 || ctx->internal->tsip_cipher == R_TSIP_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) { - enc->aes->nonceSz = AEAD_MAX_IMP_SZ; - dec->aes->nonceSz = AEAD_MAX_IMP_SZ; + enc->aes->nonceSz = AEAD_NONCE_SZ; + dec->aes->nonceSz = AEAD_NONCE_SZ; } enc->aes->devId = devId; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 6960a29fe38..169311d99ac 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1868,7 +1868,15 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); #endif /* Set max implicit IV size for AEAD cipher suites */ -#define AEAD_MAX_IMP_SZ 12 +#if defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) && defined(WOLFSSL_SHA384) + /* Integrity-only cipher suites use IV size equal to hash output size */ + #define AEAD_MAX_IMP_SZ 48 +#elif defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) && !defined(NO_SHA256) + /* Integrity-only cipher suites use IV size equal to hash output size */ + #define AEAD_MAX_IMP_SZ 32 +#else + #define AEAD_MAX_IMP_SZ 12 +#endif /* Set max explicit IV size for AEAD cipher suites */ #define AEAD_MAX_EXP_SZ 8 @@ -2853,7 +2861,15 @@ struct WOLFSSL_BIO { WOLFSSL_LOCAL socklen_t wolfSSL_BIO_ADDR_size(const WOLFSSL_BIO_ADDR *addr); #endif -#define MAX_WRITE_IV_SZ 16 /* max size of client/server write_IV */ +#if defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) && defined(WOLFSSL_SHA384) + /* Integrity-only cipher suites use IV size equal to hash output size */ + #define MAX_WRITE_IV_SZ 48 +#elif defined(WOLFSSL_TLS13) && defined(HAVE_NULL_CIPHER) && !defined(NO_SHA256) + /* Integrity-only cipher suites use IV size equal to hash output size */ + #define MAX_WRITE_IV_SZ 32 +#else + #define MAX_WRITE_IV_SZ 16 /* max size of client/server write_IV */ +#endif /* keys and secrets * keep as a constant size (no additional ifdefs) for session export */