diff --git a/Makefile.am b/Makefile.am index 09e1e7219..3ad41c388 100644 --- a/Makefile.am +++ b/Makefile.am @@ -38,6 +38,18 @@ CLEANFILES+= cert.der \ othercert.der \ othercert.pem \ pkcs7cert.der \ + pkcs7encryptedDataAES128CBC.der \ + pkcs7encryptedDataAES192CBC.der \ + pkcs7encryptedDataAES256CBC_attribs.der \ + pkcs7encryptedDataAES256CBC.der \ + pkcs7encryptedDataAES256CBC_multi_attribs.der \ + pkcs7encryptedDataDES3.der \ + pkcs7encryptedDataDES.der \ + pkcs7envelopedDataAES256CBC_ECDH.der \ + pkcs7envelopedDataAES128CBC_ECDH_SHA1KDF.der \ + pkcs7envelopedDataAES256CBC_ECDH_SHA256KDF.der \ + pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF.der \ + pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF_ukm.der \ pkcs7envelopedDataDES3.der \ pkcs7envelopedDataAES128CBC.der \ pkcs7envelopedDataAES192CBC.der \ diff --git a/configure.ac b/configure.ac index 227ed80af..c524b7d3d 100644 --- a/configure.ac +++ b/configure.ac @@ -3011,6 +3011,16 @@ if test "x$ENABLED_PKCS7" = "xyes" then AM_CFLAGS="$AM_CFLAGS -DHAVE_PKCS7" # Enable prereqs if not already enabled + if test "x$ENABLED_AESKEYWRAP" = "xno" + then + ENABLED_AESKEYWRAP="yes" + AM_CFLAGS="$AM_CFLAGS -DHAVE_AES_KEYWRAP -DWOLFSSL_AES_DIRECT" + fi + if test "x$ENABLED_X963KDF" = "xno" + then + ENABLED_X963KDF="yes" + AM_CFLAGS="$AM_CFLAGS -DHAVE_X963_KDF" + fi AS_IF([test "x$ENABLED_DES3" = "xno"], [ENABLED_DES3=yes]) fi diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 28e3cb02a..d5b99a0b0 100755 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -802,6 +802,19 @@ static const byte blkAes256CbcOid[] = {96, 134, 72, 1, 101, 3, 4, 1, 42}; static const byte blkDesCbcOid[] = {43, 14, 3, 2, 7}; static const byte blkDes3CbcOid[] = {42, 134, 72, 134, 247, 13, 3, 7}; +/* keyWrapType */ +static const byte wrapAes128Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 5}; +static const byte wrapAes192Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 25}; +static const byte wrapAes256Oid[] = {96, 134, 72, 1, 101, 3, 4, 1, 45}; + +/* cmsKeyAgreeType */ +static const byte dhSinglePass_stdDH_sha1kdf_Oid[] = + {43, 129, 5, 16, 134, 72, 63, 0, 2}; +static const byte dhSinglePass_stdDH_sha224kdf_Oid[] = {43, 129, 4, 1, 11, 0}; +static const byte dhSinglePass_stdDH_sha256kdf_Oid[] = {43, 129, 4, 1, 11, 1}; +static const byte dhSinglePass_stdDH_sha384kdf_Oid[] = {43, 129, 4, 1, 11, 2}; +static const byte dhSinglePass_stdDH_sha512kdf_Oid[] = {43, 129, 4, 1, 11, 3}; + /* ocspType */ #ifdef HAVE_OCSP static const byte ocspBasicOid[] = {43, 6, 1, 5, 5, 7, 48, 1, 1}; @@ -1124,6 +1137,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) *oidSz = sizeof(extExtKeyUsageOcspSignOid); break; } + break; case oidKdfType: switch (id) { @@ -1134,6 +1148,48 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; + case oidKeyWrapType: + switch (id) { + case AES128_WRAP: + oid = wrapAes128Oid; + *oidSz = sizeof(wrapAes128Oid); + break; + case AES192_WRAP: + oid = wrapAes192Oid; + *oidSz = sizeof(wrapAes192Oid); + break; + case AES256_WRAP: + oid = wrapAes256Oid; + *oidSz = sizeof(wrapAes256Oid); + break; + } + break; + + case oidCmsKeyAgreeType: + switch (id) { + case dhSinglePass_stdDH_sha1kdf_scheme: + oid = dhSinglePass_stdDH_sha1kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha1kdf_Oid); + break; + case dhSinglePass_stdDH_sha224kdf_scheme: + oid = dhSinglePass_stdDH_sha224kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha224kdf_Oid); + break; + case dhSinglePass_stdDH_sha256kdf_scheme: + oid = dhSinglePass_stdDH_sha256kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha256kdf_Oid); + break; + case dhSinglePass_stdDH_sha384kdf_scheme: + oid = dhSinglePass_stdDH_sha384kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha384kdf_Oid); + break; + case dhSinglePass_stdDH_sha512kdf_scheme: + oid = dhSinglePass_stdDH_sha512kdf_Oid; + *oidSz = sizeof(dhSinglePass_stdDH_sha512kdf_Oid); + break; + } + break; + case oidIgnoreType: default: break; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index b80b634ef..65351f09f 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -49,9 +49,16 @@ #endif /* WOLFSSL_HAVE_MIN */ +/* direction for processing, encoding or decoding */ +typedef enum { + WC_PKCS7_ENCODE, + WC_PKCS7_DECODE +} pkcs7Direction; + + /* placed ASN.1 contentType OID into *output, return idx on success, * 0 upon failure */ -WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output) +static int wc_SetContentType(int pkcs7TypeOID, byte* output) { /* PKCS#7 content types, RFC 2315, section 14 */ const byte pkcs7[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, @@ -123,13 +130,12 @@ WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output) idx += typeSz; return idx; - } /* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */ -int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, - word32 maxIdx) +static int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, + word32 maxIdx) { WOLFSSL_ENTER("wc_GetContentType"); if (GetObjectId(input, inOutIdx, oid, oidIgnoreType, maxIdx) < 0) @@ -139,14 +145,71 @@ int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, } -int wc_PKCS7_SetHeap(PKCS7* pkcs7, void* heap) +/* return block size for algorithm represented by oid, or <0 on error */ +static int wc_PKCS7_GetOIDBlockSize(int oid) { - if (pkcs7 == NULL) { - return BAD_FUNC_ARG; - } - pkcs7->heap = heap; + int blockSz; - return 0; + switch (oid) { +#ifndef NO_AES + case AES128CBCb: + case AES192CBCb: + case AES256CBCb: + blockSz = AES_BLOCK_SIZE; + break; +#endif +#ifndef NO_DES3 + case DESb: + case DES3b: + blockSz = DES_BLOCK_SIZE; + break; +#endif + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + return blockSz; +} + + +/* get key size for algorithm represented by oid, or <0 on error */ +static int wc_PKCS7_GetOIDKeySize(int oid) +{ + int blockKeySz; + + switch (oid) { +#ifndef NO_AES + case AES128CBCb: + case AES128_WRAP: + blockKeySz = 16; + break; + + case AES192CBCb: + case AES192_WRAP: + blockKeySz = 24; + break; + + case AES256CBCb: + case AES256_WRAP: + blockKeySz = 32; + break; +#endif +#ifndef NO_DES3 + case DESb: + blockKeySz = DES_KEYLEN; + break; + + case DES3b: + blockKeySz = DES3_KEYLEN; + break; +#endif + default: + WOLFSSL_MSG("Unsupported content cipher type"); + return ALGO_ID_E; + }; + + return blockKeySz; } @@ -169,7 +232,7 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) DecodedCert* dCert; dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (dCert == NULL) return MEMORY_E; #else @@ -185,13 +248,14 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) if (ret < 0) { FreeDecodedCert(dCert); #ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(dCert, NULL, DYNAMIC_TYPE_PKCS7); #endif return ret; } XMEMCPY(pkcs7->publicKey, dCert->publicKey, dCert->pubKeySize); pkcs7->publicKeySz = dCert->pubKeySize; + pkcs7->publicKeyOID = dCert->keyOID; XMEMCPY(pkcs7->issuerHash, dCert->issuerHash, KEYID_SIZE); pkcs7->issuer = dCert->issuerRaw; pkcs7->issuerSz = dCert->issuerRawLen; @@ -200,7 +264,7 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) FreeDecodedCert(dCert); #ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(dCert, NULL, DYNAMIC_TYPE_PKCS7); #endif } @@ -208,10 +272,39 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) } +/* free linked list of PKCS7DecodedAttrib structs */ +static void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, void* heap) +{ + PKCS7DecodedAttrib* current; + + if (attrib == NULL) { + return; + } + + current = attrib; + while (current != NULL) { + PKCS7DecodedAttrib* next = current->next; + if (current->oid != NULL) { + XFREE(current->oid, heap, DYNAMIC_TYPE_PKCS7); + } + if (current->value != NULL) { + XFREE(current->value, heap, DYNAMIC_TYPE_PKCS7); + } + XFREE(current, heap, DYNAMIC_TYPE_PKCS7); + current = next; + } + + (void)heap; +} + + /* releases any memory allocated by a PKCS7 initializer */ void wc_PKCS7_Free(PKCS7* pkcs7) { - (void)pkcs7; + if (pkcs7 == NULL) + return; + + wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap); } @@ -956,12 +1049,706 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } +/* KARI == KeyAgreeRecipientInfo (key agreement) */ +typedef struct WC_PKCS7_KARI { + DecodedCert* decoded; /* decoded recip cert */ + void* heap; /* user heap, points to PKCS7->heap */ + ecc_key* recipKey; /* recip key (pub | priv) */ + ecc_key* senderKey; /* sender key (pub | priv) */ + byte* senderKeyExport; /* sender ephemeral key DER */ + byte* kek; /* key encryption key */ + byte* ukm; /* OPTIONAL user keying material */ + byte* sharedInfo; /* ECC-CMS-SharedInfo ASN.1 encoded blob */ + word32 senderKeyExportSz; /* size of sender ephemeral key DER */ + word32 kekSz; /* size of key encryption key */ + word32 ukmSz; /* size of user keying material */ + word32 sharedInfoSz; /* size of ECC-CMS-SharedInfo encoded */ + byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */ + byte direction; /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */ +} WC_PKCS7_KARI; + + +/* wrap CEK (content encryption key) with KEK, 0 on success, < 0 on error */ +static int wc_PKCS7_KariKeyWrap(byte* cek, word32 cekSz, byte* kek, + word32 kekSz, byte* out, word32 outSz, + int keyWrapAlgo, int direction) +{ + int ret; + + if (cek == NULL || kek == NULL || out == NULL) + return BAD_FUNC_ARG; + + switch (keyWrapAlgo) { + case AES128_WRAP: + case AES192_WRAP: + case AES256_WRAP: + + if (direction == AES_ENCRYPTION) { + + ret = wc_AesKeyWrap(kek, kekSz, cek, cekSz, + out, outSz, NULL); + + } else if (direction == AES_DECRYPTION) { + + ret = wc_AesKeyUnWrap(kek, kekSz, cek, cekSz, + out, outSz, NULL); + } else { + WOLFSSL_MSG("Bad key un/wrap direction"); + return BAD_FUNC_ARG; + } + + if (ret <= 0) + return ret; + + break; + + default: + WOLFSSL_MSG("Unsupported key wrap algorithm"); + return BAD_FUNC_ARG; + }; + + return ret; +} + + +/* allocate and create new WC_PKCS7_KARI struct, + * returns struct pointer on success, NULL on failure */ +static WC_PKCS7_KARI* wc_PKCS7_KariNew(PKCS7* pkcs7, byte direction) +{ + WC_PKCS7_KARI* kari = NULL; + + if (pkcs7 == NULL) + return NULL; + + kari = (WC_PKCS7_KARI*)XMALLOC(sizeof(WC_PKCS7_KARI), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari == NULL) { + WOLFSSL_MSG("Failed to allocate WC_PKCS7_KARI"); + return NULL; + } + + kari->decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->decoded == NULL) { + WOLFSSL_MSG("Failed to allocate DecodedCert"); + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + return NULL; + } + + kari->recipKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->recipKey == NULL) { + WOLFSSL_MSG("Failed to allocate recipient ecc_key"); + XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + return NULL; + } + + kari->senderKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->senderKey == NULL) { + WOLFSSL_MSG("Failed to allocate sender ecc_key"); + XFREE(kari->recipKey, heap, DYNAMIC_TYPE_PKCS7); + XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + return NULL; + } + + kari->senderKeyExport = NULL; + kari->senderKeyExportSz = 0; + kari->kek = NULL; + kari->kekSz = 0; + kari->ukm = NULL; + kari->ukmSz = 0; + kari->ukmOwner = 0; + kari->sharedInfo = NULL; + kari->sharedInfoSz = 0; + kari->direction = direction; + + kari->heap = pkcs7->heap; + + return kari; +} + + +/* free WC_PKCS7_KARI struct, return 0 on success */ +static int wc_PKCS7_KariFree(WC_PKCS7_KARI* kari) +{ + void* heap; + + if (kari) { + heap = kari->heap; + + if (kari->decoded) { + FreeDecodedCert(kari->decoded); + XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); + } + if (kari->senderKey) { + wc_ecc_free(kari->senderKey); + XFREE(kari->senderKey, heap, DYNAMIC_TYPE_PKCS7); + } + if (kari->recipKey) { + wc_ecc_free(kari->recipKey); + XFREE(kari->recipKey, heap, DYNAMIC_TYPE_PKCS7); + } + if (kari->senderKeyExport) { + ForceZero(kari->senderKeyExport, kari->senderKeyExportSz); + XFREE(kari->senderKeyExport, heap, DYNAMIC_TYPE_PKCS7); + kari->senderKeyExportSz = 0; + } + if (kari->kek) { + ForceZero(kari->kek, kari->kekSz); + XFREE(kari->kek, heap, DYNAMIC_TYPE_PKCS7); + kari->kekSz = 0; + } + if (kari->ukm) { + if (kari->ukmOwner == 1) { + XFREE(kari->ukm, heap, DYNAMIC_TYPE_PKCS7); + } + kari->ukmSz = 0; + } + if (kari->sharedInfo) { + ForceZero(kari->sharedInfo, kari->sharedInfoSz); + XFREE(kari->sharedInfo, heap, DYNAMIC_TYPE_PKCS7); + kari->sharedInfoSz = 0; + } + XFREE(kari, heap, DYNAMIC_TYPE_PKCS7); + } + + (void)heap; + + return 0; +} + + +/* parse recipient cert/key, return 0 on success, negative on error + * key/keySz only needed during decoding (WC_PKCS7_DECODE) */ +static int wc_PKCS7_KariParseRecipCert(WC_PKCS7_KARI* kari, const byte* cert, + word32 certSz, const byte* key, + word32 keySz) +{ + int ret; + word32 idx; + + if (kari == NULL || kari->decoded == NULL || + cert == NULL || certSz == 0) + return BAD_FUNC_ARG; + + if (kari->direction == WC_PKCS7_DECODE && + (key == NULL || keySz == 0)) + return BAD_FUNC_ARG; + + /* decode certificate */ + InitDecodedCert(kari->decoded, (byte*)cert, certSz, kari->heap); + ret = ParseCert(kari->decoded, CA_TYPE, NO_VERIFY, 0); + if (ret < 0) + return ret; + + /* make sure subject key id was read from cert */ + if (kari->decoded->extSubjKeyIdSet == 0) { + WOLFSSL_MSG("Failed to read subject key ID from recipient cert"); + return BAD_FUNC_ARG; + } + + ret = wc_ecc_init(kari->recipKey); + if (ret != 0) + return ret; + + /* get recip public key */ + if (kari->direction == WC_PKCS7_ENCODE) { + + ret = wc_ecc_import_x963(kari->decoded->publicKey, + kari->decoded->pubKeySize, + kari->recipKey); + } + /* get recip private key */ + else if (kari->direction == WC_PKCS7_DECODE) { + + idx = 0; + ret = wc_EccPrivateKeyDecode(key, &idx, kari->recipKey, keySz); + if (ret != 0) + return ret; + + } else { + /* bad direction */ + return BAD_FUNC_ARG; + } + + if (ret != 0) + return ret; + + (void)idx; + + return 0; +} + + +/* create ephemeral ECC key, places ecc_key in kari->senderKey, + * DER encoded in kari->senderKeyExport. return 0 on success, + * negative on error */ +static int wc_PKCS7_KariGenerateEphemeralKey(WC_PKCS7_KARI* kari, RNG* rng) +{ + int ret; + + if (kari == NULL || kari->decoded == NULL || + kari->recipKey == NULL || kari->recipKey->dp == NULL || + rng == NULL) + return BAD_FUNC_ARG; + + kari->senderKeyExport = (byte*)XMALLOC(kari->decoded->pubKeySize, kari->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->senderKeyExport == NULL) + return MEMORY_E; + + kari->senderKeyExportSz = kari->decoded->pubKeySize; + + ret = wc_ecc_init(kari->senderKey); + if (ret != 0) + return ret; + + ret = wc_ecc_make_key_ex(rng, kari->recipKey->dp->size, + kari->senderKey, kari->recipKey->dp->id); + if (ret != 0) + return ret; + + /* dump generated key to X.963 DER for output in CMS bundle */ + ret = wc_ecc_export_x963(kari->senderKey, kari->senderKeyExport, + &kari->senderKeyExportSz); + if (ret != 0) + return ret; + + return 0; +} + + +/* create ASN.1 encoded ECC-CMS-SharedInfo using specified key wrap algorithm, + * place in kari->sharedInfo. returns 0 on success, negative on error */ +static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID) +{ + int idx = 0; + int sharedInfoSeqSz = 0; + int keyInfoSz = 0; + int suppPubInfoSeqSz = 0; + int entityUInfoOctetSz = 0; + int kekOctetSz = 0; + int sharedInfoSz = 0; + + word32 kekBitSz = 0; + + byte sharedInfoSeq[MAX_SEQ_SZ]; + byte keyInfo[MAX_ALGO_SZ]; + byte suppPubInfoSeq[MAX_SEQ_SZ]; + byte entityUInfoOctet[MAX_OCTET_STR_SZ]; + byte kekOctet[MAX_OCTET_STR_SZ]; + + if (kari == NULL) + return BAD_FUNC_ARG; + + if ((kari->ukmSz > 0) && (kari->ukm == NULL)) + return BAD_FUNC_ARG; + + /* kekOctet */ + kekOctetSz = SetOctetString(sizeof(word32), kekOctet); + sharedInfoSz += (kekOctetSz + sizeof(word32)); + + /* suppPubInfo */ + suppPubInfoSeqSz = SetImplicit(ASN_SEQUENCE, 2, + kekOctetSz + sizeof(word32), + suppPubInfoSeq); + sharedInfoSz += suppPubInfoSeqSz; + + /* optional ukm/entityInfo */ + if (kari->ukmSz > 0) { + entityUInfoOctetSz = SetOctetString(kari->ukmSz, entityUInfoOctet); + sharedInfoSz += (entityUInfoOctetSz + kari->ukmSz); + } + + /* keyInfo */ + keyInfoSz = SetAlgoID(keyWrapOID, keyInfo, oidKeyWrapType, 0); + sharedInfoSz += keyInfoSz; + + /* sharedInfo */ + sharedInfoSeqSz = SetSequence(sharedInfoSz, sharedInfoSeq); + sharedInfoSz += sharedInfoSeqSz; + + kari->sharedInfo = (byte*)XMALLOC(sharedInfoSz, kari->heap, + DYNAMIC_TYPE_PKCS7); + if (kari->sharedInfo == NULL) + return MEMORY_E; + + kari->sharedInfoSz = sharedInfoSz; + + XMEMCPY(kari->sharedInfo + idx, sharedInfoSeq, sharedInfoSeqSz); + idx += sharedInfoSeqSz; + XMEMCPY(kari->sharedInfo + idx, keyInfo, keyInfoSz); + idx += keyInfoSz; + if (kari->ukmSz > 0) { + XMEMCPY(kari->sharedInfo + idx, entityUInfoOctet, entityUInfoOctetSz); + idx += entityUInfoOctetSz; + XMEMCPY(kari->sharedInfo + idx, kari->ukm, kari->ukmSz); + idx += kari->ukmSz; + } + XMEMCPY(kari->sharedInfo + idx, suppPubInfoSeq, suppPubInfoSeqSz); + idx += suppPubInfoSeqSz; + XMEMCPY(kari->sharedInfo + idx, kekOctet, kekOctetSz); + idx += kekOctetSz; + + kekBitSz = (kari->kekSz) * 8; /* convert to bits */ +#ifdef LITTLE_ENDIAN_ORDER + kekBitSz = ByteReverseWord32(kekBitSz); /* network byte order */ +#endif + XMEMCPY(kari->sharedInfo + idx, &kekBitSz, sizeof(kekBitSz)); + + return 0; +} + + +/* create key encryption key (KEK) using key wrap algorithm and key encryption + * algorithm, place in kari->kek. return 0 on success, <0 on error. */ +static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, + int keyWrapOID, int keyEncOID) +{ + int ret; + int kSz, kdfType; + byte* secret; + word32 secretSz; + + if (kari == NULL || kari->recipKey == NULL || + kari->senderKey == NULL || kari->senderKey->dp == NULL) + return BAD_FUNC_ARG; + + /* get KEK size, allocate buff */ + kSz = wc_PKCS7_GetOIDKeySize(keyWrapOID); + if (kSz < 0) + return kSz; + + kari->kek = (byte*)XMALLOC(kSz, kari->heap, DYNAMIC_TYPE_PKCS7); + if (kari->kek == NULL) + return MEMORY_E; + + kari->kekSz = (word32)kSz; + + /* generate ECC-CMS-SharedInfo */ + ret = wc_PKCS7_KariGenerateSharedInfo(kari, keyWrapOID); + if (ret != 0) + return ret; + + /* generate shared secret */ + secretSz = kari->senderKey->dp->size; + secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7); + if (secret == NULL) + return MEMORY_E; + + if (kari->direction == WC_PKCS7_ENCODE) { + + ret = wc_ecc_shared_secret(kari->senderKey, kari->recipKey, + secret, &secretSz); + + } else if (kari->direction == WC_PKCS7_DECODE) { + + ret = wc_ecc_shared_secret(kari->recipKey, kari->senderKey, + secret, &secretSz); + + } else { + /* bad direction */ + return BAD_FUNC_ARG; + } + + if (ret != 0) { + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + /* run through KDF */ + switch (keyEncOID) { + + #ifndef NO_SHA + case dhSinglePass_stdDH_sha1kdf_scheme: + kdfType = WC_HASH_TYPE_SHA; + break; + #endif + #ifndef WOLF_SHA224 + case dhSinglePass_stdDH_sha224kdf_scheme: + kdfType = WC_HASH_TYPE_SHA224; + break; + #endif + #ifndef NO_SHA256 + case dhSinglePass_stdDH_sha256kdf_scheme: + kdfType = WC_HASH_TYPE_SHA256; + break; + #endif + #ifdef WOLFSSL_SHA384 + case dhSinglePass_stdDH_sha384kdf_scheme: + kdfType = WC_HASH_TYPE_SHA384; + break; + #endif + #ifdef WOLFSSL_SHA512 + case dhSinglePass_stdDH_sha512kdf_scheme: + kdfType = WC_HASH_TYPE_SHA512; + break; + #endif + default: + WOLFSSL_MSG("Unsupported key agreement algorithm"); + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + return BAD_FUNC_ARG; + }; + + ret = wc_X963_KDF(kdfType, secret, secretSz, kari->sharedInfo, + kari->sharedInfoSz, kari->kek, kari->kekSz); + if (ret != 0) { + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); + + return 0; +} + + +/* create ASN.1 formatted KeyAgreeRecipientInfo (kari) for use with ECDH, + * return sequence size or negative on error */ +static int wc_CreateKeyAgreeRecipientInfo(PKCS7* pkcs7, const byte* cert, + word32 certSz, int keyAgreeAlgo, int blockKeySz, + int keyWrapAlgo, int keyEncAlgo, WC_RNG* rng, + byte* contentKeyPlain, byte* contentKeyEnc, + int* keyEncSz, byte* out, word32 outSz) +{ + int ret = 0, idx = 0; + int keySz; + + /* ASN.1 layout */ + int totalSz = 0; + int kariSeqSz = 0; + byte kariSeq[MAX_SEQ_SZ]; /* IMPLICIT [1] */ + int verSz = 0; + byte ver[MAX_VERSION_SZ]; + + int origIdOrKeySeqSz = 0; + byte origIdOrKeySeq[MAX_SEQ_SZ]; /* IMPLICIT [0] */ + int origPubKeySeqSz = 0; + byte origPubKeySeq[MAX_SEQ_SZ]; /* IMPLICIT [1] */ + int origAlgIdSz = 0; + byte origAlgId[MAX_ALGO_SZ]; + int origPubKeyStrSz = 0; + byte origPubKeyStr[MAX_OCTET_STR_SZ]; + + /* optional user keying material */ + int ukmOctetSz = 0; + byte ukmOctetStr[MAX_OCTET_STR_SZ]; + int ukmExplicitSz = 0; + byte ukmExplicitSeq[MAX_SEQ_SZ]; + + int keyEncryptAlgoIdSz = 0; + byte keyEncryptAlgoId[MAX_ALGO_SZ]; + int keyWrapAlgSz = 0; + byte keyWrapAlg[MAX_ALGO_SZ]; + + int recipEncKeysSeqSz = 0; + byte recipEncKeysSeq[MAX_SEQ_SZ]; + int recipEncKeySeqSz = 0; + byte recipEncKeySeq[MAX_SEQ_SZ]; + int recipKeyIdSeqSz = 0; + byte recipKeyIdSeq[MAX_SEQ_SZ]; /* IMPLICIT [0] */ + int subjKeyIdOctetSz = 0; + byte subjKeyIdOctet[MAX_OCTET_STR_SZ]; + int encryptedKeyOctetSz = 0; + byte encryptedKeyOctet[MAX_OCTET_STR_SZ]; + + WC_PKCS7_KARI* kari; + + /* only supports ECDSA for now */ + if (keyAgreeAlgo != ECDSAk) + return BAD_FUNC_ARG; + + kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_ENCODE); + if (kari == NULL) + return MEMORY_E; + + /* set user keying material if available */ + if ((pkcs7->ukmSz > 0) && (pkcs7->ukm != NULL)) { + kari->ukm = pkcs7->ukm; + kari->ukmSz = pkcs7->ukmSz; + kari->ukmOwner = 0; + } + + /* parse recipient cert, get public key */ + ret = wc_PKCS7_KariParseRecipCert(kari, cert, certSz, NULL, 0); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* generate sender ephemeral ECC key */ + ret = wc_PKCS7_KariGenerateEphemeralKey(kari, rng); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* generate KEK (key encryption key) */ + ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapAlgo, keyEncAlgo); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* encrypt CEK with KEK */ + keySz = wc_PKCS7_KariKeyWrap(contentKeyPlain, blockKeySz, kari->kek, + kari->kekSz, contentKeyEnc, *keyEncSz, keyWrapAlgo, + AES_ENCRYPTION); + if (keySz <= 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + *keyEncSz = (word32)keySz; + + /* Start of RecipientEncryptedKeys */ + + /* EncryptedKey */ + encryptedKeyOctetSz = SetOctetString(*keyEncSz, encryptedKeyOctet); + totalSz += (encryptedKeyOctetSz + *keyEncSz); + + /* SubjectKeyIdentifier */ + subjKeyIdOctetSz = SetOctetString(KEYID_SIZE, subjKeyIdOctet); + totalSz += (subjKeyIdOctetSz + KEYID_SIZE); + + /* RecipientKeyIdentifier IMPLICIT [0] */ + recipKeyIdSeqSz = SetImplicit(ASN_SEQUENCE, 0, subjKeyIdOctetSz + + KEYID_SIZE, recipKeyIdSeq); + totalSz += recipKeyIdSeqSz; + + /* RecipientEncryptedKey */ + recipEncKeySeqSz = SetSequence(totalSz, recipEncKeySeq); + totalSz += recipEncKeySeqSz; + + /* RecipientEncryptedKeys */ + recipEncKeysSeqSz = SetSequence(totalSz, recipEncKeysSeq); + totalSz += recipEncKeysSeqSz; + + /* Start of optional UserKeyingMaterial */ + + if (kari->ukmSz > 0) { + ukmOctetSz = SetOctetString(kari->ukmSz, ukmOctetStr); + totalSz += (ukmOctetSz + kari->ukmSz); + + ukmExplicitSz = SetExplicit(1, ukmOctetSz + kari->ukmSz, + ukmExplicitSeq); + totalSz += ukmExplicitSz; + } + + /* Start of KeyEncryptionAlgorithmIdentifier */ + + /* KeyWrapAlgorithm */ + keyWrapAlgSz = SetAlgoID(keyWrapAlgo, keyWrapAlg, oidKeyWrapType, 0); + totalSz += keyWrapAlgSz; + + /* KeyEncryptionAlgorithmIdentifier */ + keyEncryptAlgoIdSz = SetAlgoID(keyEncAlgo, keyEncryptAlgoId, + oidCmsKeyAgreeType, keyWrapAlgSz); + totalSz += keyEncryptAlgoIdSz; + + /* Start of OriginatorIdentifierOrKey */ + + /* recipient ECPoint, public key */ + XMEMSET(origPubKeyStr, 0, sizeof(origPubKeyStr)); /* no unused bits */ + origPubKeyStr[0] = ASN_BIT_STRING; + origPubKeyStrSz = SetLength(kari->senderKeyExportSz + 1, + origPubKeyStr + 1) + 2; + totalSz += (origPubKeyStrSz + kari->senderKeyExportSz); + + /* Originator AlgorithmIdentifier */ + origAlgIdSz = SetAlgoID(ECDSAk, origAlgId, oidKeyType, 0); + totalSz += origAlgIdSz; + + /* outer OriginatorPublicKey IMPLICIT [1] */ + origPubKeySeqSz = SetImplicit(ASN_SEQUENCE, 1, + origAlgIdSz + origPubKeyStrSz + + kari->senderKeyExportSz, origPubKeySeq); + totalSz += origPubKeySeqSz; + + /* outer OriginatorIdentiferOrKey IMPLICIT [0] */ + origIdOrKeySeqSz = SetImplicit(ASN_SEQUENCE, 0, + origPubKeySeqSz + origAlgIdSz + + origPubKeyStrSz + kari->senderKeyExportSz, + origIdOrKeySeq); + totalSz += origIdOrKeySeqSz; + + /* version, always 3 */ + verSz = SetMyVersion(3, ver, 0); + totalSz += verSz; + + /* outer IMPLICIT [1] kari */ + kariSeqSz = SetImplicit(ASN_SEQUENCE, 1, totalSz, kariSeq); + totalSz += kariSeqSz; + + if ((word32)totalSz > outSz) { + WOLFSSL_MSG("KeyAgreeRecipientInfo output buffer too small"); + wc_PKCS7_KariFree(kari); + + return BUFFER_E; + } + + XMEMCPY(out + idx, kariSeq, kariSeqSz); + idx += kariSeqSz; + XMEMCPY(out + idx, ver, verSz); + idx += verSz; + + XMEMCPY(out + idx, origIdOrKeySeq, origIdOrKeySeqSz); + idx += origIdOrKeySeqSz; + XMEMCPY(out + idx, origPubKeySeq, origPubKeySeqSz); + idx += origPubKeySeqSz; + XMEMCPY(out + idx, origAlgId, origAlgIdSz); + idx += origAlgIdSz; + XMEMCPY(out + idx, origPubKeyStr, origPubKeyStrSz); + idx += origPubKeyStrSz; + /* ephemeral public key */ + XMEMCPY(out + idx, kari->senderKeyExport, kari->senderKeyExportSz); + idx += kari->senderKeyExportSz; + + if (kari->ukmSz > 0) { + XMEMCPY(out + idx, ukmExplicitSeq, ukmExplicitSz); + idx += ukmExplicitSz; + XMEMCPY(out + idx, ukmOctetStr, ukmOctetSz); + idx += ukmOctetSz; + XMEMCPY(out + idx, kari->ukm, kari->ukmSz); + idx += kari->ukmSz; + } + + XMEMCPY(out + idx, keyEncryptAlgoId, keyEncryptAlgoIdSz); + idx += keyEncryptAlgoIdSz; + XMEMCPY(out + idx, keyWrapAlg, keyWrapAlgSz); + idx += keyWrapAlgSz; + + XMEMCPY(out + idx, recipEncKeysSeq, recipEncKeysSeqSz); + idx += recipEncKeysSeqSz; + XMEMCPY(out + idx, recipEncKeySeq, recipEncKeySeqSz); + idx += recipEncKeySeqSz; + XMEMCPY(out + idx, recipKeyIdSeq, recipKeyIdSeqSz); + idx += recipKeyIdSeqSz; + XMEMCPY(out + idx, subjKeyIdOctet, subjKeyIdOctetSz); + idx += subjKeyIdOctetSz; + /* subject key id */ + XMEMCPY(out + idx, kari->decoded->extSubjKeyId, KEYID_SIZE); + idx += KEYID_SIZE; + XMEMCPY(out + idx, encryptedKeyOctet, encryptedKeyOctetSz); + idx += encryptedKeyOctetSz; + /* encrypted CEK */ + XMEMCPY(out + idx, contentKeyEnc, *keyEncSz); + idx += *keyEncSz; + + wc_PKCS7_KariFree(kari); + + return idx; +} + + /* create ASN.1 formatted RecipientInfo structure, returns sequence size */ -WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, - int keyEncAlgo, int blockKeySz, - WC_RNG* rng, byte* contentKeyPlain, - byte* contentKeyEnc, int* keyEncSz, - byte* out, word32 outSz, void* heap) +static int wc_CreateRecipientInfo(const byte* cert, word32 certSz, + int keyEncAlgo, int blockKeySz, + WC_RNG* rng, byte* contentKeyPlain, + byte* contentKeyEnc, int* keyEncSz, + byte* out, word32 outSz, void* heap) { word32 idx = 0; int ret = 0, totalSz = 0; @@ -978,7 +1765,7 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, #ifdef WOLFSSL_SMALL_STACK byte *serial; byte *keyAlgArray; - + RsaKey* pubKey; DecodedCert* decoded; @@ -993,11 +1780,11 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, if (decoded) XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } - + #else byte serial[MAX_SN_SZ]; byte keyAlgArray[MAX_ALGO_SZ]; - + RsaKey stack_pubKey; RsaKey* pubKey = &stack_pubKey; DecodedCert stack_decoded; @@ -1177,9 +1964,10 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, } -int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out) +/* encrypt content using encryptOID algo */ +static int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, + byte* iv, int ivSz, byte* in, int inSz, + byte* out) { int ret; #ifndef NO_AES @@ -1198,7 +1986,10 @@ int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, case AES128CBCb: case AES192CBCb: case AES256CBCb: - if (ivSz != AES_BLOCK_SIZE) + if ( (encryptOID == AES128CBCb && keySz != 16 ) || + (encryptOID == AES192CBCb && keySz != 24 ) || + (encryptOID == AES256CBCb && keySz != 32 ) || + (ivSz != AES_BLOCK_SIZE) ) return BAD_FUNC_ARG; ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION); @@ -1237,9 +2028,10 @@ int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, } -int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out) +/* decrypt content using encryptOID algo */ +static int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, + byte* iv, int ivSz, byte* in, int inSz, + byte* out) { int ret; #ifndef NO_AES @@ -1258,7 +2050,10 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, case AES128CBCb: case AES192CBCb: case AES256CBCb: - if (ivSz != AES_BLOCK_SIZE) + if ( (encryptOID == AES128CBCb && keySz != 16 ) || + (encryptOID == AES192CBCb && keySz != 24 ) || + (encryptOID == AES256CBCb && keySz != 32 ) || + (ivSz != AES_BLOCK_SIZE) ) return BAD_FUNC_ARG; ret = wc_AesSetKey(&aes, key, keySz, iv, AES_DECRYPTION); @@ -1296,11 +2091,85 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, } +/* generate random IV, place in iv, return 0 on success negative on error */ +static int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) +{ + int ret; + WC_RNG* random = NULL; + + if (iv == NULL || ivSz == 0) + return BAD_FUNC_ARG; + + /* input RNG is optional, init local one if input rng is NULL */ + if (rng == NULL) { + random = XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG); + if (random == NULL) + return MEMORY_E; + + ret = wc_InitRng(random); + if (ret != 0) + return ret; + + } else { + random = rng; + } + + ret = wc_RNG_GenerateBlock(random, iv, ivSz); + + if (rng == NULL) { + wc_FreeRng(random); + XFREE(random, NULL, DYNAMIC_TYPE_RNG); + } + + return ret; +} + + +/* return size of padded data, padded to blockSz chunks, or negative on error */ +static int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) +{ + int padSz; + + if (blockSz == 0) + return BAD_FUNC_ARG; + + padSz = blockSz - (inputSz % blockSz); + + return padSz; +} + + +/* pad input data to blockSz chunk, place in outSz. out must be big enough + * for input + pad bytes. See wc_PKCS7_GetPadLength() helper. */ +static int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, + word32 blockSz) +{ + int i, padSz; + + if (in == NULL || inSz == 0 || + out == NULL || outSz == 0) + return BAD_FUNC_ARG; + + padSz = blockSz - (inSz % blockSz); + + if (outSz < (inSz + padSz)) + return BAD_FUNC_ARG; + + XMEMCPY(out, in, inSz); + + for (i = 0; i < padSz; i++) { + out[inSz + i] = (byte)padSz; + } + + return inSz + padSz; +} + + /* build PKCS#7 envelopedData content type, return enveloped size */ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) { - int i, ret, idx = 0; - int totalSz, padSz, desOutSz; + int ret, idx = 0; + int totalSz, padSz, encryptedOutSz; int contentInfoSeqSz, outerContentTypeSz, outerContentSz; byte contentInfoSeq[MAX_SEQ_SZ]; @@ -1340,50 +2209,30 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) byte encContentOctet[MAX_OCTET_STR_SZ]; if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || - pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL) + pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL || + pkcs7->publicKeyOID == 0) return BAD_FUNC_ARG; if (output == NULL || outputSz == 0) return BAD_FUNC_ARG; - /* wolfCrypt PKCS#7 supports AES-128/192/256-CBC, DES, 3DES for now */ - switch (pkcs7->encryptOID) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - blockSz = AES_BLOCK_SIZE; - break; + blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); + if (blockKeySz < 0) + return blockKeySz; - case AES192CBCb: - blockKeySz = 24; - blockSz = AES_BLOCK_SIZE; - break; - - case AES256CBCb: - blockKeySz = 32; - blockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - blockSz = DES_BLOCK_SIZE; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - blockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; + blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); + if (blockSz < 0) + return blockSz; /* outer content type */ outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType); /* version, defined as 0 in RFC 2315 */ - verSz = SetMyVersion(0, ver, 0); + if (pkcs7->publicKeyOID == ECDSAk) { + verSz = SetMyVersion(2, ver, 0); + } else { + verSz = SetMyVersion(0, ver, 0); + } /* generate random content encryption key */ ret = wc_InitRng(&rng); @@ -1397,46 +2246,67 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) } #ifdef WOLFSSL_SMALL_STACK - recip = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); - contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); + recip = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_PKCS7); + contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_PKCS7); if (contentKeyEnc == NULL || recip == NULL) { - if (recip) XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (recip) XFREE(recip, NULL, DYNAMIC_TYPE_PKCS7); + if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_PKCS7); wc_FreeRng(&rng); return MEMORY_E; } - #endif + contentKeyEncSz = MAX_ENCRYPTED_KEY_SZ; /* build RecipientInfo, only handle 1 for now */ - recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk, - blockKeySz, &rng, contentKeyPlain, - contentKeyEnc, &contentKeyEncSz, recip, - MAX_RECIP_SZ, pkcs7->heap); - + switch (pkcs7->publicKeyOID) { + + case RSAk: + recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, + pkcs7->singleCertSz, + pkcs7->publicKeyOID, + blockKeySz, &rng, contentKeyPlain, + contentKeyEnc, &contentKeyEncSz, recip, + MAX_RECIP_SZ, pkcs7->heap); + break; + + case ECDSAk: + recipSz = wc_CreateKeyAgreeRecipientInfo(pkcs7, pkcs7->singleCert, + pkcs7->singleCertSz, + pkcs7->publicKeyOID, + blockKeySz, pkcs7->keyWrapOID, + pkcs7->keyAgreeOID, &rng, + contentKeyPlain, contentKeyEnc, + &contentKeyEncSz, recip, MAX_RECIP_SZ); + break; + + default: + WOLFSSL_MSG("Unsupported RecipientInfo public key type"); + return BAD_FUNC_ARG; + }; + ForceZero(contentKeyEnc, MAX_ENCRYPTED_KEY_SZ); - + #ifdef WOLFSSL_SMALL_STACK - XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_PKCS7); #endif if (recipSz < 0) { WOLFSSL_MSG("Failed to create RecipientInfo"); wc_FreeRng(&rng); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return recipSz; } recipSetSz = SetSet(recipSz, recipSet); /* generate IV for block cipher */ - ret = wc_RNG_GenerateBlock(&rng, tmpIv, blockSz); + ret = wc_PKCS7_GenerateIV(&rng, tmpIv, blockSz); wc_FreeRng(&rng); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return ret; } @@ -1445,34 +2315,36 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); if (contentTypeSz == 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BAD_FUNC_ARG; } /* allocate encrypted content buffer and PKCS#7 padding */ - padSz = blockSz - (pkcs7->contentSz % blockSz); - desOutSz = pkcs7->contentSz + padSz; + padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz); + if (padSz < 0) + return padSz; - plain = (byte*)XMALLOC(desOutSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (plain == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif + encryptedOutSz = pkcs7->contentSz + padSz; + + plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (plain == NULL) return MEMORY_E; - } - XMEMCPY(plain, pkcs7->content, pkcs7->contentSz); - for (i = 0; i < padSz; i++) { - plain[pkcs7->contentSz + i] = (byte)padSz; + ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, + encryptedOutSz, blockSz); + if (ret < 0) { + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ret; } - encryptedContent = (byte*)XMALLOC(desOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } @@ -1486,38 +2358,40 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) oidBlkType, ivOctetStringSz + blockSz); if (contentEncAlgoSz == 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMIC_TYPE_PKCS7); #endif return BAD_FUNC_ARG; } /* encrypt content */ ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, contentKeyPlain, - blockKeySz, tmpIv, blockSz, plain, desOutSz, encryptedContent); + blockKeySz, tmpIv, blockSz, plain, encryptedOutSz, + encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMIC_TYPE_PKCS7); #endif return ret; } - encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, - desOutSz, encContentOctet); + encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz, + encContentOctet); encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + ivOctetStringSz + blockSz + - encContentOctetSz + desOutSz, encContentSeq); + encContentOctetSz + encryptedOutSz, + encContentSeq); /* keep track of sizes for outer wrapper layering */ totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + ivOctetStringSz + blockSz + - encContentOctetSz + desOutSz; + encContentOctetSz + encryptedOutSz; /* EnvelopedData */ envDataSeqSz = SetSequence(totalSz, envDataSeq); @@ -1534,10 +2408,10 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (totalSz > (int)outputSz) { WOLFSSL_MSG("Pkcs7_encrypt output buffer too small"); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return BUFFER_E; } @@ -1568,35 +2442,37 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) idx += blockSz; XMEMCPY(output + idx, encContentOctet, encContentOctetSz); idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, desOutSz); - idx += desOutSz; + XMEMCPY(output + idx, encryptedContent, encryptedOutSz); + idx += encryptedOutSz; ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER); #endif return idx; } -/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ -WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, - word32 pkiMsgSz, byte* output, - word32 outputSz) -{ - int recipFound = 0; - int ret, version, length; - word32 savedIdx = 0, idx = 0; - word32 contentType, encOID; - byte issuerHash[SHA_DIGEST_SIZE]; - int encryptedKeySz, keySz, expBlockSz, blockKeySz; - byte tmpIv[MAX_CONTENT_IV_SIZE]; - byte* decryptedKey = NULL; +/* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */ +static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + word32* idx, byte* decryptedKey, + word32* decryptedKeySz, int* recipFound) +{ + int length, encryptedKeySz, ret; + int keySz; + word32 encOID; + word32 keyIdx; + byte issuerHash[SHA_DIGEST_SIZE]; + byte* outKey = NULL; + +#ifdef WC_RSA_BLINDING + WC_RNG rng; +#endif #ifdef WOLFSSL_SMALL_STACK mp_int* serialNum; @@ -1606,16 +2482,575 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, mp_int stack_serialNum; mp_int* serialNum = &stack_serialNum; byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; - + RsaKey stack_privKey; RsaKey* privKey = &stack_privKey; #endif + + /* remove IssuerAndSerialNumber */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetNameHash(pkiMsg, idx, issuerHash, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* if we found correct recipient, issuer hashes will match */ + if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { + *recipFound = 1; + } + +#ifdef WOLFSSL_SMALL_STACK + serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (serialNum == NULL) + return MEMORY_E; +#endif + + if (GetInt(serialNum, pkiMsg, idx, pkiMsgSz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + mp_clear(serialNum); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* key encryption algorithm must be RSA for now */ + if (encOID != RSAk) + return ALGO_ID_E; + + /* read encryptedKey */ +#ifdef WOLFSSL_SMALL_STACK + encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encryptedKey == NULL) + return MEMORY_E; +#endif + + if (pkiMsg[(*idx)++] != ASN_OCTET_STRING) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (GetLength(pkiMsg, idx, &encryptedKeySz, pkiMsgSz) < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ASN_PARSE_E; + } + + if (*recipFound == 1) + XMEMCPY(encryptedKey, &pkiMsg[*idx], encryptedKeySz); + *idx += encryptedKeySz; + + /* load private key */ +#ifdef WOLFSSL_SMALL_STACK + privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (privKey == NULL) { + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + ret = wc_InitRsaKey(privKey, 0); + if (ret != 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + keyIdx = 0; + ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &keyIdx, privKey, + pkcs7->privateKeySz); + if (ret != 0) { + WOLFSSL_MSG("Failed to decode RSA private key"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + /* decrypt encryptedKey */ + #ifdef WC_RSA_BLINDING + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_RsaSetRNG(privKey, &rng); + } + #endif + if (ret == 0) { + keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, + &outKey, privKey); + #ifdef WC_RSA_BLINDING + wc_FreeRng(&rng); + #endif + } else { + keySz = ret; + } + wc_FreeRsaKey(privKey); + + if (keySz <= 0 || outKey == NULL) { + ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return keySz; + } else { + *decryptedKeySz = keySz; + XMEMCPY(decryptedKey, outKey, keySz); + ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return 0; +} + + +/* remove ASN.1 OriginatorIdentifierOrKey, return 0 on success, <0 on error */ +static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx) +{ + int ret, length; + word32 keyOID; + + if (kari == NULL || pkiMsg == NULL || idx == NULL) + return BAD_FUNC_ARG; + + /* remove OriginatorIdentifierOrKey */ + if (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { + (*idx)++; + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + } else { + return ASN_PARSE_E; + } + + /* remove OriginatorPublicKey */ + if (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + (*idx)++; + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + } else { + return ASN_PARSE_E; + } + + /* remove AlgorithmIdentifier */ + if (GetAlgoId(pkiMsg, idx, &keyOID, oidKeyType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (keyOID != ECDSAk) + return ASN_PARSE_E; + + /* remove ECPoint BIT STRING */ + if ((pkiMsgSz > (*idx + 1)) && (pkiMsg[(*idx)++] != ASN_BIT_STRING)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if ((pkiMsgSz < (*idx + 1)) || (pkiMsg[(*idx)++] != 0x00)) + return ASN_EXPECT_0_E; + + /* get sender ephemeral public ECDSA key */ + ret = wc_ecc_init(kari->senderKey); + if (ret != 0) + return ret; + + /* length-1 for unused bits counter */ + ret = wc_ecc_import_x963(pkiMsg + (*idx), length - 1, kari->senderKey); + if (ret != 0) + return ret; + + (*idx) += length - 1; + + return 0; +} + + +/* remove optional UserKeyingMaterial if available, return 0 on success, + * < 0 on error */ +static int wc_PKCS7_KariGetUserKeyingMaterial(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx) +{ + int length; + word32 savedIdx; + + if (kari == NULL || pkiMsg == NULL || idx == NULL) + return BAD_FUNC_ARG; + + savedIdx = *idx; + + /* starts with EXPLICIT [1] */ + if (pkiMsg[(*idx)++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + *idx = savedIdx; + return 0; + } + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) { + *idx = savedIdx; + return 0; + } + + /* get OCTET STRING */ + if ( (pkiMsgSz > ((*idx) + 1)) && + (pkiMsg[(*idx)++] != ASN_OCTET_STRING) ) { + *idx = savedIdx; + return 0; + } + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) { + *idx = savedIdx; + return 0; + } + + kari->ukm = (byte*)XMALLOC(length, kari->heap, DYNAMIC_TYPE_PKCS7); + if (kari->ukm == NULL) + return MEMORY_E; + + XMEMCPY(kari->ukm, pkiMsg + (*idx), length); + (*idx) += length; + kari->ukmSz = length; + kari->ukmOwner = 1; + + return 0; +} + + +/* remove ASN.1 KeyEncryptionAlgorithmIdentifier, return 0 on success, + * < 0 on error */ +static int wc_PKCS7_KariGetKeyEncryptionAlgorithmId(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx, + word32* keyAgreeOID, word32* keyWrapOID) +{ + if (kari == NULL || pkiMsg == NULL || idx == NULL || + keyAgreeOID == NULL || keyWrapOID == NULL) + return BAD_FUNC_ARG; + + /* remove KeyEncryptionAlgorithmIdentifier */ + if (GetAlgoId(pkiMsg, idx, keyAgreeOID, oidCmsKeyAgreeType, + pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove KeyWrapAlgorithm, stored in parameter of KeyEncAlgoId */ + if (GetAlgoId(pkiMsg, idx, keyWrapOID, oidKeyWrapType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + return 0; +} + + +/* remove ASN.1 RecipientEncryptedKeys, return 0 on success, < 0 on error */ +static int wc_PKCS7_KariGetRecipientEncryptedKeys(WC_PKCS7_KARI* kari, + byte* pkiMsg, word32 pkiMsgSz, word32* idx, + int* recipFound, byte* encryptedKey, + int* encryptedKeySz) +{ + int length; + byte subjKeyId[KEYID_SIZE]; + + if (kari == NULL || pkiMsg == NULL || idx == NULL || + recipFound == NULL || encryptedKey == NULL) + return BAD_FUNC_ARG; + + /* remove RecipientEncryptedKeys */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove RecipientEncryptedKeys */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove RecipientKeyIdentifier IMPLICIT [0] */ + if ( (pkiMsgSz > (*idx + 1)) && + (pkiMsg[(*idx)++] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) ) { + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + } else { + return ASN_PARSE_E; + } + + /* remove SubjectKeyIdentifier */ + if ( (pkiMsgSz > (*idx + 1)) && + (pkiMsg[(*idx)++] != ASN_OCTET_STRING) ) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (length != KEYID_SIZE) + return ASN_PARSE_E; + + XMEMCPY(subjKeyId, pkiMsg + (*idx), KEYID_SIZE); + (*idx) += length; + + /* subject key id should match if recipient found */ + if (XMEMCMP(subjKeyId, kari->decoded->extSubjKeyId, KEYID_SIZE) == 0) { + *recipFound = 1; + } + + /* remove EncryptedKey */ + if ( (pkiMsgSz > (*idx + 1)) && + (pkiMsg[(*idx)++] != ASN_OCTET_STRING) ) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* put encrypted CEK in decryptedKey buffer for now, decrypt later */ + if (length > *encryptedKeySz) + return BUFFER_E; + + XMEMCPY(encryptedKey, pkiMsg + (*idx), length); + *encryptedKeySz = length; + (*idx) += length; + + return 0; +} + + +/* decode ASN.1 KeyAgreeRecipientInfo (kari), return 0 on success, + * < 0 on error */ +static int wc_PKCS7_DecodeKari(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + word32* idx, byte* decryptedKey, + word32* decryptedKeySz, int* recipFound) +{ + int ret, keySz; + int encryptedKeySz; + word32 keyAgreeOID, keyWrapOID; + +#ifdef WOLFSSL_SMALL_STACK + byte* encryptedKey; +#else + byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; +#endif + + WC_PKCS7_KARI* kari; + + if (pkcs7 == NULL || pkcs7->singleCert == NULL || + pkcs7->singleCertSz == 0 || pkiMsg == NULL || + idx == NULL || decryptedKey == NULL || decryptedKeySz == NULL) { + return BAD_FUNC_ARG; + } + + kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_DECODE); + if (kari == NULL) + return MEMORY_E; + +#ifdef WOLFSSL_SMALL_STACK + encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_PKCS7); + if (encryptedKey == NULL) { + wc_PKCS7_KariFree(kari); + return MEMORY_E; + } +#endif + encryptedKeySz = MAX_ENCRYPTED_KEY_SZ; + + /* parse cert and key */ + ret = wc_PKCS7_KariParseRecipCert(kari, (byte*)pkcs7->singleCert, + pkcs7->singleCertSz, pkcs7->privateKey, + pkcs7->privateKeySz); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + return ret; + } + + /* remove OriginatorIdentifierOrKey */ + ret = wc_PKCS7_KariGetOriginatorIdentifierOrKey(kari, pkiMsg, + pkiMsgSz, idx); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* try and remove optional UserKeyingMaterial */ + ret = wc_PKCS7_KariGetUserKeyingMaterial(kari, pkiMsg, pkiMsgSz, idx); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* remove KeyEncryptionAlgorithmIdentifier */ + ret = wc_PKCS7_KariGetKeyEncryptionAlgorithmId(kari, pkiMsg, pkiMsgSz, + idx, &keyAgreeOID, + &keyWrapOID); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* remove RecipientEncryptedKeys */ + ret = wc_PKCS7_KariGetRecipientEncryptedKeys(kari, pkiMsg, pkiMsgSz, + idx, recipFound, encryptedKey, &encryptedKeySz); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* create KEK */ + ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, pkcs7->keyAgreeOID); + if (ret != 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return ret; + } + + /* decrypt CEK with KEK */ + keySz = wc_PKCS7_KariKeyWrap(encryptedKey, encryptedKeySz, kari->kek, + kari->kekSz, decryptedKey, *decryptedKeySz, + keyWrapOID, AES_DECRYPTION); + if (keySz <= 0) { + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + return keySz; + } + *decryptedKeySz = (word32)keySz; + + wc_PKCS7_KariFree(kari); + #ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + #endif + + return 0; +} + + +/* decode ASN.1 RecipientInfos SET, return 0 on success, < 0 on error */ +static int wc_PKCS7_DecodeRecipientInfos(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, word32* idx, byte* decryptedKey, + word32* decryptedKeySz, int* recipFound) +{ + word32 savedIdx; + int version, ret, length; + + if (pkcs7 == NULL || pkiMsg == NULL || idx == NULL || + decryptedKey == NULL || decryptedKeySz == NULL || + recipFound == NULL) { + return BAD_FUNC_ARG; + } + + savedIdx = *idx; + + /* when looking for next recipient, use first sequence and version to + * indicate there is another, if not, move on */ + while(*recipFound == 0) { + + /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to + * last good saved one */ + if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) > 0) { + + if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) { + *idx = savedIdx; + break; + } + + if (version != 0) + return ASN_VERSION_E; + + /* found ktri */ + ret = wc_PKCS7_DecodeKtri(pkcs7, pkiMsg, pkiMsgSz, idx, + decryptedKey, decryptedKeySz, + recipFound); + if (ret != 0) + return ret; + } + else { + /* kari is IMPLICIT[1] */ + *idx = savedIdx; + if (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { + (*idx)++; + + if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) { + *idx = savedIdx; + break; + } + + if (version != 3) + return ASN_VERSION_E; + + /* found kari */ + ret = wc_PKCS7_DecodeKari(pkcs7, pkiMsg, pkiMsgSz, idx, + decryptedKey, decryptedKeySz, + recipFound); + if (ret != 0) + return ret; + } + else { + /* failed to find RecipientInfo, restore idx and continue */ + *idx = savedIdx; + break; + } + } + + /* update good idx */ + savedIdx = *idx; + } + + return 0; +} + + +/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ +WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, byte* output, + word32 outputSz) +{ + int recipFound = 0; + int ret, version, length; + word32 idx = 0; + word32 contentType, encOID; + word32 decryptedKeySz; + + int expBlockSz, blockKeySz; + byte tmpIv[MAX_CONTENT_IV_SIZE]; + +#ifdef WOLFSSL_SMALL_STACK + byte* decryptedKey; +#else + byte decryptedKey[MAX_ENCRYPTED_KEY_SZ]; +#endif int encryptedContentSz; byte padLen; byte* encryptedContent = NULL; -#ifdef WC_RSA_BLINDING - WC_RNG rng; -#endif if (pkcs7 == NULL || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || @@ -1651,7 +3086,9 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) return ASN_PARSE_E; - if (version != 0) { + /* TODO :: make this more accurate */ + if ((pkcs7->publicKeyOID == RSAk && version != 0) || + (pkcs7->publicKeyOID == ECDSAk && version != 2)) { WOLFSSL_MSG("PKCS#7 envelopedData needs to be of version 0"); return ASN_VERSION_E; } @@ -1661,123 +3098,27 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, return ASN_PARSE_E; #ifdef WOLFSSL_SMALL_STACK - encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (encryptedKey == NULL) + decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL, + DYNAMIC_TYPE_PKCS7); + if (decryptedKey == NULL) return MEMORY_E; #endif - - savedIdx = idx; - recipFound = 0; + decryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - /* when looking for next recipient, use first sequence and version to - * indicate there is another, if not, move on */ - while(recipFound == 0) { - - /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to - * last good saved one */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { - idx = savedIdx; - break; - } - - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) { - idx = savedIdx; - break; - } - - if (version != 0) { + ret = wc_PKCS7_DecodeRecipientInfos(pkcs7, pkiMsg, pkiMsgSz, &idx, + decryptedKey, &decryptedKeySz, + &recipFound); + if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif - return ASN_VERSION_E; - } - - /* remove IssuerAndSerialNumber */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - /* if we found correct recipient, issuer hashes will match */ - if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { - recipFound = 1; - } - -#ifdef WOLFSSL_SMALL_STACK - serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (serialNum == NULL) { - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - if (GetInt(serialNum, pkiMsg, &idx, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - mp_clear(serialNum); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (GetAlgoId(pkiMsg, &idx, &encOID, oidKeyType, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - /* key encryption algorithm must be RSA for now */ - if (encOID != RSAk) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ALGO_ID_E; - } - - /* read encryptedKey */ - if (pkiMsg[idx++] != ASN_OCTET_STRING) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (recipFound == 1) - XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz); - idx += encryptedKeySz; - - /* update good idx */ - savedIdx = idx; + return ret; } if (recipFound == 0) { WOLFSSL_MSG("No recipient found in envelopedData that matches input"); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return PKCS7_RECIP_E; } @@ -1785,69 +3126,48 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, /* remove EncryptedContentInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } - /* wolfCrypt PKCS#7 supports AES-128-CBC, DES, 3DES for now */ - switch(encOID) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - expBlockSz = AES_BLOCK_SIZE; - break; + blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); + if (blockKeySz < 0) { + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + return blockKeySz; + } - case AES192CBCb: - blockKeySz = 24; - expBlockSz = AES_BLOCK_SIZE; - break; - - case AES256CBCb: - blockKeySz = 32; - expBlockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - expBlockSz = DES_BLOCK_SIZE; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - expBlockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; + expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); + if (expBlockSz < 0) { + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); + return expBlockSz; + } /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } @@ -1855,7 +3175,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, if (length != expBlockSz) { WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } @@ -1866,101 +3186,37 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, /* read encryptedContent, cont[0] */ if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ASN_PARSE_E; } encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) { #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return MEMORY_E; } XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - /* load private key */ -#ifdef WOLFSSL_SMALL_STACK - privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) { - XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - ret = wc_InitRsaKey(privKey, 0); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - idx = 0; - - ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey, - pkcs7->privateKeySz); - if (ret != 0) { - WOLFSSL_MSG("Failed to decode RSA private key"); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* decrypt encryptedKey */ - #ifdef WC_RSA_BLINDING - ret = wc_InitRng(&rng); - if (ret == 0) { - ret = wc_RsaSetRNG(privKey, &rng); - } - #endif - if (ret == 0) { - keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, - &decryptedKey, privKey); - #ifdef WC_RSA_BLINDING - wc_FreeRng(&rng); - #endif - } else { - keySz = ret; - } - wc_FreeRsaKey(privKey); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (keySz <= 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return keySz; - } - /* decrypt encryptedContent */ ret = wc_PKCS7_DecryptContent(encOID, decryptedKey, blockKeySz, tmpIv, expBlockSz, encryptedContent, encryptedContentSz, encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return ret; } @@ -1971,17 +3227,478 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* free memory, zero out keys */ - ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); #endif return encryptedContentSz - padLen; } +/* build PKCS#7 encryptedData content type, return encrypted size */ +int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) +{ + int ret, idx = 0; + int totalSz, padSz, encryptedOutSz; + + int contentInfoSeqSz, outerContentTypeSz, outerContentSz; + byte contentInfoSeq[MAX_SEQ_SZ]; + byte outerContentType[MAX_ALGO_SZ]; + byte outerContent[MAX_SEQ_SZ]; + + int encDataSeqSz, verSz, blockSz; + byte encDataSeq[MAX_SEQ_SZ]; + byte ver[MAX_VERSION_SZ]; + + byte* plain = NULL; + byte* encryptedContent = NULL; + + int encContentOctetSz, encContentSeqSz, contentTypeSz; + int contentEncAlgoSz, ivOctetStringSz; + byte encContentSeq[MAX_SEQ_SZ]; + byte contentType[MAX_ALGO_SZ]; + byte contentEncAlgo[MAX_ALGO_SZ]; + byte tmpIv[MAX_CONTENT_IV_SIZE]; + byte ivOctetString[MAX_OCTET_STR_SZ]; + byte encContentOctet[MAX_OCTET_STR_SZ]; + + byte attribSet[MAX_SET_SZ]; + EncodedAttrib* attribs = NULL; + word32 attribsSz; + word32 attribsCount; + word32 attribsSetSz; + + byte* flatAttribs = NULL; + + if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || + pkcs7->encryptOID == 0 || pkcs7->encryptionKey == NULL || + pkcs7->encryptionKeySz == 0) + return BAD_FUNC_ARG; + + if (output == NULL || outputSz == 0) + return BAD_FUNC_ARG; + + /* outer content type */ + outerContentTypeSz = wc_SetContentType(ENCRYPTED_DATA, outerContentType); + + /* version, 2 if unprotectedAttrs present, 0 if absent */ + if (pkcs7->unprotectedAttribsSz > 0) { + verSz = SetMyVersion(2, ver, 0); + } else { + verSz = SetMyVersion(0, ver, 0); + } + + /* EncryptedContentInfo */ + contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); + if (contentTypeSz == 0) + return BAD_FUNC_ARG; + + /* allocate encrypted content buffer, do PKCS#7 padding */ + blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); + if (blockSz < 0) + return blockSz; + + padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz); + if (padSz < 0) + return padSz; + + encryptedOutSz = pkcs7->contentSz + padSz; + + plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (plain == NULL) + return MEMORY_E; + + ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, + encryptedOutSz, blockSz); + if (ret < 0) { + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (encryptedContent == NULL) { + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + + /* put together IV OCTET STRING */ + ivOctetStringSz = SetOctetString(blockSz, ivOctetString); + + /* build up ContentEncryptionAlgorithmIdentifier sequence, + adding (ivOctetStringSz + blockSz) for IV OCTET STRING */ + contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, + oidBlkType, ivOctetStringSz + blockSz); + if (contentEncAlgoSz == 0) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return BAD_FUNC_ARG; + } + + /* encrypt content */ + ret = wc_PKCS7_GenerateIV(NULL, tmpIv, blockSz); + if (ret != 0) + return ret; + + ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->encryptionKey, + pkcs7->encryptionKeySz, tmpIv, blockSz, plain, encryptedOutSz, + encryptedContent); + if (ret != 0) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, + encryptedOutSz, encContentOctet); + + encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + + ivOctetStringSz + blockSz + + encContentOctetSz + encryptedOutSz, + encContentSeq); + + /* optional UnprotectedAttributes */ + if (pkcs7->unprotectedAttribsSz != 0) { + + if (pkcs7->unprotectedAttribs == NULL) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return BAD_FUNC_ARG; + } + + attribs = (EncodedAttrib*)XMALLOC( + sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz, + pkcs7->heap, DYNAMIC_TYPE_PKCS); + if (attribs == NULL) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + + attribsCount = pkcs7->unprotectedAttribsSz; + attribsSz = EncodeAttributes(attribs, pkcs7->unprotectedAttribsSz, + pkcs7->unprotectedAttribs, + pkcs7->unprotectedAttribsSz); + + flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS); + if (flatAttribs == NULL) { + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + + FlattenAttributes(flatAttribs, attribs, attribsCount); + attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet); + + } else { + attribsSz = 0; + attribsSetSz = 0; + } + + /* keep track of sizes for outer wrapper layering */ + totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + + ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz + + attribsSz + attribsSetSz;; + + /* EncryptedData */ + encDataSeqSz = SetSequence(totalSz, encDataSeq); + totalSz += encDataSeqSz; + + /* outer content */ + outerContentSz = SetExplicit(0, totalSz, outerContent); + totalSz += outerContentTypeSz; + totalSz += outerContentSz; + + /* ContentInfo */ + contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); + totalSz += contentInfoSeqSz; + + if (totalSz > (int)outputSz) { + WOLFSSL_MSG("PKCS#7 output buffer too small"); + if (pkcs7->unprotectedAttribsSz != 0) { + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + } + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return BUFFER_E; + } + + XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz); + idx += contentInfoSeqSz; + XMEMCPY(output + idx, outerContentType, outerContentTypeSz); + idx += outerContentTypeSz; + XMEMCPY(output + idx, outerContent, outerContentSz); + idx += outerContentSz; + XMEMCPY(output + idx, encDataSeq, encDataSeqSz); + idx += encDataSeqSz; + XMEMCPY(output + idx, ver, verSz); + idx += verSz; + XMEMCPY(output + idx, encContentSeq, encContentSeqSz); + idx += encContentSeqSz; + XMEMCPY(output + idx, contentType, contentTypeSz); + idx += contentTypeSz; + XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz); + idx += contentEncAlgoSz; + XMEMCPY(output + idx, ivOctetString, ivOctetStringSz); + idx += ivOctetStringSz; + XMEMCPY(output + idx, tmpIv, blockSz); + idx += blockSz; + XMEMCPY(output + idx, encContentOctet, encContentOctetSz); + idx += encContentOctetSz; + XMEMCPY(output + idx, encryptedContent, encryptedOutSz); + idx += encryptedOutSz; + + if (pkcs7->unprotectedAttribsSz != 0) { + XMEMCPY(output + idx, attribSet, attribsSetSz); + idx += attribsSetSz; + XMEMCPY(output + idx, flatAttribs, attribsSz); + idx += attribsSz; + XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); + } + + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + + return idx; +} + + +/* decode and store unprotected attributes in PKCS7->decodedAttrib. Return + * 0 on success, negative on error. User must call wc_PKCS7_Free(). */ +static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, word32* inOutIdx) +{ + int length, attribLen; + word32 oid, savedIdx, idx; + PKCS7DecodedAttrib* attrib = NULL; + + if (pkcs7 == NULL || pkiMsg == NULL || + pkiMsgSz == 0 || inOutIdx == NULL) + return BAD_FUNC_ARG; + + idx = *inOutIdx; + + if (pkiMsg[idx] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) + return ASN_PARSE_E; + idx++; + + if (GetLength(pkiMsg, &idx, &attribLen, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* loop through attributes */ + while (attribLen > 0) { + + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + attribLen -= (length + 2); /* TAG + LENGTH + DATA */ + savedIdx = idx; + + attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib), + pkcs7->heap, DYNAMIC_TYPE_PKCS); + if (attrib == NULL) { + return MEMORY_E; + } + XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); + + /* save attribute OID bytes and size */ + if (GetObjectId(pkiMsg, &idx, &oid, oidIgnoreType, pkiMsgSz) < 0) { + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + return ASN_PARSE_E; + } + + attrib->oidSz = idx - savedIdx; + attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS); + if (attrib->oid == NULL) { + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + return MEMORY_E; + } + XMEMCPY(attrib->oid, pkiMsg + savedIdx, attrib->oidSz); + + /* save attribute value bytes and size */ + if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) { + return ASN_PARSE_E; + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + } + + if ((pkiMsgSz - idx) < (word32)length) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + return ASN_PARSE_E; + } + + attrib->valueSz = (word32)length; + attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS); + if (attrib->value == NULL) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS); + return MEMORY_E; + } + XMEMCPY(attrib->value, pkiMsg + idx, attrib->valueSz); + idx += length; + + /* store attribute in linked list */ + if (pkcs7->decodedAttrib != NULL) { + attrib->next = pkcs7->decodedAttrib; + pkcs7->decodedAttrib = attrib; + } else { + pkcs7->decodedAttrib = attrib; + } + } + + *inOutIdx = idx; + + return 0; +} + + +/* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */ +int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, + byte* output, word32 outputSz) +{ + int ret, version, length, haveAttribs; + word32 idx = 0; + word32 contentType, encOID; + + int expBlockSz; + byte tmpIv[MAX_CONTENT_IV_SIZE]; + + int encryptedContentSz; + byte padLen; + byte* encryptedContent = NULL; + + if (pkcs7 == NULL || pkcs7->encryptionKey == NULL || + pkcs7->encryptionKeySz == 0) + return BAD_FUNC_ARG; + + if (pkiMsg == NULL || pkiMsgSz == 0 || + output == NULL || outputSz == 0) + return BAD_FUNC_ARG; + + /* read past ContentInfo, verify type is encrypted-data */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (contentType != ENCRYPTED_DATA) { + WOLFSSL_MSG("PKCS#7 input not of type EncryptedData"); + return PKCS7_OID_E; + } + + if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove EncryptedData and version */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* get version, check later */ + haveAttribs = 0; + if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) + return ASN_PARSE_E; + + /* remove EncryptedContentInfo */ + if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) + return ASN_PARSE_E; + + expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); + if (expBlockSz < 0) + return expBlockSz; + + /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ + if (pkiMsg[idx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) + return ASN_PARSE_E; + + if (length != expBlockSz) { + WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); + return ASN_PARSE_E; + } + + XMEMCPY(tmpIv, &pkiMsg[idx], length); + idx += length; + + /* read encryptedContent, cont[0] */ + if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) + return ASN_PARSE_E; + + if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) + return ASN_PARSE_E; + + encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (encryptedContent == NULL) + return MEMORY_E; + + XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); + idx += encryptedContentSz; + + /* decrypt encryptedContent */ + ret = wc_PKCS7_DecryptContent(encOID, pkcs7->encryptionKey, + pkcs7->encryptionKeySz, tmpIv, expBlockSz, + encryptedContent, encryptedContentSz, + encryptedContent); + if (ret != 0) { + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ret; + } + + padLen = encryptedContent[encryptedContentSz-1]; + + /* copy plaintext to output */ + XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); + + /* get implicit[1] unprotected attributes, optional */ + pkcs7->decodedAttrib = NULL; + if (idx < pkiMsgSz) { + + haveAttribs = 1; + + ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg, + pkiMsgSz, &idx); + if (ret != 0) { + ForceZero(encryptedContent, encryptedContentSz); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ASN_PARSE_E; + } + } + + /* go back and check the version now that attribs have been processed */ + if ((haveAttribs == 0 && version != 0) || + (haveAttribs == 1 && version != 2) ) { + WOLFSSL_MSG("Wrong PKCS#7 EncryptedData version"); + return ASN_VERSION_E; + } + + ForceZero(encryptedContent, encryptedContentSz); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + + return encryptedContentSz - padLen; +} + #else /* HAVE_PKCS7 */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f8b38871a..e3f26f761 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -238,6 +238,7 @@ int pbkdf2_test(void); #ifdef HAVE_PKCS7 int pkcs7enveloped_test(void); int pkcs7signed_test(void); + int pkcs7encrypted_test(void); #endif #if defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_TEST_CERT) int certext_test(void); @@ -474,7 +475,6 @@ int wolfcrypt_test(void* args) else printf( "HMAC-KDF test passed!\n"); #endif - #endif #ifdef HAVE_X963_KDF @@ -708,6 +708,11 @@ int wolfcrypt_test(void* args) return err_sys("PKCS7signed test failed!\n", ret); else printf( "PKCS7signed test passed!\n"); + + if ( (ret = pkcs7encrypted_test()) != 0) + return err_sys("PKCS7encrypted test failed!\n", ret); + else + printf( "PKCS7encrypted test passed!\n"); #endif #if defined(USE_WOLFSSL_MEMORY) && defined(WOLFSSL_TRACK_MEMORY) @@ -4433,6 +4438,10 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #ifdef FREESCALE_MQX static const char* clientKey = "a:\\certs\\client-key.der"; static const char* clientCert = "a:\\certs\\client-cert.der"; + #ifdef HAVE_PKCS7 + static const char* eccClientKey = "a:\\certs\\ecc-client-key.der"; + static const char* eccClientCert = "a:\\certs\\client-ecc-cert.der"; + #endif #ifdef WOLFSSL_CERT_EXT static const char* clientKeyPub = "a:\\certs\\client-keyPub.der"; #endif @@ -4455,6 +4464,12 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) static char* clientCert = "certs/client-cert.der"; void set_clientKey(char *key) { clientKey = key ; } void set_clientCert(char *cert) { clientCert = cert ; } + #ifdef HAVE_PKCS7 + static const char* eccClientKey = "certs/ecc-client-key.der"; + static const char* eccClientCert = "certs/client-ecc-cert.der"; + void set_eccClientKey(char* key) { eccClientKey = key ; } + void set_eccClientCert(char* cert) { eccClientCert = cert ; } + #endif #ifdef WOLFSSL_CERT_EXT static const char* clientKeyPub = "certs/client-keyPub.der"; void set_clientKeyPub(char *key) { clientKeyPub = key ; } @@ -4482,6 +4497,10 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #else static const char* clientKey = "./certs/client-key.der"; static const char* clientCert = "./certs/client-cert.der"; + #ifdef HAVE_PKCS7 + static const char* eccClientKey = "./certs/ecc-client-key.der"; + static const char* eccClientCert = "./certs/client-ecc-cert.der"; + #endif #ifdef WOLFSSL_CERT_EXT static const char* clientKeyPub = "./certs/client-keyPub.der"; #endif @@ -9034,175 +9053,470 @@ int compress_test(void) #ifdef HAVE_PKCS7 +/* External Debugging/Testing Note: + * + * PKCS#7 test functions can output generated PKCS#7/CMS bundles for + * additional testing. To dump bundles to files DER encoded files, please + * define: + * + * #define PKCS7_OUTPUT_TEST_BUNDLES + */ + typedef struct { - const char* outFileName; - const byte* content; - word32 contentSz; - int contentOID; - int encryptOID; - byte* privateKey; - word32 privateKeySz; + const byte* content; + word32 contentSz; + int contentOID; + int encryptOID; + int keyWrapOID; + int keyAgreeOID; + byte* cert; + size_t certSz; + byte* privateKey; + word32 privateKeySz; + byte* optionalUkm; + word32 optionalUkmSz; + const char* outFileName; } pkcs7EnvelopedVector; -int pkcs7enveloped_test(void) + +static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, + byte* rsaPrivKey, word32 rsaPrivKeySz, + byte* eccCert, word32 eccCertSz, + byte* eccPrivKey, word32 eccPrivKeySz) { - int ret = 0; - + int ret, testSz, i; int envelopedSz, decodedSz; - PKCS7 pkcs7; - byte* cert; - byte* privKey; - byte enveloped[2048]; - byte decoded[2048]; - size_t certSz; - size_t privKeySz; - FILE* certFile; - FILE* keyFile; + byte enveloped[2048]; + byte decoded[2048]; + PKCS7 pkcs7; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES FILE* pkcs7File; +#endif const byte data[] = { /* Hello World */ 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f, 0x72,0x6c,0x64 }; - pkcs7EnvelopedVector a; -#ifndef NO_AES - pkcs7EnvelopedVector b, c, d; - pkcs7EnvelopedVector test_pkcs7env[4]; -#else - pkcs7EnvelopedVector test_pkcs7env[1]; -#endif - int times = sizeof(test_pkcs7env) / sizeof(pkcs7EnvelopedVector), i; + byte optionalUkm[] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 + }; - /* read client cert and key in DER format */ - cert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - if (cert == NULL) + const pkcs7EnvelopedVector testVectors[] = + { + /* key transport key encryption technique */ +#ifndef NO_RSA + {data, (word32)sizeof(data), DATA, DES3b, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataDES3.der"}, + + #ifndef NO_AES + {data, (word32)sizeof(data), DATA, AES128CBCb, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataAES128CBC.der"}, + + {data, (word32)sizeof(data), DATA, AES192CBCb, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataAES192CBC.der"}, + + {data, (word32)sizeof(data), DATA, AES256CBCb, 0, 0, rsaCert, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, NULL, 0, "pkcs7envelopedDataAES256CBC.der"}, + #endif /* NO_AES */ +#endif + + /* key agreement key encryption technique*/ +#ifdef HAVE_ECC + #ifndef NO_AES + #ifndef NO_SHA + {data, (word32)sizeof(data), DATA, AES128CBCb, AES128_WRAP, + dhSinglePass_stdDH_sha1kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, NULL, 0, + "pkcs7envelopedDataAES128CBC_ECDH_SHA1KDF.der"}, + #endif + + #ifndef NO_SHA256 + {data, (word32)sizeof(data), DATA, AES256CBCb, AES256_WRAP, + dhSinglePass_stdDH_sha256kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, NULL, 0, + "pkcs7envelopedDataAES256CBC_ECDH_SHA256KDF.der"}, + #endif /* NO_SHA256 */ + + #ifdef WOLFSSL_SHA512 + {data, (word32)sizeof(data), DATA, AES256CBCb, AES256_WRAP, + dhSinglePass_stdDH_sha512kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, NULL, 0, + "pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF.der"}, + + /* with optional user keying material (ukm) */ + {data, (word32)sizeof(data), DATA, AES256CBCb, AES256_WRAP, + dhSinglePass_stdDH_sha512kdf_scheme, eccCert, eccCertSz, eccPrivKey, + eccPrivKeySz, optionalUkm, sizeof(optionalUkm), + "pkcs7envelopedDataAES256CBC_ECDH_SHA512KDF_ukm.der"}, + #endif /* WOLFSSL_SHA512 */ + #endif /* NO_AES */ +#endif + }; + + testSz = sizeof(testVectors) / sizeof(pkcs7EnvelopedVector); + + for (i = 0; i < testSz; i++) { + + ret = wc_PKCS7_InitWithCert(&pkcs7, testVectors[i].cert, + (word32)testVectors[i].certSz); + if (ret != 0) + return -209; + + pkcs7.content = (byte*)testVectors[i].content; + pkcs7.contentSz = testVectors[i].contentSz; + pkcs7.contentOID = testVectors[i].contentOID; + pkcs7.encryptOID = testVectors[i].encryptOID; + pkcs7.keyWrapOID = testVectors[i].keyWrapOID; + pkcs7.keyAgreeOID = testVectors[i].keyAgreeOID; + pkcs7.privateKey = testVectors[i].privateKey; + pkcs7.privateKeySz = testVectors[i].privateKeySz; + pkcs7.ukm = testVectors[i].optionalUkm; + pkcs7.ukmSz = testVectors[i].optionalUkmSz; + + /* encode envelopedData */ + envelopedSz = wc_PKCS7_EncodeEnvelopedData(&pkcs7, enveloped, + sizeof(enveloped)); + if (envelopedSz <= 0) + return -210; + + /* decode envelopedData */ + decodedSz = wc_PKCS7_DecodeEnvelopedData(&pkcs7, enveloped, envelopedSz, + decoded, sizeof(decoded)); + if (decodedSz <= 0) + return -211; + + /* test decode result */ + if (XMEMCMP(decoded, data, sizeof(data)) != 0) + return -212; + +#ifdef PKCS7_OUTPUT_TEST_BUNDLES + /* output pkcs7 envelopedData for external testing */ + pkcs7File = fopen(testVectors[i].outFileName, "wb"); + if (!pkcs7File) + return -213; + + ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); + fclose(pkcs7File); +#endif /* PKCS7_OUTPUT_TEST_BUNDLES */ + + wc_PKCS7_Free(&pkcs7); + } + + return 0; +} + + +int pkcs7enveloped_test(void) +{ + int ret = 0; + + byte* rsaCert = NULL; + byte* eccCert = NULL; + byte* rsaPrivKey = NULL; + byte* eccPrivKey = NULL; + + size_t rsaCertSz = 0; + size_t eccCertSz = 0; + size_t rsaPrivKeySz = 0; + size_t eccPrivKeySz = 0; + + FILE* certFile; + FILE* keyFile; + +#ifndef NO_RSA + /* read client RSA cert and key in DER format */ + rsaCert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (rsaCert == NULL) return -201; - privKey =(byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + rsaPrivKey = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (rsaPrivKey == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); return -202; } certFile = fopen(clientCert, "rb"); if (!certFile) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); err_sys("can't open ./certs/client-cert.der, " "Please run from wolfSSL home dir", -42); - return -42; + return -203; } - certSz = fread(cert, 1, FOURK_BUF, certFile); + rsaCertSz = fread(rsaCert, 1, FOURK_BUF, certFile); fclose(certFile); keyFile = fopen(clientKey, "rb"); if (!keyFile) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); err_sys("can't open ./certs/client-key.der, " "Please run from wolfSSL home dir", -43); - return -43; + return -204; } - privKeySz = fread(privKey, 1, FOURK_BUF, keyFile); + rsaPrivKeySz = fread(rsaPrivKey, 1, FOURK_BUF, keyFile); fclose(keyFile); +#endif /* NO_RSA */ - wc_PKCS7_InitWithCert(&pkcs7, cert, (word32)certSz); +#ifdef HAVE_ECC + /* read client ECC cert and key in DER format */ + eccCert = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (eccCert == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return -205; + } - /* set up test vectors */ - a.content = data; - a.contentSz = (word32)sizeof(data); - a.contentOID = DATA; - a.encryptOID = DES3b; - a.privateKey = privKey; - a.privateKeySz = (word32)privKeySz; - a.outFileName = "pkcs7envelopedDataDES3.der"; + eccPrivKey =(byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (eccPrivKey == NULL) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return -206; + } -#ifndef NO_AES - b.content = data; - b.contentSz = (word32)sizeof(data); - b.contentOID = DATA; - b.encryptOID = AES128CBCb; - b.privateKey = privKey; - b.privateKeySz = (word32)privKeySz; - b.outFileName = "pkcs7envelopedDataAES128CBC.der"; + certFile = fopen(eccClientCert, "rb"); + if (!certFile) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + err_sys("can't open ./certs/client-ecc-cert.der, " + "Please run from wolfSSL home dir", -42); + return -207; + } - c.content = data; - c.contentSz = (word32)sizeof(data); - c.contentOID = DATA; - c.encryptOID = AES192CBCb; - c.privateKey = privKey; - c.privateKeySz = (word32)privKeySz; - c.outFileName = "pkcs7envelopedDataAES192CBC.der"; + eccCertSz = fread(eccCert, 1, FOURK_BUF, certFile); + fclose(certFile); - d.content = data; - d.contentSz = (word32)sizeof(data); - d.contentOID = DATA; - d.encryptOID = AES256CBCb; - d.privateKey = privKey; - d.privateKeySz = (word32)privKeySz; - d.outFileName = "pkcs7envelopedDataAES256CBC.der"; + keyFile = fopen(eccClientKey, "rb"); + if (!keyFile) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + err_sys("can't open ./certs/ecc-client-key.der, " + "Please run from wolfSSL home dir", -43); + return -208; + } + + eccPrivKeySz = fread(eccPrivKey, 1, FOURK_BUF, keyFile); + fclose(keyFile); +#endif /* HAVE_ECC */ + + ret = pkcs7enveloped_run_vectors(rsaCert, (word32)rsaCertSz, + rsaPrivKey, (word32)rsaPrivKeySz, + eccCert, (word32)eccCertSz, + eccPrivKey, (word32)eccPrivKeySz); + if (ret != 0) { + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + + return 0; +} + + +typedef struct { + const byte* content; + word32 contentSz; + int contentOID; + int encryptOID; + byte* encryptionKey; + word32 encryptionKeySz; + PKCS7Attrib* attribs; + word32 attribsSz; + const char* outFileName; +} pkcs7EncryptedVector; + + +int pkcs7encrypted_test(void) +{ + int ret = 0; + int i, testSz; + int encryptedSz, decodedSz, attribIdx; + PKCS7 pkcs7; + byte encrypted[2048]; + byte decoded[2048]; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES + FILE* pkcs7File; #endif - test_pkcs7env[0] = a; + PKCS7Attrib* expectedAttrib; + PKCS7DecodedAttrib* decodedAttrib; + + const byte data[] = { /* Hello World */ + 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f, + 0x72,0x6c,0x64 + }; + + byte desKey[] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef + }; + byte des3Key[] = { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 + }; + byte aes128Key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + byte aes192Key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + byte aes256Key[] = { + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, + 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08 + }; + + /* Attribute example from RFC 4134, Section 7.2 + * OID = 1.2.5555 + * OCTET STRING = 'This is a test General ASN Attribute, number 1.' */ + static byte genAttrOid[] = { 0x06, 0x03, 0x2a, 0xab, 0x33 }; + static byte genAttr[] = { 0x04, 47, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x41, + 0x53, 0x4e, 0x20, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x2c, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x31, 0x2e }; + + static byte genAttrOid2[] = { 0x06, 0x03, 0x2a, 0xab, 0x34 }; + static byte genAttr2[] = { 0x04, 47, + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x41, + 0x53, 0x4e, 0x20, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x2c, 0x20, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x20, 0x32, 0x2e }; + + PKCS7Attrib attribs[] = + { + { genAttrOid, sizeof(genAttrOid), genAttr, sizeof(genAttr) } + }; + + PKCS7Attrib multiAttribs[] = + { + { genAttrOid, sizeof(genAttrOid), genAttr, sizeof(genAttr) }, + { genAttrOid2, sizeof(genAttrOid2), genAttr2, sizeof(genAttr2) } + }; + + const pkcs7EncryptedVector testVectors[] = + { +#ifndef NO_DES3 + {data, (word32)sizeof(data), DATA, DES3b, des3Key, sizeof(des3Key), + NULL, 0, "pkcs7encryptedDataDES3.der"}, + + {data, (word32)sizeof(data), DATA, DESb, desKey, sizeof(desKey), + NULL, 0, "pkcs7encryptedDataDES.der"}, +#endif /* NO_DES3 */ + #ifndef NO_AES - test_pkcs7env[1] = b; - test_pkcs7env[2] = c; - test_pkcs7env[3] = d; -#endif + {data, (word32)sizeof(data), DATA, AES128CBCb, aes128Key, + sizeof(aes128Key), NULL, 0, "pkcs7encryptedDataAES128CBC.der"}, - for (i = 0; i < times; i++) { - pkcs7.content = (byte*)test_pkcs7env[i].content; - pkcs7.contentSz = test_pkcs7env[i].contentSz; - pkcs7.contentOID = test_pkcs7env[i].contentOID; - pkcs7.encryptOID = test_pkcs7env[i].encryptOID; - pkcs7.privateKey = test_pkcs7env[i].privateKey; - pkcs7.privateKeySz = test_pkcs7env[i].privateKeySz; + {data, (word32)sizeof(data), DATA, AES192CBCb, aes192Key, + sizeof(aes192Key), NULL, 0, "pkcs7encryptedDataAES192CBC.der"}, - /* encode envelopedData */ - envelopedSz = wc_PKCS7_EncodeEnvelopedData(&pkcs7, enveloped, - sizeof(enveloped)); - if (envelopedSz <= 0) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - printf("envelopedSz = %d\n", envelopedSz); + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), NULL, 0, "pkcs7encryptedDataAES256CBC.der"}, + + /* test with optional unprotected attributes */ + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7encryptedDataAES256CBC_attribs.der"}, + + /* test with multiple optional unprotected attributes */ + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), multiAttribs, + (sizeof(multiAttribs)/sizeof(PKCS7Attrib)), + "pkcs7encryptedDataAES256CBC_multi_attribs.der"}, +#endif /* NO_AES */ + }; + + testSz = sizeof(testVectors) / sizeof(pkcs7EncryptedVector); + + for (i = 0; i < testSz; i++) { + pkcs7.content = (byte*)testVectors[i].content; + pkcs7.contentSz = testVectors[i].contentSz; + pkcs7.contentOID = testVectors[i].contentOID; + pkcs7.encryptOID = testVectors[i].encryptOID; + pkcs7.encryptionKey = testVectors[i].encryptionKey; + pkcs7.encryptionKeySz = testVectors[i].encryptionKeySz; + pkcs7.unprotectedAttribs = testVectors[i].attribs; + pkcs7.unprotectedAttribsSz = testVectors[i].attribsSz; + + /* encode encryptedData */ + encryptedSz = wc_PKCS7_EncodeEncryptedData(&pkcs7, encrypted, + sizeof(encrypted)); + if (encryptedSz <= 0) return -203; - } - /* decode envelopedData */ - decodedSz = wc_PKCS7_DecodeEnvelopedData(&pkcs7, enveloped, envelopedSz, - decoded, sizeof(decoded)); - if (decodedSz <= 0) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + /* decode encryptedData */ + decodedSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, encrypted, encryptedSz, + decoded, sizeof(decoded)); + if (decodedSz <= 0) return -204; - } /* test decode result */ - if (XMEMCMP(decoded, data, sizeof(data)) != 0) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (XMEMCMP(decoded, data, sizeof(data)) != 0) return -205; + + /* verify decoded unprotected attributes */ + if (pkcs7.decodedAttrib != NULL) { + decodedAttrib = pkcs7.decodedAttrib; + attribIdx = 1; + + while (decodedAttrib != NULL) { + + /* expected attribute, stored list is reversed */ + expectedAttrib = &(pkcs7.unprotectedAttribs + [pkcs7.unprotectedAttribsSz - attribIdx]); + + /* verify oid */ + if (XMEMCMP(decodedAttrib->oid, expectedAttrib->oid, + decodedAttrib->oidSz) != 0) + return -206; + + /* verify value */ + if (XMEMCMP(decodedAttrib->value, expectedAttrib->value, + decodedAttrib->valueSz) != 0) + return -207; + + decodedAttrib = decodedAttrib->next; + attribIdx++; + } } +#ifdef PKCS7_OUTPUT_TEST_BUNDLES /* output pkcs7 envelopedData for external testing */ - pkcs7File = fopen(test_pkcs7env[i].outFileName, "wb"); - if (!pkcs7File) { - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - return -206; - } + pkcs7File = fopen(testVectors[i].outFileName, "wb"); + if (!pkcs7File) + return -208; - ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); + ret = (int)fwrite(encrypted, encryptedSz, 1, pkcs7File); fclose(pkcs7File); - } +#endif - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - wc_PKCS7_Free(&pkcs7); + wc_PKCS7_Free(&pkcs7); + } if (ret > 0) return 0; @@ -9351,6 +9665,7 @@ int pkcs7signed_test(void) else outSz = ret; +#ifdef PKCS7_OUTPUT_TEST_BUNDLES /* write PKCS#7 to output file for more testing */ file = fopen("./pkcs7signedData.der", "wb"); if (!file) { @@ -9369,6 +9684,7 @@ int pkcs7signed_test(void) wc_PKCS7_Free(&msg); return -218; } +#endif /* PKCS7_OUTPUT_TEST_BUNDLES */ wc_PKCS7_Free(&msg); wc_PKCS7_InitWithCert(&msg, NULL, 0); @@ -9390,6 +9706,7 @@ int pkcs7signed_test(void) return -215; } +#ifdef PKCS7_OUTPUT_TEST_BUNDLES file = fopen("./pkcs7cert.der", "wb"); if (!file) { XFREE(certDer, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -9400,6 +9717,7 @@ int pkcs7signed_test(void) } ret = (int)fwrite(msg.singleCert, 1, msg.singleCertSz, file); fclose(file); +#endif /* PKCS7_OUTPUT_TEST_BUNDLES */ XFREE(certDer, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(keyDer, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index b2f0c67d7..fdb8dc7dc 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -213,6 +213,8 @@ enum Oid_Types { oidCertAltNameType = 9, oidCertKeyUseType = 10, oidKdfType = 11, + oidKeyWrapType = 12, + oidCmsKeyAgreeType = 13, oidIgnoreType }; @@ -245,6 +247,22 @@ enum Key_Sum { }; +enum KeyWrap_Sum { + AES128_WRAP = 417, + AES192_WRAP = 437, + AES256_WRAP = 457 +}; + + +enum Key_Agree { + dhSinglePass_stdDH_sha1kdf_scheme = 464, + dhSinglePass_stdDH_sha224kdf_scheme = 188, + dhSinglePass_stdDH_sha256kdf_scheme = 189, + dhSinglePass_stdDH_sha384kdf_scheme = 190, + dhSinglePass_stdDH_sha512kdf_scheme = 191, +}; + + enum Ecc_Sum { ECC_SECP112R1_OID = 182, ECC_SECP112R2_OID = 183, diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 931564796..5ffab85ba 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -78,6 +78,15 @@ typedef struct PKCS7Attrib { } PKCS7Attrib; +typedef struct PKCS7DecodedAttrib { + byte* oid; + word32 oidSz; + byte* value; + word32 valueSz; + struct PKCS7DecodedAttrib* next; +} PKCS7DecodedAttrib; + + typedef struct PKCS7 { byte* content; /* inner content, not owner */ word32 contentSz; /* content size */ @@ -87,6 +96,8 @@ typedef struct PKCS7 { int hashOID; int encryptOID; /* key encryption algorithm OID */ + int keyWrapOID; /* key wrap algorithm OID */ + int keyAgreeOID; /* key agreement algorithm OID */ void* heap; /* heap hint for dynamic memory */ byte* singleCert; /* recipient cert, DER, not owner */ @@ -96,35 +107,33 @@ typedef struct PKCS7 { word32 issuerSz; /* length of issuer name */ byte issuerSn[MAX_SN_SZ]; /* singleCert's serial number */ word32 issuerSnSz; /* length of serial number */ + byte publicKey[512]; word32 publicKeySz; + word32 publicKeyOID; /* key OID (RSAk, ECDSAk, etc) */ byte* privateKey; /* private key, DER, not owner */ word32 privateKeySz; /* size of private key buffer, bytes */ PKCS7Attrib* signedAttribs; word32 signedAttribsSz; + + /* Enveloped-data optional ukm, not owner */ + byte* ukm; + word32 ukmSz; + + /* Encrypted-data Content Type */ + byte* encryptionKey; /* block cipher encryption key */ + word32 encryptionKeySz; /* size of key buffer, bytes */ + PKCS7Attrib* unprotectedAttribs; /* optional */ + word32 unprotectedAttribsSz; + PKCS7DecodedAttrib* decodedAttrib; /* linked list of decoded attribs */ } PKCS7; -WOLFSSL_LOCAL int wc_PKCS7_SetHeap(PKCS7* pkcs7, void* heap); -WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output); -WOLFSSL_LOCAL int wc_GetContentType(const byte* input, word32* inOutIdx, - word32* oid, word32 maxIdx); -WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, - int keyEncAlgo, int blockKeySz, - WC_RNG* rng, byte* contentKeyPlain, - byte* contentKeyEnc, int* keyEncSz, - byte* out, word32 outSz, void* heap); -WOLFSSL_LOCAL int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out); -WOLFSSL_LOCAL int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* in, int inSz, - byte* out); - WOLFSSL_API int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz); WOLFSSL_API void wc_PKCS7_Free(PKCS7* pkcs7); -WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz); +WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, + word32 outputSz); WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz); WOLFSSL_API int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, @@ -134,7 +143,11 @@ WOLFSSL_API int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* output, word32 outputSz); - +WOLFSSL_API int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, + byte* output, word32 outputSz); +WOLFSSL_API int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, byte* output, + word32 outputSz); #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index a67ad9b47..6a1117d86 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1464,6 +1464,15 @@ static char *fgets(char *buff, int sz, FILE *fp) #endif #endif +#ifdef HAVE_PKCS7 + #ifndef HAVE_AES_KEYWRAP + #error PKCS7 requires AES key wrap please define HAVE_AES_KEYWRAP + #endif + #ifndef HAVE_X963_KDF + #error PKCS7 requires X963 KDF please define HAVE_X963_KDF + #endif +#endif + /* Place any other flags or defines here */ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 5d04be8f6..c1e26429a 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -338,7 +338,8 @@ DYNAMIC_TYPE_DTLS_BUFFER = 56, DYNAMIC_TYPE_SESSION_TICK = 57, DYNAMIC_TYPE_PKCS = 58, - DYNAMIC_TYPE_MUTEX = 59 + DYNAMIC_TYPE_MUTEX = 59, + DYNAMIC_TYPE_PKCS7 = 60 }; /* max error buffer string size */