From dad0cfda92ec15ddbfede240359ea01af7e4132f Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 9 Dec 2016 17:22:09 -0700 Subject: [PATCH] add EnvelopedData ECC support, refactor pkcs7 --- Makefile.am | 12 + configure.ac | 10 + wolfcrypt/src/asn.c | 56 + wolfcrypt/src/pkcs7.c | 1912 +++++++++++++++++++++++++++------- wolfcrypt/test/test.c | 519 ++++----- wolfssl/wolfcrypt/asn.h | 18 + wolfssl/wolfcrypt/pkcs7.h | 36 +- wolfssl/wolfcrypt/settings.h | 9 + wolfssl/wolfcrypt/types.h | 3 +- 9 files changed, 1921 insertions(+), 654 deletions(-) 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 be33c1d84..0e534a5a8 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,6 +272,32 @@ 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) { @@ -959,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 */ + ecc_key* recipKey; /* recip key (pub | priv) */ + ecc_key* senderKey; /* sender key (pub | priv) */ + byte* senderKeyExport; /* sender ephemeral key DER */ + word32 senderKeyExportSz; /* size of sender ephemeral key DER */ + byte* kek; /* key encryption key */ + word32 kekSz; /* size of key encryption key */ + byte* ukm; /* OPTIONAL user keying material */ + word32 ukmSz; /* size of user keying material */ + byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */ + byte* sharedInfo; /* ECC-CMS-SharedInfo ASN.1 encoded blob */ + word32 sharedInfoSz; /* size of ECC-CMS-SharedInfo encoded */ + byte direction; /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */ + void* heap; /* user heap, points to PKCS7->heap */ +} 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; @@ -981,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; @@ -996,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; @@ -1180,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 @@ -1243,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 @@ -1306,7 +2092,7 @@ int wc_PKCS7_DecryptContent(int encryptOID, byte* key, int keySz, /* generate random IV, place in iv, return 0 on success negative on error */ -int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) +static int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) { int ret; WC_RNG* random = NULL; @@ -1340,7 +2126,7 @@ int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz) /* return size of padded data, padded to blockSz chunks, or negative on error */ -int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) +static int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) { int padSz; @@ -1355,8 +2141,8 @@ int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) /* pad input data to blockSz chunk, place in outSz. out must be big enough * for input + pad bytes. See wc_PKCS7_GetPadLength() helper. */ -int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, - word32 blockSz) +static int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, + word32 blockSz) { int i, padSz; @@ -1379,67 +2165,6 @@ int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, } -int wc_PKCS7_GetOIDBlockSize(int oid) -{ - int blockSz; - - switch (oid) { -#ifndef NO_AES - case AES128CBCb: - case AES192CBCb: - case AES256CBCb: - blockSz = AES_BLOCK_SIZE; - break; -#endif - case DESb: - case DES3b: - blockSz = DES_BLOCK_SIZE; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - return blockSz; -} - - -int wc_PKCS7_GetOIDKeySize(int oid) -{ - int blockKeySz; - - switch (oid) { -#ifndef NO_AES - case AES128CBCb: - blockKeySz = 16; - break; - - case AES192CBCb: - blockKeySz = 24; - break; - - case AES256CBCb: - blockKeySz = 32; - break; -#endif - case DESb: - blockKeySz = DES_KEYLEN; - break; - - case DES3b: - blockKeySz = DES3_KEYLEN; - break; - - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - return blockKeySz; -} - - /* build PKCS#7 envelopedData content type, return enveloped size */ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) { @@ -1484,7 +2209,8 @@ 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) @@ -1494,7 +2220,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (blockKeySz < 0) return blockKeySz; - blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); + blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); if (blockSz < 0) return blockSz; @@ -1502,7 +2228,11 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) 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); @@ -1516,35 +2246,56 @@ 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; } @@ -1555,7 +2306,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) 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; } @@ -1564,7 +2315,7 @@ 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; } @@ -1577,27 +2328,23 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) encryptedOutSz = pkcs7->contentSz + padSz; plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (plain == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER); -#endif + 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_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + 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; } @@ -1611,10 +2358,10 @@ 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; } @@ -1625,10 +2372,10 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) 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; } @@ -1661,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; } @@ -1700,30 +2447,32 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) 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; + +#ifdef WC_RSA_BLINDING + WC_RNG rng; +#endif #ifdef WOLFSSL_SMALL_STACK mp_int* serialNum; @@ -1733,16 +2482,571 @@ 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); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + if (keySz <= 0) { + ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + return keySz; + } else { + *decryptedKeySz = keySz; + XMEMCPY(decryptedKey, outKey, keySz); + ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); + } + + 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 || @@ -1778,7 +3082,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; } @@ -1788,123 +3094,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; } @@ -1912,48 +3122,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; } blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); if (blockKeySz < 0) { - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(decryptedKey, NULL, DYNAMIC_TYPE_PKCS7); return blockKeySz; } expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); if (expBlockSz < 0) { - XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); + 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; } @@ -1961,7 +3171,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; } @@ -1972,101 +3182,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; } @@ -2077,11 +3223,11 @@ 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; @@ -2158,21 +3304,21 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) encryptedOutSz = pkcs7->contentSz + padSz; plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + 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_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return MEMORY_E; } @@ -2184,8 +3330,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, 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); return BAD_FUNC_ARG; } @@ -2198,8 +3344,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) pkcs7->encryptionKeySz, 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); return ret; } @@ -2215,8 +3361,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (pkcs7->unprotectedAttribsSz != 0) { if (pkcs7->unprotectedAttribs == NULL) { - 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); return BAD_FUNC_ARG; } @@ -2224,8 +3370,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS); if (attribs == NULL) { - 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); return MEMORY_E; } @@ -2237,8 +3383,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) 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_TMP_BUFFER); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return MEMORY_E; } @@ -2274,8 +3420,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); } - 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); return BUFFER_E; } @@ -2313,42 +3459,17 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS); } - 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); return idx; } -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; -} - - /* decode and store unprotected attributes in PKCS7->decodedAttrib. Return * 0 on success, negative on error. User must call wc_PKCS7_Free(). */ -int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, - word32 pkiMsgSz, word32* inOutIdx) +static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, + word32 pkiMsgSz, word32* inOutIdx) { int length, attribLen; word32 oid, savedIdx, idx; @@ -2384,8 +3505,10 @@ int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); /* save attribute OID bytes and size */ - if (GetObjectId(pkiMsg, &idx, &oid, oidIgnoreType, pkiMsgSz) < 0) + 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, @@ -2397,11 +3520,17 @@ int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, XMEMCPY(attrib->oid, pkiMsg + savedIdx, attrib->oidSz); /* save attribute value bytes and size */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) + 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) + 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, @@ -2516,7 +3645,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, return ASN_PARSE_E; encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_PKCS7); if (encryptedContent == NULL) return MEMORY_E; @@ -2529,7 +3658,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, encryptedContent, encryptedContentSz, encryptedContent); if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ret; } @@ -2539,17 +3668,16 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* get implicit[1] unprotected attributes, optional */ + pkcs7->decodedAttrib = NULL; if (idx < pkiMsgSz) { haveAttribs = 1; - pkcs7->decodedAttrib = NULL; ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg, pkiMsgSz, &idx); if (ret != 0) { - printf("DEBUG: DecodeUnprotectedAttributes failed!\n"); ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return ASN_PARSE_E; } } @@ -2562,7 +3690,7 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, } ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); return encryptedContentSz - padLen; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ab444ef2d..5278f90a7 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -474,7 +474,6 @@ int wolfcrypt_test(void* args) else printf( "HMAC-KDF test passed!\n"); #endif - #endif #ifdef HAVE_X963_KDF @@ -4438,6 +4437,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 @@ -4460,6 +4463,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 ; } @@ -4487,6 +4496,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 @@ -9040,34 +9053,33 @@ int compress_test(void) #ifdef HAVE_PKCS7 typedef struct { - const char* outFileName; const byte* content; word32 contentSz; int contentOID; int encryptOID; + int keyWrapOID; + int keyAgreeOID; + byte* cert; + size_t certSz; byte* privateKey; word32 privateKeySz; - byte* encryptionKey; - word32 encryptionKeySz; - PKCS7Attrib* attribs; - word32 attribsSz; -} pkcs7Vector; + 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; FILE* pkcs7File; const byte data[] = { /* Hello World */ @@ -9075,152 +9087,251 @@ int pkcs7enveloped_test(void) 0x72,0x6c,0x64 }; - pkcs7Vector a; -#ifndef NO_AES - pkcs7Vector b, c, d; - pkcs7Vector test_pkcs7env[4]; -#else - pkcs7Vector test_pkcs7env[1]; -#endif - int times = sizeof(test_pkcs7env) / sizeof(pkcs7Vector), 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; + + /* 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); + + 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); - - /* 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"; - -#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"; - - 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"; - - 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"; -#endif - - test_pkcs7env[0] = a; -#ifndef NO_AES - test_pkcs7env[1] = b; - test_pkcs7env[2] = c; - test_pkcs7env[3] = d; -#endif - - 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; - - /* 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); - 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); - 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); - return -205; - } - - /* 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; - } - - ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); - fclose(pkcs7File); +#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; } - XFREE(cert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - wc_PKCS7_Free(&pkcs7); + 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; + } - if (ret > 0) - return 0; + 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; + } - return ret; + eccCertSz = fread(eccCert, 1, FOURK_BUF, certFile); + fclose(certFile); + + 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, rsaCertSz, + rsaPrivKey, rsaPrivKeySz, + eccCert, eccCertSz, + eccPrivKey, 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, encryptedSz, decodedSz; + int ret, i, testSz; + int encryptedSz, decodedSz, attribIdx; PKCS7 pkcs7; byte encrypted[2048]; byte decoded[2048]; @@ -9248,8 +9359,8 @@ int pkcs7encrypted_test(void) }; byte aes192Key[] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,0x05,0x06,0x07,0x08, - 0x01,0x02,0x03,0x05,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, @@ -9290,108 +9401,50 @@ int pkcs7encrypted_test(void) { genAttrOid2, sizeof(genAttrOid2), genAttr2, sizeof(genAttr2) } }; - pkcs7Vector a, b; -#ifndef NO_AES - pkcs7Vector c, d, e, f, g; - pkcs7Vector test_pkcs7enc[7]; -#else - pkcs7Vector test_pkcs7enc[1]; -#endif - int times = sizeof(test_pkcs7enc) / sizeof(pkcs7Vector); - int i, attribIdx; + const pkcs7EncryptedVector testVectors[] = + { +#ifndef NO_DES3 + {data, (word32)sizeof(data), DATA, DES3b, des3Key, sizeof(des3Key), + NULL, 0, "pkcs7encryptedDataDES3.der"}, - /* set up test vectors */ - a.content = data; - a.contentSz = (word32)sizeof(data); - a.contentOID = DATA; - a.encryptOID = DES3b; - a.encryptionKey = des3Key; - a.encryptionKeySz = sizeof(des3Key); - a.outFileName = "pkcs7encryptedDataDES3.der"; - a.attribs = NULL; - a.attribsSz = 0; - - b.content = data; - b.contentSz = (word32)sizeof(data); - b.contentOID = DATA; - b.encryptOID = DESb; - b.encryptionKey = desKey; - b.encryptionKeySz = sizeof(desKey); - b.outFileName = "pkcs7encryptedDataDES.der"; - b.attribs = NULL; - b.attribsSz = 0; + {data, (word32)sizeof(data), DATA, DESb, desKey, sizeof(desKey), + NULL, 0, "pkcs7encryptedDataDES.der"}, +#endif /* NO_DES3 */ #ifndef NO_AES - c.content = data; - c.contentSz = (word32)sizeof(data); - c.contentOID = DATA; - c.encryptOID = AES128CBCb; - c.encryptionKey = aes128Key; - c.encryptionKeySz = sizeof(aes128Key); - c.outFileName = "pkcs7encryptedDataAES128CBC.der"; - c.attribs = NULL; - c.attribsSz = 0; + {data, (word32)sizeof(data), DATA, AES128CBCb, aes128Key, + sizeof(aes128Key), NULL, 0, "pkcs7encryptedDataAES128CBC.der"}, - d.content = data; - d.contentSz = (word32)sizeof(data); - d.contentOID = DATA; - d.encryptOID = AES192CBCb; - d.encryptionKey = aes192Key; - d.encryptionKeySz = sizeof(aes192Key); - d.outFileName = "pkcs7encryptedDataAES192CBC.der"; - d.attribs = NULL; - d.attribsSz = 0; + {data, (word32)sizeof(data), DATA, AES192CBCb, aes192Key, + sizeof(aes192Key), NULL, 0, "pkcs7encryptedDataAES192CBC.der"}, - e.content = data; - e.contentSz = (word32)sizeof(data); - e.contentOID = DATA; - e.encryptOID = AES256CBCb; - e.encryptionKey = aes256Key; - e.encryptionKeySz = sizeof(aes256Key); - e.outFileName = "pkcs7encryptedDataAES256CBC.der"; - e.attribs = NULL; - e.attribsSz = 0; + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), NULL, 0, "pkcs7encryptedDataAES256CBC.der"}, - f.content = data; - f.contentSz = (word32)sizeof(data); - f.contentOID = DATA; - f.encryptOID = AES256CBCb; - f.encryptionKey = aes256Key; - f.encryptionKeySz = sizeof(aes256Key); - f.outFileName = "pkcs7encryptedDataAES256CBC_attribs.der"; - f.attribs = attribs; - f.attribsSz = sizeof(attribs)/sizeof(PKCS7Attrib); + /* test with optional unprotected attributes */ + {data, (word32)sizeof(data), DATA, AES256CBCb, aes256Key, + sizeof(aes256Key), attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7encryptedDataAES256CBC_attribs.der"}, - g.content = data; - g.contentSz = (word32)sizeof(data); - g.contentOID = DATA; - g.encryptOID = AES256CBCb; - g.encryptionKey = aes256Key; - g.encryptionKeySz = sizeof(aes256Key); - g.outFileName = "pkcs7encryptedDataAES256CBC_multi_attribs.der"; - g.attribs = multiAttribs; - g.attribsSz = sizeof(multiAttribs)/sizeof(PKCS7Attrib); -#endif + /* 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 */ + }; - test_pkcs7enc[0] = a; - test_pkcs7enc[1] = b; -#ifndef NO_AES - test_pkcs7enc[2] = c; - test_pkcs7enc[3] = d; - test_pkcs7enc[4] = e; - test_pkcs7enc[5] = f; - test_pkcs7enc[6] = g; -#endif + testSz = sizeof(testVectors) / sizeof(pkcs7EncryptedVector); - for (i = 0; i < times; i++) { - pkcs7.content = (byte*)test_pkcs7enc[i].content; - pkcs7.contentSz = test_pkcs7enc[i].contentSz; - pkcs7.contentOID = test_pkcs7enc[i].contentOID; - pkcs7.encryptOID = test_pkcs7enc[i].encryptOID; - pkcs7.encryptionKey = test_pkcs7enc[i].encryptionKey; - pkcs7.encryptionKeySz = test_pkcs7enc[i].encryptionKeySz; - pkcs7.unprotectedAttribs = test_pkcs7enc[i].attribs; - pkcs7.unprotectedAttribsSz = test_pkcs7enc[i].attribsSz; + 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, @@ -9436,15 +9489,15 @@ int pkcs7encrypted_test(void) } /* output pkcs7 envelopedData for external testing */ - pkcs7File = fopen(test_pkcs7enc[i].outFileName, "wb"); + pkcs7File = fopen(testVectors[i].outFileName, "wb"); if (!pkcs7File) return -208; ret = (int)fwrite(encrypted, encryptedSz, 1, pkcs7File); fclose(pkcs7File); - } - wc_PKCS7_Free(&pkcs7); + wc_PKCS7_Free(&pkcs7); + } if (ret > 0) return 0; 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 357b24ea7..5ffab85ba 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -96,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 */ @@ -105,14 +107,20 @@ 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 */ @@ -122,34 +130,6 @@ typedef struct PKCS7 { } 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_LOCAL int wc_PKCS7_GenerateIV(WC_RNG* rng, byte* iv, word32 ivSz); -WOLFSSL_LOCAL int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz); -WOLFSSL_LOCAL int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, - word32 blockSz); -WOLFSSL_LOCAL int wc_PKCS7_GetOIDBlockSize(int oid); -WOLFSSL_LOCAL int wc_PKCS7_GetOIDKeySize(int oid); -WOLFSSL_LOCAL int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, - byte* pkiMsg, word32 pkiMsgSz, - word32* inOutIdx); -WOLFSSL_LOCAL void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, - void* heap); - - 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, diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 95fbf5179..a0b238ae8 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1448,6 +1448,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 8a2022808..e5aa83b3a 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 */