@@ -21830,6 +21830,107 @@ static int test_wc_CreateEncryptedPKCS8Key(void)
2183021830 return EXPECT_RESULT();
2183121831}
2183221832
21833+ #if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && !defined(NO_SHA) && \
21834+ !defined(NO_ASN_CRYPT) && ((defined(WOLFSSL_AES_256) && \
21835+ !defined(NO_AES_CBC)) || !defined(NO_DES3) || !defined(NO_RC4))
21836+ /* Encrypt a block-aligned plaintext PKCS#8 and verify the trailing encrypted
21837+ * OCTET STRING length. expExtra is the padding expected: a full block for CBC
21838+ * ciphers, 0 for stream ciphers. Also confirms a decrypt round-trip. */
21839+ static int enc_pkcs8_pad_check(int vPKCS, int pbeOid, int encAlgId,
21840+ word32 expExtra)
21841+ {
21842+ EXPECT_DECLS;
21843+ WC_RNG rng;
21844+ byte* encKey = NULL;
21845+ word32 encKeySz = 0;
21846+ int decKeySz = 0;
21847+ word32 expEncLen = 0;
21848+ const char password[] = "Lorem ipsum dolor sit amet";
21849+ word32 passwordSz = (word32)XSTRLEN(password);
21850+ /* Block-aligned plaintext: a valid 48-byte DER SEQUENCE (a multiple of both
21851+ * the 8- and 16-byte block sizes). Content is arbitrary; only the header
21852+ * must parse so decrypt can strip padding by re-reading the DER length. */
21853+ byte plain[48];
21854+
21855+ XMEMSET(plain, 0, sizeof(plain));
21856+ plain[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
21857+ plain[1] = (byte)(sizeof(plain) - 2); /* content length = 46 */
21858+
21859+ XMEMSET(&rng, 0, sizeof(WC_RNG));
21860+ ExpectIntEQ(wc_InitRng(&rng), 0);
21861+ PRIVATE_KEY_UNLOCK();
21862+ /* Query required output size. */
21863+ ExpectIntEQ(wc_EncryptPKCS8Key(plain, (word32)sizeof(plain), NULL, &encKeySz,
21864+ password, (int)passwordSz, vPKCS, pbeOid, encAlgId, NULL, 0,
21865+ WC_PKCS12_ITT_DEFAULT, &rng, NULL), WC_NO_ERR_TRACE(LENGTH_ONLY_E));
21866+ ExpectNotNull(encKey = (byte*)XMALLOC(encKeySz, HEAP_HINT,
21867+ DYNAMIC_TYPE_TMP_BUFFER));
21868+ ExpectIntGT(wc_EncryptPKCS8Key(plain, (word32)sizeof(plain), encKey,
21869+ &encKeySz, password, (int)passwordSz, vPKCS, pbeOid, encAlgId, NULL, 0,
21870+ WC_PKCS12_ITT_DEFAULT, &rng, NULL), 0);
21871+
21872+ /* The encrypted content is the trailing OCTET STRING, extending to the end
21873+ * of the buffer. Its length is plaintext + expected pad (short-form since
21874+ * it is < 128): a full block for a block cipher, none for a stream cipher. */
21875+ expEncLen = (word32)sizeof(plain) + expExtra;
21876+ ExpectIntGE(encKeySz, expEncLen + 2);
21877+ if (encKeySz >= expEncLen + 2) {
21878+ ExpectIntEQ(encKey[encKeySz - expEncLen - 2], ASN_OCTET_STRING);
21879+ ExpectIntEQ(encKey[encKeySz - expEncLen - 1], (byte)expEncLen);
21880+ }
21881+
21882+ /* Round-trip: decrypt recovers the original plaintext. */
21883+ ExpectIntGT(decKeySz = wc_DecryptPKCS8Key(encKey, encKeySz, password,
21884+ (int)passwordSz), 0);
21885+ ExpectIntEQ(decKeySz, (int)sizeof(plain));
21886+ ExpectIntEQ(XMEMCMP(encKey, plain, sizeof(plain)), 0);
21887+ PRIVATE_KEY_LOCK();
21888+
21889+ XFREE(encKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
21890+ wc_FreeRng(&rng);
21891+ return EXPECT_RESULT();
21892+ }
21893+ #endif
21894+
21895+ /* PBES2 / AES-256-CBC (blockSz 16): a block-aligned plaintext must get a full
21896+ * pad block. The path the fix corrects; the helper's direct length check (not
21897+ * its round-trip, which false-passes here) is what detects a missing block. */
21898+ static int test_wc_EncryptPKCS8Key_blockAligned(void)
21899+ {
21900+ EXPECT_DECLS;
21901+ #if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && defined(WOLFSSL_AES_256) \
21902+ && !defined(NO_AES_CBC) && !defined(NO_SHA) && !defined(NO_ASN_CRYPT)
21903+ EXPECT_TEST(enc_pkcs8_pad_check(PKCS5, PBES2, AES256CBCb, AES_BLOCK_SIZE));
21904+ #endif
21905+ return EXPECT_RESULT();
21906+ }
21907+
21908+ /* PBES1 / SHA1-DES (blockSz 8): exercises the PBES1 encoder branch and a
21909+ * different block size; a block-aligned plaintext gets a full 8-byte pad
21910+ * block. */
21911+ static int test_wc_EncryptPKCS8Key_pbes1BlockAligned(void)
21912+ {
21913+ EXPECT_DECLS;
21914+ #if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && !defined(NO_DES3) \
21915+ && !defined(NO_SHA) && !defined(NO_ASN_CRYPT)
21916+ EXPECT_TEST(enc_pkcs8_pad_check(PKCS5, PBES1_SHA1_DES, 0, DES_BLOCK_SIZE));
21917+ #endif
21918+ return EXPECT_RESULT();
21919+ }
21920+
21921+ /* PKCS12 / RC4 (blockSz 1): a stream cipher adds no padding even for a
21922+ * block-aligned plaintext. Exercises the blockSz > 1 guard in
21923+ * wc_EncryptPKCS8Key_ex. */
21924+ static int test_wc_EncryptPKCS8Key_rc4NoPad(void)
21925+ {
21926+ EXPECT_DECLS;
21927+ #if defined(HAVE_PKCS8) && !defined(NO_PWDBASED) && !defined(NO_RC4) \
21928+ && !defined(NO_SHA) && !defined(NO_ASN_CRYPT)
21929+ EXPECT_TEST(enc_pkcs8_pad_check(1, PBE_SHA1_RC4_128, 0, 0));
21930+ #endif
21931+ return EXPECT_RESULT();
21932+ }
21933+
2183321934static int test_wc_DecryptedPKCS8Key(void)
2183421935{
2183521936 EXPECT_DECLS;
@@ -35063,6 +35164,9 @@ TEST_CASE testCases[] = {
3506335164 /* wolfCrypt ASN tests */
3506435165 TEST_DECL(test_ToTraditional),
3506535166 TEST_DECL(test_wc_CreateEncryptedPKCS8Key),
35167+ TEST_DECL(test_wc_EncryptPKCS8Key_blockAligned),
35168+ TEST_DECL(test_wc_EncryptPKCS8Key_pbes1BlockAligned),
35169+ TEST_DECL(test_wc_EncryptPKCS8Key_rc4NoPad),
3506635170 TEST_DECL(test_wc_DecryptedPKCS8Key),
3506735171 TEST_DECL(test_wc_GetPkcs8TraditionalOffset),
3506835172
0 commit comments