From 268b81c29e475c43945a12cec4369d3b6b470223 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 18 Nov 2025 10:28:24 -0500 Subject: [PATCH 1/6] TLSv1.3 certificate verify: report rsa_pss_pss_* signature algorithm when supported --- src/ssl_load.c | 6 ++++++ src/tls13.c | 23 +++++++++++++++++++---- wolfssl/internal.h | 3 +++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/ssl_load.c b/src/ssl_load.c index bb14cbef3..5d9eadda4 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -1624,6 +1624,12 @@ static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, ret = CHECK_KEY_SZ(ssl ? ssl->options.minRsaKeySz : ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E); } + #ifdef WC_RSA_PSS + if (ssl) + ssl->ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1u : 0u; + else + ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1u : 0u; + #endif break; #endif /* !NO_RSA */ #ifdef HAVE_ECC diff --git a/src/tls13.c b/src/tls13.c index 517a97cbf..3133dc8c3 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7867,8 +7867,9 @@ static int SendTls13CertificateRequest(WOLFSSL* ssl, byte* reqCtx, * hsType The signature type. * output The buffer to encode into. */ -static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) +static WC_INLINE void EncodeSigAlg(const WOLFSSL * ssl, byte hashAlgo, byte hsType, byte* output) { + (void)ssl; switch (hsType) { #ifdef HAVE_ECC case ecc_dsa_sa_algo: @@ -7899,10 +7900,24 @@ static WC_INLINE void EncodeSigAlg(byte hashAlgo, byte hsType, byte* output) break; #endif #ifndef NO_RSA - /* PSS signatures: 0x080[4-6] */ + /* PSS signatures: 0x080[4-6] or 0x080[9-B] */ case rsa_pss_sa_algo: output[0] = rsa_pss_sa_algo; - output[1] = hashAlgo; +#ifdef WC_RSA_PSS + /* If the private key uses the RSA-PSS OID, and the peer supports + * the rsa_pss_pss_* signature algorithm in use, then report + * rsa_pss_pss_* rather than rsa_pss_rsae_*. */ + if (ssl->ctx->useRsaPss && + ((ssl->pssAlgo & (1u << hashAlgo)) != 0u) && + (sha256_mac <= hashAlgo) && (hashAlgo <= sha512_mac)) + { + output[1] = PSS_RSAE_TO_PSS_PSS(hashAlgo); + } + else +#endif + { + output[1] = hashAlgo; + } break; #endif #ifdef HAVE_FALCON @@ -9361,7 +9376,7 @@ static int SendTls13CertificateVerify(WOLFSSL* ssl) } else #endif /* WOLFSSL_DUAL_ALG_CERTS */ - EncodeSigAlg(ssl->options.hashAlgo, args->sigAlgo, + EncodeSigAlg(ssl, ssl->options.hashAlgo, args->sigAlgo, args->verify); if (args->sigData == NULL) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 08549f6b5..75be406a2 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3907,6 +3907,9 @@ struct WOLFSSL_CTX { #endif #ifndef NO_RSA short minRsaKeySz; /* minimum RSA key size */ +#ifdef WC_RSA_PSS + word8 useRsaPss; +#endif #endif #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) short minEccKeySz; /* minimum ECC key size */ From 2c4b6f46b7bab18f5ae40fc3ec1802af2e92dd0c Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 19 Nov 2025 11:49:28 -0500 Subject: [PATCH 2/6] Add scripts/rsapss.test to test RSA-PSS signature algorithm negotiation --- scripts/include.am | 1 + scripts/rsapss.test | 92 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100755 scripts/rsapss.test diff --git a/scripts/include.am b/scripts/include.am index 95e95e8ad..7325d3b66 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -116,6 +116,7 @@ EXTRA_DIST += scripts/sniffer-static-rsa.pcap \ # leave openssl.test as extra until non bash works EXTRA_DIST += scripts/openssl.test +EXTRA_DIST += scripts/rsapss.test EXTRA_DIST += scripts/dertoc.pl diff --git a/scripts/rsapss.test b/scripts/rsapss.test new file mode 100755 index 000000000..8a6b857a0 --- /dev/null +++ b/scripts/rsapss.test @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +# rsapss.test + +if ! ./examples/client/client -V | grep -q 4; then + echo "skipping because TLS 1.3 not enabled in this build" + exit 0 +fi +if ! grep -q -- -DWC_RSA_PSS config.log 2>/dev/null; then + echo "skipping because WC_RSA_PSS not enabled in this build" + exit 0 +fi +if ! grep -q -- '-DHAVE_ECC\>' config.log 2>/dev/null; then + echo "skipping because HAVE_ECC not enabled in this build" + exit 0 +fi +if grep -q -- '-DNO_CODING' config.log 2>/dev/null; then + echo "skipping because NO_CODING is defined in this build" + exit 0 +fi + +CERT_DIR="$PWD/$(dirname "$0")/../certs" +if [ "$OPENSSL" = "" ]; then + OPENSSL=openssl +fi + +# if we can, isolate the network namespace to eliminate port collisions. +if [[ -n "$NETWORK_UNSHARE_HELPER" ]]; then + if [[ -z "$NETWORK_UNSHARE_HELPER_CALLED" ]]; then + export NETWORK_UNSHARE_HELPER_CALLED=yes + exec "$NETWORK_UNSHARE_HELPER" "$0" "$@" || exit $? + fi +elif [ "${AM_BWRAPPED-}" != "yes" ]; then + bwrap_path="$(command -v bwrap)" + if [ -n "$bwrap_path" ]; then + export AM_BWRAPPED=yes + exec "$bwrap_path" --unshare-net --dev-bind / / "$0" "$@" + fi + unset AM_BWRAPPED +fi + +# need a unique port since may run the same time as testsuite +generate_port() { + #-------------------------------------------------------------------------# + # Generate a random port number + #-------------------------------------------------------------------------# + + if [[ "$OSTYPE" == "linux"* ]]; then + port=$(($(od -An -N2 /dev/urandom) % (65535-49512) + 49512)) + elif [[ "$OSTYPE" == "darwin"* ]]; then + port=$(($(od -An -N2 /dev/random) % (65535-49512) + 49512)) + else + echo "skipping due to unsupported OS" + exit 0 + fi +} + +WOLFSSL_SERVER=./examples/server/server + +start_wolfssl_server() { + generate_port + server_port=$port + $WOLFSSL_SERVER -p $server_port -v 4 -c $CERT_DIR/rsapss/server-rsapss.pem -k $CERT_DIR/rsapss/server-rsapss-priv.pem -A $CERT_DIR/rsapss/root-rsapss.pem -d & +} + +# +# Run OpenSSL client against wolfSSL server +# +do_openssl_client() { + echo "test connection" | $OPENSSL s_client -connect 127.0.0.1:$server_port -cert $CERT_DIR/rsapss/client-rsapss.pem -key $CERT_DIR/rsapss/client-rsapss-priv.pem -CAfile $CERT_DIR/rsapss/root-rsapss.pem > rsapss.test.log + result=$? + cat rsapss.test.log + if [ $result != 0 ] + then + echo "$OPENSSL s_client command failed" + exit 1 + fi + grep -q "Peer signature type:.*rsa_pss_rsae_sha256" rsapss.test.log + result=$? + rm -f rsapss.test.log + if [ $result == 0 ] + then + echo "Test failed: Peer signature type identified as rsa_pss_rsae_sha256" + exit 1 + fi +} + +start_wolfssl_server +sleep 1 +do_openssl_client +echo -e "\nSuccess!\n\n" +exit 0 From bb8673070abfd1bc558ae7fd44a595dee6ae08f9 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 19 Nov 2025 23:52:21 -0500 Subject: [PATCH 3/6] Use uppercase U --- src/ssl_load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ssl_load.c b/src/ssl_load.c index 5d9eadda4..ab2ddd83b 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -1626,9 +1626,9 @@ static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } #ifdef WC_RSA_PSS if (ssl) - ssl->ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1u : 0u; + ssl->ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1U : 0U; else - ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1u : 0u; + ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1U : 0U; #endif break; #endif /* !NO_RSA */ From 80d3037332524b0829661e0008b5db531d71d40b Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 20 Nov 2025 08:34:45 -0500 Subject: [PATCH 4/6] Use more uppercase U's --- src/tls13.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tls13.c b/src/tls13.c index 3133dc8c3..b4379000f 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7908,7 +7908,7 @@ static WC_INLINE void EncodeSigAlg(const WOLFSSL * ssl, byte hashAlgo, byte hsTy * the rsa_pss_pss_* signature algorithm in use, then report * rsa_pss_pss_* rather than rsa_pss_rsae_*. */ if (ssl->ctx->useRsaPss && - ((ssl->pssAlgo & (1u << hashAlgo)) != 0u) && + ((ssl->pssAlgo & (1U << hashAlgo)) != 0U) && (sha256_mac <= hashAlgo) && (hashAlgo <= sha512_mac)) { output[1] = PSS_RSAE_TO_PSS_PSS(hashAlgo); From d766b82bacc2dc74e01cfb324ee68de19587e64a Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 24 Nov 2025 15:55:32 -0500 Subject: [PATCH 5/6] Remove conditional and just assign boolean result --- src/ssl_load.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ssl_load.c b/src/ssl_load.c index ab2ddd83b..a3625052e 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -1626,9 +1626,9 @@ static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } #ifdef WC_RSA_PSS if (ssl) - ssl->ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1U : 0U; + ssl->ctx->useRsaPss = cert->keyOID == RSAPSSk; else - ctx->useRsaPss = (cert->keyOID == RSAPSSk) ? 1U : 0U; + ctx->useRsaPss = cert->keyOID == RSAPSSk; #endif break; #endif /* !NO_RSA */ From 36418aca76a3f3369b5e640809c8b82cc88ceda7 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 26 Nov 2025 10:30:38 -0500 Subject: [PATCH 6/6] Set useRsaPss flag in both SSL and CTX structures --- src/internal.c | 3 +++ src/ssl_load.c | 8 +++++--- src/tls13.c | 2 +- wolfssl/internal.h | 5 ++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/internal.c b/src/internal.c index 1bbd98d8c..4f39fac1a 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6983,6 +6983,9 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #endif #ifndef NO_RSA ssl->options.minRsaKeySz = ctx->minRsaKeySz; + #ifdef WC_RSA_PSS + ssl->useRsaPss = ctx->useRsaPss; + #endif #endif #ifdef HAVE_ECC ssl->options.minEccKeySz = ctx->minEccKeySz; diff --git a/src/ssl_load.c b/src/ssl_load.c index a3625052e..dc652748c 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -1625,10 +1625,12 @@ static int ProcessBufferCertPublicKey(WOLFSSL_CTX* ctx, WOLFSSL* ssl, ctx->minRsaKeySz, RSA_MAX_SIZE / 8, keySz, RSA_KEY_SIZE_E); } #ifdef WC_RSA_PSS - if (ssl) - ssl->ctx->useRsaPss = cert->keyOID == RSAPSSk; - else + if (ssl) { + ssl->useRsaPss = cert->keyOID == RSAPSSk; + } + if (ctx) { ctx->useRsaPss = cert->keyOID == RSAPSSk; + } #endif break; #endif /* !NO_RSA */ diff --git a/src/tls13.c b/src/tls13.c index b4379000f..b071d5490 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -7907,7 +7907,7 @@ static WC_INLINE void EncodeSigAlg(const WOLFSSL * ssl, byte hashAlgo, byte hsTy /* If the private key uses the RSA-PSS OID, and the peer supports * the rsa_pss_pss_* signature algorithm in use, then report * rsa_pss_pss_* rather than rsa_pss_rsae_*. */ - if (ssl->ctx->useRsaPss && + if (ssl->useRsaPss && ((ssl->pssAlgo & (1U << hashAlgo)) != 0U) && (sha256_mac <= hashAlgo) && (hashAlgo <= sha512_mac)) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 75be406a2..4f8cd2a29 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -3908,7 +3908,7 @@ struct WOLFSSL_CTX { #ifndef NO_RSA short minRsaKeySz; /* minimum RSA key size */ #ifdef WC_RSA_PSS - word8 useRsaPss; + word8 useRsaPss; /* cert supports RSA-PSS */ #endif #endif #if defined(HAVE_ECC) || defined(HAVE_ED25519) || defined(HAVE_ED448) @@ -5941,6 +5941,9 @@ struct WOLFSSL { byte* peerSceTsipEncRsaKeyIndex; #endif byte peerRsaKeyPresent; +#ifdef WC_RSA_PSS + word8 useRsaPss; /* cert supports RSA-PSS */ +#endif #endif #if defined(WOLFSSL_TLS13) || defined(HAVE_FFDHE) word16 namedGroup;