Fix integrity-only cipher nonce calculation

This commit is contained in:
Josh Holtrop
2026-02-16 21:29:41 -05:00
parent d81bb7234a
commit 2be175fa35
7 changed files with 165 additions and 59 deletions
+118 -32
View File
@@ -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,69 @@ 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
# 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
+1 -1
View File
@@ -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;
+8 -8
View File
@@ -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;
+16 -12
View File
@@ -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;
@@ -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;
@@ -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;
+18 -2
View File
@@ -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 */