From b65ab815241bcd1fa7e6a38e164b8aa7d92b5630 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Fri, 30 Oct 2026 14:24:04 -0700 Subject: [PATCH] Test FIPS builds with DES3 and MD5 enabled --- .github/workflows/fips-ready.yml | 11 +++++-- include/wolfprovider/internal.h | 11 +++++++ scripts/build-wolfprovider.sh | 1 + scripts/utils-wolfssl.sh | 2 +- src/wp_ecdsa_sig.c | 11 ++----- test/test_ecc.c | 53 ++++++++++++++++---------------- test/test_tls1_prf.c | 5 +-- 7 files changed, 53 insertions(+), 41 deletions(-) diff --git a/.github/workflows/fips-ready.yml b/.github/workflows/fips-ready.yml index 4e599c6e..0f738713 100644 --- a/.github/workflows/fips-ready.yml +++ b/.github/workflows/fips-ready.yml @@ -64,7 +64,7 @@ jobs: fips_ready_test: needs: [discover_versions, require_fips_resolved] if: github.event_name != 'pull_request' || github.event.pull_request.draft == false - name: FIPS Ready ${{ matrix.wolfssl_bundle_ref }} (${{ matrix.openssl_ref }}) + name: FIPS Ready ${{ matrix.wolfssl_bundle_ref }} (${{ matrix.openssl_ref }})${{ matrix.wolfssl_extra_opts != '' && format(' {0}', matrix.wolfssl_extra_opts) || '' }} runs-on: ubuntu-22.04 permissions: contents: read @@ -75,7 +75,13 @@ jobs: matrix: wolfssl_bundle_ref: ${{ fromJson(needs.discover_versions.outputs.fips_ready_pr_array) }} openssl_ref: ${{ fromJson(needs.discover_versions.outputs.openssl_latest_ref_array) }} + wolfssl_extra_opts: [ '' ] # force_fail collapsed into sequential runs in the test step + include: + # DES3 also enables MD5, so non-FIPS algorithms are in the build + - wolfssl_bundle_ref: ${{ needs.discover_versions.outputs.fips_ready_latest }} + openssl_ref: ${{ needs.discover_versions.outputs.openssl_latest_ref }} + wolfssl_extra_opts: '--enable-des3' steps: - name: Checkout wolfProvider uses: actions/checkout@v4 @@ -92,7 +98,7 @@ jobs: # The build below sets WOLFPROV_FIPS_FORCE_FAIL, which adds # -DHAVE_FORCE_FIPS_FAILURE to the wolfSSL build; key the cached # install on it so a wolfSSL built without the define is never reused. - extra_key: forcefail + extra_key: forcefail${{ matrix.wolfssl_extra_opts }} github_token: ${{ secrets.GITHUB_TOKEN }} - name: Download FIPS Ready Bundle @@ -107,6 +113,7 @@ jobs: # flag) that enables HAVE_FORCE_FIPS_FAILURE for the fips_status test. OPENSSL_TAG=${{ matrix.openssl_ref }} \ WOLFPROV_FIPS_FORCE_FAIL=1 \ + WOLFSSL_EXTRA_CONFIG_OPTS="${{ matrix.wolfssl_extra_opts }}" \ ./scripts/build-wolfprovider.sh --fips-bundle="$FIPS_BUNDLE_PATH" \ --fips-check=ready --wolfssl-ver=v${{matrix.wolfssl_bundle_ref}}-stable diff --git a/include/wolfprovider/internal.h b/include/wolfprovider/internal.h index 0b10515c..291dad22 100644 --- a/include/wolfprovider/internal.h +++ b/include/wolfprovider/internal.h @@ -74,6 +74,17 @@ #define WP_DH_MIN_BITS 1024 #endif +/* Fallbacks for digest minimums that older wolfSSL versions lack. */ +#ifndef WC_MIN_DIGEST_SIZE +#define WC_MIN_DIGEST_SIZE 20 +#endif /* !WC_MIN_DIGEST_SIZE */ +#ifndef WC_MIN_DIGEST_SIZE_FOR_SIGN +#define WC_MIN_DIGEST_SIZE_FOR_SIGN WC_MIN_DIGEST_SIZE +#endif /* !WC_MIN_DIGEST_SIZE_FOR_SIGN */ +#ifndef WC_MIN_DIGEST_SIZE_FOR_VERIFY +#define WC_MIN_DIGEST_SIZE_FOR_VERIFY WC_MIN_DIGEST_SIZE +#endif /* !WC_MIN_DIGEST_SIZE_FOR_VERIFY */ + /* DER key encoding/decoding formats. */ /** SubjectPublicKeyInfo encoding format. */ #define WP_ENC_FORMAT_SPKI 1 diff --git a/scripts/build-wolfprovider.sh b/scripts/build-wolfprovider.sh index ab9f2cb0..45684602 100755 --- a/scripts/build-wolfprovider.sh +++ b/scripts/build-wolfprovider.sh @@ -46,6 +46,7 @@ show_help() { echo " WOLFSSL_ISFIPS If set to 1, clones a wolfSSL FIPS bundle from GitHub" echo " WOLFSSL_FIPS_BUNDLE Directory containing the wolfSSL FIPS bundle to use instead of cloning from GitHub" echo " WOLFSSL_FIPS_CHECK_TAG Tag for wolfSSL FIPS bundle (v5.2.1, v5.2.4, linuxv5.2.1, v6.0.0, ready, etc). Automatically determines configure option (default: v5.2.4)" + echo " WOLFSSL_EXTRA_CONFIG_OPTS Extra wolfSSL configure options added to the defaults (e.g., --enable-des3)" echo " WOLFPROV_CLEAN If set to 1, run make clean in OpenSSL, wolfSSL, and wolfProvider" echo " WOLFPROV_DISTCLEAN If set to 1, remove the source and install directories of OpenSSL, wolfSSL, and wolfProvider" echo " WOLFPROV_DEBUG If set to 1, builds OpenSSL, wolfSSL, and wolfProvider with debug options enabled" diff --git a/scripts/utils-wolfssl.sh b/scripts/utils-wolfssl.sh index bc3a2c06..a0b54d7d 100644 --- a/scripts/utils-wolfssl.sh +++ b/scripts/utils-wolfssl.sh @@ -202,7 +202,7 @@ install_wolfssl() { printf "\tConfigure wolfSSL ${WOLFSSL_TAG} ... " ./autogen.sh >>$LOG_FILE 2>&1 - CONF_ARGS="-prefix=${WOLFSSL_INSTALL_DIR}" + CONF_ARGS="-prefix=${WOLFSSL_INSTALL_DIR} ${WOLFSSL_EXTRA_CONFIG_OPTS}" if [ "$WOLFPROV_DEBUG" = "1" ]; then CONF_ARGS+=" --enable-debug --enable-keylog-export" diff --git a/src/wp_ecdsa_sig.c b/src/wp_ecdsa_sig.c index 992eaef7..d4af24c8 100644 --- a/src/wp_ecdsa_sig.c +++ b/src/wp_ecdsa_sig.c @@ -32,13 +32,6 @@ #ifdef WP_HAVE_ECDSA -/* WC_MIN_DIGEST_SIZE was introduced in wolfSSL v5.9.1. Fall back to the - * SHA-1 digest size on older releases so the raw-ECDSA minimum matches the - * behavior FIPS 186-4 requires. */ -#ifndef WC_MIN_DIGEST_SIZE -#define WC_MIN_DIGEST_SIZE 20 -#endif - /** * ECDSA signature context. * @@ -291,7 +284,7 @@ static int wp_ecdsa_sign(wp_EcdsaSigCtx *ctx, unsigned char *sig, ok = 0; } else if ((hashType == WC_HASH_TYPE_NONE) && - (tbsLen < WC_MIN_DIGEST_SIZE)) { + (tbsLen < WC_MIN_DIGEST_SIZE_FOR_SIGN)) { ok = 0; } else if ((ok = wp_ecc_check_usage(ctx->ecc))) { @@ -391,7 +384,7 @@ static int wp_ecdsa_verify(wp_EcdsaSigCtx *ctx, const unsigned char *sig, ok = 0; } else if ((hashType == WC_HASH_TYPE_NONE) && - (tbsLen < WC_MIN_DIGEST_SIZE)) { + (tbsLen < WC_MIN_DIGEST_SIZE_FOR_VERIFY)) { ok = 0; } else if ((!WP_FITS_WORD32(sigLen)) || (!WP_FITS_WORD32(tbsLen))) { diff --git a/test/test_ecc.c b/test/test_ecc.c index 87003a73..8449e048 100644 --- a/test/test_ecc.c +++ b/test/test_ecc.c @@ -27,12 +27,7 @@ #include #include -#include - -/* Mirror the fallback used in src/wp_ecdsa_sig.c for wolfSSL < v5.9.1. */ -#ifndef WC_MIN_DIGEST_SIZE -#define WC_MIN_DIGEST_SIZE 20 -#endif +#include #ifdef WP_HAVE_ECC @@ -2029,17 +2024,19 @@ int test_ecdsa_p256_pkey(void *data) return err; } -/* Raw EVP_PKEY_verify must reject inputs below WC_MIN_DIGEST_SIZE. */ +/* Raw ECDSA sign and verify must reject inputs below wolfSSL's minimums. */ int test_ecdsa_verify_undersized_hash(void *data) { - /* Boundaries track WC_MIN_DIGEST_SIZE so the assertions stay valid for - * whatever hash set the wolfSSL build enabled (typically 20 for SHA-1, - * but 16 when MD5 is on or 28+ in FIPS 186-5 builds). */ - static const size_t sizes[] = { 0, - WC_MIN_DIGEST_SIZE - 1, - WC_MIN_DIGEST_SIZE, - WC_MAX_DIGEST_SIZE }; - static const int expectFail[] = { 1, 1, 0, 0 }; + /* Minimums vary with the hash set and FIPS level, e.g. 16 with MD5. */ + static const size_t verifySizes[] = { 0, + WC_MIN_DIGEST_SIZE_FOR_VERIFY - 1, + WC_MIN_DIGEST_SIZE_FOR_VERIFY, + WC_MAX_DIGEST_SIZE }; + static const size_t signSizes[] = { 0, + WC_MIN_DIGEST_SIZE_FOR_SIGN - 1, + WC_MIN_DIGEST_SIZE_FOR_SIGN, + WC_MAX_DIGEST_SIZE }; + static const int expectFail[] = { 1, 1, 0, 0 }; int err; size_t i; EVP_PKEY *pkey = NULL; @@ -2056,26 +2053,28 @@ int test_ecdsa_verify_undersized_hash(void *data) err = pkey == NULL; } - for (i = 0; (err == 0) && (i < sizeof(sizes)/sizeof(sizes[0])); i++) { - PRINT_MSG("verify tbsLen=%zu", sizes[i]); + for (i = 0; (err == 0) && (i < sizeof(verifySizes)/sizeof(verifySizes[0])); + i++) { + PRINT_MSG("verify tbsLen=%zu", verifySizes[i]); ecdsaSigLen = sizeof(ecdsaSig); - err = test_pkey_sign_ecc(pkey, osslLibCtx, buf, sizes[i], ecdsaSig, - &ecdsaSigLen); + err = test_pkey_sign_ecc(pkey, osslLibCtx, buf, verifySizes[i], + ecdsaSig, &ecdsaSigLen); if (err == 0) { - int verifyErr = test_pkey_verify_ecc(pkey, wpLibCtx, buf, sizes[i], - ecdsaSig, ecdsaSigLen); + int verifyErr = test_pkey_verify_ecc(pkey, wpLibCtx, buf, + verifySizes[i], ecdsaSig, + ecdsaSigLen); err = (verifyErr != 0) != expectFail[i]; } } - /* Same minimum applies on the sign side: wolfProvider must refuse to - * produce a raw signature it would later refuse to verify. */ - for (i = 0; (err == 0) && (i < sizeof(sizes)/sizeof(sizes[0])); i++) { + /* The sign minimum is never below the verify minimum. */ + for (i = 0; (err == 0) && (i < sizeof(signSizes)/sizeof(signSizes[0])); + i++) { int signErr; - PRINT_MSG("sign tbsLen=%zu", sizes[i]); + PRINT_MSG("sign tbsLen=%zu", signSizes[i]); ecdsaSigLen = sizeof(ecdsaSig); - signErr = test_pkey_sign_ecc(pkey, wpLibCtx, buf, sizes[i], ecdsaSig, - &ecdsaSigLen); + signErr = test_pkey_sign_ecc(pkey, wpLibCtx, buf, signSizes[i], + ecdsaSig, &ecdsaSigLen); err = (signErr != 0) != expectFail[i]; } diff --git a/test/test_tls1_prf.c b/test/test_tls1_prf.c index 65ee8842..3ef8d8ae 100644 --- a/test/test_tls1_prf.c +++ b/test/test_tls1_prf.c @@ -531,9 +531,10 @@ int test_tls1_prf(void *data) (void)data; -#ifdef WP_HAVE_MD5_SHA1 +#if defined(WP_HAVE_MD5_SHA1) && \ + (!defined(HAVE_FIPS) || defined(WP_ALLOW_NON_FIPS)) err = test_tls1_prf_md(EVP_md5_sha1()); -#endif +#endif /* WP_HAVE_MD5_SHA1 && (!HAVE_FIPS || WP_ALLOW_NON_FIPS) */ #ifdef WP_HAVE_SHA256 if (err == 0) { err = test_tls1_prf_md(EVP_sha256());