mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 09:30:51 +02:00
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().
This commit is contained in:
@@ -667,7 +667,6 @@ WC_NO_ASYNC_SLEEP
|
||||
WC_NO_RNG_SIMPLE
|
||||
WC_NO_STATIC_ASSERT
|
||||
WC_NO_VERBOSE_RNG
|
||||
WC_PBKDF_MAX_ITERATIONS
|
||||
WC_PKCS11_FIND_WITH_ID_ONLY
|
||||
WC_PKCS12_PBKDF_USING_MP_API
|
||||
WC_PROTECT_ENCRYPTED_MEM
|
||||
|
||||
@@ -175,7 +175,7 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,
|
||||
|
||||
\return 0 on success
|
||||
\return BAD_FUNC_ARG on invalid arguments or iterations is greater than
|
||||
WC_PBKDF_MAX_ITERATIONS
|
||||
current_wc_pbkdf_max_iterations
|
||||
\return MEMORY_E on memory allocation error
|
||||
|
||||
\param key Output key buffer
|
||||
@@ -200,6 +200,8 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,
|
||||
\endcode
|
||||
|
||||
\sa wc_PBKDF1
|
||||
\sa wc_PBKDF_max_iterations_set
|
||||
\sa wc_PBKDF_max_iterations_get
|
||||
*/
|
||||
int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
|
||||
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,
|
||||
|
||||
\return 0 on success
|
||||
\return BAD_FUNC_ARG on invalid arguments or iterations is greater than
|
||||
WC_PBKDF_MAX_ITERATIONS
|
||||
current_wc_pbkdf_max_iterations
|
||||
\return MEMORY_E on memory allocation error
|
||||
|
||||
\param output Output key buffer
|
||||
@@ -236,6 +238,8 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
|
||||
\endcode
|
||||
|
||||
\sa wc_PBKDF2
|
||||
\sa wc_PBKDF_max_iterations_set
|
||||
\sa wc_PBKDF_max_iterations_get
|
||||
*/
|
||||
int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen,
|
||||
const byte* salt, int sLen, int iterations, int kLen,
|
||||
@@ -247,7 +251,7 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen,
|
||||
|
||||
\return 0 on success
|
||||
\return BAD_FUNC_ARG on invalid arguments or iterations is greater than
|
||||
WC_PBKDF_MAX_ITERATIONS
|
||||
current_wc_pbkdf_max_iterations
|
||||
\return MEMORY_E on memory allocation error
|
||||
|
||||
\param output Output key buffer
|
||||
@@ -271,6 +275,8 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen,
|
||||
\endcode
|
||||
|
||||
\sa wc_PKCS12_PBKDF
|
||||
\sa wc_PBKDF_max_iterations_set
|
||||
\sa wc_PBKDF_max_iterations_get
|
||||
*/
|
||||
int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd,int passLen,
|
||||
const byte* salt, int saltLen, int iterations, int kLen,
|
||||
@@ -341,3 +347,44 @@ int wc_scrypt(byte* output, const byte* passwd, int passLen,
|
||||
int wc_scrypt_ex(byte* output, const byte* passwd, int passLen,
|
||||
const byte* salt, int saltLen, word32 iterations, int blockSize,
|
||||
int parallel, int dkLen);
|
||||
|
||||
/*!
|
||||
\ingroup Password
|
||||
\brief Set the current iteration limit for PBKDF.
|
||||
|
||||
By default, the iteration limit is set to WC_PBKDF_DEFAULT_MAX_ITERATIONS,
|
||||
which can be overridden at build time. This function allows runtime
|
||||
override of the limit.
|
||||
|
||||
Note that `wc_PBKDF_max_iterations_set()` has no provisions for thread
|
||||
synchronization. Users should arrange to call it at startup or idle times,
|
||||
when there are no other PBKDF calls in progress.
|
||||
|
||||
\return Previous iteration limit on success
|
||||
\return BAD_FUNC_ARG on invalid arguments
|
||||
|
||||
\param iters The new iteration limit.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
int prev_iter_limit = wc_PBKDF_max_iterations_set(100000000);
|
||||
\endcode
|
||||
|
||||
\sa wc_scrypt
|
||||
*/
|
||||
int wc_PBKDF_max_iterations_set(int iters);
|
||||
|
||||
/*!
|
||||
\ingroup Password
|
||||
\brief Get the current iteration limit for PBKDF.
|
||||
|
||||
\return Current iteration limit
|
||||
|
||||
_Example_
|
||||
\code
|
||||
int cur_iter_limit = wc_PBKDF_max_iterations_get();
|
||||
\endcode
|
||||
|
||||
\sa wc_scrypt
|
||||
*/
|
||||
int wc_PBKDF_max_iterations_get(void);
|
||||
|
||||
@@ -54,6 +54,22 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
static int current_wc_pbkdf_max_iterations = WC_PBKDF_DEFAULT_MAX_ITERATIONS;
|
||||
|
||||
int wc_PBKDF_max_iterations_set(int iters) {
|
||||
if (iters <= 0)
|
||||
return BAD_FUNC_ARG;
|
||||
else {
|
||||
int prev = current_wc_pbkdf_max_iterations;
|
||||
current_wc_pbkdf_max_iterations = iters;
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
int wc_PBKDF_max_iterations_get(void) {
|
||||
return current_wc_pbkdf_max_iterations;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PBKDF1
|
||||
|
||||
/* PKCS#5 v1.5 with non standard extension to optionally derive the extra data (IV) */
|
||||
@@ -82,8 +98,8 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
|
||||
if (iterations <= 0)
|
||||
iterations = 1;
|
||||
|
||||
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
|
||||
WOLFSSL_MSG("PBKDF1 iteration count exceeds WC_PBKDF_MAX_ITERATIONS");
|
||||
if (iterations > current_wc_pbkdf_max_iterations) {
|
||||
WOLFSSL_MSG("PBKDF1 iteration count exceeds current_wc_pbkdf_max_iterations");
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
@@ -223,8 +239,8 @@ int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen, const byte* salt,
|
||||
if (iterations <= 0)
|
||||
iterations = 1;
|
||||
|
||||
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
|
||||
WOLFSSL_MSG("PBKDF2 iteration count exceeds WC_PBKDF_MAX_ITERATIONS");
|
||||
if (iterations > current_wc_pbkdf_max_iterations) {
|
||||
WOLFSSL_MSG("PBKDF2 iteration count exceeds current_wc_pbkdf_max_iterations");
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
@@ -416,9 +432,9 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
|
||||
if (iterations <= 0)
|
||||
iterations = 1;
|
||||
|
||||
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
|
||||
if (iterations > current_wc_pbkdf_max_iterations) {
|
||||
WOLFSSL_MSG("PKCS12 PBKDF iteration count exceeds "
|
||||
"WC_PBKDF_MAX_ITERATIONS");
|
||||
"current_wc_pbkdf_max_iterations");
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
@@ -650,9 +666,9 @@ int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
|
||||
iterations = 1;
|
||||
}
|
||||
|
||||
if (iterations > WC_PBKDF_MAX_ITERATIONS) {
|
||||
if (iterations > current_wc_pbkdf_max_iterations) {
|
||||
WOLFSSL_MSG("PKCS12 PBKDF iteration count exceeds "
|
||||
"WC_PBKDF_MAX_ITERATIONS");
|
||||
"current_wc_pbkdf_max_iterations");
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
|
||||
@@ -32046,6 +32046,53 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pwdbased_test(void)
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif
|
||||
#if defined(HAVE_PKCS12) && !defined(NO_ASN) && !defined(NO_PWDBASED) && \
|
||||
!defined(NO_HMAC) && !defined(NO_CERTS)
|
||||
/* Test that a crafted PKCS#12 with INT_MAX MAC iterations is rejected
|
||||
* immediately rather than hanging in DoPKCS12Hash(). */
|
||||
{
|
||||
static const byte evil_p12[] = {
|
||||
0x30, 0x58, 0x02, 0x01, 0x03, 0x30, 0x1e, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
||||
0x07, 0x01, 0xa0, 0x11, 0x04, 0x0f, 0x30, 0x0d,
|
||||
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x33, 0x30,
|
||||
0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
|
||||
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x02, 0x04, 0x7f, 0xff,
|
||||
0xff, 0xff
|
||||
};
|
||||
WC_PKCS12* evilPkcs12 = wc_PKCS12_new_ex(HEAP_HINT);
|
||||
if (evilPkcs12 == NULL)
|
||||
return WC_TEST_RET_ENC_EC(MEMORY_E);
|
||||
|
||||
ret = wc_d2i_PKCS12(evil_p12, (word32)sizeof(evil_p12), evilPkcs12);
|
||||
if (ret == 0) {
|
||||
byte* evilKey = NULL;
|
||||
byte* evilCert = NULL;
|
||||
word32 evilKeySz = 0, evilCertSz = 0;
|
||||
WC_DerCertList* evilCa = NULL;
|
||||
|
||||
ret = wc_PKCS12_parse(evilPkcs12, "test", &evilKey, &evilKeySz,
|
||||
&evilCert, &evilCertSz, &evilCa);
|
||||
XFREE(evilKey, HEAP_HINT, DYNAMIC_TYPE_PKCS);
|
||||
XFREE(evilCert, HEAP_HINT, DYNAMIC_TYPE_PKCS);
|
||||
if (evilCa)
|
||||
wc_FreeCertList(evilCa, HEAP_HINT);
|
||||
wc_PKCS12_free(evilPkcs12);
|
||||
/* Parse must fail (iteration cap), not succeed or hang */
|
||||
if (ret == 0)
|
||||
return WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
else {
|
||||
wc_PKCS12_free(evilPkcs12);
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
#endif /* HAVE_PKCS12 && !NO_ASN && !NO_PWDBASED && !NO_HMAC && !NO_CERTS */
|
||||
#ifdef HAVE_SCRYPT
|
||||
ret = scrypt_test();
|
||||
if (ret != 0)
|
||||
@@ -32145,6 +32192,56 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pkcs12_test(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Test that a crafted PKCS#12 with INT_MAX MAC iterations is rejected
|
||||
* immediately rather than hanging in DoPKCS12Hash(). This is a 90-byte
|
||||
* minimal PKCS#12 with mac->itt = 0x7FFFFFFF (2,147,483,647). */
|
||||
{
|
||||
static const byte evil_p12[] = {
|
||||
0x30, 0x58, 0x02, 0x01, 0x03, 0x30, 0x1e, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
||||
0x07, 0x01, 0xa0, 0x11, 0x04, 0x0f, 0x30, 0x0d,
|
||||
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x33, 0x30,
|
||||
0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
|
||||
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x02, 0x04, 0x7f, 0xff,
|
||||
0xff, 0xff
|
||||
};
|
||||
WC_PKCS12* evilPkcs12 = wc_PKCS12_new_ex(HEAP_HINT);
|
||||
if (evilPkcs12 == NULL) {
|
||||
ret = WC_TEST_RET_ENC_EC(MEMORY_E);
|
||||
goto out;
|
||||
}
|
||||
ret = wc_d2i_PKCS12(evil_p12, (word32)sizeof(evil_p12), evilPkcs12);
|
||||
if (ret != 0) {
|
||||
wc_PKCS12_free(evilPkcs12);
|
||||
ret = WC_TEST_RET_ENC_EC(ret);
|
||||
goto out;
|
||||
}
|
||||
{
|
||||
byte* evilKey = NULL;
|
||||
byte* evilCert = NULL;
|
||||
word32 evilKeySz = 0, evilCertSz = 0;
|
||||
WC_DerCertList* evilCa = NULL;
|
||||
ret = wc_PKCS12_parse(evilPkcs12, "test", &evilKey, &evilKeySz,
|
||||
&evilCert, &evilCertSz, &evilCa);
|
||||
XFREE(evilKey, HEAP_HINT, DYNAMIC_TYPE_PKCS);
|
||||
XFREE(evilCert, HEAP_HINT, DYNAMIC_TYPE_PKCS);
|
||||
if (evilCa)
|
||||
wc_FreeCertList(evilCa, HEAP_HINT);
|
||||
}
|
||||
wc_PKCS12_free(evilPkcs12);
|
||||
/* Must have been rejected (not hung) */
|
||||
if (ret == 0) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
goto out;
|
||||
}
|
||||
ret = 0; /* rejection is the expected outcome */
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (derCaListOut)
|
||||
|
||||
@@ -38,12 +38,23 @@
|
||||
/* Maximum allowed PBKDF iteration count to prevent CPU exhaustion DoS.
|
||||
* Attacker-controlled PKCS#12 files can specify iterations up to INT_MAX
|
||||
* (2,147,483,647) in the MAC data, causing hours of CPU time.
|
||||
* Override by defining WC_PBKDF_MAX_ITERATIONS before including this header.
|
||||
* Normal p12 files use 1k to 10k iterations. */
|
||||
#ifndef WC_PBKDF_MAX_ITERATIONS
|
||||
#define WC_PBKDF_MAX_ITERATIONS 2000000
|
||||
* Override by defining WC_PBKDF_DEFAULT_MAX_ITERATIONS before including
|
||||
* this header, and override at runtime by calling
|
||||
* wc_PBKDF_max_iterations_set() at application startup.
|
||||
*
|
||||
* Note that typical PKCS12 files use 1k to 10k iterations.
|
||||
*/
|
||||
#ifndef WC_PBKDF_DEFAULT_MAX_ITERATIONS
|
||||
#define WC_PBKDF_DEFAULT_MAX_ITERATIONS 10000000
|
||||
#endif
|
||||
|
||||
/* Note that wc_PBKDF_max_iterations_set() has no provisions for thread
|
||||
* synchronization. Users should arrange to call it at startup or idle times,
|
||||
* when there are no other PBKDF calls in progress.
|
||||
*/
|
||||
WOLFSSL_API int wc_PBKDF_max_iterations_set(int iters);
|
||||
WOLFSSL_API int wc_PBKDF_max_iterations_get(void);
|
||||
|
||||
#if FIPS_VERSION3_GE(6,0,0)
|
||||
extern const unsigned int wolfCrypt_FIPS_pbkdf_ro_sanity[2];
|
||||
WOLFSSL_LOCAL int wolfCrypt_FIPS_PBKDF_sanity(void);
|
||||
|
||||
Reference in New Issue
Block a user