Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: wolfcrypt/src/pkcs7.c
- Revision:
- 17:ff9d1e86ad5f
- Parent:
- 16:048e5e270a58
diff -r 048e5e270a58 -r ff9d1e86ad5f wolfcrypt/src/pkcs7.c --- a/wolfcrypt/src/pkcs7.c Tue Nov 19 14:32:16 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5102 +0,0 @@ -/* pkcs7.c - * - * Copyright (C) 2006-2017 wolfSSL Inc. - * - * This file is part of wolfSSL. - * - * wolfSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * wolfSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - - -#ifdef HAVE_CONFIG_H - #include <config.h> -#endif - -#include <wolfssl/wolfcrypt/settings.h> - -#ifdef HAVE_PKCS7 - -#include <wolfssl/wolfcrypt/pkcs7.h> -#include <wolfssl/wolfcrypt/error-crypt.h> -#include <wolfssl/wolfcrypt/logging.h> -#include <wolfssl/wolfcrypt/hash.h> -#ifndef NO_RSA - #include <wolfssl/wolfcrypt/rsa.h> -#endif -#ifdef HAVE_ECC - #include <wolfssl/wolfcrypt/ecc.h> -#endif -#ifdef NO_INLINE - #include <wolfssl/wolfcrypt/misc.h> -#else - #define WOLFSSL_MISC_INCLUDED - #include <wolfcrypt/src/misc.c> -#endif - - -/* direction for processing, encoding or decoding */ -typedef enum { - WC_PKCS7_ENCODE, - WC_PKCS7_DECODE -} pkcs7Direction; - -#define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ + \ - MAX_OCTET_STR_SZ + WC_MAX_DIGEST_SIZE) - - -/* placed ASN.1 contentType OID into *output, return idx on success, - * 0 upon failure */ -static int wc_SetContentType(int pkcs7TypeOID, byte* output) -{ - /* PKCS#7 content types, RFC 2315, section 14 */ - const byte pkcs7[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07 }; - const byte data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07, 0x01 }; - const byte signedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07, 0x02}; - const byte envelopedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07, 0x03 }; - const byte signedAndEnveloped[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07, 0x04 }; - const byte digestedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07, 0x05 }; - -#ifndef NO_PKCS7_ENCRYPTED_DATA - const byte encryptedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x07, 0x06 }; -#endif - - int idSz; - int typeSz = 0, idx = 0; - const byte* typeName = 0; - byte ID_Length[MAX_LENGTH_SZ]; - - switch (pkcs7TypeOID) { - case PKCS7_MSG: - typeSz = sizeof(pkcs7); - typeName = pkcs7; - break; - - case DATA: - typeSz = sizeof(data); - typeName = data; - break; - - case SIGNED_DATA: - typeSz = sizeof(signedData); - typeName = signedData; - break; - - case ENVELOPED_DATA: - typeSz = sizeof(envelopedData); - typeName = envelopedData; - break; - - case SIGNED_AND_ENVELOPED_DATA: - typeSz = sizeof(signedAndEnveloped); - typeName = signedAndEnveloped; - break; - - case DIGESTED_DATA: - typeSz = sizeof(digestedData); - typeName = digestedData; - break; - -#ifndef NO_PKCS7_ENCRYPTED_DATA - case ENCRYPTED_DATA: - typeSz = sizeof(encryptedData); - typeName = encryptedData; - break; -#endif - - default: - WOLFSSL_MSG("Unknown PKCS#7 Type"); - return 0; - }; - - idSz = SetLength(typeSz, ID_Length); - output[idx++] = ASN_OBJECT_ID; - XMEMCPY(output + idx, ID_Length, idSz); - idx += idSz; - XMEMCPY(output + idx, typeName, typeSz); - idx += typeSz; - - return idx; -} - - -/* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */ -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) - return ASN_PARSE_E; - - return 0; -} - - -/* return block size for algorithm represented by oid, or <0 on error */ -static int wc_PKCS7_GetOIDBlockSize(int oid) -{ - int blockSz; - - switch (oid) { -#ifndef NO_AES - #ifdef WOLFSSL_AES_128 - case AES128CBCb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - #endif - 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 - #ifdef WOLFSSL_AES_128 - case AES128CBCb: - case AES128_WRAP: - blockKeySz = 16; - break; - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - case AES192_WRAP: - blockKeySz = 24; - break; - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - case AES256_WRAP: - blockKeySz = 32; - break; - #endif -#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; -} - - -PKCS7* wc_PKCS7_New(void* heap, int devId) -{ - PKCS7* pkcs7 = (PKCS7*)XMALLOC(sizeof(PKCS7), heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7) { - XMEMSET(pkcs7, 0, sizeof(PKCS7)); - if (wc_PKCS7_Init(pkcs7, heap, devId) == 0) { - pkcs7->isDynamic = 1; - } - else { - XFREE(pkcs7, heap, DYNAMIC_TYPE_PKCS7); - pkcs7 = NULL; - } - } - return pkcs7; -} - -/* This is to initialize a PKCS7 structure. It sets all values to 0 and can be - * used to set the heap hint. - * - * pkcs7 PKCS7 structure to initialize - * heap memory heap hint for PKCS7 structure to use - * devId currently not used but a place holder for async operations - * - * returns 0 on success or a negative value for failure - */ -int wc_PKCS7_Init(PKCS7* pkcs7, void* heap, int devId) -{ - WOLFSSL_ENTER("wc_PKCS7_Init"); - - if (pkcs7 == NULL) { - return BAD_FUNC_ARG; - } - - XMEMSET(pkcs7, 0, sizeof(PKCS7)); -#ifdef WOLFSSL_HEAP_TEST - pkcs7->heap = (void*)WOLFSSL_HEAP_TEST; -#else - pkcs7->heap = heap; -#endif - pkcs7->devId = devId; - - return 0; -} - - -/* init PKCS7 struct with recipient cert, decode into DecodedCert - * NOTE: keeps previously set pkcs7 heap hint, devId and isDynamic */ -int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz) -{ - int ret = 0; - void* heap; - int devId; - word16 isDynamic; - - if (pkcs7 == NULL || (cert == NULL && certSz != 0)) { - return BAD_FUNC_ARG; - } - - heap = pkcs7->heap; - devId = pkcs7->devId; - isDynamic = pkcs7->isDynamic; - ret = wc_PKCS7_Init(pkcs7, heap, devId); - if (ret != 0) - return ret; - pkcs7->isDynamic = isDynamic; - - if (cert != NULL && certSz > 0) { -#ifdef WOLFSSL_SMALL_STACK - DecodedCert* dCert; - - dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap, - DYNAMIC_TYPE_DCERT); - if (dCert == NULL) - return MEMORY_E; -#else - DecodedCert stack_dCert; - DecodedCert* dCert = &stack_dCert; -#endif - - pkcs7->singleCert = cert; - pkcs7->singleCertSz = certSz; - InitDecodedCert(dCert, cert, certSz, pkcs7->heap); - - ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0); - if (ret < 0) { - FreeDecodedCert(dCert); -#ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#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; - XMEMCPY(pkcs7->issuerSn, dCert->serial, dCert->serialSz); - pkcs7->issuerSnSz = dCert->serialSz; - FreeDecodedCert(dCert); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#endif - } - - return ret; -} - - -/* 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) -{ - if (pkcs7 == NULL) - return; - - wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap); - -#ifdef ASN_BER_TO_DER - if (pkcs7->der != NULL) - XFREE(pkcs7->der, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - - if (pkcs7->isDynamic) { - pkcs7->isDynamic = 0; - XFREE(pkcs7, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } -} - - -/* helper function for parsing through attributes and finding a specific one. - * returns PKCS7DecodedAttrib pointer on success */ -static PKCS7DecodedAttrib* findAttrib(PKCS7* pkcs7, const byte* oid, word32 oidSz) -{ - PKCS7DecodedAttrib* list; - - if (pkcs7 == NULL || oid == NULL) { - return NULL; - } - - /* search attributes for pkiStatus */ - list = pkcs7->decodedAttrib; - while (list != NULL) { - word32 sz = oidSz; - word32 idx = 0; - int length = 0; - - if (list->oid[idx++] != ASN_OBJECT_ID) { - WOLFSSL_MSG("Bad attribute ASN1 syntax"); - return NULL; - } - - if (GetLength(list->oid, &idx, &length, list->oidSz) < 0) { - WOLFSSL_MSG("Bad attribute length"); - return NULL; - } - - sz = (sz < (word32)length)? sz : (word32)length; - if (XMEMCMP(oid, list->oid + idx, sz) == 0) { - return list; - } - list = list->next; - } - return NULL; -} - - -/* Searches through decoded attributes and returns the value for the first one - * matching the oid passed in. Note that this value includes the leading ASN1 - * syntax. So for a printable string of "3" this would be something like - * - * 0x13, 0x01, 0x33 - * ID SIZE "3" - * - * pkcs7 structure to get value from - * oid OID value to search for with attributes - * oidSz size of oid buffer - * out buffer to hold result - * outSz size of out buffer (if out is NULL this is set to needed size and - LENGTH_ONLY_E is returned) - * - * returns size of value on success - */ -int wc_PKCS7_GetAttributeValue(PKCS7* pkcs7, const byte* oid, word32 oidSz, - byte* out, word32* outSz) -{ - PKCS7DecodedAttrib* attrib; - - if (pkcs7 == NULL || oid == NULL || outSz == NULL) { - return BAD_FUNC_ARG; - } - - attrib = findAttrib(pkcs7, oid, oidSz); - if (attrib == NULL) { - return ASN_PARSE_E; - } - - if (out == NULL) { - *outSz = attrib->valueSz; - return LENGTH_ONLY_E; - } - - if (*outSz < attrib->valueSz) { - return BUFFER_E; - } - - XMEMCPY(out, attrib->value, attrib->valueSz); - return attrib->valueSz; -} - - -/* build PKCS#7 data content type */ -int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz) -{ - static const byte oid[] = - { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, - 0x07, 0x01 }; - byte seq[MAX_SEQ_SZ]; - byte octetStr[MAX_OCTET_STR_SZ]; - word32 seqSz; - word32 octetStrSz; - word32 oidSz = (word32)sizeof(oid); - int idx = 0; - - if (pkcs7 == NULL || output == NULL) { - return BAD_FUNC_ARG; - } - - octetStrSz = SetOctetString(pkcs7->contentSz, octetStr); - seqSz = SetSequence(pkcs7->contentSz + octetStrSz + oidSz, seq); - - if (outputSz < pkcs7->contentSz + octetStrSz + oidSz + seqSz) - return BUFFER_E; - - XMEMCPY(output, seq, seqSz); - idx += seqSz; - XMEMCPY(output + idx, oid, oidSz); - idx += oidSz; - XMEMCPY(output + idx, octetStr, octetStrSz); - idx += octetStrSz; - XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); - idx += pkcs7->contentSz; - - return idx; -} - - -typedef struct EncodedAttrib { - byte valueSeq[MAX_SEQ_SZ]; - const byte* oid; - byte valueSet[MAX_SET_SZ]; - const byte* value; - word32 valueSeqSz, oidSz, idSz, valueSetSz, valueSz, totalSz; -} EncodedAttrib; - - -typedef struct ESD { - wc_HashAlg hash; - enum wc_HashType hashType; - byte contentDigest[WC_MAX_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */ - byte contentAttribsDigest[WC_MAX_DIGEST_SIZE]; - byte encContentDigest[MAX_ENCRYPTED_KEY_SZ]; - - byte outerSeq[MAX_SEQ_SZ]; - byte outerContent[MAX_EXP_SZ]; - byte innerSeq[MAX_SEQ_SZ]; - byte version[MAX_VERSION_SZ]; - byte digAlgoIdSet[MAX_SET_SZ]; - byte singleDigAlgoId[MAX_ALGO_SZ]; - - byte contentInfoSeq[MAX_SEQ_SZ]; - byte innerContSeq[MAX_EXP_SZ]; - byte innerOctets[MAX_OCTET_STR_SZ]; - - byte certsSet[MAX_SET_SZ]; - - byte signerInfoSet[MAX_SET_SZ]; - byte signerInfoSeq[MAX_SEQ_SZ]; - byte signerVersion[MAX_VERSION_SZ]; - byte issuerSnSeq[MAX_SEQ_SZ]; - byte issuerName[MAX_SEQ_SZ]; - byte issuerSn[MAX_SN_SZ]; - byte signerDigAlgoId[MAX_ALGO_SZ]; - byte digEncAlgoId[MAX_ALGO_SZ]; - byte signedAttribSet[MAX_SET_SZ]; - EncodedAttrib signedAttribs[6]; - byte signerDigest[MAX_OCTET_STR_SZ]; - word32 innerOctetsSz, innerContSeqSz, contentInfoSeqSz; - word32 outerSeqSz, outerContentSz, innerSeqSz, versionSz, digAlgoIdSetSz, - singleDigAlgoIdSz, certsSetSz; - word32 signerInfoSetSz, signerInfoSeqSz, signerVersionSz, - issuerSnSeqSz, issuerNameSz, issuerSnSz, - signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz; - word32 encContentDigestSz, signedAttribsSz, signedAttribsCount, - signedAttribSetSz; -} ESD; - - -static int EncodeAttributes(EncodedAttrib* ea, int eaSz, - PKCS7Attrib* attribs, int attribsSz) -{ - int i; - int maxSz = min(eaSz, attribsSz); - int allAttribsSz = 0; - - for (i = 0; i < maxSz; i++) - { - int attribSz = 0; - - ea[i].value = attribs[i].value; - ea[i].valueSz = attribs[i].valueSz; - attribSz += ea[i].valueSz; - ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet); - attribSz += ea[i].valueSetSz; - ea[i].oid = attribs[i].oid; - ea[i].oidSz = attribs[i].oidSz; - attribSz += ea[i].oidSz; - ea[i].valueSeqSz = SetSequence(attribSz, ea[i].valueSeq); - attribSz += ea[i].valueSeqSz; - ea[i].totalSz = attribSz; - - allAttribsSz += attribSz; - } - return allAttribsSz; -} - - -static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz) -{ - int i, idx; - - idx = 0; - for (i = 0; i < eaSz; i++) { - XMEMCPY(output + idx, ea[i].valueSeq, ea[i].valueSeqSz); - idx += ea[i].valueSeqSz; - XMEMCPY(output + idx, ea[i].oid, ea[i].oidSz); - idx += ea[i].oidSz; - XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz); - idx += ea[i].valueSetSz; - XMEMCPY(output + idx, ea[i].value, ea[i].valueSz); - idx += ea[i].valueSz; - } - return 0; -} - - -#ifndef NO_RSA - -/* returns size of signature put into out, negative on error */ -static int wc_PKCS7_RsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) -{ - int ret; - word32 idx; -#ifdef WOLFSSL_SMALL_STACK - RsaKey* privKey; -#else - RsaKey stack_privKey; - RsaKey* privKey = &stack_privKey; -#endif - - if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) - return MEMORY_E; -#endif - - ret = wc_InitRsaKey_ex(privKey, pkcs7->heap, pkcs7->devId); - if (ret == 0) { - if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) { - idx = 0; - ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey, - pkcs7->privateKeySz); - } - else if (pkcs7->devId == INVALID_DEVID) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - ret = wc_RsaSSL_Sign(in, inSz, esd->encContentDigest, - sizeof(esd->encContentDigest), - privKey, pkcs7->rng); - } - - wc_FreeRsaKey(privKey); -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -#endif /* NO_RSA */ - - -#ifdef HAVE_ECC - -/* returns size of signature put into out, negative on error */ -static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) -{ - int ret; - word32 outSz, idx; -#ifdef WOLFSSL_SMALL_STACK - ecc_key* privKey; -#else - ecc_key stack_privKey; - ecc_key* privKey = &stack_privKey; -#endif - - if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - privKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) - return MEMORY_E; -#endif - - ret = wc_ecc_init_ex(privKey, pkcs7->heap, pkcs7->devId); - if (ret == 0) { - if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) { - idx = 0; - ret = wc_EccPrivateKeyDecode(pkcs7->privateKey, &idx, privKey, - pkcs7->privateKeySz); - } - else if (pkcs7->devId == INVALID_DEVID) { - ret = BAD_FUNC_ARG; - } - } - if (ret == 0) { - outSz = sizeof(esd->encContentDigest); - ret = wc_ecc_sign_hash(in, inSz, esd->encContentDigest, - &outSz, pkcs7->rng, privKey); - if (ret == 0) - ret = (int)outSz; - } - - wc_ecc_free(privKey); -#ifdef WOLFSSL_SMALL_STACK - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -#endif /* HAVE_ECC */ - - -/* builds up SignedData signed attributes, including default ones. - * - * pkcs7 - pointer to initialized PKCS7 structure - * esd - pointer to initialized ESD structure, used for output - * - * return 0 on success, negative on error */ -static int wc_PKCS7_BuildSignedAttributes(PKCS7* pkcs7, ESD* esd, - byte* contentTypeOid, word32 contentTypeOidSz, - byte* contentType, word32 contentTypeSz, - byte* messageDigestOid, word32 messageDigestOidSz) -{ - int hashSz; - - PKCS7Attrib cannedAttribs[2]; - word32 cannedAttribsCount; - - if (pkcs7 == NULL || esd == NULL || contentTypeOid == NULL || - contentType == NULL || messageDigestOid == NULL) - return BAD_FUNC_ARG; - - hashSz = wc_HashGetDigestSize(esd->hashType); - if (hashSz < 0) - return hashSz; - - cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib); - - cannedAttribs[0].oid = contentTypeOid; - cannedAttribs[0].oidSz = contentTypeOidSz; - cannedAttribs[0].value = contentType; - cannedAttribs[0].valueSz = contentTypeSz; - cannedAttribs[1].oid = messageDigestOid; - cannedAttribs[1].oidSz = messageDigestOidSz; - cannedAttribs[1].value = esd->contentDigest; - cannedAttribs[1].valueSz = hashSz + 2; /* ASN.1 heading */ - - esd->signedAttribsCount += cannedAttribsCount; - esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[0], 2, - cannedAttribs, cannedAttribsCount); - - esd->signedAttribsCount += pkcs7->signedAttribsSz; - esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[2], 4, - pkcs7->signedAttribs, pkcs7->signedAttribsSz); - - return 0; -} - - -/* gets correct encryption algo ID for SignedData, either CTC_<hash>wRSA or - * CTC_<hash>wECDSA, from pkcs7->publicKeyOID and pkcs7->hashOID. - * - * pkcs7 - pointer to PKCS7 structure - * digEncAlgoId - [OUT] output int to store correct algo ID in - * digEncAlgoType - [OUT] output for algo ID type - * - * return 0 on success, negative on error */ -static int wc_PKCS7_SignedDataGetEncAlgoId(PKCS7* pkcs7, int* digEncAlgoId, - int* digEncAlgoType) -{ - int algoId = 0; - int algoType = 0; - - if (pkcs7 == NULL || digEncAlgoId == NULL || digEncAlgoType == NULL) - return BAD_FUNC_ARG; - - if (pkcs7->publicKeyOID == RSAk) { - - algoType = oidSigType; - - switch (pkcs7->hashOID) { - #ifndef NO_SHA - case SHAh: - algoId = CTC_SHAwRSA; - break; - #endif - #ifdef WOLFSSL_SHA224 - case SHA224h: - algoId = CTC_SHA224wRSA; - break; - #endif - #ifndef NO_SHA256 - case SHA256h: - algoId = CTC_SHA256wRSA; - break; - #endif - #ifdef WOLFSSL_SHA384 - case SHA384h: - algoId = CTC_SHA384wRSA; - break; - #endif - #ifdef WOLFSSL_SHA512 - case SHA512h: - algoId = CTC_SHA512wRSA; - break; - #endif - } - - } -#ifdef HAVE_ECC - else if (pkcs7->publicKeyOID == ECDSAk) { - - algoType = oidSigType; - - switch (pkcs7->hashOID) { - #ifndef NO_SHA - case SHAh: - algoId = CTC_SHAwECDSA; - break; - #endif - #ifdef WOLFSSL_SHA224 - case SHA224h: - algoId = CTC_SHA224wECDSA; - break; - #endif - #ifndef NO_SHA256 - case SHA256h: - algoId = CTC_SHA256wECDSA; - break; - #endif - #ifdef WOLFSSL_SHA384 - case SHA384h: - algoId = CTC_SHA384wECDSA; - break; - #endif - #ifdef WOLFSSL_SHA512 - case SHA512h: - algoId = CTC_SHA512wECDSA; - break; - #endif - } - } -#endif /* HAVE_ECC */ - - if (algoId == 0) { - WOLFSSL_MSG("Invalid signature algorithm type"); - return BAD_FUNC_ARG; - } - - *digEncAlgoId = algoId; - *digEncAlgoType = algoType; - - return 0; -} - - -/* build SignedData DigestInfo for use with PKCS#7/RSA - * - * pkcs7 - pointer to initialized PKCS7 struct - * flatSignedAttribs - flattened, signed attributes - * flatSignedAttrbsSz - size of flatSignedAttribs, octets - * esd - pointer to initialized ESD struct - * digestInfo - [OUT] output array for DigestInfo - * digestInfoSz - [IN/OUT] - input size of array, size of digestInfo - * - * return 0 on success, negative on error */ -static int wc_PKCS7_BuildDigestInfo(PKCS7* pkcs7, byte* flatSignedAttribs, - word32 flatSignedAttribsSz, ESD* esd, - byte* digestInfo, word32* digestInfoSz) -{ - int ret, hashSz, digIdx = 0; - byte digestInfoSeq[MAX_SEQ_SZ]; - byte digestStr[MAX_OCTET_STR_SZ]; - byte attribSet[MAX_SET_SZ]; - byte algoId[MAX_ALGO_SZ]; - word32 digestInfoSeqSz, digestStrSz, algoIdSz; - word32 attribSetSz; - - if (pkcs7 == NULL || esd == NULL || digestInfo == NULL || - digestInfoSz == NULL) { - return BAD_FUNC_ARG; - } - - hashSz = wc_HashGetDigestSize(esd->hashType); - if (hashSz < 0) - return hashSz; - - if (pkcs7->signedAttribsSz != 0) { - - if (flatSignedAttribs == NULL) - return BAD_FUNC_ARG; - - attribSetSz = SetSet(flatSignedAttribsSz, attribSet); - - ret = wc_HashInit(&esd->hash, esd->hashType); - if (ret < 0) - return ret; - - ret = wc_HashUpdate(&esd->hash, esd->hashType, - attribSet, attribSetSz); - if (ret < 0) - return ret; - - ret = wc_HashUpdate(&esd->hash, esd->hashType, - flatSignedAttribs, flatSignedAttribsSz); - if (ret < 0) - return ret; - - ret = wc_HashFinal(&esd->hash, esd->hashType, - esd->contentAttribsDigest); - if (ret < 0) - return ret; - - } else { - /* when no attrs, digest is contentDigest without tag and length */ - XMEMCPY(esd->contentAttribsDigest, esd->contentDigest + 2, hashSz); - } - - /* set algoID, with NULL attributes */ - algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0); - - digestStrSz = SetOctetString(hashSz, digestStr); - digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz, - digestInfoSeq); - - if (*digestInfoSz < (digestInfoSeqSz + algoIdSz + digestStrSz + hashSz)) { - return BUFFER_E; - } - - XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); - digIdx += digestInfoSeqSz; - XMEMCPY(digestInfo + digIdx, algoId, algoIdSz); - digIdx += algoIdSz; - XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); - digIdx += digestStrSz; - XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest, hashSz); - digIdx += hashSz; - - *digestInfoSz = digIdx; - - return 0; -} - - -/* build SignedData signature over DigestInfo or content digest - * - * pkcs7 - pointer to initizlied PKCS7 struct - * flatSignedAttribs - flattened, signed attributes - * flatSignedAttribsSz - size of flatSignedAttribs, octets - * esd - pointer to initialized ESD struct - * - * returns length of signature on success, negative on error */ -static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7, - byte* flatSignedAttribs, - word32 flatSignedAttribsSz, - ESD* esd) -{ - int ret; -#ifdef HAVE_ECC - int hashSz; -#endif - word32 digestInfoSz = MAX_PKCS7_DIGEST_SZ; -#ifdef WOLFSSL_SMALL_STACK - byte* digestInfo; -#else - byte digestInfo[MAX_PKCS7_DIGEST_SZ]; -#endif - - if (pkcs7 == NULL || esd == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_SMALL_STACK - digestInfo = (byte*)XMALLOC(digestInfoSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (digestInfo == NULL) { - return MEMORY_E; - } -#endif - - ret = wc_PKCS7_BuildDigestInfo(pkcs7, flatSignedAttribs, - flatSignedAttribsSz, esd, digestInfo, - &digestInfoSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* sign digestInfo */ - switch (pkcs7->publicKeyOID) { - -#ifndef NO_RSA - case RSAk: - ret = wc_PKCS7_RsaSign(pkcs7, digestInfo, digestInfoSz, esd); - break; -#endif - -#ifdef HAVE_ECC - case ECDSAk: - /* CMS with ECDSA does not sign DigestInfo structure - * like PKCS#7 with RSA does */ - hashSz = wc_HashGetDigestSize(esd->hashType); - if (hashSz < 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return hashSz; - } - - ret = wc_PKCS7_EcdsaSign(pkcs7, esd->contentAttribsDigest, - hashSz, esd); - break; -#endif - - default: - WOLFSSL_MSG("Unsupported public key type"); - ret = BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (ret >= 0) { - esd->encContentDigestSz = (word32)ret; - } - - return ret; -} - -/* build PKCS#7 signedData content type */ -int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) -{ - static const byte outerOid[] = - { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, - 0x07, 0x02 }; - static const byte innerOid[] = - { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, - 0x07, 0x01 }; - - byte contentTypeOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, - 0x09, 0x03 }; - byte contentType[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x07, 0x01 }; - byte messageDigestOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x04 }; - -#ifdef WOLFSSL_SMALL_STACK - ESD* esd = NULL; -#else - ESD stack_esd; - ESD* esd = &stack_esd; -#endif - - word32 signerInfoSz = 0; - word32 totalSz = 0; - int idx = 0, ret = 0; - int digEncAlgoId, digEncAlgoType, hashSz; - byte* flatSignedAttribs = NULL; - word32 flatSignedAttribsSz = 0; - word32 innerOidSz = sizeof(innerOid); - word32 outerOidSz = sizeof(outerOid); - - if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || - pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 || - pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || - output == NULL || outputSz == 0) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (esd == NULL) - return MEMORY_E; -#endif - - XMEMSET(esd, 0, sizeof(ESD)); - - esd->hashType = wc_OidGetHash(pkcs7->hashOID); - ret = wc_HashGetDigestSize(esd->hashType); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - hashSz = ret; - - ret = wc_HashInit(&esd->hash, esd->hashType); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (pkcs7->contentSz != 0) - { - ret = wc_HashUpdate(&esd->hash, esd->hashType, - pkcs7->content, pkcs7->contentSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - esd->contentDigest[0] = ASN_OCTET_STRING; - esd->contentDigest[1] = (byte)hashSz; - ret = wc_HashFinal(&esd->hash, esd->hashType, - &esd->contentDigest[2]); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - } - - esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets); - esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + pkcs7->contentSz, - esd->innerContSeq); - esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz + esd->innerOctetsSz + - innerOidSz + esd->innerContSeqSz, - esd->contentInfoSeq); - - esd->issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz, - esd->issuerSn, MAX_SN_SZ); - signerInfoSz += esd->issuerSnSz; - esd->issuerNameSz = SetSequence(pkcs7->issuerSz, esd->issuerName); - signerInfoSz += esd->issuerNameSz + pkcs7->issuerSz; - esd->issuerSnSeqSz = SetSequence(signerInfoSz, esd->issuerSnSeq); - signerInfoSz += esd->issuerSnSeqSz; - esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0); - signerInfoSz += esd->signerVersionSz; - esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId, - oidHashType, 0); - signerInfoSz += esd->signerDigAlgoIdSz; - - /* set signatureAlgorithm */ - ret = wc_PKCS7_SignedDataGetEncAlgoId(pkcs7, &digEncAlgoId, - &digEncAlgoType); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - esd->digEncAlgoIdSz = SetAlgoID(digEncAlgoId, esd->digEncAlgoId, - digEncAlgoType, 0); - signerInfoSz += esd->digEncAlgoIdSz; - - if (pkcs7->signedAttribsSz != 0) { - - /* build up signed attributes */ - ret = wc_PKCS7_BuildSignedAttributes(pkcs7, esd, - contentTypeOid, sizeof(contentTypeOid), - contentType, sizeof(contentType), - messageDigestOid, sizeof(messageDigestOid)); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return MEMORY_E; - } - - flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - flatSignedAttribsSz = esd->signedAttribsSz; - if (flatSignedAttribs == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return MEMORY_E; - } - - FlattenAttributes(flatSignedAttribs, - esd->signedAttribs, esd->signedAttribsCount); - esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz, - esd->signedAttribSet); - } - - /* Calculate the final hash and encrypt it. */ - ret = wc_PKCS7_SignedDataBuildSignature(pkcs7, flatSignedAttribs, - flatSignedAttribsSz, esd); - if (ret < 0) { - if (pkcs7->signedAttribsSz != 0) - XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - signerInfoSz += flatSignedAttribsSz + esd->signedAttribSetSz; - - esd->signerDigestSz = SetOctetString(esd->encContentDigestSz, - esd->signerDigest); - signerInfoSz += esd->signerDigestSz + esd->encContentDigestSz; - - esd->signerInfoSeqSz = SetSequence(signerInfoSz, esd->signerInfoSeq); - signerInfoSz += esd->signerInfoSeqSz; - esd->signerInfoSetSz = SetSet(signerInfoSz, esd->signerInfoSet); - signerInfoSz += esd->signerInfoSetSz; - - esd->certsSetSz = SetImplicit(ASN_SET, 0, pkcs7->singleCertSz, - esd->certsSet); - - esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId, - oidHashType, 0); - esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet); - - - esd->versionSz = SetMyVersion(1, esd->version, 0); - - totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz + - esd->contentInfoSeqSz + esd->certsSetSz + pkcs7->singleCertSz + - esd->innerOctetsSz + esd->innerContSeqSz + - innerOidSz + pkcs7->contentSz + - signerInfoSz; - esd->innerSeqSz = SetSequence(totalSz, esd->innerSeq); - totalSz += esd->innerSeqSz; - esd->outerContentSz = SetExplicit(0, totalSz, esd->outerContent); - totalSz += esd->outerContentSz + outerOidSz; - esd->outerSeqSz = SetSequence(totalSz, esd->outerSeq); - totalSz += esd->outerSeqSz; - - if (outputSz < totalSz) { - if (pkcs7->signedAttribsSz != 0) - XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BUFFER_E; - } - - idx = 0; - XMEMCPY(output + idx, esd->outerSeq, esd->outerSeqSz); - idx += esd->outerSeqSz; - XMEMCPY(output + idx, outerOid, outerOidSz); - idx += outerOidSz; - XMEMCPY(output + idx, esd->outerContent, esd->outerContentSz); - idx += esd->outerContentSz; - XMEMCPY(output + idx, esd->innerSeq, esd->innerSeqSz); - idx += esd->innerSeqSz; - XMEMCPY(output + idx, esd->version, esd->versionSz); - idx += esd->versionSz; - XMEMCPY(output + idx, esd->digAlgoIdSet, esd->digAlgoIdSetSz); - idx += esd->digAlgoIdSetSz; - XMEMCPY(output + idx, esd->singleDigAlgoId, esd->singleDigAlgoIdSz); - idx += esd->singleDigAlgoIdSz; - XMEMCPY(output + idx, esd->contentInfoSeq, esd->contentInfoSeqSz); - idx += esd->contentInfoSeqSz; - XMEMCPY(output + idx, innerOid, innerOidSz); - idx += innerOidSz; - XMEMCPY(output + idx, esd->innerContSeq, esd->innerContSeqSz); - idx += esd->innerContSeqSz; - XMEMCPY(output + idx, esd->innerOctets, esd->innerOctetsSz); - idx += esd->innerOctetsSz; - XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); - idx += pkcs7->contentSz; - XMEMCPY(output + idx, esd->certsSet, esd->certsSetSz); - idx += esd->certsSetSz; - XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz); - idx += pkcs7->singleCertSz; - XMEMCPY(output + idx, esd->signerInfoSet, esd->signerInfoSetSz); - idx += esd->signerInfoSetSz; - XMEMCPY(output + idx, esd->signerInfoSeq, esd->signerInfoSeqSz); - idx += esd->signerInfoSeqSz; - XMEMCPY(output + idx, esd->signerVersion, esd->signerVersionSz); - idx += esd->signerVersionSz; - XMEMCPY(output + idx, esd->issuerSnSeq, esd->issuerSnSeqSz); - idx += esd->issuerSnSeqSz; - XMEMCPY(output + idx, esd->issuerName, esd->issuerNameSz); - idx += esd->issuerNameSz; - XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz); - idx += pkcs7->issuerSz; - XMEMCPY(output + idx, esd->issuerSn, esd->issuerSnSz); - idx += esd->issuerSnSz; - XMEMCPY(output + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); - idx += esd->signerDigAlgoIdSz; - - /* SignerInfo:Attributes */ - if (flatSignedAttribsSz > 0) { - XMEMCPY(output + idx, esd->signedAttribSet, esd->signedAttribSetSz); - idx += esd->signedAttribSetSz; - XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz); - idx += flatSignedAttribsSz; - XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - - XMEMCPY(output + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz); - idx += esd->digEncAlgoIdSz; - XMEMCPY(output + idx, esd->signerDigest, esd->signerDigestSz); - idx += esd->signerDigestSz; - XMEMCPY(output + idx, esd->encContentDigest, esd->encContentDigestSz); - idx += esd->encContentDigestSz; - -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return idx; -} - - -#ifndef NO_RSA - -/* returns size of signature put into out, negative on error */ -static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, - byte* hash, word32 hashSz) -{ - int ret = 0; - word32 scratch = 0; -#ifdef WOLFSSL_SMALL_STACK - byte* digest; - RsaKey* key; -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; - RsaKey stack_key; - RsaKey* key = &stack_key; -#endif - - if (pkcs7 == NULL || sig == NULL || hash == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (digest == NULL) - return MEMORY_E; - - key = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (key == NULL) { - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); - - ret = wc_InitRsaKey_ex(key, pkcs7->heap, pkcs7->devId); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (wc_RsaPublicKeyDecode(pkcs7->publicKey, &scratch, key, - pkcs7->publicKeySz) < 0) { - WOLFSSL_MSG("ASN RSA key decode error"); - wc_FreeRsaKey(key); -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return PUBLIC_KEY_E; - } - - ret = wc_RsaSSL_Verify(sig, sigSz, digest, MAX_PKCS7_DIGEST_SZ, key); - - wc_FreeRsaKey(key); - - if (((int)hashSz != ret) || (XMEMCMP(digest, hash, ret) != 0)) { - ret = SIG_VERIFY_E; - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -#endif /* NO_RSA */ - - -#ifdef HAVE_ECC - -/* returns size of signature put into out, negative on error */ -static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, - byte* hash, word32 hashSz) -{ - int ret = 0; - int res = 0; -#ifdef WOLFSSL_SMALL_STACK - byte* digest; - ecc_key* key; -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; - ecc_key stack_key; - ecc_key* key = &stack_key; -#endif - word32 idx = 0; - - if (pkcs7 == NULL || sig == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_SMALL_STACK - digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (digest == NULL) - return MEMORY_E; - - key = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (key == NULL) { - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); - - ret = wc_ecc_init_ex(key, pkcs7->heap, pkcs7->devId); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (wc_EccPublicKeyDecode(pkcs7->publicKey, &idx, key, - pkcs7->publicKeySz) < 0) { - WOLFSSL_MSG("ASN ECDSA key decode error"); - wc_ecc_free(key); -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return PUBLIC_KEY_E; - } - - ret = wc_ecc_verify_hash(sig, sigSz, hash, hashSz, &res, key); - - wc_ecc_free(key); - - if (ret == 0 && res != 1) { - ret = SIG_VERIFY_E; - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -#endif /* HAVE_ECC */ - - -/* build SignedData digest, both in PKCS#7 DigestInfo format and - * as plain digest for CMS. - * - * pkcs7 - pointer to initialized PKCS7 struct - * signedAttrib - signed attributes - * signedAttribSz - size of signedAttrib, octets - * pkcs7Digest - [OUT] PKCS#7 DigestInfo - * pkcs7DigestSz - [IN/OUT] size of pkcs7Digest - * plainDigest - [OUT] pointer to plain digest, offset into pkcs7Digest - * plainDigestSz - [OUT] size of digest at plainDigest - * - * returns 0 on success, negative on error */ -static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, - word32 signedAttribSz, byte* pkcs7Digest, - word32* pkcs7DigestSz, byte** plainDigest, - word32* plainDigestSz) -{ - int ret = 0, digIdx = 0, hashSz; - word32 attribSetSz; - byte attribSet[MAX_SET_SZ]; - byte digest[WC_MAX_DIGEST_SIZE]; - byte digestInfoSeq[MAX_SEQ_SZ]; - byte digestStr[MAX_OCTET_STR_SZ]; - byte algoId[MAX_ALGO_SZ]; - word32 digestInfoSeqSz, digestStrSz, algoIdSz; -#ifdef WOLFSSL_SMALL_STACK - byte* digestInfo; -#else - byte digestInfo[MAX_PKCS7_DIGEST_SZ]; -#endif - - wc_HashAlg hash; - enum wc_HashType hashType; - - if (pkcs7 == NULL || pkcs7Digest == NULL || - pkcs7DigestSz == NULL || plainDigest == NULL) { - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - digestInfo = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (digestInfo == NULL) - return MEMORY_E; -#endif - - XMEMSET(pkcs7Digest, 0, *pkcs7DigestSz); - XMEMSET(digest, 0, WC_MAX_DIGEST_SIZE); - XMEMSET(digestInfo, 0, MAX_PKCS7_DIGEST_SZ); - - hashType = wc_OidGetHash(pkcs7->hashOID); - ret = wc_HashGetDigestSize(hashType); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - hashSz = ret; - - /* calculate digest */ - ret = wc_HashInit(&hash, hashType); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (signedAttribSz > 0) { - - if (signedAttrib == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BAD_FUNC_ARG; - } - - attribSetSz = SetSet(signedAttribSz, attribSet); - ret = wc_HashUpdate(&hash, hashType, attribSet, attribSetSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - ret = wc_HashUpdate(&hash, hashType, signedAttrib, signedAttribSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - ret = wc_HashFinal(&hash, hashType, digest); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - } else { - - if (pkcs7->content == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BAD_FUNC_ARG; - } - - ret = wc_HashUpdate(&hash, hashType, pkcs7->content, pkcs7->contentSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - ret = wc_HashFinal(&hash, hashType, digest); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - } - - /* Set algoID, with NULL attributes */ - algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0); - - digestStrSz = SetOctetString(hashSz, digestStr); - digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz, - digestInfoSeq); - - XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); - digIdx += digestInfoSeqSz; - XMEMCPY(digestInfo + digIdx, algoId, algoIdSz); - digIdx += algoIdSz; - XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); - digIdx += digestStrSz; - XMEMCPY(digestInfo + digIdx, digest, hashSz); - digIdx += hashSz; - - XMEMCPY(pkcs7Digest, digestInfo, digIdx); - *pkcs7DigestSz = digIdx; - - /* set plain digest pointer */ - *plainDigest = pkcs7Digest + digIdx - hashSz; - *plainDigestSz = hashSz; - -#ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return 0; -} - - -/* verifies SignedData signature, over either PKCS#7 DigestInfo or - * content digest. - * - * pkcs7 - pointer to initialized PKCS7 struct - * sig - signature to verify - * sigSz - size of sig - * signedAttrib - signed attributes, or null if empty - * signedAttribSz - size of signedAttributes - * - * return 0 on success, negative on error */ -static int wc_PKCS7_SignedDataVerifySignature(PKCS7* pkcs7, byte* sig, - word32 sigSz, byte* signedAttrib, - word32 signedAttribSz) -{ - int ret = 0; - word32 plainDigestSz = 0, pkcs7DigestSz; - byte* plainDigest = NULL; /* offset into pkcs7Digest */ -#ifdef WOLFSSL_SMALL_STACK - byte* pkcs7Digest; -#else - byte pkcs7Digest[MAX_PKCS7_DIGEST_SZ]; -#endif - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_SMALL_STACK - pkcs7Digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (pkcs7Digest == NULL) - return MEMORY_E; -#endif - - /* build hash to verify against */ - pkcs7DigestSz = MAX_PKCS7_DIGEST_SZ; - ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib, - signedAttribSz, pkcs7Digest, - &pkcs7DigestSz, &plainDigest, - &plainDigestSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - switch (pkcs7->publicKeyOID) { - -#ifndef NO_RSA - case RSAk: - ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, pkcs7Digest, - pkcs7DigestSz); - if (ret < 0) { - WOLFSSL_MSG("PKCS#7 verification failed, trying CMS"); - ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, plainDigest, - plainDigestSz); - } - break; -#endif - -#ifdef HAVE_ECC - case ECDSAk: - ret = wc_PKCS7_EcdsaVerify(pkcs7, sig, sigSz, plainDigest, - plainDigestSz); - break; -#endif - - default: - WOLFSSL_MSG("Unsupported public key type"); - ret = BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; -} - - -/* set correct public key OID based on signature OID, stores in - * pkcs7->publicKeyOID and returns same value */ -static int wc_PKCS7_SetPublicKeyOID(PKCS7* pkcs7, int sigOID) -{ - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - pkcs7->publicKeyOID = 0; - - switch (sigOID) { - - #ifndef NO_RSA - /* RSA signature types */ - case CTC_MD2wRSA: - case CTC_MD5wRSA: - case CTC_SHAwRSA: - case CTC_SHA224wRSA: - case CTC_SHA256wRSA: - case CTC_SHA384wRSA: - case CTC_SHA512wRSA: - pkcs7->publicKeyOID = RSAk; - break; - - /* if sigOID is already RSAk */ - case RSAk: - pkcs7->publicKeyOID = sigOID; - break; - #endif - - #ifndef NO_DSA - /* DSA signature types */ - case CTC_SHAwDSA: - pkcs7->publicKeyOID = DSAk; - break; - - /* if sigOID is already DSAk */ - case DSAk: - pkcs7->publicKeyOID = sigOID; - break; - #endif - - #ifdef HAVE_ECC - /* ECDSA signature types */ - case CTC_SHAwECDSA: - case CTC_SHA224wECDSA: - case CTC_SHA256wECDSA: - case CTC_SHA384wECDSA: - case CTC_SHA512wECDSA: - pkcs7->publicKeyOID = ECDSAk; - break; - - /* if sigOID is already ECDSAk */ - case ECDSAk: - pkcs7->publicKeyOID = sigOID; - break; - #endif - - default: - WOLFSSL_MSG("Unsupported public key algorithm"); - return ASN_SIG_KEY_E; - } - - return pkcs7->publicKeyOID; -} - - -/* Parses through the attributes and adds them to the PKCS7 structure - * Creates dynamic attribute structures that are free'd with calling - * wc_PKCS7_Free() - * - * NOTE: An attribute has the ASN1 format of - ** Sequence - ****** Object ID - ****** Set - ********** {PritnableString, UTCTime, OCTET STRING ...} - * - * pkcs7 the PKCS7 structure to put the parsed attributes into - * in buffer holding all attributes - * inSz size of in buffer - * - * returns the number of attributes parsed on success - */ -static int wc_PKCS7_ParseAttribs(PKCS7* pkcs7, byte* in, int inSz) -{ - int found = 0; - word32 idx = 0; - word32 oid; - - if (pkcs7 == NULL || in == NULL || inSz < 0) { - return BAD_FUNC_ARG; - } - - while (idx < (word32)inSz) { - int length = 0; - int oidIdx; - PKCS7DecodedAttrib* attrib; - - if (GetSequence(in, &idx, &length, inSz) < 0) - return ASN_PARSE_E; - - attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib), - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (attrib == NULL) { - return MEMORY_E; - } - XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); - - oidIdx = idx; - if (GetObjectId(in, &idx, &oid, oidIgnoreType, inSz) - < 0) { - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - attrib->oidSz = idx - oidIdx; - attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (attrib->oid == NULL) { - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - XMEMCPY(attrib->oid, in + oidIdx, attrib->oidSz); - - - /* Get Set that contains the printable string value */ - if (GetSet(in, &idx, &length, inSz) < 0) { - XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if ((inSz - idx) < (word32)length) { - XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - attrib->valueSz = (word32)length; - attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (attrib->value == NULL) { - XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - XMEMCPY(attrib->value, in + idx, attrib->valueSz); - idx += length; - - /* store attribute in linked list */ - if (pkcs7->decodedAttrib != NULL) { - attrib->next = pkcs7->decodedAttrib; - pkcs7->decodedAttrib = attrib; - } else { - pkcs7->decodedAttrib = attrib; - } - found++; - } - - return found; -} - - -/* Finds the certificates in the message and saves it. */ -int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) -{ - word32 idx, contentType, hashOID, sigOID; - int length, version, ret; - byte* content = NULL; - byte* sig = NULL; - byte* cert = NULL; - byte* signedAttrib = NULL; - int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0; - byte degenerate; -#ifdef ASN_BER_TO_DER - byte* der; -#endif - - if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0) - return BAD_FUNC_ARG; - - idx = 0; - - /* Get the contentInfo sequence */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (length == 0 && pkiMsg[idx-1] == 0x80) { -#ifdef ASN_BER_TO_DER - word32 len = 0; - - ret = wc_BerToDer(pkiMsg, pkiMsgSz, NULL, &len); - if (ret != LENGTH_ONLY_E) - return ret; - pkcs7->der = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7->der == NULL) - return MEMORY_E; - ret = wc_BerToDer(pkiMsg, pkiMsgSz, pkcs7->der, &len); - if (ret < 0) - return ret; - - pkiMsg = pkcs7->der; - pkiMsgSz = len; - idx = 0; - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; -#else - return BER_INDEF_E; -#endif - } - - /* Get the contentInfo contentType */ - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (contentType != SIGNED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type SignedData"); - return PKCS7_OID_E; - } - - /* get the ContentInfo content */ - if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Get the signedData sequence */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Get the version */ - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (version != 1) { - WOLFSSL_MSG("PKCS#7 signedData needs to be of version 1"); - return ASN_VERSION_E; - } - - /* Get the set of DigestAlgorithmIdentifiers */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Skip the set. */ - idx += length; - degenerate = (length == 0)? 1 : 0; - - /* Get the inner ContentInfo sequence */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Get the inner ContentInfo contentType */ - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (contentType != DATA) { - WOLFSSL_MSG("PKCS#7 inner input not of type Data"); - return PKCS7_OID_E; - } - - /* Check for content info, it could be omitted when degenerate */ - { - word32 localIdx = idx; - ret = 0; - if (pkiMsg[localIdx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, pkiMsgSz) <= 0) - ret = ASN_PARSE_E; - - if (ret == 0 && pkiMsg[localIdx++] != ASN_OCTET_STRING) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - /* Save the inner data as the content. */ - if (length > 0) { - /* Local pointer for calculating hashes later */ - content = &pkiMsg[localIdx]; - contentSz = length; - localIdx += length; - } - - /* update idx if successful */ - if (ret == 0) { - idx = localIdx; - } - } - - /* If getting the content info failed with non degenerate then return the - * error case. Otherwise with a degenerate it is ok if the content - * info was omitted */ - if (!degenerate && ret != 0) { - return ret; - } - - /* Get the implicit[0] set of certificates */ - if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - idx++; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (length > 0) { - /* At this point, idx is at the first certificate in - * a set of certificates. There may be more than one, - * or none, or they may be a PKCS 6 extended - * certificate. We want to save the first cert if it - * is X.509. */ - - word32 certIdx = idx; - - if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { - if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0) - return ASN_PARSE_E; - - cert = &pkiMsg[idx]; - certSz += (certIdx - idx); - } - -#ifdef ASN_BER_TO_DER - der = pkcs7->der; -#endif - /* This will reset PKCS7 structure and then set the certificate */ - wc_PKCS7_InitWithCert(pkcs7, cert, certSz); -#ifdef ASN_BER_TO_DER - pkcs7->der = der; -#endif - - /* iterate through any additional certificates */ - if (MAX_PKCS7_CERTS > 0) { - word32 localIdx; - int sz = 0; - int i; - - pkcs7->cert[0] = cert; - pkcs7->certSz[0] = certSz; - certIdx = idx + certSz; - - for (i = 1; i < MAX_PKCS7_CERTS && certIdx + 1 < pkiMsgSz; i++) { - localIdx = certIdx; - - if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { - if (GetLength(pkiMsg, &certIdx, &sz, pkiMsgSz) < 0) - return ASN_PARSE_E; - - pkcs7->cert[i] = &pkiMsg[localIdx]; - pkcs7->certSz[i] = sz + (certIdx - localIdx); - certIdx += sz; - } - } - } - } - idx += length; - } - - /* set content and size after init of PKCS7 structure */ - pkcs7->content = content; - pkcs7->contentSz = contentSz; - - /* Get the implicit[1] set of crls */ - if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { - idx++; - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Skip the set */ - idx += length; - } - - /* Get the set of signerInfos */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (length > 0) { - /* Get the sequence of the first signerInfo */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Get the version */ - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (version != 1) { - WOLFSSL_MSG("PKCS#7 signerInfo needs to be of version 1"); - return ASN_VERSION_E; - } - - /* Get the sequence of IssuerAndSerialNumber */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Skip it */ - idx += length; - - /* Get the sequence of digestAlgorithm */ - if (GetAlgoId(pkiMsg, &idx, &hashOID, oidHashType, pkiMsgSz) < 0) { - return ASN_PARSE_E; - } - pkcs7->hashOID = (int)hashOID; - - /* Get the IMPLICIT[0] SET OF signedAttributes */ - if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - idx++; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* save pointer and length */ - signedAttrib = &pkiMsg[idx]; - signedAttribSz = length; - - if (wc_PKCS7_ParseAttribs(pkcs7, signedAttrib, signedAttribSz) <0) { - WOLFSSL_MSG("Error parsing signed attributes"); - return ASN_PARSE_E; - } - - idx += length; - } - - /* Get digestEncryptionAlgorithm */ - if (GetAlgoId(pkiMsg, &idx, &sigOID, oidSigType, pkiMsgSz) < 0) { - return ASN_PARSE_E; - } - - /* store public key type based on digestEncryptionAlgorithm */ - ret = wc_PKCS7_SetPublicKeyOID(pkcs7, sigOID); - if (ret <= 0) { - WOLFSSL_MSG("Failed to set public key OID from signature"); - return ret; - } - - /* Get the signature */ - if (pkiMsg[idx] == ASN_OCTET_STRING) { - idx++; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* save pointer and length */ - sig = &pkiMsg[idx]; - sigSz = length; - - idx += length; - } - - pkcs7->content = content; - pkcs7->contentSz = contentSz; - - ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz, - signedAttrib, signedAttribSz); - if (ret < 0) - return ret; - } - - return 0; -} - - -#ifdef HAVE_ECC - -/* KARI == KeyAgreeRecipientInfo (key agreement) */ -typedef struct WC_PKCS7_KARI { - DecodedCert* decoded; /* decoded recip cert */ - void* heap; /* user heap, points to PKCS7->heap */ - int devId; /* device ID for HW based private key */ - ecc_key* recipKey; /* recip key (pub | priv) */ - ecc_key* senderKey; /* sender key (pub | priv) */ - byte* senderKeyExport; /* sender ephemeral key DER */ - byte* kek; /* key encryption key */ - byte* ukm; /* OPTIONAL user keying material */ - byte* sharedInfo; /* ECC-CMS-SharedInfo ASN.1 encoded blob */ - word32 senderKeyExportSz; /* size of sender ephemeral key DER */ - word32 kekSz; /* size of key encryption key */ - word32 ukmSz; /* size of user keying material */ - word32 sharedInfoSz; /* size of ECC-CMS-SharedInfo encoded */ - byte ukmOwner; /* do we own ukm buffer? 1:yes, 0:no */ - byte direction; /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */ - byte decodedInit : 1; /* indicates decoded was initialized */ - byte recipKeyInit : 1; /* indicates recipKey was initialized */ - byte senderKeyInit : 1; /* indicates senderKey was initialized */ -} 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) { -#ifndef NO_AES - #ifdef WOLFSSL_AES_128 - case AES128_WRAP: - #endif - #ifdef WOLFSSL_AES_192 - case AES192_WRAP: - #endif - #ifdef WOLFSSL_AES_256 - case AES256_WRAP: - #endif - - 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; -#endif /* NO_AES */ - - default: - WOLFSSL_MSG("Unsupported key wrap algorithm"); - return BAD_KEYWRAP_ALG_E; - }; - - (void)cekSz; - (void)kekSz; - (void)outSz; - (void)direction; - 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, pkcs7->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, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kari, pkcs7->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, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kari->decoded, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kari, pkcs7->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->decodedInit = 0; - kari->recipKeyInit = 0; - kari->senderKeyInit = 0; - - kari->heap = pkcs7->heap; - kari->devId = pkcs7->devId; - - 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) { - if (kari->decodedInit) - FreeDecodedCert(kari->decoded); - XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7); - } - if (kari->senderKey) { - if (kari->senderKeyInit) - wc_ecc_free(kari->senderKey); - XFREE(kari->senderKey, heap, DYNAMIC_TYPE_PKCS7); - } - if (kari->recipKey) { - if (kari->recipKeyInit) - 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; - - /* decode certificate */ - InitDecodedCert(kari->decoded, (byte*)cert, certSz, kari->heap); - kari->decodedInit = 1; - 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_ex(kari->recipKey, kari->heap, kari->devId); - if (ret != 0) - return ret; - - kari->recipKeyInit = 1; - - /* get recip public key */ - if (kari->direction == WC_PKCS7_ENCODE) { - - idx = 0; - ret = wc_EccPublicKeyDecode(kari->decoded->publicKey, &idx, - kari->recipKey, kari->decoded->pubKeySize); - if (ret != 0) - return ret; - } - /* get recip private key */ - else if (kari->direction == WC_PKCS7_DECODE) { - if (key != NULL && keySz > 0) { - idx = 0; - ret = wc_EccPrivateKeyDecode(key, &idx, kari->recipKey, keySz); - } - else if (kari->devId == INVALID_DEVID) { - ret = BAD_FUNC_ARG; - } - if (ret != 0) - return ret; - - } else { - /* bad direction */ - return BAD_FUNC_ARG; - } - - (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, WC_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_ex(kari->senderKey, kari->heap, kari->devId); - if (ret != 0) - return ret; - - kari->senderKeyInit = 1; - - 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 entityUInfoExplicitSz = 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 entityUInfoExplicitSeq[MAX_SEQ_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); - - entityUInfoExplicitSz = SetExplicit(0, entityUInfoOctetSz + - kari->ukmSz, - entityUInfoExplicitSeq); - sharedInfoSz += entityUInfoExplicitSz; - } - - /* 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, entityUInfoExplicitSeq, - entityUInfoExplicitSz); - idx += entityUInfoExplicitSz; - 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; - enum wc_HashType 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 */ - XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7); - 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 WOLFSSL_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, direction = 0; - - /* 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; - - /* set direction based on keyWrapAlgo */ - switch (keyWrapAlgo) { -#ifndef NO_AES - #ifdef WOLFSSL_AES_128 - case AES128_WRAP: - #endif - #ifdef WOLFSSL_AES_192 - case AES192_WRAP: - #endif - #ifdef WOLFSSL_AES_256 - case AES256_WRAP: - #endif - direction = AES_ENCRYPTION; - break; -#endif - default: - WOLFSSL_MSG("Unsupported key wrap algorithm"); - return BAD_KEYWRAP_ALG_E; - } - - 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, - direction); - 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; -} - -#endif /* HAVE_ECC */ - -#ifndef NO_RSA - -/* create ASN.1 formatted RecipientInfo structure, returns sequence size */ -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; - int verSz, issuerSz, snSz, keyEncAlgSz; - int issuerSeqSz, recipSeqSz, issuerSerialSeqSz; - int encKeyOctetStrSz; - - byte ver[MAX_VERSION_SZ]; - byte issuerSerialSeq[MAX_SEQ_SZ]; - byte recipSeq[MAX_SEQ_SZ]; - byte issuerSeq[MAX_SEQ_SZ]; - byte encKeyOctetStr[MAX_OCTET_STR_SZ]; - -#ifdef WOLFSSL_SMALL_STACK - byte *serial; - byte *keyAlgArray; - - RsaKey* pubKey; - DecodedCert* decoded; - - serial = (byte*)XMALLOC(MAX_SN_SZ, heap, DYNAMIC_TYPE_TMP_BUFFER); - keyAlgArray = (byte*)XMALLOC(MAX_SN_SZ, heap, DYNAMIC_TYPE_TMP_BUFFER); - decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (decoded == NULL || serial == NULL || keyAlgArray == NULL) { - if (serial) XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (keyAlgArray) XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (decoded) XFREE(decoded, heap, 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; - DecodedCert* decoded = &stack_decoded; -#endif - - InitDecodedCert(decoded, (byte*)cert, certSz, heap); - ret = ParseCert(decoded, CA_TYPE, NO_VERIFY, 0); - if (ret < 0) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* version */ - verSz = SetMyVersion(0, ver, 0); - - /* IssuerAndSerialNumber */ - if (decoded->issuerRaw == NULL || decoded->issuerRawLen == 0) { - WOLFSSL_MSG("DecodedCert lacks raw issuer pointer and length"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return -1; - } - issuerSz = decoded->issuerRawLen; - issuerSeqSz = SetSequence(issuerSz, issuerSeq); - - if (decoded->serialSz == 0) { - WOLFSSL_MSG("DecodedCert missing serial number"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return -1; - } - snSz = SetSerialNumber(decoded->serial, decoded->serialSz, serial, MAX_SN_SZ); - - issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz, - issuerSerialSeq); - - /* KeyEncryptionAlgorithmIdentifier, only support RSA now */ - if (keyEncAlgo != RSAk) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ALGO_ID_E; - } - - keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, oidKeyType, 0); - if (keyEncAlgSz == 0) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_TMP_BUFFER); - if (pubKey == NULL) { - FreeDecodedCert(decoded); - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - /* EncryptedKey */ - ret = wc_InitRsaKey_ex(pubKey, heap, INVALID_DEVID); - if (ret != 0) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(pubKey, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (wc_RsaPublicKeyDecode(decoded->publicKey, &idx, pubKey, - decoded->pubKeySize) < 0) { - WOLFSSL_MSG("ASN RSA key decode error"); - wc_FreeRsaKey(pubKey); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(pubKey, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return PUBLIC_KEY_E; - } - - *keyEncSz = wc_RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc, - MAX_ENCRYPTED_KEY_SZ, pubKey, rng); - wc_FreeRsaKey(pubKey); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(pubKey, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (*keyEncSz < 0) { - WOLFSSL_MSG("RSA Public Encrypt failed"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return *keyEncSz; - } - - encKeyOctetStrSz = SetOctetString(*keyEncSz, encKeyOctetStr); - - /* RecipientInfo */ - recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz + - issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz + - *keyEncSz, recipSeq); - - if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz + - keyEncAlgSz + encKeyOctetStrSz + *keyEncSz > (int)outSz) { - WOLFSSL_MSG("RecipientInfo output buffer too small"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BUFFER_E; - } - - XMEMCPY(out + totalSz, recipSeq, recipSeqSz); - totalSz += recipSeqSz; - XMEMCPY(out + totalSz, ver, verSz); - totalSz += verSz; - XMEMCPY(out + totalSz, issuerSerialSeq, issuerSerialSeqSz); - totalSz += issuerSerialSeqSz; - XMEMCPY(out + totalSz, issuerSeq, issuerSeqSz); - totalSz += issuerSeqSz; - XMEMCPY(out + totalSz, decoded->issuerRaw, issuerSz); - totalSz += issuerSz; - XMEMCPY(out + totalSz, serial, snSz); - totalSz += snSz; - XMEMCPY(out + totalSz, keyAlgArray, keyEncAlgSz); - totalSz += keyEncAlgSz; - XMEMCPY(out + totalSz, encKeyOctetStr, encKeyOctetStrSz); - totalSz += encKeyOctetStrSz; - XMEMCPY(out + totalSz, contentKeyEnc, *keyEncSz); - totalSz += *keyEncSz; - - FreeDecodedCert(decoded); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return totalSz; -} -#endif /* !NO_RSA */ - - -/* 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 - Aes aes; -#endif -#ifndef NO_DES3 - Des des; - Des3 des3; -#endif - - if (key == NULL || iv == NULL || in == NULL || out == NULL) - return BAD_FUNC_ARG; - - switch (encryptOID) { -#ifndef NO_AES - #ifdef WOLFSSL_AES_128 - case AES128CBCb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - #endif - if ( - #ifdef WOLFSSL_AES_128 - (encryptOID == AES128CBCb && keySz != 16 ) || - #endif - #ifdef WOLFSSL_AES_192 - (encryptOID == AES192CBCb && keySz != 24 ) || - #endif - #ifdef WOLFSSL_AES_256 - (encryptOID == AES256CBCb && keySz != 32 ) || - #endif - (ivSz != AES_BLOCK_SIZE) ) - return BAD_FUNC_ARG; - - ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION); - if (ret == 0) - ret = wc_AesCbcEncrypt(&aes, out, in, inSz); - - break; -#endif -#ifndef NO_DES3 - case DESb: - if (keySz != DES_KEYLEN || ivSz != DES_BLOCK_SIZE) - return BAD_FUNC_ARG; - - ret = wc_Des_SetKey(&des, key, iv, DES_ENCRYPTION); - if (ret == 0) - ret = wc_Des_CbcEncrypt(&des, out, in, inSz); - - break; - - case DES3b: - if (keySz != DES3_KEYLEN || ivSz != DES_BLOCK_SIZE) - return BAD_FUNC_ARG; - - ret = wc_Des3_SetKey(&des3, key, iv, DES_ENCRYPTION); - if (ret == 0) - ret = wc_Des3_CbcEncrypt(&des3, out, in, inSz); - - break; -#endif - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - return ret; -} - - -/* 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 - Aes aes; -#endif -#ifndef NO_DES3 - Des des; - Des3 des3; -#endif - - if (key == NULL || iv == NULL || in == NULL || out == NULL) - return BAD_FUNC_ARG; - - switch (encryptOID) { -#ifndef NO_AES - #ifdef WOLFSSL_AES_128 - case AES128CBCb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - #endif - if ( - #ifdef WOLFSSL_AES_128 - (encryptOID == AES128CBCb && keySz != 16 ) || - #endif - #ifdef WOLFSSL_AES_192 - (encryptOID == AES192CBCb && keySz != 24 ) || - #endif - #ifdef WOLFSSL_AES_256 - (encryptOID == AES256CBCb && keySz != 32 ) || - #endif - (ivSz != AES_BLOCK_SIZE) ) - return BAD_FUNC_ARG; - - ret = wc_AesSetKey(&aes, key, keySz, iv, AES_DECRYPTION); - if (ret == 0) - ret = wc_AesCbcDecrypt(&aes, out, in, inSz); - - break; -#endif -#ifndef NO_DES3 - case DESb: - if (keySz != DES_KEYLEN || ivSz != DES_BLOCK_SIZE) - return BAD_FUNC_ARG; - - ret = wc_Des_SetKey(&des, key, iv, DES_DECRYPTION); - if (ret == 0) - ret = wc_Des_CbcDecrypt(&des, out, in, inSz); - - break; - case DES3b: - if (keySz != DES3_KEYLEN || ivSz != DES_BLOCK_SIZE) - return BAD_FUNC_ARG; - - ret = wc_Des3_SetKey(&des3, key, iv, DES_DECRYPTION); - if (ret == 0) - ret = wc_Des3_CbcDecrypt(&des3, out, in, inSz); - - break; -#endif - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - - return ret; -} - - -/* generate random IV, place in iv, return 0 on success negative on error */ -static int wc_PKCS7_GenerateIV(PKCS7* pkcs7, WC_RNG* rng, byte* iv, word32 ivSz) -{ - int ret; - WC_RNG* rnd = NULL; - - if (iv == NULL || ivSz == 0) - return BAD_FUNC_ARG; - - /* input RNG is optional, init local one if input rng is NULL */ - if (rng == NULL) { - rnd = (WC_RNG*)XMALLOC(sizeof(WC_RNG), pkcs7->heap, DYNAMIC_TYPE_RNG); - if (rnd == NULL) - return MEMORY_E; - - ret = wc_InitRng_ex(rnd, pkcs7->heap, pkcs7->devId); - if (ret != 0) { - XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG); - return ret; - } - - } else { - rnd = rng; - } - - ret = wc_RNG_GenerateBlock(rnd, iv, ivSz); - - if (rng == NULL) { - wc_FreeRng(rnd); - XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG); - } - - return ret; -} - - -/* return size of padded data, padded to blockSz chunks, or negative on error */ -int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz) -{ - int padSz; - - if (blockSz == 0) - return BAD_FUNC_ARG; - - padSz = blockSz - (inputSz % blockSz); - - return padSz; -} - - -/* pad input data to blockSz chunk, place in outSz. out must be big enough - * for input + pad bytes. See wc_PKCS7_GetPadSize() helper. */ -int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz, - word32 blockSz) -{ - int i, padSz; - - if (in == NULL || inSz == 0 || - out == NULL || outSz == 0) - return BAD_FUNC_ARG; - - padSz = wc_PKCS7_GetPadSize(inSz, blockSz); - - if (outSz < (inSz + padSz)) - return BAD_FUNC_ARG; - - XMEMCPY(out, in, inSz); - - for (i = 0; i < padSz; i++) { - out[inSz + i] = (byte)padSz; - } - - return inSz + padSz; -} - - -/* build PKCS#7 envelopedData content type, return enveloped size */ -int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) -{ - int ret, idx = 0; - int totalSz, padSz, encryptedOutSz; - - int contentInfoSeqSz, outerContentTypeSz, outerContentSz; - byte contentInfoSeq[MAX_SEQ_SZ]; - byte outerContentType[MAX_ALGO_SZ]; - byte outerContent[MAX_SEQ_SZ]; - - int envDataSeqSz, verSz; - byte envDataSeq[MAX_SEQ_SZ]; - byte ver[MAX_VERSION_SZ]; - - WC_RNG rng; - int contentKeyEncSz, blockSz, blockKeySz; - byte contentKeyPlain[MAX_CONTENT_KEY_LEN]; -#ifdef WOLFSSL_SMALL_STACK - byte* contentKeyEnc; -#else - byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ]; -#endif - byte* plain; - byte* encryptedContent; - - int recipSz, recipSetSz; -#ifdef WOLFSSL_SMALL_STACK - byte* recip; -#else - byte recip[MAX_RECIP_SZ]; -#endif - byte recipSet[MAX_SET_SZ]; - - int encContentOctetSz, encContentSeqSz, contentTypeSz; - int contentEncAlgoSz, ivOctetStringSz; - byte encContentSeq[MAX_SEQ_SZ]; - byte contentType[MAX_ALGO_SZ]; - byte contentEncAlgo[MAX_ALGO_SZ]; - byte tmpIv[MAX_CONTENT_IV_SIZE]; - byte ivOctetString[MAX_OCTET_STR_SZ]; - byte encContentOctet[MAX_OCTET_STR_SZ]; - - if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || - pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL || - pkcs7->publicKeyOID == 0) - return BAD_FUNC_ARG; - - if (output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - - blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); - if (blockKeySz < 0) - return blockKeySz; - - blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); - if (blockSz < 0) - return blockSz; - - /* outer content type */ - outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType); - - /* version, defined as 0 in RFC 2315 */ -#ifdef HAVE_ECC - if (pkcs7->publicKeyOID == ECDSAk) { - verSz = SetMyVersion(2, ver, 0); - } else -#endif - { - verSz = SetMyVersion(0, ver, 0); - } - - /* generate random content encryption key */ - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret != 0) - return ret; - - ret = wc_RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz); - if (ret != 0) { - wc_FreeRng(&rng); - return ret; - } - -#ifdef WOLFSSL_SMALL_STACK - recip = (byte*)XMALLOC(MAX_RECIP_SZ, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (contentKeyEnc == NULL || recip == NULL) { - if (recip) XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (contentKeyEnc) XFREE(contentKeyEnc, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - wc_FreeRng(&rng); - return MEMORY_E; - } -#endif - contentKeyEncSz = MAX_ENCRYPTED_KEY_SZ; - - /* build RecipientInfo, only handle 1 for now */ - switch (pkcs7->publicKeyOID) { -#ifndef NO_RSA - case RSAk: - recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, - pkcs7->singleCertSz, - pkcs7->publicKeyOID, - blockKeySz, &rng, contentKeyPlain, - contentKeyEnc, &contentKeyEncSz, recip, - MAX_RECIP_SZ, pkcs7->heap); - break; -#endif -#ifdef HAVE_ECC - 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; -#endif - - default: - WOLFSSL_MSG("Unsupported RecipientInfo public key type"); - return BAD_FUNC_ARG; - }; - - ForceZero(contentKeyEnc, MAX_ENCRYPTED_KEY_SZ); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(contentKeyEnc, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - - if (recipSz < 0) { - WOLFSSL_MSG("Failed to create RecipientInfo"); - wc_FreeRng(&rng); -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return recipSz; - } - recipSetSz = SetSet(recipSz, recipSet); - - /* generate IV for block cipher */ - ret = wc_PKCS7_GenerateIV(pkcs7, &rng, tmpIv, blockSz); - wc_FreeRng(&rng); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* EncryptedContentInfo */ - contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); - if (contentTypeSz == 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BAD_FUNC_ARG; - } - - /* allocate encrypted content buffer and PKCS#7 padding */ - padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz); - if (padSz < 0) - return padSz; - - encryptedOutSz = pkcs7->contentSz + padSz; - - plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (plain == NULL) - return MEMORY_E; - - ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, - encryptedOutSz, blockSz); - if (ret < 0) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return MEMORY_E; - } - - /* put together IV OCTET STRING */ - ivOctetStringSz = SetOctetString(blockSz, ivOctetString); - - /* build up our ContentEncryptionAlgorithmIdentifier sequence, - * adding (ivOctetStringSz + blockSz) for IV OCTET STRING */ - contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, - oidBlkType, ivOctetStringSz + blockSz); - - if (contentEncAlgoSz == 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return BAD_FUNC_ARG; - } - - /* encrypt content */ - ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, contentKeyPlain, - blockKeySz, tmpIv, blockSz, plain, encryptedOutSz, - encryptedContent); - - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ret; - } - - encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz, - encContentOctet); - - encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + - ivOctetStringSz + blockSz + - encContentOctetSz + encryptedOutSz, - encContentSeq); - - /* keep track of sizes for outer wrapper layering */ - totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + - contentEncAlgoSz + ivOctetStringSz + blockSz + - encContentOctetSz + encryptedOutSz; - - /* EnvelopedData */ - envDataSeqSz = SetSequence(totalSz, envDataSeq); - totalSz += envDataSeqSz; - - /* outer content */ - outerContentSz = SetExplicit(0, totalSz, outerContent); - totalSz += outerContentTypeSz; - totalSz += outerContentSz; - - /* ContentInfo */ - contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); - totalSz += contentInfoSeqSz; - - if (totalSz > (int)outputSz) { - WOLFSSL_MSG("Pkcs7_encrypt output buffer too small"); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return BUFFER_E; - } - - XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz); - idx += contentInfoSeqSz; - XMEMCPY(output + idx, outerContentType, outerContentTypeSz); - idx += outerContentTypeSz; - XMEMCPY(output + idx, outerContent, outerContentSz); - idx += outerContentSz; - XMEMCPY(output + idx, envDataSeq, envDataSeqSz); - idx += envDataSeqSz; - XMEMCPY(output + idx, ver, verSz); - idx += verSz; - XMEMCPY(output + idx, recipSet, recipSetSz); - idx += recipSetSz; - XMEMCPY(output + idx, recip, recipSz); - idx += recipSz; - XMEMCPY(output + idx, encContentSeq, encContentSeqSz); - idx += encContentSeqSz; - XMEMCPY(output + idx, contentType, contentTypeSz); - idx += contentTypeSz; - XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz); - idx += contentEncAlgoSz; - XMEMCPY(output + idx, ivOctetString, ivOctetStringSz); - idx += ivOctetStringSz; - XMEMCPY(output + idx, tmpIv, blockSz); - idx += blockSz; - XMEMCPY(output + idx, encContentOctet, encContentOctetSz); - idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, encryptedOutSz); - idx += encryptedOutSz; - - ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN); - - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return idx; -} - -#ifndef NO_RSA -/* 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[KEYID_SIZE]; - byte* outKey = NULL; - -#ifdef WC_RSA_BLINDING - WC_RNG rng; -#endif - -#ifdef WOLFSSL_SMALL_STACK - mp_int* serialNum; - byte* encryptedKey; - RsaKey* privKey; -#else - 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, KEYID_SIZE) == 0) { - *recipFound = 1; - } - -#ifdef WOLFSSL_SMALL_STACK - serialNum = (mp_int*)XMALLOC(sizeof(mp_int), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (serialNum == NULL) - return MEMORY_E; -#endif - - if (GetInt(serialNum, pkiMsg, idx, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(serialNum, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - mp_clear(serialNum); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(serialNum, pkcs7->heap, 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, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (encryptedKey == NULL) - return MEMORY_E; -#endif - - if (pkiMsg[(*idx)++] != ASN_OCTET_STRING) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, idx, &encryptedKeySz, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, 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), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (privKey == NULL) { - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - ret = wc_InitRsaKey_ex(privKey, pkcs7->heap, INVALID_DEVID); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) { - keyIdx = 0; - ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &keyIdx, privKey, - pkcs7->privateKeySz); - } - else if (pkcs7->devId == INVALID_DEVID) { - ret = BAD_FUNC_ARG; - } - if (ret != 0) { - WOLFSSL_MSG("Failed to decode RSA private key"); - wc_FreeRsaKey(privKey); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* decrypt encryptedKey */ - #ifdef WC_RSA_BLINDING - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret == 0) { - ret = wc_RsaSetRNG(privKey, &rng); - } - #endif - if (ret == 0) { - keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, - &outKey, privKey); - #ifdef WC_RSA_BLINDING - wc_FreeRng(&rng); - #endif - } else { - keySz = ret; - } - wc_FreeRsaKey(privKey); - - if (keySz <= 0 || outKey == NULL) { - ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return keySz; - } else { - *decryptedKeySz = keySz; - XMEMCPY(decryptedKey, outKey, keySz); - ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ); - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return 0; -} -#endif /* !NO_RSA */ - -#ifdef HAVE_ECC - -/* 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_ex(kari->senderKey, kari->heap, kari->devId); - if (ret != 0) - return ret; - - kari->senderKeyInit = 1; - - /* 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 = NULL; - if (length > 0) { - kari->ukm = (byte*)XMALLOC(length, kari->heap, DYNAMIC_TYPE_PKCS7); - if (kari->ukm == NULL) - return MEMORY_E; - - XMEMCPY(kari->ukm, pkiMsg + (*idx), length); - kari->ukmOwner = 1; - } - - (*idx) += length; - kari->ukmSz = length; - - 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 SubjectKeyIdentifier, return 0 on success, < 0 on error - * if subject key ID matches, recipFound is set to 1 */ -static int wc_PKCS7_KariGetSubjectKeyIdentifier(WC_PKCS7_KARI* kari, - byte* pkiMsg, word32 pkiMsgSz, word32* idx, - int* recipFound) -{ - int length; - byte subjKeyId[KEYID_SIZE]; - - if (kari == NULL || pkiMsg == NULL || idx == NULL || recipFound == NULL) - return BAD_FUNC_ARG; - - /* 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; - } - - return 0; -} - - -/* remove ASN.1 IssuerAndSerialNumber, return 0 on success, < 0 on error - * if issuer and serial number match, recipFound is set to 1 */ -static int wc_PKCS7_KariGetIssuerAndSerialNumber(WC_PKCS7_KARI* kari, - byte* pkiMsg, word32 pkiMsgSz, word32* idx, - int* recipFound) -{ - int length, ret; - byte issuerHash[KEYID_SIZE]; -#ifdef WOLFSSL_SMALL_STACK - mp_int* serial; - mp_int* recipSerial; -#else - mp_int stack_serial; - mp_int* serial = &stack_serial; - - mp_int stack_recipSerial; - mp_int* recipSerial = &stack_recipSerial; -#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, kari->decoded->issuerHash, KEYID_SIZE) == 0) { - *recipFound = 1; - } - -#ifdef WOLFSSL_SMALL_STACK - serial = (mp_int*)XMALLOC(sizeof(mp_int), kari->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (serial == NULL) - return MEMORY_E; - - recipSerial = (mp_int*)XMALLOC(sizeof(mp_int), kari->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (recipSerial == NULL) { - XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - if (GetInt(serial, pkiMsg, idx, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ASN_PARSE_E; - } - - ret = mp_read_unsigned_bin(recipSerial, kari->decoded->serial, - kari->decoded->serialSz); - if (ret != MP_OKAY) { - mp_clear(serial); - WOLFSSL_MSG("Failed to parse CMS recipient serial number"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - if (mp_cmp(recipSerial, serial) != MP_EQ) { - mp_clear(serial); - mp_clear(recipSerial); - WOLFSSL_MSG("CMS serial number does not match recipient"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return PKCS7_RECIP_E; - } - - mp_clear(serial); - mp_clear(recipSerial); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - 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; - int ret = 0; - - 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; - - /* KeyAgreeRecipientIdentifier is CHOICE of IssuerAndSerialNumber - * or [0] IMMPLICIT RecipientKeyIdentifier */ - if ( (pkiMsgSz > (*idx + 1)) && - (pkiMsg[*idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) ) { - - /* try to get RecipientKeyIdentifier */ - ret = wc_PKCS7_KariGetSubjectKeyIdentifier(kari, pkiMsg, pkiMsgSz, - idx, recipFound); - } else { - /* try to get IssuerAndSerialNumber */ - ret = wc_PKCS7_KariGetIssuerAndSerialNumber(kari, pkiMsg, pkiMsgSz, - idx, recipFound); - } - - /* if we don't have either option, malformed CMS */ - if (ret != 0) - return ret; - - /* 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; -} - -#endif /* HAVE_ECC */ - - -/* 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) -{ -#ifdef HAVE_ECC - int ret, keySz; - int encryptedKeySz; - int direction = 0; - 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, pkcs7->heap, - 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); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - 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, pkcs7->heap, 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, pkcs7->heap, 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, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - return ret; - } - - /* if user has not explicitly set keyAgreeOID, set from one in bundle */ - if (pkcs7->keyAgreeOID == 0) - pkcs7->keyAgreeOID = keyAgreeOID; - - /* set direction based on key wrap algorithm */ - switch (keyWrapOID) { -#ifndef NO_AES - #ifdef WOLFSSL_AES_128 - case AES128_WRAP: - #endif - #ifdef WOLFSSL_AES_192 - case AES192_WRAP: - #endif - #ifdef WOLFSSL_AES_256 - case AES256_WRAP: - #endif - direction = AES_DECRYPTION; - break; -#endif - default: - wc_PKCS7_KariFree(kari); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - WOLFSSL_MSG("AES key wrap algorithm unsupported"); - return BAD_KEYWRAP_ALG_E; - } - - /* 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, pkcs7->heap, 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, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - return ret; - } - - /* decrypt CEK with KEK */ - keySz = wc_PKCS7_KariKeyWrap(encryptedKey, encryptedKeySz, kari->kek, - kari->kekSz, decryptedKey, *decryptedKeySz, - keyWrapOID, direction); - if (keySz <= 0) { - wc_PKCS7_KariFree(kari); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - return keySz; - } - *decryptedKeySz = (word32)keySz; - - wc_PKCS7_KariFree(kari); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - - return 0; -#else - (void)pkcs7; - (void)pkiMsg; - (void)pkiMsgSz; - (void)idx; - (void)decryptedKey; - (void)decryptedKeySz; - (void)recipFound; - - return NOT_COMPILED_IN; -#endif /* HAVE_ECC */ -} - - -/* 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; - - #ifndef NO_RSA - /* found ktri */ - ret = wc_PKCS7_DecodeKtri(pkcs7, pkiMsg, pkiMsgSz, idx, - decryptedKey, decryptedKeySz, - recipFound); - if (ret != 0) - return ret; - #else - return NOT_COMPILED_IN; - #endif - } - 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; - int explicitOctet; - - if (pkcs7 == NULL || pkcs7->singleCert == NULL || - pkcs7->singleCertSz == 0) - return BAD_FUNC_ARG; - - if (pkiMsg == NULL || pkiMsgSz == 0 || - output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - - /* read past ContentInfo, verify type is envelopedData */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (length == 0 && pkiMsg[idx-1] == 0x80) { -#ifdef ASN_BER_TO_DER - word32 len = 0; - - ret = wc_BerToDer(pkiMsg, pkiMsgSz, NULL, &len); - if (ret != LENGTH_ONLY_E) - return ret; - pkcs7->der = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7->der == NULL) - return MEMORY_E; - ret = wc_BerToDer(pkiMsg, pkiMsgSz, pkcs7->der, &len); - if (ret < 0) - return ret; - - pkiMsg = pkcs7->der; - pkiMsgSz = len; - idx = 0; - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; -#else - return BER_INDEF_E; -#endif - } - - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (contentType != ENVELOPED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData"); - return PKCS7_OID_E; - } - - if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* remove EnvelopedData and version */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* TODO :: make this more accurate */ - if ((pkcs7->publicKeyOID == RSAk && version != 0) - #ifdef HAVE_ECC - || (pkcs7->publicKeyOID == ECDSAk && version != 2) - #endif - ) { - WOLFSSL_MSG("PKCS#7 envelopedData needs to be of version 0"); - return ASN_VERSION_E; - } - - /* walk through RecipientInfo set, find correct recipient */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - -#ifdef WOLFSSL_SMALL_STACK - decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (decryptedKey == NULL) - return MEMORY_E; -#endif - decryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - - ret = wc_PKCS7_DecodeRecipientInfos(pkcs7, pkiMsg, pkiMsgSz, &idx, - decryptedKey, &decryptedKeySz, - &recipFound); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ret; - } - - if (recipFound == 0) { - WOLFSSL_MSG("No recipient found in envelopedData that matches input"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return PKCS7_RECIP_E; - } - - /* remove EncryptedContentInfo */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); - if (blockKeySz < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return blockKeySz; - } - - expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); - if (expBlockSz < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return expBlockSz; - } - - /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ - if (pkiMsg[idx++] != ASN_OCTET_STRING) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - if (length != expBlockSz) { - WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - XMEMCPY(tmpIv, &pkiMsg[idx], length); - idx += length; - - explicitOctet = pkiMsg[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0); - - /* read encryptedContent, cont[0] */ - if (pkiMsg[idx] != (ASN_CONTEXT_SPECIFIC | 0) && - pkiMsg[idx] != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - idx++; - - if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) <= 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - if (explicitOctet) { - if (pkiMsg[idx++] != ASN_OCTET_STRING) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) <= 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ASN_PARSE_E; - } - } - - encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return MEMORY_E; - } - - XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - - /* decrypt encryptedContent */ - ret = wc_PKCS7_DecryptContent(encOID, decryptedKey, blockKeySz, - tmpIv, expBlockSz, encryptedContent, - encryptedContentSz, encryptedContent); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - return ret; - } - - padLen = encryptedContent[encryptedContentSz-1]; - - /* copy plaintext to output */ - XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); - - /* free memory, zero out keys */ - ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - - return encryptedContentSz - padLen; -} - - -#ifndef NO_PKCS7_ENCRYPTED_DATA - -/* build PKCS#7 encryptedData content type, return encrypted size */ -int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) -{ - int ret, idx = 0; - int totalSz, padSz, encryptedOutSz; - - int contentInfoSeqSz, outerContentTypeSz, outerContentSz; - byte contentInfoSeq[MAX_SEQ_SZ]; - byte outerContentType[MAX_ALGO_SZ]; - byte outerContent[MAX_SEQ_SZ]; - - int encDataSeqSz, verSz, blockSz; - byte encDataSeq[MAX_SEQ_SZ]; - byte ver[MAX_VERSION_SZ]; - - byte* plain = NULL; - byte* encryptedContent = NULL; - - int encContentOctetSz, encContentSeqSz, contentTypeSz; - int contentEncAlgoSz, ivOctetStringSz; - byte encContentSeq[MAX_SEQ_SZ]; - byte contentType[MAX_ALGO_SZ]; - byte contentEncAlgo[MAX_ALGO_SZ]; - byte tmpIv[MAX_CONTENT_IV_SIZE]; - byte ivOctetString[MAX_OCTET_STR_SZ]; - byte encContentOctet[MAX_OCTET_STR_SZ]; - - byte attribSet[MAX_SET_SZ]; - EncodedAttrib* attribs = NULL; - word32 attribsSz; - word32 attribsCount; - word32 attribsSetSz; - - byte* flatAttribs = NULL; - - if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || - pkcs7->encryptOID == 0 || pkcs7->encryptionKey == NULL || - pkcs7->encryptionKeySz == 0) - return BAD_FUNC_ARG; - - if (output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - - /* outer content type */ - outerContentTypeSz = wc_SetContentType(ENCRYPTED_DATA, outerContentType); - - /* version, 2 if unprotectedAttrs present, 0 if absent */ - if (pkcs7->unprotectedAttribsSz > 0) { - verSz = SetMyVersion(2, ver, 0); - } else { - verSz = SetMyVersion(0, ver, 0); - } - - /* EncryptedContentInfo */ - contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType); - if (contentTypeSz == 0) - return BAD_FUNC_ARG; - - /* allocate encrypted content buffer, do PKCS#7 padding */ - blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID); - if (blockSz < 0) - return blockSz; - - padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz); - if (padSz < 0) - return padSz; - - encryptedOutSz = pkcs7->contentSz + padSz; - - plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (plain == NULL) - return MEMORY_E; - - ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain, - encryptedOutSz, blockSz); - if (ret < 0) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) { - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - /* put together IV OCTET STRING */ - ivOctetStringSz = SetOctetString(blockSz, ivOctetString); - - /* build up ContentEncryptionAlgorithmIdentifier sequence, - adding (ivOctetStringSz + blockSz) for IV OCTET STRING */ - contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, - oidBlkType, ivOctetStringSz + blockSz); - if (contentEncAlgoSz == 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BAD_FUNC_ARG; - } - - /* encrypt content */ - ret = wc_PKCS7_GenerateIV(pkcs7, NULL, tmpIv, blockSz); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->encryptionKey, - pkcs7->encryptionKeySz, tmpIv, blockSz, plain, encryptedOutSz, - encryptedContent); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, - encryptedOutSz, encContentOctet); - - encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + - ivOctetStringSz + blockSz + - encContentOctetSz + encryptedOutSz, - encContentSeq); - - /* optional UnprotectedAttributes */ - if (pkcs7->unprotectedAttribsSz != 0) { - - if (pkcs7->unprotectedAttribs == NULL) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BAD_FUNC_ARG; - } - - attribs = (EncodedAttrib*)XMALLOC( - sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz, - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (attribs == NULL) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - attribsCount = pkcs7->unprotectedAttribsSz; - attribsSz = EncodeAttributes(attribs, pkcs7->unprotectedAttribsSz, - pkcs7->unprotectedAttribs, - pkcs7->unprotectedAttribsSz); - - flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (flatAttribs == NULL) { - XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - FlattenAttributes(flatAttribs, attribs, attribsCount); - attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet); - - } else { - attribsSz = 0; - attribsSetSz = 0; - } - - /* keep track of sizes for outer wrapper layering */ - totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz + - ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz + - attribsSz + attribsSetSz;; - - /* EncryptedData */ - encDataSeqSz = SetSequence(totalSz, encDataSeq); - totalSz += encDataSeqSz; - - /* outer content */ - outerContentSz = SetExplicit(0, totalSz, outerContent); - totalSz += outerContentTypeSz; - totalSz += outerContentSz; - - /* ContentInfo */ - contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); - totalSz += contentInfoSeqSz; - - if (totalSz > (int)outputSz) { - WOLFSSL_MSG("PKCS#7 output buffer too small"); - if (pkcs7->unprotectedAttribsSz != 0) { - XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz); - idx += contentInfoSeqSz; - XMEMCPY(output + idx, outerContentType, outerContentTypeSz); - idx += outerContentTypeSz; - XMEMCPY(output + idx, outerContent, outerContentSz); - idx += outerContentSz; - XMEMCPY(output + idx, encDataSeq, encDataSeqSz); - idx += encDataSeqSz; - XMEMCPY(output + idx, ver, verSz); - idx += verSz; - XMEMCPY(output + idx, encContentSeq, encContentSeqSz); - idx += encContentSeqSz; - XMEMCPY(output + idx, contentType, contentTypeSz); - idx += contentTypeSz; - XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz); - idx += contentEncAlgoSz; - XMEMCPY(output + idx, ivOctetString, ivOctetStringSz); - idx += ivOctetStringSz; - XMEMCPY(output + idx, tmpIv, blockSz); - idx += blockSz; - XMEMCPY(output + idx, encContentOctet, encContentOctetSz); - idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, encryptedOutSz); - idx += encryptedOutSz; - - if (pkcs7->unprotectedAttribsSz != 0) { - XMEMCPY(output + idx, attribSet, attribsSetSz); - idx += attribsSetSz; - XMEMCPY(output + idx, flatAttribs, attribsSz); - idx += attribsSz; - XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return idx; -} - - -/* decode and store unprotected attributes in PKCS7->decodedAttrib. Return - * 0 on success, negative on error. User must call wc_PKCS7_Free(). */ -static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, - word32 pkiMsgSz, word32* inOutIdx) -{ - int ret, attribLen; - word32 idx; - - if (pkcs7 == NULL || pkiMsg == NULL || - pkiMsgSz == 0 || inOutIdx == NULL) - return BAD_FUNC_ARG; - - idx = *inOutIdx; - - if (pkiMsg[idx] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) - return ASN_PARSE_E; - idx++; - - if (GetLength(pkiMsg, &idx, &attribLen, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* loop through attributes */ - if ((ret = wc_PKCS7_ParseAttribs(pkcs7, pkiMsg + idx, attribLen)) < 0) { - return ret; - } - - *inOutIdx = idx; - - return 0; -} - - -/* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */ -int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, - byte* output, word32 outputSz) -{ - int ret, version, length, haveAttribs; - word32 idx = 0; - word32 contentType, encOID; - - int expBlockSz; - byte tmpIv[MAX_CONTENT_IV_SIZE]; - - int encryptedContentSz; - byte padLen; - byte* encryptedContent = NULL; - - if (pkcs7 == NULL || pkcs7->encryptionKey == NULL || - pkcs7->encryptionKeySz == 0) - return BAD_FUNC_ARG; - - if (pkiMsg == NULL || pkiMsgSz == 0 || - output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - /* read past ContentInfo, verify type is encrypted-data */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (contentType != ENCRYPTED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type EncryptedData"); - return PKCS7_OID_E; - } - - if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* remove EncryptedData and version */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get version, check later */ - haveAttribs = 0; - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* remove EncryptedContentInfo */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); - if (expBlockSz < 0) - return expBlockSz; - - /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ - if (pkiMsg[idx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (length != expBlockSz) { - WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); - return ASN_PARSE_E; - } - - XMEMCPY(tmpIv, &pkiMsg[idx], length); - idx += length; - - /* read encryptedContent, cont[0] */ - if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) <= 0) - return ASN_PARSE_E; - - encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) - return MEMORY_E; - - XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - idx += encryptedContentSz; - - /* decrypt encryptedContent */ - ret = wc_PKCS7_DecryptContent(encOID, pkcs7->encryptionKey, - pkcs7->encryptionKeySz, tmpIv, expBlockSz, - encryptedContent, encryptedContentSz, - encryptedContent); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - padLen = encryptedContent[encryptedContentSz-1]; - - /* copy plaintext to output */ - XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); - - /* get implicit[1] unprotected attributes, optional */ - pkcs7->decodedAttrib = NULL; - if (idx < pkiMsgSz) { - - haveAttribs = 1; - - ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg, - pkiMsgSz, &idx); - if (ret != 0) { - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - } - - /* go back and check the version now that attribs have been processed */ - if ((haveAttribs == 0 && version != 0) || - (haveAttribs == 1 && version != 2) ) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - WOLFSSL_MSG("Wrong PKCS#7 EncryptedData version"); - return ASN_VERSION_E; - } - - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return encryptedContentSz - padLen; -} - -#endif /* NO_PKCS7_ENCRYPTED_DATA */ - -#else /* HAVE_PKCS7 */ - - -#ifdef _MSC_VER - /* 4206 warning for blank file */ - #pragma warning(disable: 4206) -#endif - - -#endif /* HAVE_PKCS7 */ - -