Skip to content

Commit b358ee3

Browse files
committed
pbkdf2: 16-byte PBES2 default salt; callers accept the v7 short-salt indicator
1 parent 0ac786e commit b358ee3

7 files changed

Lines changed: 82 additions & 5 deletions

File tree

‎tests/api.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21812,7 +21812,7 @@ static int test_wolfSSL_PKCS8_d2i(void)
2181221812
#if !defined(NO_DES3) && !defined(NO_SHA) && defined(HAVE_PBKDF2)
2181321813
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
2181421814
/* Write Encrypted PKCS#8 PEM to BIO. */
21815-
bytes = 1834;
21815+
bytes = 1846;
2181621816
ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_des_ede3_cbc(),
2181721817
NULL, 0, PasswordCallBack, (void*)"yassl123"), bytes);
2181821818
ExpectIntEQ(PEM_write_PKCS8PrivateKey(stderr, pkey, EVP_des_ede3_cbc(),
@@ -21895,8 +21895,8 @@ static int test_wolfSSL_PKCS8_d2i(void)
2189521895
bio = NULL;
2189621896
#ifdef HAVE_PBKDF2
2189721897
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
21898-
/* Write Encrypted PKCS#8 PEM to BIO (test write 0 then 379) */
21899-
bytes = 379;
21898+
/* Write Encrypted PKCS#8 PEM to BIO (test write 0 then 391) */
21899+
bytes = 391;
2190021900
ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_aes_256_cbc(),
2190121901
NULL, 0, NoPasswordCallBack, (void*)"yassl123"), 0);
2190221902
ExpectIntEQ(PEM_write_bio_PKCS8PrivateKey(bio, pkey, EVP_aes_256_cbc(),

‎tests/api/test_asn.c‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6923,8 +6923,10 @@ int test_wc_Pkcs8EncryptDecisionCoverage(void)
69236923
WC_RNG rng;
69246924
byte key[32];
69256925
byte out[512];
6926+
byte fill[512];
69266927
byte salt[8];
69276928
word32 outSz;
6929+
word32 need = 0;
69286930

69296931
XMEMSET(key, 3, sizeof(key));
69306932
XMEMSET(salt, 4, sizeof(salt));
@@ -6949,6 +6951,34 @@ int test_wc_Pkcs8EncryptDecisionCoverage(void)
69496951
"pw", 2, PKCS5, PBES2, AES128CBCb, salt, sizeof(salt), 1000,
69506952
0x7FFFFFFF, &rng, HEAP_HINT), WC_NO_ERR_TRACE(ALGO_ID_E));
69516953

6954+
/* Zero and one byte short return BUFFER_E and leave the buffer
6955+
* untouched; the queried size succeeds. */
6956+
outSz = 0;
6957+
ExpectIntEQ(wc_EncryptPKCS8Key_ex(key, sizeof(key), NULL, &outSz,
6958+
"pw", 2, PKCS5, PBES2, AES128CBCb, NULL, 0, 1000, 0, &rng,
6959+
HEAP_HINT), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
6960+
need = outSz;
6961+
ExpectIntGT(need, 1);
6962+
ExpectIntLE(need, sizeof(out));
6963+
XMEMSET(out, 0xA5, sizeof(out));
6964+
XMEMSET(fill, 0xA5, sizeof(fill));
6965+
outSz = 0;
6966+
ExpectIntEQ(wc_EncryptPKCS8Key_ex(key, sizeof(key), out, &outSz,
6967+
"pw", 2, PKCS5, PBES2, AES128CBCb, NULL, 0, 1000, 0, &rng,
6968+
HEAP_HINT), WC_NO_ERR_TRACE(BUFFER_E));
6969+
outSz = need - 1;
6970+
ExpectIntEQ(wc_EncryptPKCS8Key_ex(key, sizeof(key), out, &outSz,
6971+
"pw", 2, PKCS5, PBES2, AES128CBCb, NULL, 0, 1000, 0, &rng,
6972+
HEAP_HINT), WC_NO_ERR_TRACE(BUFFER_E));
6973+
ExpectBufEQ(out, fill, sizeof(out));
6974+
#if defined(HAVE_PBKDF2) && !defined(NO_HMAC) && !defined(NO_SHA)
6975+
outSz = need;
6976+
ExpectIntEQ(wc_EncryptPKCS8Key_ex(key, sizeof(key), out, &outSz,
6977+
"pw", 2, PKCS5, PBES2, AES128CBCb, NULL, 0, 1000, 0, &rng,
6978+
HEAP_HINT), (int)need);
6979+
ExpectBufEQ(out + need, fill + need, sizeof(out) - need);
6980+
#endif
6981+
69526982
ExpectIntEQ(wc_FreeRng(&rng), 0);
69536983
#endif /* HAVE_AES_CBC && !NO_AES && WOLFSSL_AES_128 && !FIPS */
69546984
return EXPECT_RESULT();

‎tests/api/test_pwdbased.c‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,18 @@ int test_wc_PBKDF2DecisionCoverage(void)
200200
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
201201

202202
/* valid derivation */
203+
#if FIPS_VERSION3_GE(7,0,0) && defined(WC_HAVE_FIPS_INDICATOR) && \
204+
!defined(FIPS_NO_WRAPPERS)
205+
/* The 8-byte salt is below the SP 800-132 Section 5.1 minimum of 128
206+
* bits, so the v7 module derives the key and flags it not approved. */
207+
ExpectIntEQ(wc_PBKDF2_ex(derived, passwd, (int)sizeof(passwd),
208+
salt, (int)sizeof(salt), 2, (int)sizeof(derived),
209+
WC_SHA256, HEAP_HINT, INVALID_DEVID), WC_FIPS_NOT_APPROVED);
210+
#else
203211
ExpectIntEQ(wc_PBKDF2_ex(derived, passwd, (int)sizeof(passwd),
204212
salt, (int)sizeof(salt), 2, (int)sizeof(derived),
205213
WC_SHA256, HEAP_HINT, INVALID_DEVID), 0);
214+
#endif
206215
#endif
207216
return EXPECT_RESULT();
208217
}

‎wolfcrypt/src/asn.c‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11213,6 +11213,7 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz,
1121311213
word32 pbeLen = 0;
1121411214
word32 kdfLen = 0;
1121511215
word32 encLen = 0;
11216+
word32 outerLen = 0;
1121611217
byte cbcIv[MAX_IV_SIZE];
1121711218
word32 idx = 0;
1121811219
word32 encIdx = 0;
@@ -11234,7 +11235,7 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz,
1123411235
}
1123511236
if (ret == 0 && (salt == NULL || saltSz == 0)) {
1123611237
genSalt = 1;
11237-
saltSz = 8;
11238+
saltSz = (version == PKCS5v2) ? PKCS5V2_SALT_SZ : PKCS5_SALT_SZ;
1123811239
}
1123911240
if (ret == 0 && version == PKCS5v2) {
1124011241
ret = GetAlgoV2(encAlgId, &encOid, &encOidSz, &pbeId, &blockSz);
@@ -11296,7 +11297,7 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz,
1129611297
if (ret == 0) {
1129711298
/* outerLen = length of PBE encoding + octet string data */
1129811299
/* Plus 2 for tag and length for pbe */
11299-
word32 outerLen = 2 + pbeLen;
11300+
outerLen = 2 + pbeLen;
1130011301
/* Octet string tag, length */
1130111302
outerLen += 1 + SetLength(keySz + padSz, NULL);
1130211303
/* Octet string bytes */
@@ -11306,6 +11307,10 @@ int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz,
1130611307
*outSz = 1 + SetLength(outerLen, NULL) + outerLen;
1130711308
return WC_NO_ERR_TRACE(LENGTH_ONLY_E);
1130811309
}
11310+
if (*outSz < 1 + SetLength(outerLen, NULL) + outerLen)
11311+
ret = BUFFER_E;
11312+
}
11313+
if (ret == 0) {
1130911314
SetOctetString(keySz + padSz, out);
1131011315

1131111316
idx += SetSequence(outerLen, out + idx);

‎wolfcrypt/src/evp.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5537,6 +5537,12 @@ int wolfSSL_PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
55375537

55385538
ret = wc_PBKDF2((byte*)out, (byte*)pass, passlen, (byte*)salt, saltlen,
55395539
iter, keylen, WC_SHA);
5540+
#if FIPS_VERSION3_GE(7,0,0) && defined(WC_HAVE_FIPS_INDICATOR) && \
5541+
!defined(FIPS_NO_WRAPPERS)
5542+
/* The key is derived; the module only flags a salt under 128 bits. */
5543+
if (ret == WC_FIPS_NOT_APPROVED)
5544+
ret = 0;
5545+
#endif
55405546
if (ret == 0)
55415547
return WOLFSSL_SUCCESS;
55425548
else
@@ -5566,6 +5572,12 @@ int wolfSSL_PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
55665572

55675573
ret = wc_PBKDF2((byte*)out, (byte*)pass, passlen, (byte*)salt, saltlen,
55685574
iter, keylen, pbkdf2HashType);
5575+
#if FIPS_VERSION3_GE(7,0,0) && defined(WC_HAVE_FIPS_INDICATOR) && \
5576+
!defined(FIPS_NO_WRAPPERS)
5577+
/* The key is derived; the module only flags a salt under 128 bits. */
5578+
if (ret == WC_FIPS_NOT_APPROVED)
5579+
ret = 0;
5580+
#endif
55695581
if (ret == 0)
55705582
return WOLFSSL_SUCCESS;
55715583
else

‎wolfcrypt/src/wc_encrypt.c‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,17 @@ int wc_CryptKey(const char* password, int passwordSz, const byte* salt,
480480
ret = wc_PBKDF2(key, (const byte*)password, passwordSz,
481481
salt, saltSz, iterations, (int)derivedLen, typeH);
482482
PRIVATE_KEY_LOCK();
483+
#if FIPS_VERSION3_GE(7,0,0) && defined(WC_HAVE_FIPS_INDICATOR) && \
484+
!defined(FIPS_NO_WRAPPERS)
485+
/* The module derives the key and then returns the
486+
* WC_FIPS_NOT_APPROVED indicator for a salt shorter than
487+
* 128 bits (SP 800-132 Section 5.1). The key is valid, so
488+
* carry on to the cipher: left positive, ret would skip the
489+
* encryption below while callers read it as success, leaving
490+
* the input in the clear. */
491+
if (ret == WC_FIPS_NOT_APPROVED)
492+
ret = 0;
493+
#endif
483494
break;
484495
#endif
485496
#ifndef NO_SHA

‎wolfcrypt/test/test.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49611,6 +49611,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t pbkdf2_test(void)
4961149611
salt, (int)sizeof(salt), iterations,
4961249612
kLen, WC_SHA256, HEAP_HINT, devId);
4961349613
PRIVATE_KEY_LOCK();
49614+
#if FIPS_VERSION3_GE(7,0,0) && defined(WC_HAVE_FIPS_INDICATOR) && \
49615+
!defined(FIPS_NO_WRAPPERS)
49616+
/* 8-byte salt: computed, but the module must deliver the
49617+
* WC_FIPS_NOT_APPROVED indicator to the caller per SP 800-132
49618+
* Section 5.1 ("shall be at least 128 bits") and FIPS 140-3 IG 2.4.C;
49619+
* the test fails if the indicator is missing. */
49620+
if (ret != WC_FIPS_NOT_APPROVED)
49621+
return WC_TEST_RET_ENC_EC(ret);
49622+
ret = 0;
49623+
#endif
4961449624
if (ret != 0)
4961549625
return WC_TEST_RET_ENC_EC(ret);
4961649626

0 commit comments

Comments
 (0)