Skip to content

Commit 4a13896

Browse files
committed
Report cert verify failure with MD5
1 parent 9ed79a2 commit 4a13896

4 files changed

Lines changed: 92 additions & 1 deletion

File tree

.wolfssl_known_macro_extras

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,7 @@ WOLFSSL_ALLOW_CRIT_AIA
682682
WOLFSSL_ALLOW_CRIT_AKID
683683
WOLFSSL_ALLOW_CRIT_SKID
684684
WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST
685+
WOLFSSL_ALLOW_MD5_CERT_SIGS
685686
WOLFSSL_ALLOW_NO_CN_IN_SAN
686687
WOLFSSL_ALLOW_NO_SUITES
687688
WOLFSSL_ALLOW_SERVER_SC_EXT

tests/api/test_certman.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2540,3 +2540,84 @@ int test_various_pathlen_chains(void)
25402540
#endif
25412541
return EXPECT_RESULT();
25422542
}
2543+
2544+
/* Verify that certificates signed with MD5 (md5WithRSAEncryption) are
2545+
* rejected during chain verification. MD5 must not be acceptable as a
2546+
* certificate signature hash, even when MD5 is compiled in (e.g. for TLS
2547+
* 1.0 PRF or HMAC uses). Trust anchors are exempt from this check because
2548+
* ParseCertRelative skips ConfirmSignature for CA_TYPE. */
2549+
int test_wolfSSL_CertManagerRejectMD5Cert(void)
2550+
{
2551+
EXPECT_DECLS;
2552+
#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_MD5) && \
2553+
!defined(WOLFSSL_ALLOW_MD5_CERT_SIGS) && defined(WOLFSSL_CERT_GEN) && \
2554+
!defined(NO_WOLFSSL_CM_VERIFY) && !defined(NO_ASN_CRYPT) && \
2555+
!defined(USE_CERT_BUFFERS_1024)
2556+
WOLFSSL_CERT_MANAGER* cm = NULL;
2557+
RsaKey caKey;
2558+
WC_RNG rng;
2559+
Cert leaf;
2560+
byte* der = NULL;
2561+
int derSz = 0;
2562+
word32 idx = 0;
2563+
int caKeyInit = 0;
2564+
int rngInit = 0;
2565+
2566+
XMEMSET(&caKey, 0, sizeof(caKey));
2567+
XMEMSET(&rng, 0, sizeof(rng));
2568+
2569+
ExpectIntEQ(wc_InitRng(&rng), 0);
2570+
if (EXPECT_SUCCESS()) rngInit = 1;
2571+
2572+
ExpectIntEQ(wc_InitRsaKey_ex(&caKey, HEAP_HINT, testDevId), 0);
2573+
if (EXPECT_SUCCESS()) caKeyInit = 1;
2574+
ExpectIntEQ(wc_RsaPrivateKeyDecode(ca_key_der_2048, &idx, &caKey,
2575+
sizeof_ca_key_der_2048), 0);
2576+
2577+
ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT,
2578+
DYNAMIC_TYPE_TMP_BUFFER));
2579+
2580+
/* Build a leaf certificate whose issuer is the built-in 2048-bit
2581+
* wolfSSL test CA and sign it with MD5+RSA using the matching CA
2582+
* private key. */
2583+
ExpectIntEQ(wc_InitCert(&leaf), 0);
2584+
leaf.sigType = CTC_MD5wRSA;
2585+
leaf.isCA = 0;
2586+
XSTRNCPY(leaf.subject.country, "US", CTC_NAME_SIZE);
2587+
XSTRNCPY(leaf.subject.state, "MT", CTC_NAME_SIZE);
2588+
XSTRNCPY(leaf.subject.locality, "Bozeman", CTC_NAME_SIZE);
2589+
XSTRNCPY(leaf.subject.org, "wolfSSL", CTC_NAME_SIZE);
2590+
XSTRNCPY(leaf.subject.unit, "Test", CTC_NAME_SIZE);
2591+
XSTRNCPY(leaf.subject.commonName, "md5-leaf", CTC_NAME_SIZE);
2592+
XSTRNCPY(leaf.subject.email, "info@wolfssl.com", CTC_NAME_SIZE);
2593+
2594+
ExpectIntEQ(wc_SetIssuerBuffer(&leaf, ca_cert_der_2048,
2595+
sizeof_ca_cert_der_2048), 0);
2596+
2597+
/* wc_MakeCert needs an RSA public key for the subject; reuse caKey
2598+
* for simplicity (we only care about signature-side verification). */
2599+
ExpectIntGT((derSz = wc_MakeCert(&leaf, der, FOURK_BUF, &caKey, NULL,
2600+
&rng)), 0);
2601+
ExpectIntGT((derSz = wc_SignCert(leaf.bodySz, leaf.sigType, der,
2602+
FOURK_BUF, &caKey, NULL, &rng)), 0);
2603+
2604+
/* Load the SHA-256 signed CA cert as a trust anchor and attempt
2605+
* to verify the MD5-signed leaf: it must be rejected because
2606+
* HashForSignature() now returns HASH_TYPE_E for MD5 in verify mode,
2607+
* which surfaces as ASN_SIG_CONFIRM_E from ConfirmSignature(). */
2608+
ExpectNotNull(cm = wolfSSL_CertManagerNew());
2609+
ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, ca_cert_der_2048,
2610+
sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1),
2611+
WOLFSSL_SUCCESS);
2612+
2613+
ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
2614+
WOLFSSL_FILETYPE_ASN1),
2615+
WC_NO_ERR_TRACE(HASH_TYPE_E));
2616+
2617+
wolfSSL_CertManagerFree(cm);
2618+
XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
2619+
if (caKeyInit) wc_FreeRsaKey(&caKey);
2620+
if (rngInit) wc_FreeRng(&rng);
2621+
#endif
2622+
return EXPECT_RESULT();
2623+
}

tests/api/test_certman.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ int test_wolfSSL_CRL_static_revoked_list(void);
4141
int test_wolfSSL_CRL_duplicate_extensions(void);
4242
int test_wolfSSL_CertManagerCheckOCSPResponse(void);
4343
int test_various_pathlen_chains(void);
44+
int test_wolfSSL_CertManagerRejectMD5Cert(void);
4445

4546
#define TEST_CERTMAN_DECLS \
4647
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerAPI), \
@@ -59,7 +60,8 @@ int test_various_pathlen_chains(void);
5960
TEST_DECL_GROUP("certman", test_wolfSSL_CRL_static_revoked_list), \
6061
TEST_DECL_GROUP("certman", test_wolfSSL_CRL_duplicate_extensions), \
6162
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCheckOCSPResponse), \
62-
TEST_DECL_GROUP("certman", test_various_pathlen_chains)
63+
TEST_DECL_GROUP("certman", test_various_pathlen_chains), \
64+
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerRejectMD5Cert)
6365

6466
#endif /* WOLFCRYPT_TEST_CERTMAN_H */
6567

wolfcrypt/src/asn.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15880,6 +15880,13 @@ static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID,
1588015880
#endif
1588115881
#ifndef NO_MD5
1588215882
case CTC_MD5wRSA:
15883+
#ifndef WOLFSSL_ALLOW_MD5_CERT_SIGS
15884+
if (verify) {
15885+
ret = HASH_TYPE_E;
15886+
WOLFSSL_MSG("MD5 not supported for certificate verification");
15887+
break;
15888+
}
15889+
#endif
1588315890
if ((ret = wc_Md5Hash_ex(buf, bufSz, digest, heap, devId)) == 0) {
1588415891
*typeH = MD5h;
1588515892
*digestSz = WC_MD5_DIGEST_SIZE;

0 commit comments

Comments
 (0)