diff --git a/tests/api.c b/tests/api.c index 60db1b4fb..19ee23db2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18873,6 +18873,89 @@ static int test_wc_i2d_PKCS12(void) return EXPECT_RESULT(); } +static int test_wc_PKCS12_create_once(int keyEncType, int certEncType) +{ + EXPECT_DECLS; +#if !defined(NO_ASN) && defined(HAVE_PKCS12) && !defined(NO_PWDBASED) \ + && !defined(NO_HMAC) && !defined(NO_CERTS) && defined(USE_CERT_BUFFERS_2048) + + byte* inKey = (byte*) server_key_der_2048; + const word32 inKeySz= sizeof_server_key_der_2048; + byte* inCert = (byte*) server_cert_der_2048; + const word32 inCertSz = sizeof_server_cert_der_2048; + WC_DerCertList inCa = { + (byte*)ca_cert_der_2048, sizeof_ca_cert_der_2048, NULL + }; + char pkcs12Passwd[] = "test_wc_PKCS12_create"; + + WC_PKCS12* pkcs12Export = NULL; + WC_PKCS12* pkcs12Import = NULL; + byte* pkcs12Der = NULL; + byte* outKey = NULL; + byte* outCert = NULL; + WC_DerCertList* outCaList = NULL; + word32 pkcs12DerSz = 0; + word32 outKeySz = 0; + word32 outCertSz = 0; + + ExpectNotNull(pkcs12Export = wc_PKCS12_create(pkcs12Passwd, + sizeof(pkcs12Passwd) - 1, + (char*) "friendlyName" /* not used currently */, + inKey, inKeySz, inCert, inCertSz, &inCa, keyEncType, certEncType, + 2048, 2048, 0 /* not used currently */, NULL)); + pkcs12Der = NULL; + ExpectIntGE((pkcs12DerSz = wc_i2d_PKCS12(pkcs12Export, &pkcs12Der, NULL)), + 0); + + ExpectNotNull(pkcs12Import = wc_PKCS12_new_ex(NULL)); + ExpectIntGE(wc_d2i_PKCS12(pkcs12Der, pkcs12DerSz, pkcs12Import), 0); + ExpectIntEQ(wc_PKCS12_parse(pkcs12Import, pkcs12Passwd, &outKey, &outKeySz, + &outCert, &outCertSz, &outCaList), 0); + + ExpectIntEQ(outKeySz, inKeySz); + ExpectIntEQ(outCertSz, outCertSz); + ExpectNotNull(outCaList); + ExpectNotNull(outCaList->buffer); + ExpectIntEQ(outCaList->bufferSz, inCa.bufferSz); + ExpectNull(outCaList->next); + + ExpectIntEQ(XMEMCMP(inKey, outKey, outKeySz), 0); + ExpectIntEQ(XMEMCMP(inCert, outCert, outCertSz), 0); + ExpectIntEQ(XMEMCMP(inCa.buffer, outCaList->buffer, outCaList->bufferSz), + 0); + + XFREE(outKey, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(outCert, NULL, DYNAMIC_TYPE_PKCS); + wc_FreeCertList(outCaList, NULL); + wc_PKCS12_free(pkcs12Import); + XFREE(pkcs12Der, NULL, DYNAMIC_TYPE_PKCS); + wc_PKCS12_free(pkcs12Export); +#endif + (void) keyEncType; + (void) certEncType; + + return EXPECT_RESULT(); +} + +static int test_wc_PKCS12_create(void) +{ + EXPECT_DECLS; +#if !defined(NO_DES3) + ExpectIntEQ(test_wc_PKCS12_create_once(PBE_SHA1_DES3, PBE_SHA1_DES3), + TEST_SUCCESS); +#endif +#if defined(HAVE_AES_CBC) && !defined(NO_AES_256) && !defined(NO_DES3) + ExpectIntEQ(test_wc_PKCS12_create_once(PBE_AES256_CBC, PBE_SHA1_DES3), + TEST_SUCCESS); +#endif +#if defined(HAVE_AES_CBC) && !defined(NO_AES_128) && !defined(NO_DES3) + ExpectIntEQ(test_wc_PKCS12_create_once(PBE_AES128_CBC, PBE_SHA1_DES3), + TEST_SUCCESS); +#endif + (void) test_wc_PKCS12_create_once; + + return EXPECT_RESULT(); +} /*----------------------------------------------------------------------------* | ASN.1 Tests @@ -67039,6 +67122,7 @@ TEST_CASE testCases[] = { /* wolfCrypt PKCS#12 */ TEST_DECL(test_wc_i2d_PKCS12), + TEST_DECL(test_wc_PKCS12_create), /* * test_wolfCrypt_Cleanup needs to come after the above wolfCrypt tests to diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index eb09cb0f0..7cde4abf3 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -9536,10 +9536,10 @@ static int GetAlgoV2(int encAlgId, const byte** oid, int *len, int* id, return ret; } -int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, +int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, word32* outSz, const char* password, int passwordSz, int vPKCS, int pbeOid, - int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng, - void* heap) + int encAlgId, byte* salt, word32 saltSz, int itt, int hmacOid, + WC_RNG* rng, void* heap) { #ifdef WOLFSSL_SMALL_STACK byte* saltTmp = NULL; @@ -9563,10 +9563,12 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, byte cbcIv[MAX_IV_SIZE]; word32 idx = 0; word32 encIdx = 0; + const byte* hmacOidBuf = NULL; + word32 hmacOidBufSz = 0; (void)heap; - WOLFSSL_ENTER("wc_EncryptPKCS8Key"); + WOLFSSL_ENTER("wc_EncryptPKCS8Key_ex"); if (key == NULL || outSz == NULL || password == NULL) { ret = BAD_FUNC_ARG; @@ -9594,6 +9596,11 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, pbeLen = 2 + pbeOidBufSz + 2 + innerLen; } else { + if (hmacOid > 0) { + hmacOidBuf = OidFromId((word32)hmacOid, oidHmacType, + &hmacOidBufSz); + innerLen += 2 + 2 + hmacOidBufSz; + } pbeOidBuf = pbes2; pbeOidBufSz = sizeof(pbes2); /* kdf = OBJ pbkdf2 [ SEQ innerLen ] */ @@ -9650,7 +9657,7 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, } if (ret == 0) { ret = wc_CryptKey(password, passwordSz, salt, (int)saltSz, itt, pbeId, - out + encIdx, (int)keySz, version, cbcIv, 1, 0); + out + encIdx, (int)keySz, version, cbcIv, 1, hmacOid); } if (ret == 0) { if (version != PKCS5v2) { @@ -9680,6 +9687,14 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, ret = SetShortInt(out, &idx, (word32)itt, *outSz); if (ret > 0) ret = 0; + if (version == PKCS5v2) { + if (hmacOid > 0) { + idx += SetSequence(2+hmacOidBufSz, out + idx); + idx += (word32)SetObjectId((int)hmacOidBufSz, out + idx); + XMEMCPY(out + idx, hmacOidBuf, hmacOidBufSz); + idx += (word32)hmacOidBufSz; + } + } } if (ret == 0) { if (version == PKCS5v2) { @@ -9704,11 +9719,20 @@ int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif - WOLFSSL_LEAVE("wc_EncryptPKCS8Key", ret); + WOLFSSL_LEAVE("wc_EncryptPKCS8Key_ex", ret); return ret; } +int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, + const char* password, int passwordSz, int vPKCS, int pbeOid, + int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng, + void* heap) +{ + return wc_EncryptPKCS8Key_ex(key, keySz, out, outSz, password, passwordSz, + vPKCS, pbeOid, encAlgId, salt, saltSz, itt, 0, rng, heap); +} + int wc_DecryptPKCS8Key(byte* input, word32 sz, const char* password, int passwordSz) { @@ -9751,10 +9775,10 @@ int wc_DecryptPKCS8Key(byte* input, word32 sz, const char* password, * encrypted key. If out is not NULL, it will hold the encrypted key. If it's * NULL, LENGTH_ONLY_E will be returned and outSz will have the required out * buffer size. */ -int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, +int TraditionalEnc_ex(byte* key, word32 keySz, byte* out, word32* outSz, const char* password, int passwordSz, int vPKCS, int vAlgo, - int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng, - void* heap) + int encAlgId, byte* salt, word32 saltSz, int itt, int hmacOid, + WC_RNG* rng, void* heap) { int ret = 0; byte *pkcs8Key = NULL; @@ -9794,8 +9818,9 @@ int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, } #endif if (ret == 0) { - ret = wc_EncryptPKCS8Key(pkcs8Key, pkcs8KeySz, out, outSz, password, - passwordSz, vPKCS, vAlgo, encAlgId, salt, saltSz, itt, rng, heap); + ret = wc_EncryptPKCS8Key_ex(pkcs8Key, pkcs8KeySz, out, outSz, password, + passwordSz, vPKCS, vAlgo, encAlgId, salt, saltSz, itt, hmacOid, rng, + heap); } if (pkcs8Key != NULL) { @@ -9808,6 +9833,20 @@ int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, return ret; } +/* Takes an unencrypted, traditional DER-encoded key and converts it to a PKCS#8 + * encrypted key. If out is not NULL, it will hold the encrypted key. If it's + * NULL, LENGTH_ONLY_E will be returned and outSz will have the required out + * buffer size. */ +int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, + const char* password, int passwordSz, int vPKCS, int vAlgo, + int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng, + void* heap) +{ + return TraditionalEnc_ex(key, keySz, out, outSz, password, passwordSz, + vPKCS, vAlgo, encAlgId, salt, saltSz, itt, 0, rng, heap); + +} + /* Same as TraditionalEnc, but in the public API. */ int wc_CreateEncryptedPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, const char* password, int passwordSz, int vPKCS, diff --git a/wolfcrypt/src/pkcs12.c b/wolfcrypt/src/pkcs12.c index 5e995ebbd..afa5e7fd8 100644 --- a/wolfcrypt/src/pkcs12.c +++ b/wolfcrypt/src/pkcs12.c @@ -1787,6 +1787,10 @@ static int wc_PKCS12_shroud_key(WC_PKCS12* pkcs12, WC_RNG* rng, int ret; byte* pkcs8Key = NULL; + /* The blkOid and hmacOid are only valid for PKCS#5v2 (PBES2) */ + int blkOid = 0; + int hmacOid = 0; /* If 0, use the default HMAC algorithm */ + if (outSz == NULL || pkcs12 == NULL || rng == NULL || key == NULL || pass == NULL) { return BAD_FUNC_ARG; @@ -1822,13 +1826,25 @@ static int wc_PKCS12_shroud_key(WC_PKCS12* pkcs12, WC_RNG* rng, else { WOLFSSL_MSG("creating PKCS12 Shrouded Key Bag"); + /* Need to handle PKCS#5v1/v2 (=non-PKCS#12v1) encryptions */ if (vAlgo == PBE_SHA1_DES) { vPKCS = PKCS5; vAlgo = 10; } - - ret = UnTraditionalEnc(key, keySz, pkcs8Key, &sz, pass, passSz, - vPKCS, vAlgo, NULL, 0, itt, rng, heap); + else if (vAlgo == PBE_AES256_CBC) { + vPKCS = PKCS5; + vAlgo = PBES2; + blkOid = AES256CBCb; + hmacOid = HMAC_SHA256_OID; + } + else if (vAlgo == PBE_AES128_CBC) { + vPKCS = PKCS5; + vAlgo = PBES2; + blkOid = AES128CBCb; + hmacOid = HMAC_SHA256_OID; + } + ret = TraditionalEnc_ex(key, keySz, pkcs8Key, &sz, pass, passSz, + vPKCS, vAlgo, blkOid, NULL, 0, itt, hmacOid, rng, heap); } if (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { *outSz = sz + MAX_LENGTH_SZ + 1; @@ -2261,6 +2277,7 @@ static byte* PKCS12_create_key_content(WC_PKCS12* pkcs12, int nidKey, heap = wc_PKCS12_GetHeap(pkcs12); *keyCiSz = 0; switch (nidKey) { + /* supported key encryptions */ case PBE_SHA1_RC4_128: algo = 1; break; @@ -2273,8 +2290,15 @@ static byte* PKCS12_create_key_content(WC_PKCS12* pkcs12, int nidKey, algo = 3; break; - /* no encryption */ - case -1: + case PBE_AES256_CBC: + algo = PBE_AES256_CBC; + break; + + case PBE_AES128_CBC: + algo = PBE_AES128_CBC; + break; + + case -1: /* no encryption */ algo = -1; break; diff --git a/wolfcrypt/src/wc_encrypt.c b/wolfcrypt/src/wc_encrypt.c index b1e8b8229..fed9a4a5e 100644 --- a/wolfcrypt/src/wc_encrypt.c +++ b/wolfcrypt/src/wc_encrypt.c @@ -636,10 +636,14 @@ int wc_CryptKey(const char* password, int passwordSz, byte* salt, break; } #endif - #if !defined(NO_AES) && defined(HAVE_AES_CBC) + #if !defined(NO_AES) && defined(HAVE_AES_CBC) && \ + (defined(WOLFSSL_AES_256) || defined(WOLFSSL_AES_128)) #ifdef WOLFSSL_AES_256 case PBE_AES256_CBC: + #endif /* WOLFSSL_AES_256 */ + #ifdef WOLFSSL_AES_128 case PBE_AES128_CBC: + #endif /* WOLFSSL_AES_128 */ { int free_aes; @@ -686,8 +690,7 @@ int wc_CryptKey(const char* password, int passwordSz, byte* salt, #endif break; } - #endif /* WOLFSSL_AES_256 */ - #endif /* !NO_AES && HAVE_AES_CBC */ + #endif /* !NO_AES && HAVE_AES_CBC && (WOLFSSL_AES_256 || WOLFSSL_AES_128) */ #ifdef WC_RC2 case PBE_SHA1_40RC2_CBC: { diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index acd3bd18f..d0064e8a5 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2224,6 +2224,10 @@ WOLFSSL_LOCAL int ToTraditionalEnc(byte* input, word32 sz, const char* password, WOLFSSL_ASN_API int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, const char* password, int passwordSz, int vPKCS, int vAlgo, byte* salt, word32 saltSz, int itt, WC_RNG* rng, void* heap); +WOLFSSL_ASN_API int TraditionalEnc_ex(byte* key, word32 keySz, byte* out, + word32* outSz, const char* password, int passwordSz, int vPKCS, + int vAlgo, int encAlgId, byte* salt, word32 saltSz, int itt, + int hmacOid, WC_RNG* rng, void* heap); WOLFSSL_ASN_API int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, const char* password, int passwordSz, int vPKCS, int vAlgo, int encAlgId, byte* salt, word32 saltSz, int itt, diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index fba7bfe31..537a2d5c1 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -798,6 +798,10 @@ WOLFSSL_API int wc_GetPkcs8TraditionalOffset(byte* input, WOLFSSL_API int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz, int algoID, const byte* curveOID, word32 oidSz); +WOLFSSL_API int wc_EncryptPKCS8Key_ex(byte* key, word32 keySz, byte* out, + word32* outSz, const char* password, int passwordSz, int vPKCS, + int pbeOid, int encAlgId, byte* salt, word32 saltSz, int itt, + int hmacOid, WC_RNG* rng, void* heap); WOLFSSL_API int wc_EncryptPKCS8Key(byte* key, word32 keySz, byte* out, word32* outSz, const char* password, int passwordSz, int vPKCS, int pbeOid, int encAlgId, byte* salt, word32 saltSz, int itt, WC_RNG* rng,