diff --git a/src/x509.c b/src/x509.c index ff411069a6..5b24c1bb78 100644 --- a/src/x509.c +++ b/src/x509.c @@ -12897,6 +12897,16 @@ cleanup: XFREE(mldsa, x509->heap, DYNAMIC_TYPE_MLDSA); return WOLFSSL_FATAL_ERROR; } + /* sigType above came from the cached pkey->mldsaOID; require + * the decoded key to agree so a stale cache cannot emit a + * certificate whose signatureAlgorithm disagrees with the + * actual signature. */ + if (oidSum != WOLFSSL_ATOMIC_LOAD(pkey->mldsaOID)) { + WOLFSSL_MSG("ML-DSA key does not match cached pkey OID"); + wc_MlDsaKey_Free(mldsa); + XFREE(mldsa, x509->heap, DYNAMIC_TYPE_MLDSA); + return WOLFSSL_FATAL_ERROR; + } switch (oidSum) { case ML_DSA_44k: type = ML_DSA_44_TYPE; diff --git a/tests/api/test_ossl_x509_pk.c b/tests/api/test_ossl_x509_pk.c index 468123ff85..84de675afb 100644 --- a/tests/api/test_ossl_x509_pk.c +++ b/tests/api/test_ossl_x509_pk.c @@ -425,6 +425,19 @@ int test_wolfSSL_X509_set_pubkey(void) WOLFSSL_SUCCESS); wolfSSL_EVP_PKEY_free(pubkey); pubkey = NULL; + + /* A stale/tampered mldsaOID cache must fail the sign + * rather than emit a certificate whose + * signatureAlgorithm disagrees with the actual key. */ + if (EXPECT_SUCCESS() && pkey != NULL) { + int realOID = WOLFSSL_ATOMIC_LOAD(pkey->mldsaOID); + int wrongOID = (realOID == ML_DSA_44k) ? + ML_DSA_65k : ML_DSA_44k; + WOLFSSL_ATOMIC_STORE(pkey->mldsaOID, wrongOID); + ExpectIntEQ(wolfSSL_X509_sign(x509, pkey, NULL), + WC_NO_ERR_TRACE(WOLFSSL_FAILURE)); + WOLFSSL_ATOMIC_STORE(pkey->mldsaOID, realOID); + } } #endif if (ki + 1 < sizeof(keyFiles) / sizeof(keyFiles[0])) {