Skip to content

Commit 3fa1ee4

Browse files
committed
rename WC_PBKDF_MAX_ITERATIONS to WC_PBKDF_DEFAULT_MAX_ITERATIONS, raise it to 10000000, add wc_PBKDF_max_iterations_set() and wc_PBKDF_max_iterations_get(), and restore new negative tests in pwdbased_test().
1 parent 536911b commit 3fa1ee4

5 files changed

Lines changed: 186 additions & 16 deletions

File tree

.wolfssl_known_macro_extras

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,6 @@ WC_NO_ASYNC_SLEEP
646646
WC_NO_RNG_SIMPLE
647647
WC_NO_STATIC_ASSERT
648648
WC_NO_VERBOSE_RNG
649-
WC_PBKDF_MAX_ITERATIONS
650649
WC_PKCS11_FIND_WITH_ID_ONLY
651650
WC_PKCS12_PBKDF_USING_MP_API
652651
WC_PROTECT_ENCRYPTED_MEM

doc/dox_comments/header_files/pwdbased.h

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,
175175
176176
\return 0 on success
177177
\return BAD_FUNC_ARG on invalid arguments or iterations is greater than
178-
WC_PBKDF_MAX_ITERATIONS
178+
current_wc_pbkdf_max_iterations
179179
\return MEMORY_E on memory allocation error
180180
181181
\param key Output key buffer
@@ -200,6 +200,8 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,
200200
\endcode
201201
202202
\sa wc_PBKDF1
203+
\sa wc_PBKDF_max_iterations_set
204+
\sa wc_PBKDF_max_iterations_get
203205
*/
204206
int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
205207
const byte* passwd, int passwdLen, const byte* salt, int saltLen,
@@ -211,7 +213,7 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
211213
212214
\return 0 on success
213215
\return BAD_FUNC_ARG on invalid arguments or iterations is greater than
214-
WC_PBKDF_MAX_ITERATIONS
216+
current_wc_pbkdf_max_iterations
215217
\return MEMORY_E on memory allocation error
216218
217219
\param output Output key buffer
@@ -236,6 +238,8 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
236238
\endcode
237239
238240
\sa wc_PBKDF2
241+
\sa wc_PBKDF_max_iterations_set
242+
\sa wc_PBKDF_max_iterations_get
239243
*/
240244
int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen,
241245
const byte* salt, int sLen, int iterations, int kLen,
@@ -247,7 +251,7 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen,
247251
248252
\return 0 on success
249253
\return BAD_FUNC_ARG on invalid arguments or iterations is greater than
250-
WC_PBKDF_MAX_ITERATIONS
254+
current_wc_pbkdf_max_iterations
251255
\return MEMORY_E on memory allocation error
252256
253257
\param output Output key buffer
@@ -271,6 +275,8 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen,
271275
\endcode
272276
273277
\sa wc_PKCS12_PBKDF
278+
\sa wc_PBKDF_max_iterations_set
279+
\sa wc_PBKDF_max_iterations_get
274280
*/
275281
int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd,int passLen,
276282
const byte* salt, int saltLen, int iterations, int kLen,
@@ -341,3 +347,44 @@ int wc_scrypt(byte* output, const byte* passwd, int passLen,
341347
int wc_scrypt_ex(byte* output, const byte* passwd, int passLen,
342348
const byte* salt, int saltLen, word32 iterations, int blockSize,
343349
int parallel, int dkLen);
350+
351+
/*!
352+
\ingroup Password
353+
\brief Set the current iteration limit for PBKDF.
354+
355+
By default, the iteration limit is set to WC_PBKDF_DEFAULT_MAX_ITERATIONS,
356+
which can be overridden at build time. This function allows runtime
357+
override of the limit.
358+
359+
Note that `wc_PBKDF_max_iterations_set()` has no provisions for thread
360+
synchronization. Users should arrange to call it at startup or idle times,
361+
when there are no other PBKDF calls in progress.
362+
363+
\return Previous iteration limit on success
364+
\return BAD_FUNC_ARG on invalid arguments
365+
366+
\param iters The new iteration limit.
367+
368+
_Example_
369+
\code
370+
int prev_iter_limit = wc_PBKDF_max_iterations_set(100000000);
371+
\endcode
372+
373+
\sa wc_scrypt
374+
*/
375+
int wc_PBKDF_max_iterations_set(int iters);
376+
377+
/*!
378+
\ingroup Password
379+
\brief Get the current iteration limit for PBKDF.
380+
381+
\return Current iteration limit
382+
383+
_Example_
384+
\code
385+
int cur_iter_limit = wc_PBKDF_max_iterations_get();
386+
\endcode
387+
388+
\sa wc_scrypt
389+
*/
390+
int wc_PBKDF_max_iterations_get(void);

wolfcrypt/src/pwdbased.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,22 @@
5454
}
5555
#endif
5656

57+
static int current_wc_pbkdf_max_iterations = WC_PBKDF_DEFAULT_MAX_ITERATIONS;
58+
59+
int wc_PBKDF_max_iterations_set(int iters) {
60+
if (iters <= 0)
61+
return BAD_FUNC_ARG;
62+
else {
63+
int prev = current_wc_pbkdf_max_iterations;
64+
current_wc_pbkdf_max_iterations = iters;
65+
return prev;
66+
}
67+
}
68+
69+
int wc_PBKDF_max_iterations_get(void) {
70+
return current_wc_pbkdf_max_iterations;
71+
}
72+
5773
#ifdef HAVE_PBKDF1
5874

5975
/* PKCS#5 v1.5 with non standard extension to optionally derive the extra data (IV) */
@@ -79,8 +95,8 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
7995
if (iterations <= 0)
8096
iterations = 1;
8197

82-
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
83-
WOLFSSL_MSG("PBKDF1 iteration count exceeds WC_PBKDF_MAX_ITERATIONS");
98+
if (iterations > current_wc_pbkdf_max_iterations) {
99+
WOLFSSL_MSG("PBKDF1 iteration count exceeds current_wc_pbkdf_max_iterations");
84100
return BAD_FUNC_ARG;
85101
}
86102

@@ -220,8 +236,8 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen, const byte* salt,
220236
if (iterations <= 0)
221237
iterations = 1;
222238

223-
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
224-
WOLFSSL_MSG("PBKDF2 iteration count exceeds WC_PBKDF_MAX_ITERATIONS");
239+
if (iterations > current_wc_pbkdf_max_iterations) {
240+
WOLFSSL_MSG("PBKDF2 iteration count exceeds current_wc_pbkdf_max_iterations");
225241
return BAD_FUNC_ARG;
226242
}
227243

@@ -413,9 +429,9 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
413429
if (iterations <= 0)
414430
iterations = 1;
415431

416-
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
432+
if (iterations > current_wc_pbkdf_max_iterations) {
417433
WOLFSSL_MSG("PKCS12 PBKDF iteration count exceeds "
418-
"WC_PBKDF_MAX_ITERATIONS");
434+
"current_wc_pbkdf_max_iterations");
419435
return BAD_FUNC_ARG;
420436
}
421437

@@ -627,9 +643,9 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
627643
iterations = 1;
628644
}
629645

630-
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
646+
if (iterations > current_wc_pbkdf_max_iterations) {
631647
WOLFSSL_MSG("PKCS12 PBKDF iteration count exceeds "
632-
"WC_PBKDF_MAX_ITERATIONS");
648+
"current_wc_pbkdf_max_iterations");
633649
return BAD_FUNC_ARG;
634650
}
635651

wolfcrypt/test/test.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30844,6 +30844,53 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pwdbased_test(void)
3084430844
if (ret != 0)
3084530845
return ret;
3084630846
#endif
30847+
#if defined(HAVE_PKCS12) && !defined(NO_ASN) && !defined(NO_PWDBASED) && \
30848+
!defined(NO_HMAC) && !defined(NO_CERTS)
30849+
/* Test that a crafted PKCS#12 with INT_MAX MAC iterations is rejected
30850+
* immediately rather than hanging in DoPKCS12Hash(). */
30851+
{
30852+
static const byte evil_p12[] = {
30853+
0x30, 0x58, 0x02, 0x01, 0x03, 0x30, 0x1e, 0x06,
30854+
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
30855+
0x07, 0x01, 0xa0, 0x11, 0x04, 0x0f, 0x30, 0x0d,
30856+
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
30857+
0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x33, 0x30,
30858+
0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
30859+
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x00, 0x00,
30860+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30861+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30862+
0x00, 0x00, 0x04, 0x08, 0x41, 0x41, 0x41, 0x41,
30863+
0x41, 0x41, 0x41, 0x41, 0x02, 0x04, 0x7f, 0xff,
30864+
0xff, 0xff
30865+
};
30866+
WC_PKCS12* evilPkcs12 = wc_PKCS12_new_ex(HEAP_HINT);
30867+
if (evilPkcs12 == NULL)
30868+
return WC_TEST_RET_ENC_EC(MEMORY_E);
30869+
30870+
ret = wc_d2i_PKCS12(evil_p12, (word32)sizeof(evil_p12), evilPkcs12);
30871+
if (ret == 0) {
30872+
byte* evilKey = NULL;
30873+
byte* evilCert = NULL;
30874+
word32 evilKeySz = 0, evilCertSz = 0;
30875+
WC_DerCertList* evilCa = NULL;
30876+
30877+
ret = wc_PKCS12_parse(evilPkcs12, "test", &evilKey, &evilKeySz,
30878+
&evilCert, &evilCertSz, &evilCa);
30879+
XFREE(evilKey, HEAP_HINT, DYNAMIC_TYPE_PKCS);
30880+
XFREE(evilCert, HEAP_HINT, DYNAMIC_TYPE_PKCS);
30881+
if (evilCa)
30882+
wc_FreeCertList(evilCa, HEAP_HINT);
30883+
wc_PKCS12_free(evilPkcs12);
30884+
/* Parse must fail (iteration cap), not succeed or hang */
30885+
if (ret == 0)
30886+
return WC_TEST_RET_ENC_NC;
30887+
}
30888+
else {
30889+
wc_PKCS12_free(evilPkcs12);
30890+
}
30891+
ret = 0;
30892+
}
30893+
#endif /* HAVE_PKCS12 && !NO_ASN && !NO_PWDBASED && !NO_HMAC && !NO_CERTS */
3084730894
#ifdef HAVE_SCRYPT
3084830895
ret = scrypt_test();
3084930896
if (ret != 0)
@@ -30943,6 +30990,56 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs12_test(void)
3094330990
goto out;
3094430991
}
3094530992

30993+
/* Test that a crafted PKCS#12 with INT_MAX MAC iterations is rejected
30994+
* immediately rather than hanging in DoPKCS12Hash(). This is a 90-byte
30995+
* minimal PKCS#12 with mac->itt = 0x7FFFFFFF (2,147,483,647). */
30996+
{
30997+
static const byte evil_p12[] = {
30998+
0x30, 0x58, 0x02, 0x01, 0x03, 0x30, 0x1e, 0x06,
30999+
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
31000+
0x07, 0x01, 0xa0, 0x11, 0x04, 0x0f, 0x30, 0x0d,
31001+
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
31002+
0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x33, 0x30,
31003+
0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
31004+
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x00, 0x00,
31005+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31006+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31007+
0x00, 0x00, 0x04, 0x08, 0x41, 0x41, 0x41, 0x41,
31008+
0x41, 0x41, 0x41, 0x41, 0x02, 0x04, 0x7f, 0xff,
31009+
0xff, 0xff
31010+
};
31011+
WC_PKCS12* evilPkcs12 = wc_PKCS12_new_ex(HEAP_HINT);
31012+
if (evilPkcs12 == NULL) {
31013+
ret = WC_TEST_RET_ENC_EC(MEMORY_E);
31014+
goto out;
31015+
}
31016+
ret = wc_d2i_PKCS12(evil_p12, (word32)sizeof(evil_p12), evilPkcs12);
31017+
if (ret != 0) {
31018+
wc_PKCS12_free(evilPkcs12);
31019+
ret = WC_TEST_RET_ENC_EC(ret);
31020+
goto out;
31021+
}
31022+
{
31023+
byte* evilKey = NULL;
31024+
byte* evilCert = NULL;
31025+
word32 evilKeySz = 0, evilCertSz = 0;
31026+
WC_DerCertList* evilCa = NULL;
31027+
ret = wc_PKCS12_parse(evilPkcs12, "test", &evilKey, &evilKeySz,
31028+
&evilCert, &evilCertSz, &evilCa);
31029+
XFREE(evilKey, HEAP_HINT, DYNAMIC_TYPE_PKCS);
31030+
XFREE(evilCert, HEAP_HINT, DYNAMIC_TYPE_PKCS);
31031+
if (evilCa)
31032+
wc_FreeCertList(evilCa, HEAP_HINT);
31033+
}
31034+
wc_PKCS12_free(evilPkcs12);
31035+
/* Must have been rejected (not hung) */
31036+
if (ret == 0) {
31037+
ret = WC_TEST_RET_ENC_NC;
31038+
goto out;
31039+
}
31040+
ret = 0; /* rejection is the expected outcome */
31041+
}
31042+
3094631043
out:
3094731044

3094831045
if (derCaListOut)

wolfssl/wolfcrypt/pwdbased.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,23 @@
3838
/* Maximum allowed PBKDF iteration count to prevent CPU exhaustion DoS.
3939
* Attacker-controlled PKCS#12 files can specify iterations up to INT_MAX
4040
* (2,147,483,647) in the MAC data, causing hours of CPU time.
41-
* Override by defining WC_PBKDF_MAX_ITERATIONS before including this header.
42-
* Normal p12 files use 1k to 10k iterations. */
43-
#ifndef WC_PBKDF_MAX_ITERATIONS
44-
#define WC_PBKDF_MAX_ITERATIONS 2000000
41+
* Override by defining WC_PBKDF_DEFAULT_MAX_ITERATIONS before including
42+
* this header, and override at runtime by calling
43+
* wc_PBKDF_max_iterations_set() at application startup.
44+
*
45+
* Note that typical PKCS12 files use 1k to 10k iterations.
46+
*/
47+
#ifndef WC_PBKDF_DEFAULT_MAX_ITERATIONS
48+
#define WC_PBKDF_DEFAULT_MAX_ITERATIONS 10000000
4549
#endif
4650

51+
/* Note that wc_PBKDF_max_iterations_set() has no provisions for thread
52+
* synchronization. Users should arrange to call it at startup or idle times,
53+
* when there are no other PBKDF calls in progress.
54+
*/
55+
WOLFSSL_API int wc_PBKDF_max_iterations_set(int iters);
56+
WOLFSSL_API int wc_PBKDF_max_iterations_get(void);
57+
4758
#if FIPS_VERSION3_GE(6,0,0)
4859
extern const unsigned int wolfCrypt_FIPS_pbkdf_ro_sanity[2];
4960
WOLFSSL_LOCAL int wolfCrypt_FIPS_PBKDF_sanity(void);

0 commit comments

Comments
 (0)