@@ -30407,6 +30407,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs12_pbkdf_test(void)
3040730407 if (XMEMCMP(derived, verify2, 24) != 0)
3040830408 return WC_TEST_RET_ENC_NC;
3040930409
30410+ /* Test iteration cap: iterations above WC_PBKDF_MAX_ITERATIONS must be
30411+ * rejected to prevent CPU exhaustion DoS via crafted PKCS#12 files. */
30412+ ret = wc_PKCS12_PBKDF_ex(derived, passwd2, sizeof(passwd2), salt2, 8,
30413+ WC_PBKDF_MAX_ITERATIONS + 1, kLen, WC_SHA256,
30414+ id, HEAP_HINT);
30415+ if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
30416+ return WC_TEST_RET_ENC_NC;
30417+
30418+ ret = wc_PKCS12_PBKDF_ex(derived, passwd2, sizeof(passwd2), salt2, 8,
30419+ WC_PBKDF_MAX_ITERATIONS, kLen, WC_SHA256,
30420+ id, HEAP_HINT);
30421+ if (ret < 0)
30422+ return WC_TEST_RET_ENC_EC(ret);
30423+
3041030424 return 0;
3041130425}
3041230426#endif /* HAVE_PKCS12 && !NO_SHA256 */
@@ -30438,6 +30452,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pbkdf2_test(void)
3043830452 if (XMEMCMP(derived, verify, sizeof(verify)) != 0)
3043930453 return WC_TEST_RET_ENC_NC;
3044030454
30455+ /* Test iteration cap */
30456+ ret = wc_PBKDF2_ex(derived, (byte*)passwd, (int)XSTRLEN(passwd),
30457+ salt, (int)sizeof(salt), WC_PBKDF_MAX_ITERATIONS + 1,
30458+ kLen, WC_SHA256, HEAP_HINT, devId);
30459+ if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
30460+ return WC_TEST_RET_ENC_NC;
30461+
3044130462 return 0;
3044230463
3044330464}
@@ -30469,6 +30490,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pbkdf1_test(void)
3046930490 if (XMEMCMP(derived, verify, sizeof(verify)) != 0)
3047030491 return WC_TEST_RET_ENC_NC;
3047130492
30493+ /* Test iteration cap */
30494+ ret = wc_PBKDF1_ex(derived, kLen, NULL, 0, (byte*)passwd,
30495+ (int)XSTRLEN(passwd), salt, (int)sizeof(salt),
30496+ WC_PBKDF_MAX_ITERATIONS + 1, WC_SHA, HEAP_HINT);
30497+ if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG))
30498+ return WC_TEST_RET_ENC_NC;
30499+
3047230500 return 0;
3047330501}
3047430502#endif /* HAVE_PBKDF2 && !NO_SHA */
@@ -30493,6 +30521,52 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pwdbased_test(void)
3049330521 if (ret != 0)
3049430522 return ret;
3049530523#endif
30524+ #ifdef HAVE_PKCS12
30525+ /* Test that a crafted PKCS#12 with INT_MAX MAC iterations is rejected
30526+ * immediately rather than hanging in DoPKCS12Hash(). */
30527+ {
30528+ static const byte evil_p12[] = {
30529+ 0x30, 0x58, 0x02, 0x01, 0x03, 0x30, 0x1e, 0x06,
30530+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
30531+ 0x07, 0x01, 0xa0, 0x11, 0x04, 0x0f, 0x30, 0x0d,
30532+ 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
30533+ 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x33, 0x30,
30534+ 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
30535+ 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x00, 0x00,
30536+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30537+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30538+ 0x00, 0x00, 0x04, 0x08, 0x41, 0x41, 0x41, 0x41,
30539+ 0x41, 0x41, 0x41, 0x41, 0x02, 0x04, 0x7f, 0xff,
30540+ 0xff, 0xff
30541+ };
30542+ WC_PKCS12* evilPkcs12 = wc_PKCS12_new_ex(HEAP_HINT);
30543+ if (evilPkcs12 == NULL)
30544+ return WC_TEST_RET_ENC_EC(MEMORY_E);
30545+
30546+ ret = wc_d2i_PKCS12(evil_p12, (word32)sizeof(evil_p12), evilPkcs12);
30547+ if (ret == 0) {
30548+ byte* evilKey = NULL;
30549+ byte* evilCert = NULL;
30550+ word32 evilKeySz = 0, evilCertSz = 0;
30551+ WC_DerCertList* evilCa = NULL;
30552+
30553+ ret = wc_PKCS12_parse(evilPkcs12, "test", &evilKey, &evilKeySz,
30554+ &evilCert, &evilCertSz, &evilCa);
30555+ XFREE(evilKey, HEAP_HINT, DYNAMIC_TYPE_PKCS);
30556+ XFREE(evilCert, HEAP_HINT, DYNAMIC_TYPE_PKCS);
30557+ if (evilCa)
30558+ wc_FreeCertList(evilCa, HEAP_HINT);
30559+ wc_PKCS12_free(evilPkcs12);
30560+ /* Parse must fail (iteration cap), not succeed or hang */
30561+ if (ret == 0)
30562+ return WC_TEST_RET_ENC_NC;
30563+ }
30564+ else {
30565+ wc_PKCS12_free(evilPkcs12);
30566+ }
30567+ ret = 0;
30568+ }
30569+ #endif /* HAVE_PKCS12 */
3049630570#ifdef HAVE_SCRYPT
3049730571 ret = scrypt_test();
3049830572 if (ret != 0)
@@ -30592,6 +30666,56 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs12_test(void)
3059230666 goto out;
3059330667 }
3059430668
30669+ /* Test that a crafted PKCS#12 with INT_MAX MAC iterations is rejected
30670+ * immediately rather than hanging in DoPKCS12Hash(). This is a 90-byte
30671+ * minimal PKCS#12 with mac->itt = 0x7FFFFFFF (2,147,483,647). */
30672+ {
30673+ static const byte evil_p12[] = {
30674+ 0x30, 0x58, 0x02, 0x01, 0x03, 0x30, 0x1e, 0x06,
30675+ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
30676+ 0x07, 0x01, 0xa0, 0x11, 0x04, 0x0f, 0x30, 0x0d,
30677+ 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
30678+ 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x33, 0x30,
30679+ 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
30680+ 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x00, 0x00,
30681+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30682+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30683+ 0x00, 0x00, 0x04, 0x08, 0x41, 0x41, 0x41, 0x41,
30684+ 0x41, 0x41, 0x41, 0x41, 0x02, 0x04, 0x7f, 0xff,
30685+ 0xff, 0xff
30686+ };
30687+ WC_PKCS12* evilPkcs12 = wc_PKCS12_new_ex(HEAP_HINT);
30688+ if (evilPkcs12 == NULL) {
30689+ ret = WC_TEST_RET_ENC_EC(MEMORY_E);
30690+ goto out;
30691+ }
30692+ ret = wc_d2i_PKCS12(evil_p12, (word32)sizeof(evil_p12), evilPkcs12);
30693+ if (ret != 0) {
30694+ wc_PKCS12_free(evilPkcs12);
30695+ ret = WC_TEST_RET_ENC_EC(ret);
30696+ goto out;
30697+ }
30698+ {
30699+ byte* evilKey = NULL;
30700+ byte* evilCert = NULL;
30701+ word32 evilKeySz = 0, evilCertSz = 0;
30702+ WC_DerCertList* evilCa = NULL;
30703+ ret = wc_PKCS12_parse(evilPkcs12, "test", &evilKey, &evilKeySz,
30704+ &evilCert, &evilCertSz, &evilCa);
30705+ XFREE(evilKey, HEAP_HINT, DYNAMIC_TYPE_PKCS);
30706+ XFREE(evilCert, HEAP_HINT, DYNAMIC_TYPE_PKCS);
30707+ if (evilCa)
30708+ wc_FreeCertList(evilCa, HEAP_HINT);
30709+ }
30710+ wc_PKCS12_free(evilPkcs12);
30711+ /* Must have been rejected (not hung) */
30712+ if (ret == 0) {
30713+ ret = WC_TEST_RET_ENC_NC;
30714+ goto out;
30715+ }
30716+ ret = 0; /* rejection is the expected outcome */
30717+ }
30718+
3059530719out:
3059630720
3059730721 if (derCaListOut)
0 commit comments