diff options
| author | auth12 <[email protected]> | 2020-07-22 08:40:38 -0700 |
|---|---|---|
| committer | auth12 <[email protected]> | 2020-07-22 08:40:38 -0700 |
| commit | 4ff89e85e74884e8f04edb5c31a94b4323e895e9 (patch) | |
| tree | 65f98ebf9af0d0947e44bf397b1fac0f107d7a2f /client/wolfssl/wolfcrypt/src/pkcs7.c | |
| parent | Client injection. (diff) | |
| download | loader-4ff89e85e74884e8f04edb5c31a94b4323e895e9.tar.xz loader-4ff89e85e74884e8f04edb5c31a94b4323e895e9.zip | |
Removed wolfssl
Diffstat (limited to 'client/wolfssl/wolfcrypt/src/pkcs7.c')
| -rw-r--r-- | client/wolfssl/wolfcrypt/src/pkcs7.c | 12523 |
1 files changed, 0 insertions, 12523 deletions
diff --git a/client/wolfssl/wolfcrypt/src/pkcs7.c b/client/wolfssl/wolfcrypt/src/pkcs7.c deleted file mode 100644 index e420cad..0000000 --- a/client/wolfssl/wolfcrypt/src/pkcs7.c +++ /dev/null @@ -1,12523 +0,0 @@ -/* pkcs7.c - * - * Copyright (C) 2006-2020 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 HAVE_LIBZ - #include <wolfssl/wolfcrypt/compress.h> -#endif -#ifndef NO_PWDBASED - #include <wolfssl/wolfcrypt/pwdbased.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 NO_USER_CHECK 0 - -/* holds information about the signers */ -struct PKCS7SignerInfo { - int version; - byte *sid; - word32 sidSz; -}; - - -#ifndef NO_PKCS7_STREAM - -#define MAX_PKCS7_STREAM_BUFFER 256 -struct PKCS7State { - byte* tmpCert; - byte* bufferPt; - byte* key; - byte* nonce; /* stored nonce */ - byte* aad; /* additional data for AEAD algos */ - byte* tag; /* tag data for AEAD algos */ - byte* content; - byte* buffer; /* main internal read buffer */ - - /* stack variables to store for when returning */ - word32 varOne; - int varTwo; - int varThree; - - word32 vers; - word32 idx; /* index read into current input buffer */ - word32 maxLen; /* sanity cap on maximum amount of data to allow - * needed for GetSequence and other calls */ - word32 length; /* amount of data stored */ - word32 bufferSz; /* size of internal buffer */ - word32 expected; /* next amount of data expected, if needed */ - word32 totalRd; /* total amount of bytes read */ - word32 nonceSz; /* size of nonce stored */ - word32 aadSz; /* size of additional AEAD data */ - word32 tagSz; /* size of tag for AEAD */ - word32 contentSz; - byte tmpIv[MAX_CONTENT_IV_SIZE]; /* store IV if needed */ -#ifdef WC_PKCS7_STREAM_DEBUG - word32 peakUsed; /* most bytes used for struct at any one time */ - word32 peakRead; /* most bytes used by read buffer */ -#endif - byte multi:1; /* flag for if content is in multiple parts */ - byte flagOne:1; - byte detached:1; /* flag to indicate detached signature is present */ -}; - - -enum PKCS7_MaxLen { - PKCS7_DEFAULT_PEEK = 0, - PKCS7_SEQ_PEEK -}; - -/* creates a PKCS7State structure and returns 0 on success */ -static int wc_PKCS7_CreateStream(PKCS7* pkcs7) -{ - WOLFSSL_MSG("creating PKCS7 stream structure"); - pkcs7->stream = (PKCS7State*)XMALLOC(sizeof(PKCS7State), pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream == NULL) { - return MEMORY_E; - } - XMEMSET(pkcs7->stream, 0, sizeof(PKCS7State)); -#ifdef WC_PKCS7_STREAM_DEBUG - printf("\nCreating new PKCS#7 stream %p\n", pkcs7->stream); -#endif - return 0; -} - - -static void wc_PKCS7_ResetStream(PKCS7* pkcs7) -{ - if (pkcs7 != NULL && pkcs7->stream != NULL) { -#ifdef WC_PKCS7_STREAM_DEBUG - /* collect final data point in case more was read right before reset */ - if (pkcs7->stream->length > pkcs7->stream->peakRead) { - pkcs7->stream->peakRead = pkcs7->stream->length; - } - if (pkcs7->stream->bufferSz + pkcs7->stream->aadSz + - pkcs7->stream->nonceSz + pkcs7->stream->tagSz > - pkcs7->stream->peakUsed) { - pkcs7->stream->peakUsed = pkcs7->stream->bufferSz + - pkcs7->stream->aadSz + pkcs7->stream->nonceSz + - pkcs7->stream->tagSz; - } - - /* print out debugging statistics */ - if (pkcs7->stream->peakUsed > 0 || pkcs7->stream->peakRead > 0) { - printf("PKCS#7 STREAM:\n\tPeak heap used by struct = %d" - "\n\tPeak read buffer bytes = %d" - "\n\tTotal bytes read = %d" - "\n", - pkcs7->stream->peakUsed, pkcs7->stream->peakRead, - pkcs7->stream->totalRd); - } - printf("PKCS#7 stream reset : Address [%p]\n", pkcs7->stream); - #endif - - /* free any buffers that may be allocated */ - XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(pkcs7->stream->key, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->stream->aad = NULL; - pkcs7->stream->tag = NULL; - pkcs7->stream->nonce = NULL; - pkcs7->stream->buffer = NULL; - pkcs7->stream->key = NULL; - - /* reset values, note that content and tmpCert are saved */ - pkcs7->stream->maxLen = 0; - pkcs7->stream->length = 0; - pkcs7->stream->idx = 0; - pkcs7->stream->expected = 0; - pkcs7->stream->totalRd = 0; - pkcs7->stream->bufferSz = 0; - - pkcs7->stream->multi = 0; - pkcs7->stream->flagOne = 0; - pkcs7->stream->detached = 0; - pkcs7->stream->varOne = 0; - pkcs7->stream->varTwo = 0; - pkcs7->stream->varThree = 0; - } -} - - -static void wc_PKCS7_FreeStream(PKCS7* pkcs7) -{ - if (pkcs7 != NULL && pkcs7->stream != NULL) { - wc_PKCS7_ResetStream(pkcs7); - - XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(pkcs7->stream->tmpCert, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->stream->content = NULL; - pkcs7->stream->tmpCert = NULL; - - XFREE(pkcs7->stream, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->stream = NULL; - } -} - - -/* used to increase the max size for internal buffer - * returns 0 on success */ -static int wc_PKCS7_GrowStream(PKCS7* pkcs7, word32 newSz) -{ - byte* pt; - - pt = (byte*)XMALLOC(newSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pt == NULL) { - return MEMORY_E; - } - XMEMCPY(pt, pkcs7->stream->buffer, pkcs7->stream->bufferSz); - -#ifdef WC_PKCS7_STREAM_DEBUG - printf("PKCS7 increasing internal stream buffer %d -> %d\n", - pkcs7->stream->bufferSz, newSz); -#endif - pkcs7->stream->bufferSz = newSz; - XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->stream->buffer = pt; - return 0; -} - - -/* pt gets set to the buffer that is holding data in the case that stream struct - * is used. - * - * Sets idx to be the current offset into "pt" buffer - * returns 0 on success - */ -static int wc_PKCS7_AddDataToStream(PKCS7* pkcs7, byte* in, word32 inSz, - word32 expected, byte** pt, word32* idx) -{ - word32 rdSz = pkcs7->stream->idx; - - /* If the input size minus current index into input buffer is greater than - * the expected size then use the input buffer. If data is already stored - * in stream buffer or if there is not enough input data available then use - * the stream buffer. */ - if (inSz - rdSz >= expected && pkcs7->stream->length == 0) { - /* storing input buffer is not needed */ - *pt = in; /* reset in case previously used internal buffer */ - *idx = rdSz; - return 0; - } - - /* is there enough stored in buffer already? */ - if (pkcs7->stream->length >= expected) { - *idx = 0; /* start reading from beginning of stream buffer */ - *pt = pkcs7->stream->buffer; - return 0; - } - - /* check if all data has been read from input */ - if (rdSz >= inSz) { - /* no more input to read, reset input index and request more data */ - pkcs7->stream->idx = 0; - return WC_PKCS7_WANT_READ_E; - } - - /* try to store input data into stream buffer */ - if (inSz - rdSz > 0 && pkcs7->stream->length < expected) { - int len = min(inSz - rdSz, expected - pkcs7->stream->length); - - /* sanity check that the input buffer is not internal buffer */ - if (in == pkcs7->stream->buffer) { - return WC_PKCS7_WANT_READ_E; - } - - /* check if internal buffer size needs to be increased */ - if (len + pkcs7->stream->length > pkcs7->stream->bufferSz) { - int ret = wc_PKCS7_GrowStream(pkcs7, expected); - if (ret < 0) { - return ret; - } - } - XMEMCPY(pkcs7->stream->buffer + pkcs7->stream->length, in + rdSz, len); - pkcs7->stream->length += len; - pkcs7->stream->idx += len; - pkcs7->stream->totalRd += len; - } - -#ifdef WC_PKCS7_STREAM_DEBUG - /* collects memory usage for debugging */ - if (pkcs7->stream->length > pkcs7->stream->peakRead) { - pkcs7->stream->peakRead = pkcs7->stream->length; - } - if (pkcs7->stream->bufferSz + pkcs7->stream->aadSz + pkcs7->stream->nonceSz + - pkcs7->stream->tagSz > pkcs7->stream->peakUsed) { - pkcs7->stream->peakUsed = pkcs7->stream->bufferSz + - pkcs7->stream->aadSz + pkcs7->stream->nonceSz + pkcs7->stream->tagSz; - } -#endif - - /* if not enough data was read in then request more */ - if (pkcs7->stream->length < expected) { - pkcs7->stream->idx = 0; - return WC_PKCS7_WANT_READ_E; - } - - /* adjust pointer to read from stored buffer */ - *idx = 0; - *pt = pkcs7->stream->buffer; - return 0; -} - - -/* Does two things - * 1) Tries to get the length from current buffer and set it as max length - * 2) Retrieves the set max length - * - * if no flag value is set then the stored max length is returned. - * returns length found on success and defSz if no stored data is found - */ -static long wc_PKCS7_GetMaxStream(PKCS7* pkcs7, byte flag, byte* in, - word32 defSz) -{ - /* check there is a buffer to read from */ - if (pkcs7) { - int length = 0, ret; - word32 idx = 0, maxIdx; - byte* pt; - - if (flag != PKCS7_DEFAULT_PEEK) { - if (pkcs7->stream->length > 0) { - length = pkcs7->stream->length; - pt = pkcs7->stream->buffer; - } - else { - length = defSz; - pt = in; - } - maxIdx = (word32)length; - - if (length < MAX_SEQ_SZ) { - WOLFSSL_MSG("PKCS7 Error not enough data for SEQ peek\n"); - return 0; - } - if (flag == PKCS7_SEQ_PEEK) { - if ((ret = GetSequence_ex(pt, &idx, &length, maxIdx, - NO_USER_CHECK)) < 0) { - return ret; - } - - #ifdef ASN_BER_TO_DER - if (length == 0 && ret == 0) { - idx = 0; - if ((ret = wc_BerToDer(pt, defSz, NULL, - (word32*)&length)) != LENGTH_ONLY_E) { - return ret; - } - } - #endif /* ASN_BER_TO_DER */ - pkcs7->stream->maxLen = length + idx; - } - } - - if (pkcs7->stream->maxLen == 0) { - pkcs7->stream->maxLen = defSz; - } - - return pkcs7->stream->maxLen; - } - - return defSz; -} - - -/* setter function for stored variables */ -static void wc_PKCS7_StreamStoreVar(PKCS7* pkcs7, word32 var1, int var2, - int var3) -{ - if (pkcs7 != NULL && pkcs7->stream != NULL) { - pkcs7->stream->varOne = var1; - pkcs7->stream->varTwo = var2; - pkcs7->stream->varThree = var3; - } -} - -/* getter function for stored variables */ -static void wc_PKCS7_StreamGetVar(PKCS7* pkcs7, word32* var1, int* var2, - int* var3) -{ - if (pkcs7 != NULL && pkcs7->stream != NULL) { - if (var1 != NULL) *var1 = pkcs7->stream->varOne; - if (var2 != NULL) *var2 = pkcs7->stream->varTwo; - if (var3 != NULL) *var3 = pkcs7->stream->varThree; - } -} - - -/* common update of index and total read after section complete - * returns 0 on success */ -static int wc_PKCS7_StreamEndCase(PKCS7* pkcs7, word32* tmpIdx, word32* idx) -{ - int ret = 0; - - if (pkcs7->stream->length > 0) { - if (pkcs7->stream->length < *idx) { - WOLFSSL_MSG("PKCS7 read too much data from internal buffer"); - ret = BUFFER_E; - } - else { - XMEMMOVE(pkcs7->stream->buffer, pkcs7->stream->buffer + *idx, - pkcs7->stream->length - *idx); - pkcs7->stream->length -= *idx; - } - } - else { - pkcs7->stream->totalRd += *idx - *tmpIdx; - pkcs7->stream->idx = *idx; /* adjust index into input buffer */ - *tmpIdx = *idx; - } - - return ret; -} -#endif /* NO_PKCS7_STREAM */ - -#ifdef WC_PKCS7_STREAM_DEBUG -/* used to print out human readable state for debugging */ -static const char* wc_PKCS7_GetStateName(int in) -{ - switch (in) { - case WC_PKCS7_START: return "WC_PKCS7_START"; - - case WC_PKCS7_STAGE2: return "WC_PKCS7_STAGE2"; - case WC_PKCS7_STAGE3: return "WC_PKCS7_STAGE3"; - case WC_PKCS7_STAGE4: return "WC_PKCS7_STAGE4"; - case WC_PKCS7_STAGE5: return "WC_PKCS7_STAGE5"; - case WC_PKCS7_STAGE6: return "WC_PKCS7_STAGE6"; - - /* parse info set */ - case WC_PKCS7_INFOSET_START: return "WC_PKCS7_INFOSET_START"; - case WC_PKCS7_INFOSET_BER: return "WC_PKCS7_INFOSET_BER"; - case WC_PKCS7_INFOSET_STAGE1: return "WC_PKCS7_INFOSET_STAGE1"; - case WC_PKCS7_INFOSET_STAGE2: return "WC_PKCS7_INFOSET_STAGE2"; - case WC_PKCS7_INFOSET_END: return "WC_PKCS7_INFOSET_END"; - - /* decode enveloped data */ - case WC_PKCS7_ENV_2: return "WC_PKCS7_ENV_2"; - case WC_PKCS7_ENV_3: return "WC_PKCS7_ENV_3"; - case WC_PKCS7_ENV_4: return "WC_PKCS7_ENV_4"; - case WC_PKCS7_ENV_5: return "WC_PKCS7_ENV_5"; - - /* decode auth enveloped */ - case WC_PKCS7_AUTHENV_2: return "WC_PKCS7_AUTHENV_2"; - case WC_PKCS7_AUTHENV_3: return "WC_PKCS7_AUTHENV_3"; - case WC_PKCS7_AUTHENV_4: return "WC_PKCS7_AUTHENV_4"; - case WC_PKCS7_AUTHENV_5: return "WC_PKCS7_AUTHENV_5"; - case WC_PKCS7_AUTHENV_6: return "WC_PKCS7_AUTHENV_6"; - case WC_PKCS7_AUTHENV_ATRB: return "WC_PKCS7_AUTHENV_ATRB"; - case WC_PKCS7_AUTHENV_ATRBEND: return "WC_PKCS7_AUTHENV_ATRBEND"; - case WC_PKCS7_AUTHENV_7: return "WC_PKCS7_AUTHENV_7"; - - /* decryption state types */ - case WC_PKCS7_DECRYPT_KTRI: return "WC_PKCS7_DECRYPT_KTRI"; - case WC_PKCS7_DECRYPT_KTRI_2: return "WC_PKCS7_DECRYPT_KTRI_2"; - case WC_PKCS7_DECRYPT_KTRI_3: return "WC_PKCS7_DECRYPT_KTRI_3"; - - case WC_PKCS7_DECRYPT_KARI: return "WC_PKCS7_DECRYPT_KARI"; - case WC_PKCS7_DECRYPT_KEKRI: return "WC_PKCS7_DECRYPT_KEKRI"; - case WC_PKCS7_DECRYPT_PWRI: return "WC_PKCS7_DECRYPT_PWRI"; - case WC_PKCS7_DECRYPT_ORI: return "WC_PKCS7_DECRYPT_ORI"; - case WC_PKCS7_DECRYPT_DONE: return "WC_PKCS7_DECRYPT_DONE"; - - case WC_PKCS7_VERIFY_STAGE2: return "WC_PKCS7_VERIFY_STAGE2"; - case WC_PKCS7_VERIFY_STAGE3: return "WC_PKCS7_VERIFY_STAGE3"; - case WC_PKCS7_VERIFY_STAGE4: return "WC_PKCS7_VERIFY_STAGE4"; - case WC_PKCS7_VERIFY_STAGE5: return "WC_PKCS7_VERIFY_STAGE5"; - case WC_PKCS7_VERIFY_STAGE6: return "WC_PKCS7_VERIFY_STAGE6"; - - default: - return "Unknown state"; - } -} -#endif - -/* Used to change the PKCS7 state. Having state change as a function allows - * for easier debugging */ -static void wc_PKCS7_ChangeState(PKCS7* pkcs7, int newState) -{ -#ifdef WC_PKCS7_STREAM_DEBUG - printf("\tChanging from state [%02d] %s to [%02d] %s\n", - pkcs7->state, wc_PKCS7_GetStateName(pkcs7->state), - newState, wc_PKCS7_GetStateName(newState)); -#endif - pkcs7->state = newState; -} - -#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, word32 outputSz) -{ - /* 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 authEnvelopedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, - 0x0D, 0x01, 0x09, 0x10, 0x01, 0x17}; - 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 - /* FirmwarePkgData (1.2.840.113549.1.9.16.1.16), RFC 4108 */ - const byte firmwarePkgData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, - 0x01, 0x09, 0x10, 0x01, 0x10 }; -#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA) - /* id-ct-compressedData (1.2.840.113549.1.9.16.1.9), RFC 3274 */ - const byte compressedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, - 0x01, 0x09, 0x10, 0x01, 0x09 }; -#endif - -#if !defined(NO_PWDBASED) && !defined(NO_SHA) - const byte pwriKek[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, - 0x01, 0x09, 0x10, 0x03, 0x09 }; - const byte pbkdf2[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, - 0x01, 0x05, 0x0C }; -#endif - - int idSz, idx = 0; - word32 typeSz = 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 AUTH_ENVELOPED_DATA: - typeSz = sizeof(authEnvelopedData); - typeName = authEnvelopedData; - 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 -#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA) - case COMPRESSED_DATA: - typeSz = sizeof(compressedData); - typeName = compressedData; - break; -#endif - case FIRMWARE_PKG_DATA: - typeSz = sizeof(firmwarePkgData); - typeName = firmwarePkgData; - break; - -#if !defined(NO_PWDBASED) && !defined(NO_SHA) - case PWRI_KEK_WRAP: - typeSz = sizeof(pwriKek); - typeName = pwriKek; - break; - - case PBKDF2_OID: - typeSz = sizeof(pbkdf2); - typeName = pbkdf2; - break; -#endif - - default: - WOLFSSL_MSG("Unknown PKCS#7 Type"); - return 0; - }; - - if (outputSz < (MAX_LENGTH_SZ + 1 + typeSz)) { - WOLFSSL_MSG("CMS content type buffer too small"); - return BAD_FUNC_ARG; - } - - 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: - case AES128GCMb: - case AES128CCMb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - case AES192GCMb: - case AES192CCMb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - case AES256GCMb: - case AES256CCMb: - #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 AES128GCMb: - case AES128CCMb: - case AES128_WRAP: - blockKeySz = 16; - break; - #endif - #ifdef WOLFSSL_AES_192 - case AES192CBCb: - case AES192GCMb: - case AES192CCMb: - case AES192_WRAP: - blockKeySz = 24; - break; - #endif - #ifdef WOLFSSL_AES_256 - case AES256CBCb: - case AES256GCMb: - case AES256CCMb: - 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) -{ - word16 isDynamic; - - WOLFSSL_ENTER("wc_PKCS7_Init"); - - if (pkcs7 == NULL) { - return BAD_FUNC_ARG; - } - - isDynamic = pkcs7->isDynamic; - XMEMSET(pkcs7, 0, sizeof(PKCS7)); - pkcs7->isDynamic = isDynamic; -#ifdef WOLFSSL_HEAP_TEST - pkcs7->heap = (void*)WOLFSSL_HEAP_TEST; -#else - pkcs7->heap = heap; -#endif - pkcs7->devId = devId; - - return 0; -} - - -/* Certificate structure holding der pointer, size, and pointer to next - * Pkcs7Cert struct. Used when creating SignedData types with multiple - * certificates. */ -struct Pkcs7Cert { - byte* der; - word32 derSz; - Pkcs7Cert* next; -}; - - -/* Linked list of ASN.1 encoded RecipientInfos */ -struct Pkcs7EncodedRecip { - byte recip[MAX_RECIP_SZ]; - word32 recipSz; - int recipType; - int recipVersion; - Pkcs7EncodedRecip* next; -}; - - -/* free all members of Pkcs7Cert linked list */ -static void wc_PKCS7_FreeCertSet(PKCS7* pkcs7) -{ - Pkcs7Cert* curr = NULL; - Pkcs7Cert* next = NULL; - - if (pkcs7 == NULL) - return; - - curr = pkcs7->certList; - pkcs7->certList = NULL; - - while (curr != NULL) { - next = curr->next; - curr->next = NULL; - XFREE(curr, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - curr = next; - } - - return; -} - - -/* Get total size of all recipients in recipient list. - * - * Returns total size of recipients, or negative upon error */ -static int wc_PKCS7_GetRecipientListSize(PKCS7* pkcs7) -{ - int totalSz = 0; - Pkcs7EncodedRecip* tmp = NULL; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - tmp = pkcs7->recipList; - - while (tmp != NULL) { - totalSz += tmp->recipSz; - tmp = tmp->next; - } - - return totalSz; -} - - -/* free all members of Pkcs7EncodedRecip linked list */ -static void wc_PKCS7_FreeEncodedRecipientSet(PKCS7* pkcs7) -{ - Pkcs7EncodedRecip* curr = NULL; - Pkcs7EncodedRecip* next = NULL; - - if (pkcs7 == NULL) - return; - - curr = pkcs7->recipList; - pkcs7->recipList = NULL; - - while (curr != NULL) { - next = curr->next; - curr->next = NULL; - XFREE(curr, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - curr = next; - } - - return; -} - - -/* search through RecipientInfo list for specific type. - * return 1 if ANY recipient of type specified is present, otherwise - * return 0 */ -static int wc_PKCS7_RecipientListIncludesType(PKCS7* pkcs7, int type) -{ - Pkcs7EncodedRecip* tmp = NULL; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - tmp = pkcs7->recipList; - - while (tmp != NULL) { - if (tmp->recipType == type) - return 1; - - tmp = tmp->next; - } - - return 0; -} - - -/* searches through RecipientInfo list, returns 1 if all structure - * versions are set to 0, otherwise returns 0 */ -static int wc_PKCS7_RecipientListVersionsAllZero(PKCS7* pkcs7) -{ - Pkcs7EncodedRecip* tmp = NULL; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - tmp = pkcs7->recipList; - - while (tmp != NULL) { - if (tmp->recipVersion != 0) - return 0; - - tmp = tmp->next; - } - - return 1; -} - - -/* 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* derCert, word32 derCertSz) -{ - int ret = 0; - void* heap; - int devId; - Pkcs7Cert* cert; - Pkcs7Cert* lastCert; - - if (pkcs7 == NULL || (derCert == NULL && derCertSz != 0)) { - return BAD_FUNC_ARG; - } - - heap = pkcs7->heap; - devId = pkcs7->devId; - cert = pkcs7->certList; - ret = wc_PKCS7_Init(pkcs7, heap, devId); - if (ret != 0) - return ret; - pkcs7->certList = cert; - - if (derCert != NULL && derCertSz > 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 dCert[1]; -#endif - - pkcs7->singleCert = derCert; - pkcs7->singleCertSz = derCertSz; - pkcs7->cert[0] = derCert; - pkcs7->certSz[0] = derCertSz; - - /* create new Pkcs7Cert for recipient, freed during cleanup */ - cert = (Pkcs7Cert*)XMALLOC(sizeof(Pkcs7Cert), pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - XMEMSET(cert, 0, sizeof(Pkcs7Cert)); - cert->der = derCert; - cert->derSz = derCertSz; - cert->next = NULL; - - /* free existing cert list if existing */ - wc_PKCS7_FreeCertSet(pkcs7); - - /* add cert to list */ - if (pkcs7->certList == NULL) { - pkcs7->certList = cert; - } else { - lastCert = pkcs7->certList; - while (lastCert->next != NULL) { - lastCert = lastCert->next; - } - lastCert->next = cert; - } - - InitDecodedCert(dCert, derCert, derCertSz, 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; - XMEMCPY(pkcs7->issuerSubjKeyId, dCert->extSubjKeyId, KEYID_SIZE); - - /* default to IssuerAndSerialNumber for SignerIdentifier */ - pkcs7->sidType = CMS_ISSUER_AND_SERIAL_NUMBER; - - /* free existing recipient list if existing */ - wc_PKCS7_FreeEncodedRecipientSet(pkcs7); - - FreeDecodedCert(dCert); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#endif - } - - return ret; -} - - -/* Adds one DER-formatted certificate to the internal PKCS7/CMS certificate - * list, to be added as part of the certificates CertificateSet. Currently - * used in SignedData content type. - * - * Must be called after wc_PKCS7_Init() or wc_PKCS7_InitWithCert(). - * - * Does not represent the recipient/signer certificate, only certificates that - * are part of the certificate chain used to build and verify signer - * certificates. - * - * This API does not currently validate certificates. - * - * Returns 0 on success, negative upon error */ -int wc_PKCS7_AddCertificate(PKCS7* pkcs7, byte* derCert, word32 derCertSz) -{ - Pkcs7Cert* cert; - - if (pkcs7 == NULL || derCert == NULL || derCertSz == 0) - return BAD_FUNC_ARG; - - cert = (Pkcs7Cert*)XMALLOC(sizeof(Pkcs7Cert), pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (cert == NULL) - return MEMORY_E; - - cert->der = derCert; - cert->derSz = derCertSz; - - if (pkcs7->certList == NULL) { - pkcs7->certList = cert; - } else { - cert->next = pkcs7->certList; - pkcs7->certList = cert; - } - - return 0; -} - - -/* 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; -} - - -/* return 0 on success */ -static int wc_PKCS7_SignerInfoNew(PKCS7* pkcs7) -{ - if (pkcs7->signerInfo != NULL) { - XFREE(pkcs7->signerInfo, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->signerInfo = NULL; - } - - pkcs7->signerInfo = (PKCS7SignerInfo*)XMALLOC(sizeof(PKCS7SignerInfo), - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7->signerInfo == NULL) { - WOLFSSL_MSG("Unable to malloc memory for signer info"); - return MEMORY_E; - } - XMEMSET(pkcs7->signerInfo, 0, sizeof(PKCS7SignerInfo)); - return 0; -} - - -static void wc_PKCS7_SignerInfoFree(PKCS7* pkcs7) -{ - if (pkcs7->signerInfo != NULL) { - if (pkcs7->signerInfo->sid != NULL) { - XFREE(pkcs7->signerInfo->sid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->signerInfo->sid = NULL; - } - XFREE(pkcs7->signerInfo, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->signerInfo = NULL; - } -} - - -/* free's any current SID and sets it to "in" - * returns 0 on success - */ -static int wc_PKCS7_SignerInfoSetSID(PKCS7* pkcs7, byte* in, int inSz) -{ - if (pkcs7 == NULL || in == NULL || inSz < 0) { - return BAD_FUNC_ARG; - } - - if (pkcs7->signerInfo->sid != NULL) { - XFREE(pkcs7->signerInfo->sid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->signerInfo->sid = NULL; - } - pkcs7->signerInfo->sid = (byte*)XMALLOC(inSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->signerInfo->sid == NULL) { - return MEMORY_E; - } - XMEMCPY(pkcs7->signerInfo->sid, in, inSz); - pkcs7->signerInfo->sidSz = inSz; - return 0; -} - - -/* releases any memory allocated by a PKCS7 initializer */ -void wc_PKCS7_Free(PKCS7* pkcs7) -{ - if (pkcs7 == NULL) - return; - -#ifndef NO_PKCS7_STREAM - wc_PKCS7_FreeStream(pkcs7); -#endif - - wc_PKCS7_SignerInfoFree(pkcs7); - wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap); - wc_PKCS7_FreeCertSet(pkcs7); - -#ifdef ASN_BER_TO_DER - if (pkcs7->der != NULL) - XFREE(pkcs7->der, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - if (pkcs7->contentDynamic != NULL) - XFREE(pkcs7->contentDynamic, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - if (pkcs7->cek != NULL) { - ForceZero(pkcs7->cek, pkcs7->cekSz); - XFREE(pkcs7->cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - - pkcs7->contentTypeSz = 0; - - if (pkcs7->signature) { - XFREE(pkcs7->signature, pkcs7->heap, DYNAMIC_TYPE_SIGNATURE); - pkcs7->signature = NULL; - pkcs7->signatureSz = 0; - } - if (pkcs7->plainDigest) { - XFREE(pkcs7->plainDigest, pkcs7->heap, DYNAMIC_TYPE_DIGEST); - pkcs7->plainDigest = NULL; - pkcs7->plainDigestSz = 0; - } - if (pkcs7->pkcs7Digest) { - XFREE(pkcs7->pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_DIGEST); - pkcs7->pkcs7Digest = NULL; - pkcs7->pkcs7DigestSz = 0; - } - if (pkcs7->cachedEncryptedContent != NULL) { - XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->cachedEncryptedContent = NULL; - pkcs7->cachedEncryptedContentSz = 0; - } - - 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; - byte tag; - - if (GetASNTag(list->oid, &idx, &tag, list->oidSz) < 0) { - return NULL; - } - if (tag != 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]; - /* issuerAndSerialNumber ...*/ - byte issuerSnSeq[MAX_SEQ_SZ]; - byte issuerName[MAX_SEQ_SZ]; - byte issuerSn[MAX_SN_SZ]; - /* OR subjectKeyIdentifier */ - byte issuerSKIDSeq[MAX_SEQ_SZ]; - byte issuerSKID[MAX_OCTET_STR_SZ]; - byte signerDigAlgoId[MAX_ALGO_SZ]; - byte digEncAlgoId[MAX_ALGO_SZ]; - byte signedAttribSet[MAX_SET_SZ]; - EncodedAttrib signedAttribs[7]; - 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, issuerSKIDSz, - issuerSKIDSeqSz, 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; -} - - -typedef struct FlatAttrib { - byte* data; - word32 dataSz; -} FlatAttrib; - -/* Returns a pointer to FlatAttrib whose members are initialized to 0. -* Caller is expected to free. -*/ -static FlatAttrib* NewAttrib(void* heap) -{ - FlatAttrib* fb = (FlatAttrib*) XMALLOC(sizeof(FlatAttrib), heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (fb != NULL) { - ForceZero(fb, sizeof(FlatAttrib)); - } - (void)heap; - return fb; -} - -/* Free FlatAttrib array and memory allocated to internal struct members */ -static void FreeAttribArray(PKCS7* pkcs7, FlatAttrib** arr, int rows) -{ - int i; - - if (arr) { - for (i = 0; i < rows; i++) { - if (arr[i]) { - if (arr[i]->data) { - ForceZero(arr[i]->data, arr[i]->dataSz); - XFREE(arr[i]->data, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - ForceZero(arr[i], sizeof(FlatAttrib)); - XFREE(arr[i], pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - } - ForceZero(arr, rows); - XFREE(arr, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - } - (void)pkcs7; -} - - -/* Sort FlatAttrib array in ascending order */ -static int SortAttribArray(FlatAttrib** arr, int rows) -{ - int i, j; - word32 minSz, minIdx; - FlatAttrib* a = NULL; - FlatAttrib* b = NULL; - FlatAttrib* tmp = NULL; - - if (arr == NULL) { - return BAD_FUNC_ARG; - } - - for (i = 0; i < rows; i++) { - a = arr[i]; - minSz = a->dataSz; - minIdx = i; - for (j = i+1; j < rows; j++) { - b = arr[j]; - if (b->dataSz < minSz) { - minSz = b->dataSz; - minIdx = j; - } - } - if (minSz < a->dataSz) { - /* swap array positions */ - tmp = arr[i]; - arr[i] = arr[minIdx]; - arr[minIdx] = tmp; - } - } - - return 0; -} - - -/* Build up array of FlatAttrib structs from EncodedAttrib ones. FlatAttrib - * holds flattened DER encoding of each attribute */ -static int FlattenEncodedAttribs(PKCS7* pkcs7, FlatAttrib** derArr, int rows, - EncodedAttrib* ea, int eaSz) -{ - int i, idx, sz; - byte* output = NULL; - FlatAttrib* fa = NULL; - - if (pkcs7 == NULL || derArr == NULL || ea == NULL) { - WOLFSSL_MSG("Invalid arguments to FlattenEncodedAttribs"); - return BAD_FUNC_ARG; - } - - if (rows != eaSz) { - WOLFSSL_MSG("DER array not large enough to hold attribute count"); - return BAD_FUNC_ARG; - } - - for (i = 0; i < eaSz; i++) { - sz = ea[i].valueSeqSz + ea[i].oidSz + ea[i].valueSetSz + ea[i].valueSz; - - output = (byte*)XMALLOC(sz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (output == NULL) { - return MEMORY_E; - } - - idx = 0; - 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); - - fa = derArr[i]; - fa->data = output; - fa->dataSz = sz; - } - - return 0; -} - - -/* Sort and Flatten EncodedAttrib attributes into output buffer */ -static int FlattenAttributes(PKCS7* pkcs7, byte* output, EncodedAttrib* ea, - int eaSz) -{ - int i, idx, ret; - FlatAttrib** derArr = NULL; - FlatAttrib* fa = NULL; - - if (pkcs7 == NULL || output == NULL || ea == NULL) { - return BAD_FUNC_ARG; - } - - /* create array of FlatAttrib struct pointers to hold DER attribs */ - derArr = (FlatAttrib**) XMALLOC(eaSz * sizeof(FlatAttrib*), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (derArr == NULL) { - return MEMORY_E; - } - XMEMSET(derArr, 0, eaSz * sizeof(FlatAttrib*)); - - for (i = 0; i < eaSz; i++) { - derArr[i] = NewAttrib(pkcs7->heap); - if (derArr[i] == NULL) { - FreeAttribArray(pkcs7, derArr, eaSz); - return MEMORY_E; - } - ForceZero(derArr[i], sizeof(FlatAttrib)); - } - - /* flatten EncodedAttrib into DER byte arrays */ - ret = FlattenEncodedAttribs(pkcs7, derArr, eaSz, ea, eaSz); - if (ret != 0) { - FreeAttribArray(pkcs7, derArr, eaSz); - return ret; - } - - /* SET OF DER signed attributes must be sorted in ascending order */ - ret = SortAttribArray(derArr, eaSz); - if (ret != 0) { - FreeAttribArray(pkcs7, derArr, eaSz); - return ret; - } - - /* copy sorted DER attribute arrays into output buffer */ - idx = 0; - for (i = 0; i < eaSz; i++) { - fa = derArr[i]; - XMEMCPY(output + idx, fa->data, fa->dataSz); - idx += fa->dataSz; - } - - FreeAttribArray(pkcs7, derArr, eaSz); - - 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 privKey[1]; -#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) { - #ifdef WOLFSSL_ASYNC_CRYPT - do { - ret = wc_AsyncWait(ret, &privKey->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - if (ret >= 0) - #endif - { - ret = wc_RsaSSL_Sign(in, inSz, esd->encContentDigest, - sizeof(esd->encContentDigest), - privKey, pkcs7->rng); - } - #ifdef WOLFSSL_ASYNC_CRYPT - } while (ret == WC_PENDING_E); - #endif - } - - 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 privKey[1]; -#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); - #ifdef WOLFSSL_ASYNC_CRYPT - do { - ret = wc_AsyncWait(ret, &privKey->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - if (ret >= 0) - #endif - { - ret = wc_ecc_sign_hash(in, inSz, esd->encContentDigest, - &outSz, pkcs7->rng, privKey); - } - #ifdef WOLFSSL_ASYNC_CRYPT - } while (ret == WC_PENDING_E); - #endif - 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, - const byte* contentType, word32 contentTypeSz, - const byte* contentTypeOid, word32 contentTypeOidSz, - const byte* messageDigestOid, word32 messageDigestOidSz, - const byte* signingTimeOid, word32 signingTimeOidSz, - byte* signingTime, word32 signingTimeSz) -{ - int hashSz; -#ifdef NO_ASN_TIME - PKCS7Attrib cannedAttribs[2]; -#else - time_t tm; - int timeSz; - PKCS7Attrib cannedAttribs[3]; -#endif - word32 idx = 0; - word32 cannedAttribsCount; - - if (pkcs7 == NULL || esd == NULL || contentType == NULL || - contentTypeOid == NULL || messageDigestOid == NULL || - signingTimeOid == NULL) { - return BAD_FUNC_ARG; - } - - if (pkcs7->skipDefaultSignedAttribs == 0) { - hashSz = wc_HashGetDigestSize(esd->hashType); - if (hashSz < 0) - return hashSz; - - #ifndef NO_ASN_TIME - if (signingTime == NULL || signingTimeSz == 0) - return BAD_FUNC_ARG; - - tm = XTIME(0); - timeSz = GetAsnTimeString(&tm, signingTime, signingTimeSz); - if (timeSz < 0) - return timeSz; - #endif - - cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib); - - cannedAttribs[idx].oid = contentTypeOid; - cannedAttribs[idx].oidSz = contentTypeOidSz; - cannedAttribs[idx].value = contentType; - cannedAttribs[idx].valueSz = contentTypeSz; - idx++; - #ifndef NO_ASN_TIME - cannedAttribs[idx].oid = signingTimeOid; - cannedAttribs[idx].oidSz = signingTimeOidSz; - cannedAttribs[idx].value = signingTime; - cannedAttribs[idx].valueSz = timeSz; - idx++; - #endif - cannedAttribs[idx].oid = messageDigestOid; - cannedAttribs[idx].oidSz = messageDigestOidSz; - cannedAttribs[idx].value = esd->contentDigest; - cannedAttribs[idx].valueSz = hashSz + 2; /* ASN.1 heading */ - - esd->signedAttribsCount += cannedAttribsCount; - esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[0], 3, - cannedAttribs, cannedAttribsCount); - } else { - esd->signedAttribsCount = 0; - esd->signedAttribsSz = 0; - } - - /* add custom signed attributes if set */ - if (pkcs7->signedAttribsSz > 0 && pkcs7->signedAttribs != NULL) { - esd->signedAttribsCount += pkcs7->signedAttribsSz; - #ifdef NO_ASN_TIME - esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[2], 4, - pkcs7->signedAttribs, pkcs7->signedAttribsSz); - #else - esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[3], 4, - pkcs7->signedAttribs, pkcs7->signedAttribsSz); - #endif - } - -#ifdef NO_ASN_TIME - (void)signingTimeOidSz; - (void)signingTime; - (void)signingTimeSz; -#endif - - 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 (flatSignedAttribsSz != 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) - ret = wc_HashUpdate(&esd->hash, esd->hashType, - flatSignedAttribs, flatSignedAttribsSz); - if (ret == 0) - ret = wc_HashFinal(&esd->hash, esd->hashType, - esd->contentAttribsDigest); - wc_HashFree(&esd->hash, esd->hashType); - - 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 initialized 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 = 0; -#if defined(HAVE_ECC) || \ - (defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)) - int hashSz = 0; -#endif -#if defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA) - int hashOID; -#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 - XMEMSET(digestInfo, 0, digestInfoSz); - - 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; - } - -#if defined(HAVE_ECC) || \ - (defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)) - /* get digest size from hash type */ - hashSz = wc_HashGetDigestSize(esd->hashType); - if (hashSz < 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return hashSz; - } -#endif - - /* sign digestInfo */ - switch (pkcs7->publicKeyOID) { - -#ifndef NO_RSA - case RSAk: - #ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK - if (pkcs7->rsaSignRawDigestCb != NULL) { - /* get hash OID */ - hashOID = wc_HashGetOID(esd->hashType); - - /* user signing plain digest, build DigestInfo themselves */ - ret = pkcs7->rsaSignRawDigestCb(pkcs7, - esd->contentAttribsDigest, hashSz, - esd->encContentDigest, sizeof(esd->encContentDigest), - pkcs7->privateKey, pkcs7->privateKeySz, pkcs7->devId, - hashOID); - break; - } - #endif - 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 */ - 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 */ -static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd, - const byte* hashBuf, word32 hashSz, byte* output, word32* outputSz, - byte* output2, word32* output2Sz) -{ - /* contentType OID (1.2.840.113549.1.9.3) */ - const byte contentTypeOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, - 0x09, 0x03 }; - - /* messageDigest OID (1.2.840.113549.1.9.4) */ - const byte messageDigestOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x04 }; - - /* signingTime OID () */ - byte signingTimeOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, - 0x09, 0x05}; - - Pkcs7Cert* certPtr = NULL; - word32 certSetSz = 0; - - word32 signerInfoSz = 0; - word32 totalSz, total2Sz; - int idx = 0, ret = 0; - int digEncAlgoId, digEncAlgoType; - byte* flatSignedAttribs = NULL; - word32 flatSignedAttribsSz = 0; - - byte signedDataOid[MAX_OID_SZ]; - word32 signedDataOidSz; - - byte signingTime[MAX_TIME_STRING_SZ]; - - if (pkcs7 == NULL || pkcs7->contentSz == 0 || - pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 || - output == NULL || outputSz == NULL || *outputSz == 0 || hashSz == 0 || - hashBuf == NULL) { - return BAD_FUNC_ARG; - } - - /* verify the hash size matches */ -#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)); - - /* set content type based on contentOID, unless user has set custom one - with wc_PKCS7_SetContentType() */ - if (pkcs7->contentTypeSz == 0) { - - /* default to DATA content type if user has not set */ - if (pkcs7->contentOID == 0) { - pkcs7->contentOID = DATA; - } - - ret = wc_SetContentType(pkcs7->contentOID, pkcs7->contentType, - sizeof(pkcs7->contentType)); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - pkcs7->contentTypeSz = ret; - } - - /* set signedData outer content type */ - ret = wc_SetContentType(SIGNED_DATA, signedDataOid, sizeof(signedDataOid)); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - signedDataOidSz = ret; - - if (pkcs7->sidType != DEGENERATE_SID) { - esd->hashType = wc_OidGetHash(pkcs7->hashOID); - if (wc_HashGetDigestSize(esd->hashType) != (int)hashSz) { - WOLFSSL_MSG("hashSz did not match hashOID"); - #ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return BUFFER_E; - } - - /* include hash */ - esd->contentDigest[0] = ASN_OCTET_STRING; - esd->contentDigest[1] = (byte)hashSz; - XMEMCPY(&esd->contentDigest[2], hashBuf, hashSz); - } - - if (pkcs7->detached == 1) { - /* do not include content if generating detached signature */ - esd->innerOctetsSz = 0; - esd->innerContSeqSz = 0; - esd->contentInfoSeqSz = SetSequence(pkcs7->contentTypeSz, - esd->contentInfoSeq); - } else { - esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets); - esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + - pkcs7->contentSz, esd->innerContSeq); - esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz + - esd->innerOctetsSz + pkcs7->contentTypeSz + - esd->innerContSeqSz, esd->contentInfoSeq); - } - - /* SignerIdentifier */ - if (pkcs7->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - /* IssuerAndSerialNumber */ - esd->issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz, - esd->issuerSn, MAX_SN_SZ, 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; - - if (pkcs7->version == 3) { - /* RFC 4108 version MUST be 3 for firmware package signer */ - esd->signerVersionSz = SetMyVersion(3, esd->signerVersion, 0); - } - else { - /* version MUST be 1 otherwise*/ - esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0); - } - - } else if (pkcs7->sidType == CMS_SKID) { - /* SubjectKeyIdentifier */ - esd->issuerSKIDSz = SetOctetString(KEYID_SIZE, esd->issuerSKID); - esd->issuerSKIDSeqSz = SetExplicit(0, esd->issuerSKIDSz + KEYID_SIZE, - esd->issuerSKIDSeq); - signerInfoSz += (esd->issuerSKIDSz + esd->issuerSKIDSeqSz + - KEYID_SIZE); - - /* version MUST be 3 */ - esd->signerVersionSz = SetMyVersion(3, esd->signerVersion, 0); - } else if (pkcs7->sidType == DEGENERATE_SID) { - /* no signer info added */ - } else { - #ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return SKID_E; - } - - if (pkcs7->sidType != DEGENERATE_SID) { - 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; - - /* build up signed attributes, include contentType, signingTime, and - messageDigest by default */ - ret = wc_PKCS7_BuildSignedAttributes(pkcs7, esd, pkcs7->contentType, - pkcs7->contentTypeSz, - contentTypeOid, sizeof(contentTypeOid), - messageDigestOid, sizeof(messageDigestOid), - signingTimeOid, sizeof(signingTimeOid), - signingTime, sizeof(signingTime)); - if (ret < 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ret; - } - - if (esd->signedAttribsSz > 0) { - 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(pkcs7, flatSignedAttribs, - esd->signedAttribs, esd->signedAttribsCount); - esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz, - esd->signedAttribSet); - } else { - esd->signedAttribSetSz = 0; - } - - /* 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; - - /* certificates [0] IMPLICIT CertificateSet */ - /* get total certificates size */ - certPtr = pkcs7->certList; - while (certPtr != NULL) { - certSetSz += certPtr->derSz; - certPtr = certPtr->next; - } - certPtr = NULL; - - if (certSetSz > 0) - esd->certsSetSz = SetImplicit(ASN_SET, 0, certSetSz, esd->certsSet); - - if (pkcs7->sidType != DEGENERATE_SID) { - esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId, - oidHashType, 0); - } - esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet); - - if (pkcs7->version == 3) { - /* RFC 4108 version MUST be 3 for firmware package signer */ - esd->versionSz = SetMyVersion(3, esd->version, 0); - } - else { - esd->versionSz = SetMyVersion(1, esd->version, 0); - } - - totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz + - esd->contentInfoSeqSz + pkcs7->contentTypeSz + - esd->innerContSeqSz + esd->innerOctetsSz + pkcs7->contentSz; - total2Sz = esd->certsSetSz + certSetSz + signerInfoSz; - - if (pkcs7->detached) { - totalSz -= pkcs7->contentSz; - } - - esd->innerSeqSz = SetSequence(totalSz + total2Sz, esd->innerSeq); - totalSz += esd->innerSeqSz; - esd->outerContentSz = SetExplicit(0, totalSz + total2Sz, esd->outerContent); - totalSz += esd->outerContentSz + signedDataOidSz; - esd->outerSeqSz = SetSequence(totalSz + total2Sz, esd->outerSeq); - totalSz += esd->outerSeqSz; - - /* if using header/footer, we are not returning the content */ - if (output2 && output2Sz) { - if (total2Sz > *output2Sz) { - 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; - } - - if (!pkcs7->detached) { - totalSz -= pkcs7->contentSz; - } - } - else { - /* if using single output buffer include content and footer */ - totalSz += total2Sz; - } - - if (totalSz > *outputSz) { - 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, signedDataOid, signedDataOidSz); - idx += signedDataOidSz; - 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, pkcs7->contentType, pkcs7->contentTypeSz); - idx += pkcs7->contentTypeSz; - XMEMCPY(output + idx, esd->innerContSeq, esd->innerContSeqSz); - idx += esd->innerContSeqSz; - XMEMCPY(output + idx, esd->innerOctets, esd->innerOctetsSz); - idx += esd->innerOctetsSz; - - /* support returning header and footer without content */ - if (output2 && output2Sz) { - *outputSz = idx; - idx = 0; - } - else { - if (!pkcs7->detached) { - XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz); - idx += pkcs7->contentSz; - } - output2 = output; - } - - /* certificates */ - XMEMCPY(output2 + idx, esd->certsSet, esd->certsSetSz); - idx += esd->certsSetSz; - certPtr = pkcs7->certList; - while (certPtr != NULL) { - XMEMCPY(output2 + idx, certPtr->der, certPtr->derSz); - idx += certPtr->derSz; - certPtr = certPtr->next; - } - wc_PKCS7_FreeCertSet(pkcs7); - - XMEMCPY(output2 + idx, esd->signerInfoSet, esd->signerInfoSetSz); - idx += esd->signerInfoSetSz; - XMEMCPY(output2 + idx, esd->signerInfoSeq, esd->signerInfoSeqSz); - idx += esd->signerInfoSeqSz; - XMEMCPY(output2 + idx, esd->signerVersion, esd->signerVersionSz); - idx += esd->signerVersionSz; - /* SignerIdentifier */ - if (pkcs7->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - /* IssuerAndSerialNumber */ - XMEMCPY(output2 + idx, esd->issuerSnSeq, esd->issuerSnSeqSz); - idx += esd->issuerSnSeqSz; - XMEMCPY(output2 + idx, esd->issuerName, esd->issuerNameSz); - idx += esd->issuerNameSz; - XMEMCPY(output2 + idx, pkcs7->issuer, pkcs7->issuerSz); - idx += pkcs7->issuerSz; - XMEMCPY(output2 + idx, esd->issuerSn, esd->issuerSnSz); - idx += esd->issuerSnSz; - } else if (pkcs7->sidType == CMS_SKID) { - /* SubjectKeyIdentifier */ - XMEMCPY(output2 + idx, esd->issuerSKIDSeq, esd->issuerSKIDSeqSz); - idx += esd->issuerSKIDSeqSz; - XMEMCPY(output2 + idx, esd->issuerSKID, esd->issuerSKIDSz); - idx += esd->issuerSKIDSz; - XMEMCPY(output2 + idx, pkcs7->issuerSubjKeyId, KEYID_SIZE); - idx += KEYID_SIZE; - } else if (pkcs7->sidType == DEGENERATE_SID) { - /* no signer infos in degenerate case */ - } else { - #ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return SKID_E; - } - XMEMCPY(output2 + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); - idx += esd->signerDigAlgoIdSz; - - /* SignerInfo:Attributes */ - if (flatSignedAttribsSz > 0) { - XMEMCPY(output2 + idx, esd->signedAttribSet, esd->signedAttribSetSz); - idx += esd->signedAttribSetSz; - XMEMCPY(output2 + idx, flatSignedAttribs, flatSignedAttribsSz); - idx += flatSignedAttribsSz; - XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - - XMEMCPY(output2 + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz); - idx += esd->digEncAlgoIdSz; - XMEMCPY(output2 + idx, esd->signerDigest, esd->signerDigestSz); - idx += esd->signerDigestSz; - XMEMCPY(output2 + idx, esd->encContentDigest, esd->encContentDigestSz); - idx += esd->encContentDigestSz; - - if (output2 && output2Sz) { - *output2Sz = idx; - idx = 0; /* success */ - } - else { - *outputSz = idx; - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return idx; -} - -/* hashBuf: The computed digest for the pkcs7->content - * hashSz: The size of computed digest for the pkcs7->content based on hashOID - * outputHead: The PKCS7 header that goes on top of the raw data signed. - * outputFoot: The PKCS7 footer that goes at the end of the raw data signed. - * pkcs7->content: Not used - * pkcs7->contentSz: Must be provided as actual sign of raw data - * return codes: 0=success, negative=error - */ -int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf, - word32 hashSz, byte* outputHead, word32* outputHeadSz, byte* outputFoot, - word32* outputFootSz) -{ - int ret; -#ifdef WOLFSSL_SMALL_STACK - ESD* esd; -#else - ESD esd[1]; -#endif - - /* other args checked in wc_PKCS7_EncodeSigned_ex */ - if (pkcs7 == NULL || outputFoot == NULL || outputFootSz == NULL) { - 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)); - - ret = PKCS7_EncodeSigned(pkcs7, esd, hashBuf, hashSz, - outputHead, outputHeadSz, outputFoot, outputFootSz); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - -/* Toggle detached signature mode on/off for PKCS#7/CMS SignedData content type. - * By default wolfCrypt includes the data to be signed in the SignedData - * bundle. This data can be omitted in the case when a detached signature is - * being created. To enable generation of detached signatures, set flag to "1", - * otherwise set to "0": - * - * flag 1 turns on support - * flag 0 turns off support - * - * pkcs7 - pointer to initialized PKCS7 structure - * flag - turn on/off detached signature generation (1 or 0) - * - * Returns 0 on success, negative upon error. */ -int wc_PKCS7_SetDetached(PKCS7* pkcs7, word16 flag) -{ - if (pkcs7 == NULL || (flag != 0 && flag != 1)) - return BAD_FUNC_ARG; - - pkcs7->detached = flag; - - return 0; -} - -/* By default, SignedData bundles have the following signed attributes attached: - * contentType (1.2.840.113549.1.9.3) - * signgingTime (1.2.840.113549.1.9.5) - * messageDigest (1.2.840.113549.1.9.4) - * - * Calling this API before wc_PKCS7_EncodeSignedData() will disable the - * inclusion of those attributes. - * - * pkcs7 - pointer to initialized PKCS7 structure - * - * Returns 0 on success, negative upon error. */ -int wc_PKCS7_NoDefaultSignedAttribs(PKCS7* pkcs7) -{ - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - pkcs7->skipDefaultSignedAttribs = 1; - - return 0; -} - -/* return codes: >0: Size of signed PKCS7 output buffer, negative: error */ -int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) -{ - int ret; - int hashSz; - enum wc_HashType hashType; - byte hashBuf[WC_MAX_DIGEST_SIZE]; -#ifdef WOLFSSL_SMALL_STACK - ESD* esd; -#else - ESD esd[1]; -#endif - - /* other args checked in wc_PKCS7_EncodeSigned_ex */ - if (pkcs7 == NULL || pkcs7->contentSz == 0 || pkcs7->content == NULL) { - return BAD_FUNC_ARG; - } - - /* get hash type and size, validate hashOID */ - hashType = wc_OidGetHash(pkcs7->hashOID); - hashSz = wc_HashGetDigestSize(hashType); - if (hashSz < 0) - return hashSz; - -#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 = hashType; - - /* calculate hash for content */ - ret = wc_HashInit(&esd->hash, esd->hashType); - if (ret == 0) { - ret = wc_HashUpdate(&esd->hash, esd->hashType, - pkcs7->content, pkcs7->contentSz); - if (ret == 0) { - ret = wc_HashFinal(&esd->hash, esd->hashType, hashBuf); - } - wc_HashFree(&esd->hash, esd->hashType); - } - - if (ret == 0) { - ret = PKCS7_EncodeSigned(pkcs7, esd, hashBuf, hashSz, - output, &outputSz, NULL, NULL); - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - return ret; -} - - -/* Single-shot API to generate a CMS SignedData bundle that encapsulates a - * content of type FirmwarePkgData. Any recipient certificates should be - * loaded into the PKCS7 structure prior to calling this function, using - * wc_PKCS7_InitWithCert() and/or wc_PKCS7_AddCertificate(). - * - * pkcs7 - pointer to initialized PKCS7 struct - * privateKey - private RSA/ECC key, used for signing SignedData - * privateKeySz - size of privateKey, octets - * signOID - public key algorithm OID, used for sign operation - * hashOID - hash algorithm OID, used for signature generation - * content - content to be encapsulated, of type FirmwarePkgData - * contentSz - size of content, octets - * signedAttribs - optional signed attributes - * signedAttribsSz - number of PKCS7Attrib members in signedAttribs - * output - output buffer for final bundle - * outputSz - size of output buffer, octets - * - * Returns length of generated bundle on success, negative upon error. */ -int wc_PKCS7_EncodeSignedFPD(PKCS7* pkcs7, byte* privateKey, - word32 privateKeySz, int signOID, int hashOID, - byte* content, word32 contentSz, - PKCS7Attrib* signedAttribs, word32 signedAttribsSz, - byte* output, word32 outputSz) -{ - int ret = 0; - WC_RNG rng; - - if (pkcs7 == NULL || privateKey == NULL || privateKeySz == 0 || - content == NULL || contentSz == 0 || output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - - ret = wc_InitRng(&rng); - if (ret != 0) - return ret; - - pkcs7->rng = &rng; - pkcs7->content = content; - pkcs7->contentSz = contentSz; - pkcs7->contentOID = FIRMWARE_PKG_DATA; - pkcs7->hashOID = hashOID; - pkcs7->encryptOID = signOID; - pkcs7->privateKey = privateKey; - pkcs7->privateKeySz = privateKeySz; - pkcs7->signedAttribs = signedAttribs; - pkcs7->signedAttribsSz = signedAttribsSz; - pkcs7->version = 3; - - ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz); - if (ret <= 0) { - WOLFSSL_MSG("Error encoding CMS SignedData content type"); - } - - pkcs7->rng = NULL; - wc_FreeRng(&rng); - - return ret; -} - -#ifndef NO_PKCS7_ENCRYPTED_DATA - -/* Single-shot API to generate a CMS SignedData bundle that encapsulates a - * CMS EncryptedData bundle. Content of inner EncryptedData is set to that - * of FirmwarePkgData. Any recipient certificates should be loaded into the - * PKCS7 structure prior to calling this function, using wc_PKCS7_InitWithCert() - * and/or wc_PKCS7_AddCertificate(). - * - * pkcs7 - pointer to initialized PKCS7 struct - * encryptKey - encryption key used for encrypting EncryptedData - * encryptKeySz - size of encryptKey, octets - * privateKey - private RSA/ECC key, used for signing SignedData - * privateKeySz - size of privateKey, octets - * encryptOID - encryption algorithm OID, to be used as encryption - * algorithm for EncryptedData - * signOID - public key algorithm OID, to be used for sign - * operation in SignedData generation - * hashOID - hash algorithm OID, to be used for signature in - * SignedData generation - * content - content to be encapsulated - * contentSz - size of content, octets - * unprotectedAttribs - optional unprotected attributes, for EncryptedData - * unprotectedAttribsSz - number of PKCS7Attrib members in unprotectedAttribs - * signedAttribs - optional signed attributes, for SignedData - * signedAttribsSz - number of PKCS7Attrib members in signedAttribs - * output - output buffer for final bundle - * outputSz - size of output buffer, octets - * - * Returns length of generated bundle on success, negative upon error. */ -int wc_PKCS7_EncodeSignedEncryptedFPD(PKCS7* pkcs7, byte* encryptKey, - word32 encryptKeySz, byte* privateKey, - word32 privateKeySz, int encryptOID, - int signOID, int hashOID, - byte* content, word32 contentSz, - PKCS7Attrib* unprotectedAttribs, - word32 unprotectedAttribsSz, - PKCS7Attrib* signedAttribs, - word32 signedAttribsSz, - byte* output, word32 outputSz) -{ - int ret = 0, encryptedSz = 0; - byte* encrypted = NULL; - WC_RNG rng; - - if (pkcs7 == NULL || encryptKey == NULL || encryptKeySz == 0 || - privateKey == NULL || privateKeySz == 0 || content == NULL || - contentSz == 0 || output == NULL || outputSz == 0) { - return BAD_FUNC_ARG; - } - - /* 1: build up EncryptedData using FirmwarePkgData type, use output - * buffer as tmp for storage and to get size */ - - /* set struct elements, inner content type is FirmwarePkgData */ - pkcs7->content = content; - pkcs7->contentSz = contentSz; - pkcs7->contentOID = FIRMWARE_PKG_DATA; - pkcs7->encryptOID = encryptOID; - pkcs7->encryptionKey = encryptKey; - pkcs7->encryptionKeySz = encryptKeySz; - pkcs7->unprotectedAttribs = unprotectedAttribs; - pkcs7->unprotectedAttribsSz = unprotectedAttribsSz; - pkcs7->version = 3; - - encryptedSz = wc_PKCS7_EncodeEncryptedData(pkcs7, output, outputSz); - if (encryptedSz < 0) { - WOLFSSL_MSG("Error encoding CMS EncryptedData content type"); - return encryptedSz; - } - - /* save encryptedData, reset output buffer and struct */ - encrypted = (byte*)XMALLOC(encryptedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (encrypted == NULL) { - ForceZero(output, outputSz); - return MEMORY_E; - } - - XMEMCPY(encrypted, output, encryptedSz); - ForceZero(output, outputSz); - - ret = wc_InitRng(&rng); - if (ret != 0) { - ForceZero(encrypted, encryptedSz); - XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* 2: build up SignedData, encapsulating EncryptedData */ - pkcs7->rng = &rng; - pkcs7->content = encrypted; - pkcs7->contentSz = encryptedSz; - pkcs7->contentOID = ENCRYPTED_DATA; - pkcs7->hashOID = hashOID; - pkcs7->encryptOID = signOID; - pkcs7->privateKey = privateKey; - pkcs7->privateKeySz = privateKeySz; - pkcs7->signedAttribs = signedAttribs; - pkcs7->signedAttribsSz = signedAttribsSz; - - ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz); - if (ret <= 0) { - WOLFSSL_MSG("Error encoding CMS SignedData content type"); - } - - ForceZero(encrypted, encryptedSz); - XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->rng = NULL; - wc_FreeRng(&rng); - - return ret; -} - -#endif /* NO_PKCS7_ENCRYPTED_DATA */ - -#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA) -/* Single-shot API to generate a CMS SignedData bundle that encapsulates a - * CMS CompressedData bundle. Content of inner CompressedData is set to that - * of FirmwarePkgData. Any recipient certificates should be loaded into the - * PKCS7 structure prior to calling this function, using wc_PKCS7_InitWithCert() - * and/or wc_PKCS7_AddCertificate(). - * - * pkcs7 - pointer to initialized PKCS7 struct - * privateKey - private RSA/ECC key, used for signing SignedData - * privateKeySz - size of privateKey, octets - * signOID - public key algorithm OID, to be used for sign - * operation in SignedData generation - * hashOID - hash algorithm OID, to be used for signature in - * SignedData generation - * content - content to be encapsulated - * contentSz - size of content, octets - * signedAttribs - optional signed attributes, for SignedData - * signedAttribsSz - number of PKCS7Attrib members in signedAttribs - * output - output buffer for final bundle - * outputSz - size of output buffer, octets - * - * Returns length of generated bundle on success, negative upon error. */ -int wc_PKCS7_EncodeSignedCompressedFPD(PKCS7* pkcs7, byte* privateKey, - word32 privateKeySz, int signOID, - int hashOID, byte* content, - word32 contentSz, - PKCS7Attrib* signedAttribs, - word32 signedAttribsSz, byte* output, - word32 outputSz) -{ - int ret = 0, compressedSz = 0; - byte* compressed = NULL; - WC_RNG rng; - - if (pkcs7 == NULL || privateKey == NULL || privateKeySz == 0 || - content == NULL || contentSz == 0 || output == NULL || outputSz == 0) { - return BAD_FUNC_ARG; - } - - /* 1: build up CompressedData using FirmwarePkgData type, use output - * buffer as tmp for storage and to get size */ - - /* set struct elements, inner content type is FirmwarePkgData */ - pkcs7->content = content; - pkcs7->contentSz = contentSz; - pkcs7->contentOID = FIRMWARE_PKG_DATA; - pkcs7->version = 3; - - compressedSz = wc_PKCS7_EncodeCompressedData(pkcs7, output, outputSz); - if (compressedSz < 0) { - WOLFSSL_MSG("Error encoding CMS CompressedData content type"); - return compressedSz; - } - - /* save compressedData, reset output buffer and struct */ - compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (compressed == NULL) { - ForceZero(output, outputSz); - return MEMORY_E; - } - - XMEMCPY(compressed, output, compressedSz); - ForceZero(output, outputSz); - - ret = wc_InitRng(&rng); - if (ret != 0) { - ForceZero(compressed, compressedSz); - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* 2: build up SignedData, encapsulating EncryptedData */ - pkcs7->rng = &rng; - pkcs7->content = compressed; - pkcs7->contentSz = compressedSz; - pkcs7->contentOID = COMPRESSED_DATA; - pkcs7->hashOID = hashOID; - pkcs7->encryptOID = signOID; - pkcs7->privateKey = privateKey; - pkcs7->privateKeySz = privateKeySz; - pkcs7->signedAttribs = signedAttribs; - pkcs7->signedAttribsSz = signedAttribsSz; - - ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz); - if (ret <= 0) { - WOLFSSL_MSG("Error encoding CMS SignedData content type"); - } - - ForceZero(compressed, compressedSz); - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->rng = NULL; - wc_FreeRng(&rng); - - return ret; -} - -#ifndef NO_PKCS7_ENCRYPTED_DATA - -/* Single-shot API to generate a CMS SignedData bundle that encapsulates a - * CMS EncryptedData bundle, which then encapsulates a CMS CompressedData - * bundle. Content of inner CompressedData is set to that of FirmwarePkgData. - * Any recipient certificates should be loaded into the PKCS7 structure prior - * to calling this function, using wc_PKCS7_InitWithCert() and/or - * wc_PKCS7_AddCertificate(). - * - * pkcs7 - pointer to initialized PKCS7 struct - * encryptKey - encryption key used for encrypting EncryptedData - * encryptKeySz - size of encryptKey, octets - * privateKey - private RSA/ECC key, used for signing SignedData - * privateKeySz - size of privateKey, octets - * encryptOID - encryption algorithm OID, to be used as encryption - * algorithm for EncryptedData - * signOID - public key algorithm OID, to be used for sign - * operation in SignedData generation - * hashOID - hash algorithm OID, to be used for signature in - * SignedData generation - * content - content to be encapsulated - * contentSz - size of content, octets - * unprotectedAttribs - optional unprotected attributes, for EncryptedData - * unprotectedAttribsSz - number of PKCS7Attrib members in unprotectedAttribs - * signedAttribs - optional signed attributes, for SignedData - * signedAttribsSz - number of PKCS7Attrib members in signedAttribs - * output - output buffer for final bundle - * outputSz - size of output buffer, octets - * - * Returns length of generated bundle on success, negative upon error. */ -int wc_PKCS7_EncodeSignedEncryptedCompressedFPD(PKCS7* pkcs7, byte* encryptKey, - word32 encryptKeySz, byte* privateKey, - word32 privateKeySz, int encryptOID, - int signOID, int hashOID, byte* content, - word32 contentSz, - PKCS7Attrib* unprotectedAttribs, - word32 unprotectedAttribsSz, - PKCS7Attrib* signedAttribs, - word32 signedAttribsSz, - byte* output, word32 outputSz) -{ - int ret = 0, compressedSz = 0, encryptedSz = 0; - byte* compressed = NULL; - byte* encrypted = NULL; - WC_RNG rng; - - if (pkcs7 == NULL || encryptKey == NULL || encryptKeySz == 0 || - privateKey == NULL || privateKeySz == 0 || content == NULL || - contentSz == 0 || output == NULL || outputSz == 0) { - return BAD_FUNC_ARG; - } - - /* 1: build up CompressedData using FirmwarePkgData type, use output - * buffer as tmp for storage and to get size */ - pkcs7->content = content; - pkcs7->contentSz = contentSz; - pkcs7->contentOID = FIRMWARE_PKG_DATA; - pkcs7->version = 3; - - compressedSz = wc_PKCS7_EncodeCompressedData(pkcs7, output, outputSz); - if (compressedSz < 0) { - WOLFSSL_MSG("Error encoding CMS CompressedData content type"); - return compressedSz; - } - - /* save compressedData, reset output buffer and struct */ - compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (compressed == NULL) - return MEMORY_E; - - XMEMCPY(compressed, output, compressedSz); - ForceZero(output, outputSz); - - /* 2: build up EncryptedData using CompressedData, use output - * buffer as tmp for storage and to get size */ - pkcs7->content = compressed; - pkcs7->contentSz = compressedSz; - pkcs7->contentOID = COMPRESSED_DATA; - pkcs7->encryptOID = encryptOID; - pkcs7->encryptionKey = encryptKey; - pkcs7->encryptionKeySz = encryptKeySz; - pkcs7->unprotectedAttribs = unprotectedAttribs; - pkcs7->unprotectedAttribsSz = unprotectedAttribsSz; - - encryptedSz = wc_PKCS7_EncodeEncryptedData(pkcs7, output, outputSz); - if (encryptedSz < 0) { - WOLFSSL_MSG("Error encoding CMS EncryptedData content type"); - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return encryptedSz; - } - - /* save encryptedData, reset output buffer and struct */ - encrypted = (byte*)XMALLOC(encryptedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (encrypted == NULL) { - ForceZero(compressed, compressedSz); - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - XMEMCPY(encrypted, output, encryptedSz); - ForceZero(compressed, compressedSz); - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - ForceZero(output, outputSz); - - ret = wc_InitRng(&rng); - if (ret != 0) { - ForceZero(encrypted, encryptedSz); - XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* 3: build up SignedData, encapsulating EncryptedData */ - pkcs7->rng = &rng; - pkcs7->content = encrypted; - pkcs7->contentSz = encryptedSz; - pkcs7->contentOID = ENCRYPTED_DATA; - pkcs7->hashOID = hashOID; - pkcs7->encryptOID = signOID; - pkcs7->privateKey = privateKey; - pkcs7->privateKeySz = privateKeySz; - pkcs7->signedAttribs = signedAttribs; - pkcs7->signedAttribsSz = signedAttribsSz; - - ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz); - if (ret <= 0) { - WOLFSSL_MSG("Error encoding CMS SignedData content type"); - } - - ForceZero(encrypted, encryptedSz); - XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->rng = NULL; - wc_FreeRng(&rng); - - return ret; -} - -#endif /* !NO_PKCS7_ENCRYPTED_DATA */ -#endif /* HAVE_LIBZ && !NO_PKCS7_COMPRESSED_DATA */ - - -#ifndef NO_RSA - -#ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK -/* register raw RSA sign digest callback */ -int wc_PKCS7_SetRsaSignRawDigestCb(PKCS7* pkcs7, CallbackRsaSignRawDigest cb) -{ - if (pkcs7 == NULL || cb == NULL) { - return BAD_FUNC_ARG; - } - - pkcs7->rsaSignRawDigestCb = cb; - - return 0; -} -#endif - -/* 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, i; - word32 scratch = 0, verified = 0; -#ifdef WOLFSSL_SMALL_STACK - byte* digest; - RsaKey* key; - DecodedCert* dCert; -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; - RsaKey key[1]; - DecodedCert stack_dCert; - DecodedCert* dCert = &stack_dCert; -#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; - } - - dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap, - DYNAMIC_TYPE_DCERT); - if (dCert == NULL) { - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); - - /* loop over certs received in certificates set, try to find one - * that will validate signature */ - for (i = 0; i < MAX_PKCS7_CERTS; i++) { - - verified = 0; - scratch = 0; - - if (pkcs7->certSz[i] == 0) - continue; - - 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); - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#endif - return ret; - } - - InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap); - /* not verifying, only using this to extract public key */ - ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0); - if (ret < 0) { - WOLFSSL_MSG("ASN RSA cert parse error"); - FreeDecodedCert(dCert); - wc_FreeRsaKey(key); - continue; - } - - if (wc_RsaPublicKeyDecode(dCert->publicKey, &scratch, key, - dCert->pubKeySize) < 0) { - WOLFSSL_MSG("ASN RSA key decode error"); - FreeDecodedCert(dCert); - wc_FreeRsaKey(key); - continue; - } - - #ifdef WOLFSSL_ASYNC_CRYPT - do { - ret = wc_AsyncWait(ret, &key->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) { - ret = wc_RsaSSL_Verify(sig, sigSz, digest, MAX_PKCS7_DIGEST_SZ, - key); - } - #ifdef WOLFSSL_ASYNC_CRYPT - } while (ret == WC_PENDING_E); - #endif - FreeDecodedCert(dCert); - wc_FreeRsaKey(key); - - if ((ret > 0) && (hashSz == (word32)ret)) { - if (XMEMCMP(digest, hash, hashSz) == 0) { - /* found signer that successfully verified signature */ - verified = 1; - break; - } - } - } - - if (verified == 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); - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#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, i; - int res = 0; - int verified = 0; -#ifdef WOLFSSL_SMALL_STACK - byte* digest; - ecc_key* key; - DecodedCert* dCert; -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; - ecc_key key[1]; - DecodedCert stack_dCert; - DecodedCert* dCert = &stack_dCert; -#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; - } - - dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap, - DYNAMIC_TYPE_DCERT); - if (dCert == NULL) { - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#endif - - XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); - - /* loop over certs received in certificates set, try to find one - * that will validate signature */ - for (i = 0; i < MAX_PKCS7_CERTS; i++) { - - verified = 0; - - if (pkcs7->certSz[i] == 0) - continue; - - 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); - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#endif - return ret; - } - - InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap); - /* not verifying, only using this to extract public key */ - ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0); - if (ret < 0) { - WOLFSSL_MSG("ASN ECC cert parse error"); - FreeDecodedCert(dCert); - wc_ecc_free(key); - continue; - } - - if (wc_EccPublicKeyDecode(pkcs7->publicKey, &idx, key, - pkcs7->publicKeySz) < 0) { - WOLFSSL_MSG("ASN ECC key decode error"); - FreeDecodedCert(dCert); - wc_ecc_free(key); - continue; - } - - #ifdef WOLFSSL_ASYNC_CRYPT - do { - ret = wc_AsyncWait(ret, &key->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) { - ret = wc_ecc_verify_hash(sig, sigSz, hash, hashSz, &res, key); - } - #ifdef WOLFSSL_ASYNC_CRYPT - } while (ret == WC_PENDING_E); - #endif - - FreeDecodedCert(dCert); - wc_ecc_free(key); - - if (ret == 0 && res == 1) { - /* found signer that successfully verified signature */ - verified = 1; - break; - } - } - - if (verified == 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); - XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT); -#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, - const byte* hashBuf, word32 hashBufSz) -{ - int ret = 0, digIdx = 0; - word32 attribSetSz = 0, hashSz = 0; - 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; - - /* check arguments */ - if (pkcs7 == NULL || pkcs7Digest == NULL || - pkcs7DigestSz == NULL || plainDigest == NULL) { - return BAD_FUNC_ARG; - } - - hashType = wc_OidGetHash(pkcs7->hashOID); - ret = wc_HashGetDigestSize(hashType); - if (ret < 0) - return ret; - hashSz = ret; - - if (signedAttribSz > 0) { - if (signedAttrib == NULL) - return BAD_FUNC_ARG; - } - else { - if (hashBuf && hashBufSz > 0) { - if (hashSz != hashBufSz) - return BAD_FUNC_ARG; - } - else if (pkcs7->content == 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); - - - /* calculate digest */ - if (hashBuf && hashBufSz > 0 && signedAttribSz == 0) { - XMEMCPY(digest, hashBuf, hashBufSz); - } - else { - 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) { - attribSetSz = SetSet(signedAttribSz, attribSet); - - /* calculate digest */ - ret = wc_HashUpdate(&hash, hashType, attribSet, attribSetSz); - if (ret == 0) - ret = wc_HashUpdate(&hash, hashType, signedAttrib, signedAttribSz); - if (ret == 0) - ret = wc_HashFinal(&hash, hashType, digest); - } else { - ret = wc_HashUpdate(&hash, hashType, pkcs7->content, pkcs7->contentSz); - if (ret == 0) - ret = wc_HashFinal(&hash, hashType, digest); - } - - wc_HashFree(&hash, hashType); - 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 CMS/PKCS7 SignedData content digest matches that which is - * included in the messageDigest signed attribute. Only called when - * signed attributes are present, otherwise original signature verification - * is done over content. - * - * pkcs7 - pointer to initialized PKCS7 struct - * hashBuf - pointer to user-provided hash buffer, used with - * wc_PKCS7_VerifySignedData_ex() - * hashBufSz - size of hashBuf, octets - * - * return 0 on success, negative on error */ -static int wc_PKCS7_VerifyContentMessageDigest(PKCS7* pkcs7, - const byte* hashBuf, - word32 hashSz) -{ - int ret = 0, digestSz = 0, innerAttribSz = 0; - word32 idx = 0; - byte* digestBuf = NULL; -#ifdef WOLFSSL_SMALL_STACK - byte* digest = NULL; -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; -#endif - PKCS7DecodedAttrib* attrib; - enum wc_HashType hashType; - - /* messageDigest OID (1.2.840.113549.1.9.4) */ - const byte mdOid[] = - { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04 }; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - if ((pkcs7->content == NULL || pkcs7->contentSz == 0) && - (hashBuf == NULL || hashSz == 0)) { - WOLFSSL_MSG("SignedData bundle has no content or hash to verify"); - return BAD_FUNC_ARG; - } - - /* lookup messageDigest attribute */ - attrib = findAttrib(pkcs7, mdOid, sizeof(mdOid)); - if (attrib == NULL) { - WOLFSSL_MSG("messageDigest attribute not in bundle, must be when " - "signed attribs are present"); - return ASN_PARSE_E; - } - - /* advance past attrib->value ASN.1 header and length */ - if (attrib->value == NULL || attrib->valueSz == 0) - return ASN_PARSE_E; - - if (attrib->value[idx++] != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(attrib->value, &idx, &innerAttribSz, attrib->valueSz) < 0) - return ASN_PARSE_E; - - /* get hash type and size */ - hashType = wc_OidGetHash(pkcs7->hashOID); - if (hashType == WC_HASH_TYPE_NONE) { - WOLFSSL_MSG("Error getting hash type for PKCS7 content verification"); - return BAD_FUNC_ARG; - } - - /* build content hash if needed, or use existing hash value */ - if (hashBuf == NULL) { - -#ifdef WOLFSSL_SMALL_STACK - digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (digest == NULL) - return MEMORY_E; -#endif - XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); - - ret = wc_Hash(hashType, pkcs7->content, pkcs7->contentSz, digest, - MAX_PKCS7_DIGEST_SZ); - if (ret < 0) { - WOLFSSL_MSG("Error hashing PKCS7 content for verification"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - digestBuf = digest; - digestSz = wc_HashGetDigestSize(hashType); - if (digestSz < 0) { - WOLFSSL_MSG("Invalid hash type"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return digestSz; - } - } else { - - /* user passed in pre-computed hash */ - digestBuf = (byte*)hashBuf; - digestSz = (int)hashSz; - } - - /* compare generated to hash in messageDigest attribute */ - if ((innerAttribSz != digestSz) || - (XMEMCMP(attrib->value + idx, digestBuf, (word32)digestSz) != 0)) { - WOLFSSL_MSG("Content digest does not match messageDigest attrib value"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return SIG_VERIFY_E; - } - - if (hashBuf == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(digest, 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, - const byte* hashBuf, word32 hashSz) -{ - 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; - - /* allocate space to build hash */ - pkcs7DigestSz = MAX_PKCS7_DIGEST_SZ; -#ifdef WOLFSSL_SMALL_STACK - pkcs7Digest = (byte*)XMALLOC(pkcs7DigestSz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (pkcs7Digest == NULL) - return MEMORY_E; -#endif - - XMEMSET(pkcs7Digest, 0, pkcs7DigestSz); - - /* verify signed attrib digest matches that of content */ - if (signedAttrib != NULL) { - ret = wc_PKCS7_VerifyContentMessageDigest(pkcs7, hashBuf, hashSz); - if (ret != 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - } - - /* build hash to verify against */ - ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib, - signedAttribSz, pkcs7Digest, - &pkcs7DigestSz, &plainDigest, - &plainDigestSz, hashBuf, hashSz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return ret; - } - - /* If no certificates are available then store the signature and hash for - * user to verify. Make sure that different return value than success is - * returned because the signature was not verified here. */ - if (ret == 0) { - byte haveCert = 0; - int i; - - for (i = 0; i < MAX_PKCS7_CERTS; i++) { - if (pkcs7->certSz[i] == 0) - continue; - haveCert = 1; - } - - if (!haveCert) { - WOLFSSL_MSG("No certificates in bundle to verify signature"); - - /* store signature */ - XFREE(pkcs7->signature, pkcs7->heap, DYNAMIC_TYPE_SIGNATURE); - pkcs7->signature = NULL; - pkcs7->signatureSz = 0; - pkcs7->signature = (byte*)XMALLOC(sigSz, pkcs7->heap, - DYNAMIC_TYPE_SIGNATURE); - if (pkcs7->signature == NULL) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return MEMORY_E; - } - XMEMCPY(pkcs7->signature, sig, sigSz); - pkcs7->signatureSz = sigSz; - - /* store plain digest (CMS and ECC) */ - XFREE(pkcs7->plainDigest, pkcs7->heap, DYNAMIC_TYPE_DIGEST); - pkcs7->plainDigest = NULL; - pkcs7->plainDigestSz = 0; - pkcs7->plainDigest = (byte*)XMALLOC(plainDigestSz, pkcs7->heap, - DYNAMIC_TYPE_DIGEST); - if (pkcs7->plainDigest == NULL) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return MEMORY_E; - } - XMEMCPY(pkcs7->plainDigest, plainDigest, plainDigestSz); - pkcs7->plainDigestSz = plainDigestSz; - - /* store pkcs7 digest (default RSA) */ - XFREE(pkcs7->pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_DIGEST); - pkcs7->pkcs7Digest = NULL; - pkcs7->pkcs7DigestSz = 0; - pkcs7->pkcs7Digest = (byte*)XMALLOC(pkcs7DigestSz, pkcs7->heap, - DYNAMIC_TYPE_DIGEST); - if (pkcs7->pkcs7Digest == NULL) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return MEMORY_E; - } - XMEMCPY(pkcs7->pkcs7Digest, pkcs7Digest, pkcs7DigestSz); - pkcs7->pkcs7DigestSz = pkcs7DigestSz; - - #ifdef WOLFSSL_SMALL_STACK - XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return PKCS7_SIGNEEDS_CHECK; - } - } - - - - 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; -} - - -/* option to turn off support for degenerate cases - * flag 0 turns off support - * flag 1 turns on support - * - * by default support for SignedData degenerate cases is on - */ -void wc_PKCS7_AllowDegenerate(PKCS7* pkcs7, word16 flag) -{ - if (pkcs7) { - if (flag) { /* flag of 1 turns on support for degenerate */ - pkcs7->noDegenerate = 0; - } - else { /* flag of 0 turns off support */ - pkcs7->noDegenerate = 1; - } - } -} - -/* Parses through a signerInfo set. Reads buffer "in" from "idxIn" to "idxIn" + - * length treating the current "idxIn" plus the length of set as max possible - * index. - * - * In the case that signed attributes are found "signedAttrib" gets set to point - * at their location in the buffer "in". Also in this case signedAttribSz gets - * set to the size of the signedAttrib buffer. - * - * returns 0 on success - */ -static int wc_PKCS7_ParseSignerInfo(PKCS7* pkcs7, byte* in, word32 inSz, - word32* idxIn, int degenerate, byte** signedAttrib, int* signedAttribSz) -{ - int ret = 0; - int length; - int version; - word32 sigOID = 0, hashOID = 0; - word32 idx = *idxIn, localIdx; - byte tag; - - WOLFSSL_ENTER("wc_PKCS7_ParseSignerInfo"); - /* require a signer if degenerate case not allowed */ - if (inSz == 0 && pkcs7->noDegenerate == 1) { - WOLFSSL_MSG("Set to not allow degenerate cases"); - return PKCS7_NO_SIGNER_E; - } - - if (inSz == 0 && degenerate == 0) { - WOLFSSL_MSG("PKCS7 signers expected"); - return PKCS7_NO_SIGNER_E; - } - - /* not a degenerate case and there is elements in the set */ - if (inSz > 0 && degenerate == 0) { - ret = wc_PKCS7_SignerInfoNew(pkcs7); - - /* Get the sequence of the first signerInfo */ - if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) - ret = ASN_PARSE_E; - - /* Get the version */ - if (ret == 0 && GetMyVersion(in, &idx, &version, inSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0) { - pkcs7->signerInfo->version = version; - } - - if (ret == 0 && version == 1) { - /* Get the sequence of IssuerAndSerialNumber */ - if (GetSequence(in, &idx, &length, inSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0) { - ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length); - idx += length; - } - - } else if (ret == 0 && version == 3) { - /* Get the sequence of SubjectKeyIdentifier */ - if (idx + 1 > inSz) - ret = BUFFER_E; - - localIdx = idx; - if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 && - tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - idx++; - - if (GetLength(in, &idx, &length, inSz) <= 0) - ret = ASN_PARSE_E; - - if (ret == 0 && idx + 1 > inSz) - ret = BUFFER_E; - - if (ret == 0 && GetASNTag(in, &idx, &tag, inSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && tag != ASN_OCTET_STRING) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0) - ret = ASN_PARSE_E; - } - else { - /* check if SKID with ASN_CONTEXT_SPECIFIC otherwise in version - * 3 try to get issuerAndSerial */ - localIdx = idx; - if (GetASNTag(in, &localIdx, &tag, inSz) == 0 && - tag == ASN_CONTEXT_SPECIFIC) { - idx++; - if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0) - ret = ASN_PARSE_E; - } - else { - if (pkcs7->version != 3) { - WOLFSSL_MSG("Unexpected signer info found with version"); - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) - ret = ASN_PARSE_E; - } - } - - if (ret == 0) { - ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length); - idx += length; - } - - } else { - WOLFSSL_MSG("PKCS#7 signerInfo version must be 1 or 3"); - ret = ASN_VERSION_E; - } - - /* Get the sequence of digestAlgorithm */ - if (ret == 0 && GetAlgoId(in, &idx, &hashOID, oidHashType, inSz) < 0) { - ret = ASN_PARSE_E; - } - pkcs7->hashOID = (int)hashOID; - - /* Get the IMPLICIT[0] SET OF signedAttributes */ - localIdx = idx; - if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 && - tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - idx++; - - if (GetLength(in, &idx, &length, inSz) < 0) - ret = ASN_PARSE_E; - - /* save pointer and length */ - *signedAttrib = &in[idx]; - *signedAttribSz = length; - - if (ret == 0 && wc_PKCS7_ParseAttribs(pkcs7, *signedAttrib, - *signedAttribSz) < 0) { - WOLFSSL_MSG("Error parsing signed attributes"); - ret = ASN_PARSE_E; - } - - idx += length; - } - - /* Get digestEncryptionAlgorithm */ - if (ret == 0 && GetAlgoId(in, &idx, &sigOID, oidSigType, inSz) < 0) { - ret = ASN_PARSE_E; - } - - /* store public key type based on digestEncryptionAlgorithm */ - if (ret == 0) { - ret = wc_PKCS7_SetPublicKeyOID(pkcs7, sigOID); - if (ret < 0) { - WOLFSSL_MSG("Failed to set public key OID from signature"); - } - else { - /* if previous return was positive then was success */ - ret = 0; - } - } - } - - /* update index on success */ - if (ret == 0) { - *idxIn = idx; - } - - return ret; -} - - -/* Finds the certificates in the message and saves it. By default allows - * degenerate cases which can have no signer. - * - * By default expects type SIGNED_DATA (SignedData) which can have any number of - * elements in signerInfos collection, including zero. (RFC2315 section 9.1) - * When adding support for the case of SignedAndEnvelopedData content types a - * signer is required. In this case the PKCS7 flag noDegenerate could be set. - */ -static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, - word32 hashSz, byte* in, word32 inSz, - byte* in2, word32 in2Sz) -{ - word32 idx, maxIdx = inSz, outerContentType, contentTypeSz = 0, totalSz = 0; - int length = 0, version = 0, ret = 0; - byte* content = NULL; - byte* contentDynamic = NULL; - byte* sig = NULL; - byte* cert = NULL; - byte* signedAttrib = NULL; - byte* contentType = NULL; - int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0; - word32 localIdx, start; - byte degenerate = 0; - byte detached = 0; - byte tag = 0; -#ifdef ASN_BER_TO_DER - byte* der; -#endif - int multiPart = 0, keepContent; - int contentLen = 0; - - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; -#ifndef NO_PKCS7_STREAM - word32 stateIdx = 0; - long rc; -#endif - - byte* pkiMsg2 = in2; - word32 pkiMsg2Sz = in2Sz; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - -#ifndef NO_PKCS7_STREAM - /* allow for 0 size inputs with stream mode */ - if (pkiMsg == NULL && pkiMsgSz > 0) - return BAD_FUNC_ARG; - -#else - if (pkiMsg == NULL || pkiMsgSz == 0) - return BAD_FUNC_ARG; -#endif - - if ((hashSz > 0 && hashBuf == NULL) || (pkiMsg2Sz > 0 && pkiMsg2 == NULL)) { - return BAD_FUNC_ARG; - } - idx = 0; - -#ifdef ASN_BER_TO_DER - if (pkcs7->derSz > 0 && pkcs7->der) { - pkiMsg = in = pkcs7->der; - } -#endif - -#ifndef NO_PKCS7_STREAM - if (pkcs7->stream == NULL) { - if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) { - return ret; - } - } -#endif - - switch (pkcs7->state) { - case WC_PKCS7_START: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ + - MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ + - ASN_TAG_SZ + MAX_OID_SZ + MAX_SEQ_SZ, - &pkiMsg, &idx)) != 0) { - break; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz; - #endif - - /* determine total message size */ - totalSz = pkiMsgSz; - if (pkiMsg2 && pkiMsg2Sz > 0) { - totalSz += pkiMsg2Sz + pkcs7->contentSz; - } - - /* Get the contentInfo sequence */ - if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, totalSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && 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 = in = pkcs7->der; - pkiMsgSz = pkcs7->derSz = len; - idx = 0; - if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz, - NO_USER_CHECK) < 0) - return ASN_PARSE_E; - - #ifndef NO_PKCS7_STREAM - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, - pkiMsg, pkiMsgSz); - if (rc < 0) { - ret = (int)rc; - break; - } - #endif - #else - ret = BER_INDEF_E; - #endif - } - - /* Get the contentInfo contentType */ - if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &outerContentType, - pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && outerContentType != SIGNED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type SignedData"); - ret = PKCS7_OID_E; - } - - /* get the ContentInfo content */ - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, totalSz) != 0) - ret = ASN_PARSE_E; - - if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength_ex(pkiMsg, &idx, &length, totalSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - /* Get the signedData sequence */ - if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, totalSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - /* Get the version */ - if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - - /* version 1 follows RFC 2315 */ - /* version 3 follows RFC 4108 */ - if (ret == 0 && (version != 1 && version != 3)) { - WOLFSSL_MSG("PKCS#7 signedData needs to be version 1 or 3"); - ret = ASN_VERSION_E; - } - pkcs7->version = version; - - /* Get the set of DigestAlgorithmIdentifiers */ - if (ret == 0 && GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - /* Skip the set. */ - idx += length; - degenerate = (length == 0)? 1 : 0; - if (pkcs7->noDegenerate == 1 && degenerate == 1) { - ret = PKCS7_NO_SIGNER_E; - } - - if (ret != 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) { - break; - } - if (pkiMsg2 && pkiMsg2Sz > 0) { - pkcs7->stream->maxLen += pkiMsg2Sz + pkcs7->contentSz; - } - wc_PKCS7_StreamStoreVar(pkcs7, totalSz, 0, 0); - #endif - - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE2); - FALL_THROUGH; - - case WC_PKCS7_VERIFY_STAGE2: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, - MAX_SEQ_SZ + MAX_OID_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ - + ASN_TAG_SZ + MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) { - break; - } - - wc_PKCS7_StreamGetVar(pkcs7, &totalSz, 0, 0); - if (pkcs7->stream->length > 0) - pkiMsgSz = pkcs7->stream->length; - #ifdef ASN_BER_TO_DER - else if (pkcs7->der) - pkiMsgSz = pkcs7->derSz; - #endif - else - pkiMsgSz = inSz; - - #endif - /* Get the inner ContentInfo sequence */ - if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - /* Get the inner ContentInfo contentType */ - if (ret == 0) { - word32 tmpIdx = idx; - - if (GetASNObjectId(pkiMsg, &idx, &length, pkiMsgSz) != 0) - ret = ASN_PARSE_E; - - contentType = pkiMsg + tmpIdx; - contentTypeSz = length + (idx - tmpIdx); - - idx += length; - } - - if (ret != 0) - break; - - /* Check for content info, it could be omitted when degenerate */ - localIdx = idx; - ret = 0; - if (localIdx + 1 > pkiMsgSz) { - ret = BUFFER_E; - break; - } - - if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0) - ret = ASN_PARSE_E; - - if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz, - NO_USER_CHECK) <= 0) - ret = ASN_PARSE_E; - - if (localIdx >= pkiMsgSz) { - ret = BUFFER_E; - } - - /* get length of content in the case that there is multiple parts */ - if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) { - multiPart = 1; - - /* Get length of all OCTET_STRINGs. */ - if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - /* Check whether there is one OCTET_STRING inside. */ - start = localIdx; - if (localIdx >= pkiMsgSz) { - ret = BUFFER_E; - } - - if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) - != 0) - ret = ASN_PARSE_E; - - if (ret == 0 && tag != ASN_OCTET_STRING) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - if (ret == 0) { - /* Use single OCTET_STRING directly. */ - if (localIdx - start + length == (word32)contentLen) - multiPart = 0; - localIdx = start; - } - } - - /* get length of content in case of single part */ - if (ret == 0 && !multiPart) { - if (tag != ASN_OCTET_STRING) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, - &length, pkiMsgSz, NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - } - - /* update idx if successful */ - if (ret == 0) { - /* support using header and footer without content */ - if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) { - localIdx = 0; - } - idx = localIdx; - } - else { - - /* if pkcs7->content and pkcs7->contentSz are set, try to - process as a detached signature */ - if (!degenerate && - (pkcs7->content != NULL && pkcs7->contentSz != 0)) { - detached = 1; - } - - if (!degenerate && !detached && ret != 0) - break; - - length = 0; /* no content to read */ - pkiMsg2 = pkiMsg; - pkiMsg2Sz = pkiMsgSz; - } - - #ifndef NO_PKCS7_STREAM - /* save detached flag value */ - pkcs7->stream->detached = detached; - - /* save contentType */ - pkcs7->stream->nonce = (byte*)XMALLOC(contentTypeSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream->nonce == NULL) { - ret = MEMORY_E; - break; - } - else { - pkcs7->stream->nonceSz = contentTypeSz; - XMEMCPY(pkcs7->stream->nonce, contentType, contentTypeSz); - } - - /* content expected? */ - if ((ret == 0 && length > 0) && - !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0)) { - pkcs7->stream->expected = length + ASN_TAG_SZ + MAX_LENGTH_SZ; - } - else { - pkcs7->stream->expected = ASN_TAG_SZ + MAX_LENGTH_SZ; - } - - if (pkcs7->stream->expected > (pkcs7->stream->maxLen - idx)) { - pkcs7->stream->expected = pkcs7->stream->maxLen - idx; - } - - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, localIdx, length); - - /* content length is in multiple parts */ - if (multiPart) { - pkcs7->stream->expected = contentLen + ASN_TAG_SZ; - } - pkcs7->stream->multi = multiPart; - - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE3); - FALL_THROUGH; - - case WC_PKCS7_VERIFY_STAGE3: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - break; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, - pkiMsg, pkiMsgSz); - if (rc < 0) { - ret = (int)rc; - break; - } - #ifdef ASN_BER_TO_DER - if (pkcs7->derSz != 0) - pkiMsgSz = pkcs7->derSz; - else - #endif - pkiMsgSz = (word32)rc; - wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, (int*)&localIdx, &length); - - if (pkcs7->stream->length > 0) { - localIdx = 0; - } - multiPart = pkcs7->stream->multi; - detached = pkcs7->stream->detached; - maxIdx = idx + pkcs7->stream->expected; - #endif - - /* Break out before content because it can be optional in degenerate - * cases. */ - if (ret != 0 && !degenerate) - break; - - /* get parts of content */ - if (ret == 0 && multiPart) { - int i = 0; - keepContent = !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0); - - if (keepContent) { - /* Create a buffer to hold content of OCTET_STRINGs. */ - pkcs7->contentDynamic = (byte*)XMALLOC(contentLen, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->contentDynamic == NULL) - ret = MEMORY_E; - } - - start = localIdx; - /* Use the data from each OCTET_STRING. */ - while (ret == 0 && localIdx < start + contentLen) { - if (GetASNTag(pkiMsg, &localIdx, &tag, totalSz) < 0) - ret = ASN_PARSE_E; - if (ret == 0 && tag != ASN_OCTET_STRING) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) - ret = ASN_PARSE_E; - if (ret == 0 && length + localIdx > start + contentLen) - ret = ASN_PARSE_E; - - if (ret == 0) { - if (keepContent) { - XMEMCPY(pkcs7->contentDynamic + i, pkiMsg + localIdx, - length); - } - i += length; - localIdx += length; - } - } - localIdx = start; /* reset for sanity check, increment later */ - length = i; - } - - /* Save the inner data as the content. */ - if (ret == 0 && length > 0) { - contentSz = length; - - /* support using header and footer without content */ - if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) { - /* Content not provided, use provided pkiMsg2 footer */ - content = NULL; - localIdx = 0; - if (contentSz != (int)pkcs7->contentSz) { - WOLFSSL_MSG("Data signed does not match contentSz provided"); - ret = BUFFER_E; - } - } - else { - if ((word32)length > pkiMsgSz - localIdx) { - ret = BUFFER_E; - } - - /* Content pointer for calculating hashes later */ - if (ret == 0 && !multiPart) { - content = &pkiMsg[localIdx]; - } - if (ret == 0 && multiPart) { - content = pkcs7->contentDynamic; - } - - if (ret == 0) { - idx += length; - - pkiMsg2 = pkiMsg; - pkiMsg2Sz = pkiMsgSz; - #ifndef NO_PKCS7_STREAM - pkcs7->stream->varOne = pkiMsg2Sz; - pkcs7->stream->flagOne = 1; - #endif - } - } - } - else { - pkiMsg2 = pkiMsg; - pkiMsg2Sz = pkiMsgSz; - #ifndef NO_PKCS7_STREAM - pkcs7->stream->varOne = pkiMsg2Sz; - pkcs7->stream->flagOne = 1; - #endif - } - - /* 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 && !detached && (ret != 0)) { - break; - } - else { - ret = 0; /* reset ret state on degenerate case */ - } - - #ifndef NO_PKCS7_STREAM - /* save content */ - if (detached == 1) { - /* if detached, use content from user in pkcs7 struct */ - content = pkcs7->content; - contentSz = pkcs7->contentSz; - } - - if (content != NULL) { - XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->stream->content = (byte*)XMALLOC(contentSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream->content == NULL) { - ret = MEMORY_E; - break; - } - else { - XMEMCPY(pkcs7->stream->content, content, contentSz); - pkcs7->stream->contentSz = contentSz; - } - } - #endif /* !NO_PKCS7_STREAM */ - - /* Get the implicit[0] set of certificates */ - if (ret == 0 && idx >= pkiMsg2Sz) - ret = BUFFER_E; - - length = 0; /* set length to 0 to check if reading in any certs */ - localIdx = idx; - if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz) == 0 - && tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - idx++; - if (GetLength_ex(pkiMsg2, &idx, &length, maxIdx, NO_USER_CHECK) - < 0) - ret = ASN_PARSE_E; - } - - if (ret != 0) { - break; - } - #ifndef NO_PKCS7_STREAM - if (in2 && in2Sz > 0 && hashBuf && hashSz > 0) { - stateIdx = idx; /* case where all data was read from in2 */ - } - - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length); - if (length > 0) { - pkcs7->stream->expected = length; - } - else { - pkcs7->stream->expected = MAX_SEQ_SZ; - if (pkcs7->stream->expected > (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length) { - pkcs7->stream->expected = (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length; - } - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE4); - FALL_THROUGH; - - case WC_PKCS7_VERIFY_STAGE4: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - break; - } - - wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length); - if (pkcs7->stream->flagOne) { - pkiMsg2 = pkiMsg; - } - - /* restore content */ - content = pkcs7->stream->content; - contentSz = pkcs7->stream->contentSz; - - /* restore detached flag */ - detached = pkcs7->stream->detached; - - /* store certificate if needed */ - if (length > 0 && in2Sz == 0) { - /* free tmpCert if not NULL */ - XFREE(pkcs7->stream->tmpCert, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->stream->tmpCert = (byte*)XMALLOC(length, - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if ((pkiMsg2 == NULL) || (pkcs7->stream->tmpCert == NULL)) { - ret = MEMORY_E; - break; - } - XMEMCPY(pkcs7->stream->tmpCert, pkiMsg2 + idx, length); - pkiMsg2 = pkcs7->stream->tmpCert; - pkiMsg2Sz = length; - idx = 0; - } - #endif - - 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 (length < MAX_LENGTH_SZ + ASN_TAG_SZ) - ret = BUFFER_E; - - if (ret == 0) - ret = GetASNTag(pkiMsg2, &certIdx, &tag, pkiMsg2Sz); - - if (ret == 0 && tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { - if (GetLength(pkiMsg2, &certIdx, &certSz, pkiMsg2Sz) < 0) - ret = ASN_PARSE_E; - - cert = &pkiMsg2[idx]; - certSz += (certIdx - idx); - if (certSz > length) { - ret = BUFFER_E; - break; - } - } - #ifdef ASN_BER_TO_DER - der = pkcs7->der; - #endif - contentDynamic = pkcs7->contentDynamic; - version = pkcs7->version; - - - if (ret == 0) { - #ifndef NO_PKCS7_STREAM - PKCS7State* stream = pkcs7->stream; - #endif - /* This will reset PKCS7 structure and then set the - * certificate */ - ret = wc_PKCS7_InitWithCert(pkcs7, cert, certSz); - #ifndef NO_PKCS7_STREAM - pkcs7->stream = stream; - #endif - } - pkcs7->contentDynamic = contentDynamic; - pkcs7->version = version; - #ifdef ASN_BER_TO_DER - pkcs7->der = der; - #endif - if (ret != 0) - break; - - /* iterate through any additional certificates */ - if (ret == 0 && MAX_PKCS7_CERTS > 0) { - 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 < pkiMsg2Sz && - certIdx + 1 < (word32)length; i++) { - localIdx = certIdx; - - if (ret == 0 && GetASNTag(pkiMsg2, &certIdx, &tag, - pkiMsg2Sz) < 0) { - ret = ASN_PARSE_E; - break; - } - - if (ret == 0 && - tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { - if (GetLength(pkiMsg2, &certIdx, &sz, - pkiMsg2Sz) < 0) { - ret = ASN_PARSE_E; - break; - } - - pkcs7->cert[i] = &pkiMsg2[localIdx]; - pkcs7->certSz[i] = sz + (certIdx - localIdx); - certIdx += sz; - } - } - } - } - idx += length; - - if (!detached) { - /* set content and size after init of PKCS7 structure */ - pkcs7->content = content; - pkcs7->contentSz = contentSz; - } - #ifndef NO_PKCS7_STREAM - else { - /* save content if detached and using streaming API */ - if (pkcs7->content != NULL) { - XFREE(pkcs7->stream->content, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - pkcs7->stream->content = (byte*)XMALLOC(pkcs7->contentSz, - pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream->content == NULL) { - ret = MEMORY_E; - break; - } - else { - XMEMCPY(pkcs7->stream->content, pkcs7->content, - contentSz); - pkcs7->stream->contentSz = pkcs7->contentSz; - } - } - } - #endif - - if (ret != 0) { - break; - } - #ifndef NO_PKCS7_STREAM - /* factor in that recent idx was in cert buffer. If in2 buffer was - * used then don't advance idx. */ - if (length > 0 && pkcs7->stream->flagOne && - pkcs7->stream->length == 0) { - idx = stateIdx + idx; - if (idx > inSz) { - /* index is more than input size */ - ret = BUFFER_E; - break; - } - } - else { - stateIdx = idx; /* didn't read any from internal buffer */ - } - - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) { - break; - } - if (pkcs7->stream->flagOne && pkcs7->stream->length > 0) { - idx = stateIdx + idx; - } - - pkcs7->stream->expected = MAX_OID_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ + - MAX_SET_SZ; - - if (pkcs7->stream->expected > (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length) - pkcs7->stream->expected = (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length; - - wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, 0); - wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE5); - FALL_THROUGH; - - case WC_PKCS7_VERIFY_STAGE5: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - break; - } - wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length); - if (pkcs7->stream->flagOne) { - pkiMsg2 = pkiMsg; - } - - /* restore content type */ - contentType = pkcs7->stream->nonce; - contentTypeSz = pkcs7->stream->nonceSz; - - maxIdx = idx + pkcs7->stream->expected; - if (maxIdx > pkiMsg2Sz) { - ret = BUFFER_E; - break; - } - stateIdx = idx; - #endif - - /* set contentType and size after init of PKCS7 structure */ - if (ret == 0 && wc_PKCS7_SetContentType(pkcs7, contentType, - contentTypeSz) < 0) - ret = ASN_PARSE_E; - - /* Get the implicit[1] set of crls */ - if (ret == 0 && idx >= maxIdx) - ret = BUFFER_E; - - localIdx = idx; - if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz) == 0 - && tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { - idx++; - if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) - ret = ASN_PARSE_E; - - /* Skip the set */ - idx += length; - } - - /* Get the set of signerInfos */ - if (ret == 0 && GetSet_ex(pkiMsg2, &idx, &length, maxIdx, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - - if (ret != 0) - break; - #ifndef NO_PKCS7_STREAM - if (!pkcs7->stream->flagOne) { - stateIdx = idx; /* didn't read any from internal buffer */ - } - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length); - - if (in2 && in2Sz > 0 && hashBuf && hashSz > 0) { - if (length > 0) { - pkcs7->stream->expected = length; - } - else { - pkcs7->stream->expected = 0; - } - } - else { - /* last state expect the reset of the buffer */ - pkcs7->stream->expected = (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length; - } - - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE6); - FALL_THROUGH; - - case WC_PKCS7_VERIFY_STAGE6: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - break; - } - - wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length); - if (pkcs7->stream->flagOne) { - pkiMsg2 = pkiMsg; - } - - /* restore content */ - content = pkcs7->stream->content; - contentSz = pkcs7->stream->contentSz; - #endif - - ret = wc_PKCS7_ParseSignerInfo(pkcs7, pkiMsg2, pkiMsg2Sz, &idx, - degenerate, &signedAttrib, &signedAttribSz); - - /* parse out the signature if present and verify it */ - if (ret == 0 && length > 0 && degenerate == 0) { - WOLFSSL_MSG("Parsing signature and verifying"); - if (idx >= pkiMsg2Sz) - ret = BUFFER_E; - - /* Get the signature */ - localIdx = idx; - if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, - pkiMsg2Sz) == 0 && tag == ASN_OCTET_STRING) { - idx++; - - if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) - ret = ASN_PARSE_E; - - /* save pointer and length */ - sig = &pkiMsg2[idx]; - sigSz = length; - - idx += length; - } - - pkcs7->content = content; - pkcs7->contentSz = contentSz; - - if (ret == 0) { - ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz, - signedAttrib, signedAttribSz, - hashBuf, hashSz); - } - } - - if (ret < 0) - break; - - ret = 0; /* success */ - #ifndef NO_PKCS7_STREAM - wc_PKCS7_ResetStream(pkcs7); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - break; - - default: - WOLFSSL_MSG("PKCS7 Unknown verify state"); - ret = BAD_FUNC_ARG; - } - - if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) { - #ifndef NO_PKCS7_STREAM - wc_PKCS7_ResetStream(pkcs7); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - } - return ret; -} - - -/* Gets a copy of the SID parsed from signerInfo. This can be called after - * wc_PKCS7_VerifySignedData has been called. SID can be SKID in version 3 case - * or issuerAndSerialNumber. - * - * return 0 on success and LENGTH_ONLY_E if just setting "outSz" for buffer - * length needed. - */ -int wc_PKCS7_GetSignerSID(PKCS7* pkcs7, byte* out, word32* outSz) -{ - if (outSz == NULL || pkcs7 == NULL) { - return BAD_FUNC_ARG; - } - - if (pkcs7->signerInfo == NULL) { - WOLFSSL_MSG("Either the bundle had no signers or" - "wc_PKCS7_VerifySignedData needs called yet"); - return PKCS7_NO_SIGNER_E; - } - - if (pkcs7->signerInfo->sidSz == 0) { - WOLFSSL_MSG("Bundle had no signer SID set"); - return PKCS7_NO_SIGNER_E; - } - - if (out == NULL) { - *outSz = pkcs7->signerInfo->sidSz; - return LENGTH_ONLY_E; - } - - if (*outSz < pkcs7->signerInfo->sidSz) { - WOLFSSL_MSG("Buffer being passed in is not large enough for SKID"); - return BUFFER_E; - } - XMEMCPY(out, pkcs7->signerInfo->sid, pkcs7->signerInfo->sidSz); - *outSz = pkcs7->signerInfo->sidSz; - return 0; -} - - -/* variant that allows computed data hash and header/foot, - * which is useful for large data signing */ -int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf, - word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot, - word32 pkiMsgFootSz) -{ - return PKCS7_VerifySignedData(pkcs7, hashBuf, hashSz, - pkiMsgHead, pkiMsgHeadSz, pkiMsgFoot, pkiMsgFootSz); -} - -int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) -{ - return PKCS7_VerifySignedData(pkcs7, NULL, 0, pkiMsg, pkiMsgSz, NULL, 0); -} - - -/* Generate random content encryption key, store into pkcs7->cek and - * pkcs7->cekSz. - * - * pkcs7 - pointer to initialized PKCS7 structure - * len - length of key to be generated - * - * Returns 0 on success, negative upon error */ -static int PKCS7_GenerateContentEncryptionKey(PKCS7* pkcs7, word32 len) -{ - int ret; - WC_RNG rng; - byte* tmpKey; - - if (pkcs7 == NULL || len == 0) - return BAD_FUNC_ARG; - - /* if key already exists, don't need to re-generate */ - if (pkcs7->cek != NULL && pkcs7->cekSz != 0) { - - /* if key exists, but is different size, return error */ - if (pkcs7->cekSz != len) { - WOLFSSL_MSG("Random content-encryption key size is inconsistent " - "between CMS recipients"); - return WC_KEY_SIZE_E; - } - - return 0; - } - - /* allocate space for cek */ - tmpKey = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (tmpKey == NULL) - return MEMORY_E; - - XMEMSET(tmpKey, 0, len); - - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret != 0) { - XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - ret = wc_RNG_GenerateBlock(&rng, tmpKey, len); - if (ret != 0) { - wc_FreeRng(&rng); - XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* store into PKCS7, memory freed during final cleanup */ - pkcs7->cek = tmpKey; - pkcs7->cekSz = len; - - wc_FreeRng(&rng); - - return 0; -} - - -/* wrap CEK (content encryption key) with KEK, 0 on success, < 0 on error */ -static int wc_PKCS7_KeyWrap(byte* cek, word32 cekSz, byte* kek, - word32 kekSz, byte* out, word32 outSz, - int keyWrapAlgo, int direction) -{ - int ret = 0; - - 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; -} - - -#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; - - -/* 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; - - /* only supports ECDSA for now */ - if (kari->decoded->keyOID != ECDSAk) { - WOLFSSL_MSG("CMS KARI only supports ECDSA key types"); - return BAD_FUNC_ARG; - } - - /* 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) -{ - int ret; - WC_RNG rng; - - if (kari == NULL || kari->decoded == NULL || - kari->recipKey == NULL || kari->recipKey->dp == 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) { - XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - kari->senderKeyInit = 1; - - ret = wc_InitRng_ex(&rng, kari->heap, kari->devId); - if (ret != 0) { - XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - ret = wc_ecc_make_key_ex(&rng, kari->recipKey->dp->size, - kari->senderKey, kari->recipKey->dp->id); - if (ret != 0) { - XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7); - wc_FreeRng(&rng); - return ret; - } - - wc_FreeRng(&rng); - - /* 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) { - XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7); - 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; -} - - -/* Encode and add CMS EnvelopedData KARI (KeyAgreeRecipientInfo) RecipientInfo - * to CMS/PKCS#7 EnvelopedData structure. - * - * Returns 0 on success, negative upon error */ -int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, - int keyWrapOID, int keyAgreeOID, byte* ukm, - word32 ukmSz, int options) -{ - Pkcs7EncodedRecip* recip; - Pkcs7EncodedRecip* lastRecip = NULL; - WC_PKCS7_KARI* kari = NULL; - - word32 idx = 0; - word32 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - - int ret = 0; - int keySz, direction = 0; - int blockKeySz = 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]; - -#ifdef WOLFSSL_SMALL_STACK - byte* encryptedKey; - - encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (encryptedKey == NULL) { - return MEMORY_E; - } -#else - byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; -#endif - - /* allocate and init memory for recipient */ - recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (recip == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return MEMORY_E; - } - XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip)); - - /* get key size for content-encryption key based on algorithm */ - blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); - if (blockKeySz < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return blockKeySz; - } - - /* generate random content encryption key, if needed */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* set direction based on keyWrapAlgo */ - 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_ENCRYPTION; - break; -#endif - default: - WOLFSSL_MSG("Unsupported key wrap algorithm"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BAD_KEYWRAP_ALG_E; - } - - kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_ENCODE); - if (kari == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - /* set user keying material if available */ - if (ukmSz > 0 && ukm != NULL) { - kari->ukm = ukm; - kari->ukmSz = 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); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* generate sender ephemeral ECC key */ - ret = wc_PKCS7_KariGenerateEphemeralKey(kari); - if (ret != 0) { - wc_PKCS7_KariFree(kari); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* generate KEK (key encryption key) */ - ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, keyAgreeOID); - if (ret != 0) { - wc_PKCS7_KariFree(kari); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* encrypt CEK with KEK */ - keySz = wc_PKCS7_KeyWrap(pkcs7->cek, pkcs7->cekSz, kari->kek, - kari->kekSz, encryptedKey, encryptedKeySz, - keyWrapOID, direction); - if (keySz <= 0) { - wc_PKCS7_KariFree(kari); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return keySz; - } - encryptedKeySz = (word32)keySz; - - /* Start of RecipientEncryptedKeys */ - - /* EncryptedKey */ - encryptedKeyOctetSz = SetOctetString(encryptedKeySz, encryptedKeyOctet); - totalSz += (encryptedKeyOctetSz + encryptedKeySz); - - /* 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(keyWrapOID, keyWrapAlg, oidKeyWrapType, 0); - totalSz += keyWrapAlgSz; - - /* KeyEncryptionAlgorithmIdentifier */ - keyEncryptAlgoIdSz = SetAlgoID(keyAgreeOID, 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, params set to NULL for interop - compatibility */ - origAlgIdSz = SetAlgoID(ECDSAk, origAlgId, oidKeyType, 2); - origAlgId[origAlgIdSz++] = ASN_TAG_NULL; - origAlgId[origAlgIdSz++] = 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; - recip->recipVersion = 3; - - /* outer IMPLICIT [1] kari */ - kariSeqSz = SetImplicit(ASN_SEQUENCE, 1, totalSz, kariSeq); - totalSz += kariSeqSz; - - if (totalSz > MAX_RECIP_SZ) { - WOLFSSL_MSG("KeyAgreeRecipientInfo output buffer too small"); - wc_PKCS7_KariFree(kari); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - XMEMCPY(recip->recip + idx, kariSeq, kariSeqSz); - idx += kariSeqSz; - XMEMCPY(recip->recip + idx, ver, verSz); - idx += verSz; - - XMEMCPY(recip->recip + idx, origIdOrKeySeq, origIdOrKeySeqSz); - idx += origIdOrKeySeqSz; - XMEMCPY(recip->recip + idx, origPubKeySeq, origPubKeySeqSz); - idx += origPubKeySeqSz; - - /* AlgorithmIdentifier with NULL parameter */ - XMEMCPY(recip->recip + idx, origAlgId, origAlgIdSz); - idx += origAlgIdSz; - - XMEMCPY(recip->recip + idx, origPubKeyStr, origPubKeyStrSz); - idx += origPubKeyStrSz; - /* ephemeral public key */ - XMEMCPY(recip->recip + idx, kari->senderKeyExport, kari->senderKeyExportSz); - idx += kari->senderKeyExportSz; - - if (kari->ukmSz > 0) { - XMEMCPY(recip->recip + idx, ukmExplicitSeq, ukmExplicitSz); - idx += ukmExplicitSz; - XMEMCPY(recip->recip + idx, ukmOctetStr, ukmOctetSz); - idx += ukmOctetSz; - XMEMCPY(recip->recip + idx, kari->ukm, kari->ukmSz); - idx += kari->ukmSz; - } - - XMEMCPY(recip->recip + idx, keyEncryptAlgoId, keyEncryptAlgoIdSz); - idx += keyEncryptAlgoIdSz; - XMEMCPY(recip->recip + idx, keyWrapAlg, keyWrapAlgSz); - idx += keyWrapAlgSz; - - XMEMCPY(recip->recip + idx, recipEncKeysSeq, recipEncKeysSeqSz); - idx += recipEncKeysSeqSz; - XMEMCPY(recip->recip + idx, recipEncKeySeq, recipEncKeySeqSz); - idx += recipEncKeySeqSz; - XMEMCPY(recip->recip + idx, recipKeyIdSeq, recipKeyIdSeqSz); - idx += recipKeyIdSeqSz; - XMEMCPY(recip->recip + idx, subjKeyIdOctet, subjKeyIdOctetSz); - idx += subjKeyIdOctetSz; - /* subject key id */ - XMEMCPY(recip->recip + idx, kari->decoded->extSubjKeyId, KEYID_SIZE); - idx += KEYID_SIZE; - XMEMCPY(recip->recip + idx, encryptedKeyOctet, encryptedKeyOctetSz); - idx += encryptedKeyOctetSz; - /* encrypted CEK */ - XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz); - idx += encryptedKeySz; - - wc_PKCS7_KariFree(kari); -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - /* store recipient size */ - recip->recipSz = idx; - recip->recipType = PKCS7_KARI; - - /* add recipient to recip list */ - if (pkcs7->recipList == NULL) { - pkcs7->recipList = recip; - } else { - lastRecip = pkcs7->recipList; - while (lastRecip->next != NULL) { - lastRecip = lastRecip->next; - } - lastRecip->next = recip; - } - - (void)options; - - return idx; -} - -#endif /* HAVE_ECC */ - -#ifndef NO_RSA - -/* Encode and add CMS EnvelopedData KTRI (KeyTransRecipientInfo) RecipientInfo - * to CMS/PKCS#7 EnvelopedData structure. - * - * Returns 0 on success, negative upon error */ -int wc_PKCS7_AddRecipient_KTRI(PKCS7* pkcs7, const byte* cert, word32 certSz, - int options) -{ - Pkcs7EncodedRecip* recip = NULL; - Pkcs7EncodedRecip* lastRecip = NULL; - - WC_RNG rng; - word32 idx = 0; - word32 encryptedKeySz = 0; - - int ret = 0, blockKeySz; - int verSz = 0, issuerSz = 0, snSz = 0, keyEncAlgSz = 0; - int issuerSeqSz = 0, recipSeqSz = 0, issuerSerialSeqSz = 0; - int encKeyOctetStrSz; - int sidType; - - 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]; - - byte issuerSKIDSeq[MAX_SEQ_SZ]; - byte issuerSKID[MAX_OCTET_STR_SZ]; - word32 issuerSKIDSeqSz = 0, issuerSKIDSz = 0; - -#ifdef WOLFSSL_SMALL_STACK - byte* serial; - byte* keyAlgArray; - byte* encryptedKey; - RsaKey* pubKey; - DecodedCert* decoded; - - serial = (byte*)XMALLOC(MAX_SN_SZ, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - keyAlgArray = (byte*)XMALLOC(MAX_SN_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (decoded == NULL || serial == NULL || - encryptedKey == NULL || keyAlgArray == NULL) { - if (serial) - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (keyAlgArray) - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (encryptedKey) - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (decoded) - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return MEMORY_E; - } -#else - byte serial[MAX_SN_SZ]; - byte keyAlgArray[MAX_ALGO_SZ]; - byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; - - RsaKey pubKey[1]; - DecodedCert decoded[1]; -#endif - - encryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - XMEMSET(encryptedKey, 0, encryptedKeySz); - - /* default to IssuerAndSerialNumber if not set */ - if (pkcs7->sidType != 0) { - sidType = pkcs7->sidType; - } else { - sidType = CMS_ISSUER_AND_SERIAL_NUMBER; - } - - /* allow options to override SubjectIdentifier type if set */ - if (options & CMS_SKID) { - sidType = CMS_SKID; - } else if (options & CMS_ISSUER_AND_SERIAL_NUMBER) { - sidType = CMS_ISSUER_AND_SERIAL_NUMBER; - } - - /* allocate recipient struct */ - recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (recip == NULL) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - return MEMORY_E; - } - XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip)); - - /* get key size for content-encryption key based on algorithm */ - blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); - if (blockKeySz < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return blockKeySz; - } - - /* generate random content encryption key, if needed */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz); - if (ret < 0) { -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - InitDecodedCert(decoded, (byte*)cert, certSz, pkcs7->heap); - ret = ParseCert(decoded, CA_TYPE, NO_VERIFY, 0); - if (ret < 0) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - - /* version, must be 0 for IssuerAndSerialNumber */ - verSz = SetMyVersion(0, ver, 0); - recip->recipVersion = 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, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - 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, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return -1; - } - snSz = SetSerialNumber(decoded->serial, decoded->serialSz, serial, - MAX_SN_SZ, MAX_SN_SZ); - - issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz, - issuerSerialSeq); - - } else if (sidType == CMS_SKID) { - - /* version, must be 2 for SubjectKeyIdentifier */ - verSz = SetMyVersion(2, ver, 0); - recip->recipVersion = 2; - - issuerSKIDSz = SetOctetString(KEYID_SIZE, issuerSKID); - issuerSKIDSeqSz = SetExplicit(0, issuerSKIDSz + KEYID_SIZE, - issuerSKIDSeq); - } else { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return PKCS7_RECIP_E; - } - - pkcs7->publicKeyOID = decoded->keyOID; - - /* KeyEncryptionAlgorithmIdentifier, only support RSA now */ - if (pkcs7->publicKeyOID != RSAk) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ALGO_ID_E; - } - - keyEncAlgSz = SetAlgoID(pkcs7->publicKeyOID, keyAlgArray, oidKeyType, 0); - if (keyEncAlgSz == 0) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (pubKey == NULL) { - FreeDecodedCert(decoded); - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } -#endif - - /* EncryptedKey */ - ret = wc_InitRsaKey_ex(pubKey, pkcs7->heap, INVALID_DEVID); - if (ret != 0) { - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - 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, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return PUBLIC_KEY_E; - } - - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret != 0) { - wc_FreeRsaKey(pubKey); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - - ret = wc_RsaPublicEncrypt(pkcs7->cek, pkcs7->cekSz, encryptedKey, - encryptedKeySz, pubKey, &rng); - wc_FreeRsaKey(pubKey); - wc_FreeRng(&rng); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - if (ret < 0) { - WOLFSSL_MSG("RSA Public Encrypt failed"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - encryptedKeySz = ret; - - encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr); - - /* RecipientInfo */ - if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz + - issuerSz + snSz + keyEncAlgSz + - encKeyOctetStrSz + encryptedKeySz, recipSeq); - - if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz + - keyEncAlgSz + encKeyOctetStrSz + encryptedKeySz > MAX_RECIP_SZ) { - WOLFSSL_MSG("RecipientInfo output buffer too small"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - } else { - recipSeqSz = SetSequence(verSz + issuerSKIDSeqSz + issuerSKIDSz + - KEYID_SIZE + keyEncAlgSz + encKeyOctetStrSz + - encryptedKeySz, recipSeq); - - if (recipSeqSz + verSz + issuerSKIDSeqSz + issuerSKIDSz + KEYID_SIZE + - keyEncAlgSz + encKeyOctetStrSz + encryptedKeySz > MAX_RECIP_SZ) { - WOLFSSL_MSG("RecipientInfo output buffer too small"); - FreeDecodedCert(decoded); -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - } - - idx = 0; - XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz); - idx += recipSeqSz; - XMEMCPY(recip->recip + idx, ver, verSz); - idx += verSz; - if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - XMEMCPY(recip->recip + idx, issuerSerialSeq, issuerSerialSeqSz); - idx += issuerSerialSeqSz; - XMEMCPY(recip->recip + idx, issuerSeq, issuerSeqSz); - idx += issuerSeqSz; - XMEMCPY(recip->recip + idx, decoded->issuerRaw, issuerSz); - idx += issuerSz; - XMEMCPY(recip->recip + idx, serial, snSz); - idx += snSz; - } else { - XMEMCPY(recip->recip + idx, issuerSKIDSeq, issuerSKIDSeqSz); - idx += issuerSKIDSeqSz; - XMEMCPY(recip->recip + idx, issuerSKID, issuerSKIDSz); - idx += issuerSKIDSz; - XMEMCPY(recip->recip + idx, pkcs7->issuerSubjKeyId, KEYID_SIZE); - idx += KEYID_SIZE; - } - XMEMCPY(recip->recip + idx, keyAlgArray, keyEncAlgSz); - idx += keyEncAlgSz; - XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz); - idx += encKeyOctetStrSz; - XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz); - idx += encryptedKeySz; - - FreeDecodedCert(decoded); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif - - /* store recipient size */ - recip->recipSz = idx; - recip->recipType = PKCS7_KTRI; - - /* add recipient to recip list */ - if (pkcs7->recipList == NULL) { - pkcs7->recipList = recip; - } else { - lastRecip = pkcs7->recipList; - while (lastRecip->next != NULL) { - lastRecip = lastRecip->next; - } - lastRecip->next = recip; - } - - return idx; -} - -#endif /* !NO_RSA */ - - -/* encrypt content using encryptOID algo */ -static int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz, - byte* iv, int ivSz, byte* aad, word32 aadSz, - byte* authTag, word32 authTagSz, 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_AesInit(&aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION); - if (ret == 0) - ret = wc_AesCbcEncrypt(&aes, out, in, inSz); - wc_AesFree(&aes); - } - break; - #ifdef HAVE_AESGCM - #ifdef WOLFSSL_AES_128 - case AES128GCMb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192GCMb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256GCMb: - #endif - #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \ - defined(WOLFSSL_AES_256) - if (authTag == NULL) - return BAD_FUNC_ARG; - - ret = wc_AesInit(&aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesGcmSetKey(&aes, key, keySz); - if (ret == 0) - ret = wc_AesGcmEncrypt(&aes, out, in, inSz, iv, ivSz, - authTag, authTagSz, aad, aadSz); - wc_AesFree(&aes); - } - break; - #endif - #endif /* HAVE_AESGCM */ - #ifdef HAVE_AESCCM - #ifdef WOLFSSL_AES_128 - case AES128CCMb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192CCMb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256CCMb: - #endif - #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \ - defined(WOLFSSL_AES_256) - if (authTag == NULL) - return BAD_FUNC_ARG; - - ret = wc_AesInit(&aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesCcmSetKey(&aes, key, keySz); - if (ret == 0) - ret = wc_AesCcmEncrypt(&aes, out, in, inSz, iv, ivSz, - authTag, authTagSz, aad, aadSz); - wc_AesFree(&aes); - } - break; - #endif - #endif /* HAVE_AESCCM */ -#endif /* NO_AES */ -#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_Des3Init(&des3, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_Des3_SetKey(&des3, key, iv, DES_ENCRYPTION); - if (ret == 0) - ret = wc_Des3_CbcEncrypt(&des3, out, in, inSz); - wc_Des3Free(&des3); - } - break; -#endif - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - -#if defined(NO_AES) || (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM)) - (void)authTag; - (void)authTagSz; - (void)aad; - (void)aadSz; -#endif - return ret; -} - - -/* decrypt content using encryptOID algo - * returns 0 on success */ -static int wc_PKCS7_DecryptContent(PKCS7* pkcs7, int encryptOID, byte* key, - int keySz, byte* iv, int ivSz, byte* aad, word32 aadSz, byte* authTag, - word32 authTagSz, byte* in, int inSz, byte* out) -{ - int ret; -#ifndef NO_AES - Aes aes; -#endif -#ifndef NO_DES3 - Des des; - Des3 des3; -#endif - - if (iv == NULL || in == NULL || out == NULL) - return BAD_FUNC_ARG; - - if (pkcs7->decryptionCb != NULL) { - return pkcs7->decryptionCb(pkcs7, encryptOID, iv, ivSz, - aad, aadSz, authTag, authTagSz, in, - inSz, out, pkcs7->decryptionCtx); - } - - if (key == 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_AesInit(&aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesSetKey(&aes, key, keySz, iv, AES_DECRYPTION); - if (ret == 0) - ret = wc_AesCbcDecrypt(&aes, out, in, inSz); - wc_AesFree(&aes); - } - break; - #ifdef HAVE_AESGCM - #ifdef WOLFSSL_AES_128 - case AES128GCMb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192GCMb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256GCMb: - #endif - #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \ - defined(WOLFSSL_AES_256) - if (authTag == NULL) - return BAD_FUNC_ARG; - - ret = wc_AesInit(&aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesGcmSetKey(&aes, key, keySz); - if (ret == 0) - ret = wc_AesGcmDecrypt(&aes, out, in, inSz, iv, ivSz, - authTag, authTagSz, aad, aadSz); - wc_AesFree(&aes); - } - break; - #endif - #endif /* HAVE_AESGCM */ - #ifdef HAVE_AESCCM - #ifdef WOLFSSL_AES_128 - case AES128CCMb: - #endif - #ifdef WOLFSSL_AES_192 - case AES192CCMb: - #endif - #ifdef WOLFSSL_AES_256 - case AES256CCMb: - #endif - #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \ - defined(WOLFSSL_AES_256) - if (authTag == NULL) - return BAD_FUNC_ARG; - - ret = wc_AesInit(&aes, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_AesCcmSetKey(&aes, key, keySz); - if (ret == 0) - ret = wc_AesCcmDecrypt(&aes, out, in, inSz, iv, ivSz, - authTag, authTagSz, aad, aadSz); - wc_AesFree(&aes); - } - break; - #endif - #endif /* HAVE_AESCCM */ -#endif /* NO_AES */ -#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_Des3Init(&des3, NULL, INVALID_DEVID); - if (ret == 0) { - ret = wc_Des3_SetKey(&des3, key, iv, DES_DECRYPTION); - if (ret == 0) - ret = wc_Des3_CbcDecrypt(&des3, out, in, inSz); - wc_Des3Free(&des3); - } - - break; -#endif - default: - WOLFSSL_MSG("Unsupported content cipher type"); - return ALGO_ID_E; - }; - -#if defined(NO_AES) || (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM)) - (void)authTag; - (void)authTagSz; - (void)aad; - (void)aadSz; -#endif - - return ret; -} - - -/* Generate random block, place in out, return 0 on success negative on error. - * Used for generation of IV, nonce, etc */ -static int wc_PKCS7_GenerateBlock(PKCS7* pkcs7, WC_RNG* rng, byte* out, - word32 outSz) -{ - int ret; - WC_RNG* rnd = NULL; - - if (out == NULL || outSz == 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, out, outSz); - - if (rng == NULL) { - wc_FreeRng(rnd); - XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG); - } - - return ret; -} - - -/* Set default SignerIdentifier type to be used. Is either - * IssuerAndSerialNumber or SubjectKeyIdentifier. Encoding defaults to using - * IssuerAndSerialNumber unless set with this function or explicitly - * overridden via options when adding RecipientInfo type. - * - * Using the type DEGENERATE_SID skips over signer information. In degenerate - * cases there are no signers. - * - * pkcs7 - pointer to initialized PKCS7 structure - * type - either CMS_ISSUER_AND_SERIAL_NUMBER, CMS_SKID or DEGENERATE_SID - * - * return 0 on success, negative upon error */ -int wc_PKCS7_SetSignerIdentifierType(PKCS7* pkcs7, int type) -{ - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - if (type != CMS_ISSUER_AND_SERIAL_NUMBER && - type != CMS_SKID && - type != DEGENERATE_SID) { - return BAD_FUNC_ARG; - } - - pkcs7->sidType = type; - - return 0; -} - - -/* Set custom contentType, currently supported with SignedData type - * - * pkcs7 - pointer to initialized PKCS7 structure - * contentType - pointer to array with ASN.1 encoded OID value - * sz - length of contentType array, octets - * - * return 0 on success, negative upon error */ -int wc_PKCS7_SetContentType(PKCS7* pkcs7, byte* contentType, word32 sz) -{ - if (pkcs7 == NULL || contentType == NULL || sz == 0) - return BAD_FUNC_ARG; - - if (sz > MAX_OID_SZ) { - WOLFSSL_MSG("input array too large, bounded by MAX_OID_SZ"); - return BAD_FUNC_ARG; - } - - XMEMCPY(pkcs7->contentType, contentType, sz); - pkcs7->contentTypeSz = sz; - - return 0; -} - - -/* 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; -} - - -/* Encode and add CMS EnvelopedData ORI (OtherRecipientInfo) RecipientInfo - * to CMS/PKCS#7 EnvelopedData structure. - * - * Return 0 on success, negative upon error */ -int wc_PKCS7_AddRecipient_ORI(PKCS7* pkcs7, CallbackOriEncrypt oriEncryptCb, - int options) -{ - int oriTypeLenSz, blockKeySz, ret; - word32 idx, recipSeqSz; - - Pkcs7EncodedRecip* recip = NULL; - Pkcs7EncodedRecip* lastRecip = NULL; - - byte recipSeq[MAX_SEQ_SZ]; - byte oriTypeLen[MAX_LENGTH_SZ]; - - byte oriType[MAX_ORI_TYPE_SZ]; - byte oriValue[MAX_ORI_VALUE_SZ]; - word32 oriTypeSz = MAX_ORI_TYPE_SZ; - word32 oriValueSz = MAX_ORI_VALUE_SZ; - - if (pkcs7 == NULL || oriEncryptCb == NULL) { - return BAD_FUNC_ARG; - } - - /* allocate memory for RecipientInfo, KEK, encrypted key */ - recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (recip == NULL) - return MEMORY_E; - XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip)); - - /* get key size for content-encryption key based on algorithm */ - blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); - if (blockKeySz < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return blockKeySz; - } - - /* generate random content encryption key, if needed */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz); - if (ret < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* call user callback to encrypt CEK and get oriType and oriValue - values back */ - ret = oriEncryptCb(pkcs7, pkcs7->cek, pkcs7->cekSz, oriType, &oriTypeSz, - oriValue, &oriValueSz, pkcs7->oriEncryptCtx); - if (ret != 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - oriTypeLenSz = SetLength(oriTypeSz, oriTypeLen); - - recipSeqSz = SetImplicit(ASN_SEQUENCE, 4, 1 + oriTypeLenSz + oriTypeSz + - oriValueSz, recipSeq); - - idx = 0; - XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz); - idx += recipSeqSz; - /* oriType */ - recip->recip[idx] = ASN_OBJECT_ID; - idx += 1; - XMEMCPY(recip->recip + idx, oriTypeLen, oriTypeLenSz); - idx += oriTypeLenSz; - XMEMCPY(recip->recip + idx, oriType, oriTypeSz); - idx += oriTypeSz; - /* oriValue, input MUST already be ASN.1 encoded */ - XMEMCPY(recip->recip + idx, oriValue, oriValueSz); - idx += oriValueSz; - - /* store recipient size */ - recip->recipSz = idx; - recip->recipType = PKCS7_ORI; - recip->recipVersion = 4; - - /* add recipient to recip list */ - if (pkcs7->recipList == NULL) { - pkcs7->recipList = recip; - } else { - lastRecip = pkcs7->recipList; - while (lastRecip->next != NULL) { - lastRecip = lastRecip->next; - } - lastRecip->next = recip; - } - - (void)options; - - return idx; -} - -#if !defined(NO_PWDBASED) && !defined(NO_SHA) - - -static int wc_PKCS7_GenerateKEK_PWRI(PKCS7* pkcs7, byte* passwd, word32 pLen, - byte* salt, word32 saltSz, int kdfOID, - int prfOID, int iterations, byte* out, - word32 outSz) -{ - int ret; - - if (pkcs7 == NULL || passwd == NULL || salt == NULL || out == NULL) - return BAD_FUNC_ARG; - - switch (kdfOID) { - - case PBKDF2_OID: - - ret = wc_PBKDF2(out, passwd, pLen, salt, saltSz, iterations, - outSz, prfOID); - if (ret != 0) { - return ret; - } - - break; - - default: - WOLFSSL_MSG("Unsupported KDF OID"); - return PKCS7_OID_E; - } - - return 0; -} - - -/* RFC3211 (Section 2.3.1) key wrap algorithm (id-alg-PWRI-KEK). - * - * Returns output size on success, negative upon error */ -static int wc_PKCS7_PwriKek_KeyWrap(PKCS7* pkcs7, const byte* kek, word32 kekSz, - const byte* cek, word32 cekSz, - byte* out, word32 *outSz, - const byte* iv, word32 ivSz, int algID) -{ - WC_RNG rng; - int blockSz, outLen, ret; - word32 padSz; - byte* lastBlock; - - if (kek == NULL || cek == NULL || iv == NULL || outSz == NULL) - return BAD_FUNC_ARG; - - /* get encryption algorithm block size */ - blockSz = wc_PKCS7_GetOIDBlockSize(algID); - if (blockSz < 0) - return blockSz; - - /* get pad bytes needed to block boundary */ - padSz = blockSz - ((4 + cekSz) % blockSz); - outLen = 4 + cekSz + padSz; - - /* must be at least two blocks long */ - if (outLen < 2 * blockSz) - padSz += blockSz; - - /* if user set out to NULL, give back required length */ - if (out == NULL) { - *outSz = outLen; - return LENGTH_ONLY_E; - } - - /* verify output buffer is large enough */ - if (*outSz < (word32)outLen) - return BUFFER_E; - - out[0] = cekSz; - out[1] = ~cek[0]; - out[2] = ~cek[1]; - out[3] = ~cek[2]; - XMEMCPY(out + 4, cek, cekSz); - - /* random padding of size padSz */ - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret != 0) - return ret; - - ret = wc_RNG_GenerateBlock(&rng, out + 4 + cekSz, padSz); - - if (ret == 0) { - /* encrypt, normal */ - ret = wc_PKCS7_EncryptContent(algID, (byte*)kek, kekSz, (byte*)iv, - ivSz, NULL, 0, NULL, 0, out, outLen, out); - } - - if (ret == 0) { - /* encrypt again, using last ciphertext block as IV */ - lastBlock = out + (((outLen / blockSz) - 1) * blockSz); - ret = wc_PKCS7_EncryptContent(algID, (byte*)kek, kekSz, lastBlock, - blockSz, NULL, 0, NULL, 0, out, - outLen, out); - } - - if (ret == 0) { - *outSz = outLen; - } else { - outLen = ret; - } - - wc_FreeRng(&rng); - - return outLen; -} - - -/* RFC3211 (Section 2.3.2) key unwrap algorithm (id-alg-PWRI-KEK). - * - * Returns cek size on success, negative upon error */ -static int wc_PKCS7_PwriKek_KeyUnWrap(PKCS7* pkcs7, const byte* kek, - word32 kekSz, const byte* in, word32 inSz, - byte* out, word32 outSz, const byte* iv, - word32 ivSz, int algID) -{ - int blockSz, cekLen, ret; - byte* tmpIv = NULL; - byte* lastBlock = NULL; - byte* outTmp = NULL; - - if (pkcs7 == NULL || kek == NULL || in == NULL || - out == NULL || iv == NULL) { - return BAD_FUNC_ARG; - } - - outTmp = (byte*)XMALLOC(inSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (outTmp == NULL) - return MEMORY_E; - - /* get encryption algorithm block size */ - blockSz = wc_PKCS7_GetOIDBlockSize(algID); - if (blockSz < 0) { - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return blockSz; - } - - /* input needs to be blockSz multiple and at least 2 * blockSz */ - if (((inSz % blockSz) != 0) || (inSz < (2 * (word32)blockSz))) { - WOLFSSL_MSG("PWRI-KEK unwrap input must of block size and >= 2 " - "times block size"); - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return BAD_FUNC_ARG; - } - - /* use block out[n-1] as IV to decrypt block out[n] */ - lastBlock = (byte*)in + inSz - blockSz; - tmpIv = lastBlock - blockSz; - - /* decrypt last block */ - ret = wc_PKCS7_DecryptContent(pkcs7, algID, (byte*)kek, kekSz, tmpIv, - blockSz, NULL, 0, NULL, 0, lastBlock, blockSz, - outTmp + inSz - blockSz); - - if (ret == 0) { - /* using last decrypted block as IV, decrypt [0 ... n-1] blocks */ - lastBlock = outTmp + inSz - blockSz; - ret = wc_PKCS7_DecryptContent(pkcs7, algID, (byte*)kek, kekSz, - lastBlock, blockSz, NULL, 0, NULL, 0, (byte*)in, inSz - blockSz, - outTmp); - } - - if (ret == 0) { - /* decrypt using original kek and iv */ - ret = wc_PKCS7_DecryptContent(pkcs7, algID, (byte*)kek, kekSz, - (byte*)iv, ivSz, NULL, 0, NULL, 0, outTmp, inSz, outTmp); - } - - if (ret != 0) { - ForceZero(outTmp, inSz); - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - - cekLen = outTmp[0]; - - /* verify length */ - if ((word32)cekLen > inSz) { - ForceZero(outTmp, inSz); - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return BAD_FUNC_ARG; - } - - /* verify check bytes */ - if ((outTmp[1] ^ outTmp[4]) != 0xFF || - (outTmp[2] ^ outTmp[5]) != 0xFF || - (outTmp[3] ^ outTmp[6]) != 0xFF) { - ForceZero(outTmp, inSz); - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return BAD_FUNC_ARG; - } - - if (outSz < (word32)cekLen) { - ForceZero(outTmp, inSz); - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return BUFFER_E; - } - - XMEMCPY(out, outTmp + 4, outTmp[0]); - ForceZero(outTmp, inSz); - XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return cekLen; -} - - -/* Encode and add CMS EnvelopedData PWRI (PasswordRecipientInfo) RecipientInfo - * to CMS/PKCS#7 EnvelopedData structure. - * - * Return 0 on success, negative upon error */ -int wc_PKCS7_AddRecipient_PWRI(PKCS7* pkcs7, byte* passwd, word32 pLen, - byte* salt, word32 saltSz, int kdfOID, - int hashOID, int iterations, int kekEncryptOID, - int options) -{ - Pkcs7EncodedRecip* recip = NULL; - Pkcs7EncodedRecip* lastRecip = NULL; - - /* PasswordRecipientInfo */ - byte recipSeq[MAX_SEQ_SZ]; - byte ver[MAX_VERSION_SZ]; - word32 recipSeqSz, verSz; - - /* KeyDerivationAlgorithmIdentifier */ - byte kdfAlgoIdSeq[MAX_SEQ_SZ]; - byte kdfAlgoId[MAX_OID_SZ]; - byte kdfParamsSeq[MAX_SEQ_SZ]; /* PBKDF2-params */ - byte kdfSaltOctetStr[MAX_OCTET_STR_SZ]; /* salt OCTET STRING */ - byte kdfIterations[MAX_VERSION_SZ]; - word32 kdfAlgoIdSeqSz, kdfAlgoIdSz; - word32 kdfParamsSeqSz, kdfSaltOctetStrSz, kdfIterationsSz; - /* OPTIONAL: keyLength, not supported yet */ - /* OPTIONAL: prf AlgorithIdentifier, not supported yet */ - - /* KeyEncryptionAlgorithmIdentifier */ - byte keyEncAlgoIdSeq[MAX_SEQ_SZ]; - byte keyEncAlgoId[MAX_OID_SZ]; /* id-alg-PWRI-KEK */ - byte pwriEncAlgoId[MAX_ALGO_SZ]; - byte ivOctetString[MAX_OCTET_STR_SZ]; - word32 keyEncAlgoIdSeqSz, keyEncAlgoIdSz; - word32 pwriEncAlgoIdSz, ivOctetStringSz; - - /* EncryptedKey */ - byte encKeyOctetStr[MAX_OCTET_STR_SZ]; - word32 encKeyOctetStrSz; - - byte tmpIv[MAX_CONTENT_IV_SIZE]; - byte* encryptedKey = NULL; - byte* kek = NULL; - - int cekKeySz = 0, kekKeySz = 0, kekBlockSz = 0, ret = 0; - int encryptOID; - word32 idx, totalSz = 0, encryptedKeySz; - - if (pkcs7 == NULL || passwd == NULL || pLen == 0 || - salt == NULL || saltSz == 0) { - return BAD_FUNC_ARG; - } - - /* allow user to use different KEK encryption algorithm than used for - * main content encryption algorithm, if passed in */ - if (kekEncryptOID != 0) { - encryptOID = kekEncryptOID; - } else { - encryptOID = pkcs7->encryptOID; - } - - /* get content-encryption key size, based on algorithm */ - cekKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); - if (cekKeySz < 0) - return cekKeySz; - - /* get KEK encryption key size, based on algorithm */ - if (encryptOID != pkcs7->encryptOID) { - kekKeySz = wc_PKCS7_GetOIDKeySize(encryptOID); - } else { - kekKeySz = cekKeySz; - } - - /* get KEK encryption block size */ - kekBlockSz = wc_PKCS7_GetOIDBlockSize(encryptOID); - if (kekBlockSz < 0) - return kekBlockSz; - - /* generate random CEK */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, cekKeySz); - if (ret < 0) - return ret; - - /* generate random IV */ - ret = wc_PKCS7_GenerateBlock(pkcs7, NULL, tmpIv, kekBlockSz); - if (ret != 0) - return ret; - - /* allocate memory for RecipientInfo, KEK, encrypted key */ - recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (recip == NULL) - return MEMORY_E; - - kek = (byte*)XMALLOC(kekKeySz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (kek == NULL) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (encryptedKey == NULL) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - encryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip)); - XMEMSET(kek, 0, kekKeySz); - XMEMSET(encryptedKey, 0, encryptedKeySz); - - /* generate KEK: expand password into KEK */ - ret = wc_PKCS7_GenerateKEK_PWRI(pkcs7, passwd, pLen, salt, saltSz, - kdfOID, hashOID, iterations, kek, - kekKeySz); - if (ret < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* generate encrypted key: encrypt CEK with KEK */ - ret = wc_PKCS7_PwriKek_KeyWrap(pkcs7, kek, kekKeySz, pkcs7->cek, - pkcs7->cekSz, encryptedKey, &encryptedKeySz, - tmpIv, kekBlockSz, encryptOID); - if (ret < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - encryptedKeySz = ret; - - /* put together encrypted key OCTET STRING */ - encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr); - totalSz += (encKeyOctetStrSz + encryptedKeySz); - - /* put together IV OCTET STRING */ - ivOctetStringSz = SetOctetString(kekBlockSz, ivOctetString); - totalSz += (ivOctetStringSz + kekBlockSz); - - /* set PWRIAlgorithms AlgorithmIdentifier, adding (ivOctetStringSz + - blockKeySz) for IV OCTET STRING */ - pwriEncAlgoIdSz = SetAlgoID(encryptOID, pwriEncAlgoId, - oidBlkType, ivOctetStringSz + kekBlockSz); - totalSz += pwriEncAlgoIdSz; - - /* set KeyEncryptionAlgorithms OID */ - ret = wc_SetContentType(PWRI_KEK_WRAP, keyEncAlgoId, sizeof(keyEncAlgoId)); - if (ret <= 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - keyEncAlgoIdSz = ret; - totalSz += keyEncAlgoIdSz; - - /* KeyEncryptionAlgorithm SEQ */ - keyEncAlgoIdSeqSz = SetSequence(keyEncAlgoIdSz + pwriEncAlgoIdSz + - ivOctetStringSz + kekBlockSz, - keyEncAlgoIdSeq); - totalSz += keyEncAlgoIdSeqSz; - - /* set KDF salt */ - kdfSaltOctetStrSz = SetOctetString(saltSz, kdfSaltOctetStr); - totalSz += (kdfSaltOctetStrSz + saltSz); - - /* set KDF iteration count */ - kdfIterationsSz = SetMyVersion(iterations, kdfIterations, 0); - totalSz += kdfIterationsSz; - - /* set KDF params SEQ */ - kdfParamsSeqSz = SetSequence(kdfSaltOctetStrSz + saltSz + kdfIterationsSz, - kdfParamsSeq); - totalSz += kdfParamsSeqSz; - - /* set KDF algo OID */ - ret = wc_SetContentType(kdfOID, kdfAlgoId, sizeof(kdfAlgoId)); - if (ret <= 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - kdfAlgoIdSz = ret; - totalSz += kdfAlgoIdSz; - - /* set KeyDerivationAlgorithmIdentifier EXPLICIT [0] SEQ */ - kdfAlgoIdSeqSz = SetExplicit(0, kdfAlgoIdSz + kdfParamsSeqSz + - kdfSaltOctetStrSz + saltSz + kdfIterationsSz, - kdfAlgoIdSeq); - totalSz += kdfAlgoIdSeqSz; - - /* set PasswordRecipientInfo CMSVersion, MUST be 0 */ - verSz = SetMyVersion(0, ver, 0); - totalSz += verSz; - recip->recipVersion = 0; - - /* set PasswordRecipientInfo SEQ */ - recipSeqSz = SetImplicit(ASN_SEQUENCE, 3, totalSz, recipSeq); - totalSz += recipSeqSz; - - if (totalSz > MAX_RECIP_SZ) { - WOLFSSL_MSG("CMS Recipient output buffer too small"); - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - idx = 0; - XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz); - idx += recipSeqSz; - XMEMCPY(recip->recip + idx, ver, verSz); - idx += verSz; - XMEMCPY(recip->recip + idx, kdfAlgoIdSeq, kdfAlgoIdSeqSz); - idx += kdfAlgoIdSeqSz; - XMEMCPY(recip->recip + idx, kdfAlgoId, kdfAlgoIdSz); - idx += kdfAlgoIdSz; - XMEMCPY(recip->recip + idx, kdfParamsSeq, kdfParamsSeqSz); - idx += kdfParamsSeqSz; - XMEMCPY(recip->recip + idx, kdfSaltOctetStr, kdfSaltOctetStrSz); - idx += kdfSaltOctetStrSz; - XMEMCPY(recip->recip + idx, salt, saltSz); - idx += saltSz; - XMEMCPY(recip->recip + idx, kdfIterations, kdfIterationsSz); - idx += kdfIterationsSz; - XMEMCPY(recip->recip + idx, keyEncAlgoIdSeq, keyEncAlgoIdSeqSz); - idx += keyEncAlgoIdSeqSz; - XMEMCPY(recip->recip + idx, keyEncAlgoId, keyEncAlgoIdSz); - idx += keyEncAlgoIdSz; - XMEMCPY(recip->recip + idx, pwriEncAlgoId, pwriEncAlgoIdSz); - idx += pwriEncAlgoIdSz; - XMEMCPY(recip->recip + idx, ivOctetString, ivOctetStringSz); - idx += ivOctetStringSz; - XMEMCPY(recip->recip + idx, tmpIv, kekBlockSz); - idx += kekBlockSz; - XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz); - idx += encKeyOctetStrSz; - XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz); - idx += encryptedKeySz; - - ForceZero(kek, kekBlockSz); - ForceZero(encryptedKey, encryptedKeySz); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - /* store recipient size */ - recip->recipSz = idx; - recip->recipType = PKCS7_PWRI; - - /* add recipient to recip list */ - if (pkcs7->recipList == NULL) { - pkcs7->recipList = recip; - } else { - lastRecip = pkcs7->recipList; - while (lastRecip->next != NULL) { - lastRecip = lastRecip->next; - } - lastRecip->next = recip; - } - - (void)options; - - return idx; -} - -/* Import password and KDF settings into a PKCS7 structure. Used for setting - * the password info for decryption a EnvelopedData PWRI RecipientInfo. - * - * Returns 0 on success, negative upon error */ -int wc_PKCS7_SetPassword(PKCS7* pkcs7, byte* passwd, word32 pLen) -{ - if (pkcs7 == NULL || passwd == NULL || pLen == 0) - return BAD_FUNC_ARG; - - pkcs7->pass = passwd; - pkcs7->passSz = pLen; - - return 0; -} - -#endif /* NO_PWDBASED */ - - -/* Encode and add CMS EnvelopedData KEKRI (KEKRecipientInfo) RecipientInfo - * to CMS/PKCS#7 EnvelopedData structure. - * - * pkcs7 - pointer to initialized PKCS7 structure - * keyWrapOID - OID sum of key wrap algorithm identifier - * kek - key encryption key - * kekSz - size of kek, bytes - * keyID - key-encryption key identifier, pre-distributed to endpoints - * keyIDSz - size of keyID, bytes - * timePtr - pointer to "time_t", which is typically "long" (OPTIONAL) - * otherOID - ASN.1 encoded OID of other attribute (OPTIONAL) - * otherOIDSz - size of otherOID, bytes (OPTIONAL) - * other - other attribute (OPTIONAL) - * otherSz - size of other (OPTIONAL) - * - * Returns 0 on success, negative upon error */ -int wc_PKCS7_AddRecipient_KEKRI(PKCS7* pkcs7, int keyWrapOID, byte* kek, - word32 kekSz, byte* keyId, word32 keyIdSz, - void* timePtr, byte* otherOID, - word32 otherOIDSz, byte* other, word32 otherSz, - int options) -{ - Pkcs7EncodedRecip* recip = NULL; - Pkcs7EncodedRecip* lastRecip = NULL; - - byte recipSeq[MAX_SEQ_SZ]; - byte ver[MAX_VERSION_SZ]; - byte kekIdSeq[MAX_SEQ_SZ]; - byte kekIdOctetStr[MAX_OCTET_STR_SZ]; - byte genTime[ASN_GENERALIZED_TIME_SIZE]; - byte otherAttSeq[MAX_SEQ_SZ]; - byte encAlgoId[MAX_ALGO_SZ]; - byte encKeyOctetStr[MAX_OCTET_STR_SZ]; -#ifdef WOLFSSL_SMALL_STACK - byte* encryptedKey; -#else - byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; -#endif - - int blockKeySz = 0, ret = 0, direction; - word32 idx = 0; - word32 totalSz = 0; - word32 recipSeqSz = 0, verSz = 0; - word32 kekIdSeqSz = 0, kekIdOctetStrSz = 0; - word32 otherAttSeqSz = 0, encAlgoIdSz = 0, encKeyOctetStrSz = 0; - int encryptedKeySz; - - int timeSz = 0; -#ifndef NO_ASN_TIME - time_t* tm = NULL; -#endif - - if (pkcs7 == NULL || kek == NULL || keyId == NULL) - return BAD_FUNC_ARG; - - recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (recip == NULL) - return MEMORY_E; - - XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip)); - - /* get key size for content-encryption key based on algorithm */ - blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID); - if (blockKeySz < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return blockKeySz; - } - - /* generate random content encryption key, if needed */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz); - if (ret < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* EncryptedKey */ -#ifdef WOLFSSL_SMALL_STACK - encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedKey == NULL) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } -#endif - encryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - XMEMSET(encryptedKey, 0, encryptedKeySz); - - #ifndef NO_AES - direction = AES_ENCRYPTION; - #else - direction = DES_ENCRYPTION; - #endif - - encryptedKeySz = wc_PKCS7_KeyWrap(pkcs7->cek, pkcs7->cekSz, kek, kekSz, - encryptedKey, encryptedKeySz, keyWrapOID, - direction); - if (encryptedKeySz < 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return encryptedKeySz; - } - /* handle a zero size encKey case as WC_KEY_SIZE_E */ - if (encryptedKeySz == 0 || encryptedKeySz > MAX_ENCRYPTED_KEY_SZ) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return WC_KEY_SIZE_E; - } - - encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr); - totalSz += (encKeyOctetStrSz + encryptedKeySz); - - /* KeyEncryptionAlgorithmIdentifier */ - encAlgoIdSz = SetAlgoID(keyWrapOID, encAlgoId, oidKeyWrapType, 0); - totalSz += encAlgoIdSz; - - /* KEKIdentifier: keyIdentifier */ - kekIdOctetStrSz = SetOctetString(keyIdSz, kekIdOctetStr); - totalSz += (kekIdOctetStrSz + keyIdSz); - - /* KEKIdentifier: GeneralizedTime (OPTIONAL) */ -#ifndef NO_ASN_TIME - if (timePtr != NULL) { - tm = (time_t*)timePtr; - timeSz = GetAsnTimeString(tm, genTime, sizeof(genTime)); - if (timeSz < 0) { - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - return timeSz; - } - totalSz += timeSz; - } -#endif - - /* KEKIdentifier: OtherKeyAttribute SEQ (OPTIONAL) */ - if (other != NULL && otherSz > 0) { - otherAttSeqSz = SetSequence(otherOIDSz + otherSz, otherAttSeq); - totalSz += otherAttSeqSz + otherOIDSz + otherSz; - } - - /* KEKIdentifier SEQ */ - kekIdSeqSz = SetSequence(kekIdOctetStrSz + keyIdSz + timeSz + - otherAttSeqSz + otherOIDSz + otherSz, kekIdSeq); - totalSz += kekIdSeqSz; - - /* version */ - verSz = SetMyVersion(4, ver, 0); - totalSz += verSz; - recip->recipVersion = 4; - - /* KEKRecipientInfo SEQ */ - recipSeqSz = SetImplicit(ASN_SEQUENCE, 2, totalSz, recipSeq); - totalSz += recipSeqSz; - - if (totalSz > MAX_RECIP_SZ) { - WOLFSSL_MSG("CMS Recipient output buffer too small"); - XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - return BUFFER_E; - } - - XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz); - idx += recipSeqSz; - XMEMCPY(recip->recip + idx, ver, verSz); - idx += verSz; - XMEMCPY(recip->recip + idx, kekIdSeq, kekIdSeqSz); - idx += kekIdSeqSz; - XMEMCPY(recip->recip + idx, kekIdOctetStr, kekIdOctetStrSz); - idx += kekIdOctetStrSz; - XMEMCPY(recip->recip + idx, keyId, keyIdSz); - idx += keyIdSz; - if (timePtr != NULL) { - XMEMCPY(recip->recip + idx, genTime, timeSz); - idx += timeSz; - } - if (other != NULL && otherSz > 0) { - XMEMCPY(recip->recip + idx, otherAttSeq, otherAttSeqSz); - idx += otherAttSeqSz; - XMEMCPY(recip->recip + idx, otherOID, otherOIDSz); - idx += otherOIDSz; - XMEMCPY(recip->recip + idx, other, otherSz); - idx += otherSz; - } - XMEMCPY(recip->recip + idx, encAlgoId, encAlgoIdSz); - idx += encAlgoIdSz; - XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz); - idx += encKeyOctetStrSz; - XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz); - idx += encryptedKeySz; - -#ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); -#endif - - /* store recipient size */ - recip->recipSz = idx; - recip->recipType = PKCS7_KEKRI; - - /* add recipient to recip list */ - if (pkcs7->recipList == NULL) { - pkcs7->recipList = recip; - } else { - lastRecip = pkcs7->recipList; - while(lastRecip->next != NULL) { - lastRecip = lastRecip->next; - } - lastRecip->next = recip; - } - - (void)options; - - return idx; -} - - -static int wc_PKCS7_GetCMSVersion(PKCS7* pkcs7, int cmsContentType) -{ - int version = -1; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - switch (cmsContentType) { - case ENVELOPED_DATA: - - /* NOTE: EnvelopedData does not currently support - originatorInfo or unprotectedAttributes. When either of these - are added, version checking below needs to be updated to match - Section 6.1 of RFC 5652 */ - - /* if RecipientInfos include pwri or ori, version is 3 */ - if (wc_PKCS7_RecipientListIncludesType(pkcs7, PKCS7_PWRI) || - wc_PKCS7_RecipientListIncludesType(pkcs7, PKCS7_ORI)) { - version = 3; - break; - } - - /* if unprotectedAttrs is absent AND all RecipientInfo structs - are version 0, version is 0 */ - if (wc_PKCS7_RecipientListVersionsAllZero(pkcs7)) { - version = 0; - break; - } - - /* otherwise, version is 2 */ - version = 2; - break; - - default: - break; - } - - return version; -} - - -/* 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 = 0, outerContentTypeSz = 0, outerContentSz; - byte contentInfoSeq[MAX_SEQ_SZ]; - byte outerContentType[MAX_ALGO_SZ]; - byte outerContent[MAX_SEQ_SZ]; - - int kariVersion; - int envDataSeqSz, verSz; - byte envDataSeq[MAX_SEQ_SZ]; - byte ver[MAX_VERSION_SZ]; - - WC_RNG rng; - int blockSz, blockKeySz; - byte* plain; - byte* encryptedContent; - - Pkcs7EncodedRecip* tmpRecip = NULL; - int recipSz, recipSetSz; - 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) - 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; - - if (pkcs7->contentOID != FIRMWARE_PKG_DATA) { - /* outer content type */ - ret = wc_SetContentType(ENVELOPED_DATA, outerContentType, - sizeof(outerContentType)); - if (ret < 0) - return ret; - - outerContentTypeSz = ret; - } - - /* generate random content encryption key */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz); - if (ret != 0) { - return ret; - } - - /* build RecipientInfo, only if user manually set singleCert and size */ - if (pkcs7->singleCert != NULL && pkcs7->singleCertSz > 0) { - switch (pkcs7->publicKeyOID) { - #ifndef NO_RSA - case RSAk: - ret = wc_PKCS7_AddRecipient_KTRI(pkcs7, pkcs7->singleCert, - pkcs7->singleCertSz, 0); - break; - #endif - #ifdef HAVE_ECC - case ECDSAk: - ret = wc_PKCS7_AddRecipient_KARI(pkcs7, pkcs7->singleCert, - pkcs7->singleCertSz, - pkcs7->keyWrapOID, - pkcs7->keyAgreeOID, pkcs7->ukm, - pkcs7->ukmSz, 0); - break; - #endif - - default: - WOLFSSL_MSG("Unsupported RecipientInfo public key type"); - return BAD_FUNC_ARG; - }; - - if (ret < 0) { - WOLFSSL_MSG("Failed to create RecipientInfo"); - return ret; - } - } - - recipSz = wc_PKCS7_GetRecipientListSize(pkcs7); - if (recipSz < 0) { - return ret; - - } else if (recipSz == 0) { - WOLFSSL_MSG("You must add at least one CMS recipient"); - return PKCS7_RECIP_E; - } - recipSetSz = SetSet(recipSz, recipSet); - - /* version, defined in Section 6.1 of RFC 5652 */ - kariVersion = wc_PKCS7_GetCMSVersion(pkcs7, ENVELOPED_DATA); - if (kariVersion < 0) { - WOLFSSL_MSG("Failed to set CMS EnvelopedData version"); - return PKCS7_RECIP_E; - } - - verSz = SetMyVersion(kariVersion, ver, 0); - - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret != 0) - return ret; - - /* generate IV for block cipher */ - ret = wc_PKCS7_GenerateBlock(pkcs7, &rng, tmpIv, blockSz); - wc_FreeRng(&rng); - if (ret != 0) - return ret; - - /* EncryptedContentInfo */ - ret = wc_SetContentType(pkcs7->contentOID, contentType, - sizeof(contentType)); - if (ret < 0) - return ret; - - contentTypeSz = ret; - - /* 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); - 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); - return BAD_FUNC_ARG; - } - - /* encrypt content */ - ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->cek, - pkcs7->cekSz, tmpIv, blockSz, NULL, 0, NULL, 0, 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); - - /* 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; - - if (pkcs7->contentOID != FIRMWARE_PKG_DATA) { - /* 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); - return BUFFER_E; - } - - if (pkcs7->contentOID != FIRMWARE_PKG_DATA) { - 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; - /* copy in recipients from list */ - tmpRecip = pkcs7->recipList; - while (tmpRecip != NULL) { - XMEMCPY(output + idx, tmpRecip->recip, tmpRecip->recipSz); - idx += tmpRecip->recipSz; - tmpRecip = tmpRecip->next; - } - wc_PKCS7_FreeEncodedRecipientSet(pkcs7); - 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; - - XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return idx; -} - -#ifndef NO_RSA -/* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */ -static int wc_PKCS7_DecryptKtri(PKCS7* pkcs7, byte* in, word32 inSz, - word32* idx, byte* decryptedKey, - word32* decryptedKeySz, int* recipFound) -{ - int length, encryptedKeySz = 0, ret = 0; - int keySz, version, sidType = 0; - word32 encOID; - word32 keyIdx; - byte issuerHash[KEYID_SIZE]; - byte* outKey = NULL; - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - byte tag; - - -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = *idx; - long rc; -#endif -#ifdef WC_RSA_BLINDING - WC_RNG rng; -#endif - -#ifdef WOLFSSL_SMALL_STACK - mp_int* serialNum = NULL; - byte* encryptedKey = NULL; - RsaKey* privKey = NULL; -#else - mp_int serialNum[1]; - byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; - RsaKey privKey[1]; -#endif - - switch (pkcs7->state) { - case WC_PKCS7_DECRYPT_KTRI: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_VERSION_SZ, - &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, - in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - #endif - if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (version == 0) { - sidType = CMS_ISSUER_AND_SERIAL_NUMBER; - } else if (version == 2) { - sidType = CMS_SKID; - } else { - return ASN_VERSION_E; - } - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, 0, sidType, version); - - /* @TODO getting total amount left because of GetInt call later on - * this could be optimized to stream better */ - pkcs7->stream->expected = (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI_2); - FALL_THROUGH; - - case WC_PKCS7_DECRYPT_KTRI_2: - #ifndef NO_PKCS7_STREAM - - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, pkcs7->stream->expected, - &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, - in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - wc_PKCS7_StreamGetVar(pkcs7, NULL, &sidType, &version); - - /* @TODO get expected size for next part, does not account for - * GetInt call well */ - if (pkcs7->stream->expected == MAX_SEQ_SZ) { - int sz; - word32 lidx; - - if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - lidx = *idx; - ret = GetSequence(pkiMsg, &lidx, &sz, pkiMsgSz); - if (ret < 0) - return ret; - } - else { - lidx = *idx + ASN_TAG_SZ; - ret = GetLength(pkiMsg, &lidx, &sz, pkiMsgSz); - if (ret < 0) - return ret; - } - - pkcs7->stream->expected = sz + MAX_ALGO_SZ + ASN_TAG_SZ + - MAX_LENGTH_SZ; - if (pkcs7->stream->length > 0 && - pkcs7->stream->length < pkcs7->stream->expected) { - return WC_PKCS7_WANT_READ_E; - } - } - #endif /* !NO_PKCS7_STREAM */ - - if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) { - - /* 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 - - } else { - /* remove SubjectKeyIdentifier */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* if we found correct recipient, SKID will match */ - if (XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId, - KEYID_SIZE) == 0) { - *recipFound = 1; - } - (*idx) += KEYID_SIZE; - } - - 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 */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &encryptedKeySz, pkiMsgSz) < 0) { - return ASN_PARSE_E; - } - if (encryptedKeySz > MAX_ENCRYPTED_KEY_SZ) { - return BUFFER_E; - } - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, encryptedKeySz, sidType, version); - pkcs7->stream->expected = encryptedKeySz; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI_3); - FALL_THROUGH; - - case WC_PKCS7_DECRYPT_KTRI_3: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected, &pkiMsg, idx)) != 0) { - return ret; - } - encryptedKeySz = pkcs7->stream->expected; - #endif - - #ifdef WOLFSSL_SMALL_STACK - encryptedKey = (byte*)XMALLOC(encryptedKeySz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (encryptedKey == NULL) - return MEMORY_E; - #endif - - 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, encryptedKeySz); - #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, encryptedKeySz); - } - - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - #endif - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - ret = 0; /* success */ - break; - - default: - WOLFSSL_MSG("PKCS7 Unknown KTRI decrypt state"); - ret = BAD_FUNC_ARG; - } - - return ret; -} -#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, oidSum = 0; - int curve_id = ECC_CURVE_DEF; - byte tag; - - if (kari == NULL || pkiMsg == NULL || idx == NULL) - return BAD_FUNC_ARG; - - /* remove OriginatorIdentifierOrKey */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) == 0 && - tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - } else { - return ASN_PARSE_E; - } - - /* remove OriginatorPublicKey */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) == 0 && - tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { - 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; - - /* optional algorithm parameters */ - ret = GetObjectId(pkiMsg, idx, &oidSum, oidIgnoreType, pkiMsgSz); - if (ret == 0) { - /* get curve id */ - curve_id = wc_ecc_get_oid(oidSum, NULL, 0); - if (curve_id < 0) - return ECC_CURVE_OID_E; - } - - /* remove ECPoint BIT STRING */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_BIT_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_EXPECT_0_E; - - if (tag != ASN_OTHER_TYPE) - 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_ex(pkiMsg + (*idx), length - 1, kari->senderKey, - curve_id); - if (ret != 0) { - ret = wc_EccPublicKeyDecode(pkiMsg, idx, kari->senderKey, *idx + length - 1); - if (ret != 0) - return ret; - } - else { - (*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; - byte tag; - - if (kari == NULL || pkiMsg == NULL || idx == NULL) - return BAD_FUNC_ARG; - - savedIdx = *idx; - - /* starts with EXPLICIT [1] */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) { - *idx = savedIdx; - return 0; - } - if (tag != (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 (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) { - *idx = savedIdx; - return 0; - } - if (tag != 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) -{ - int length = 0; - word32 localIdx; - - if (kari == NULL || pkiMsg == NULL || idx == NULL || - keyAgreeOID == NULL || keyWrapOID == NULL) - return BAD_FUNC_ARG; - - localIdx = *idx; - - /* remove KeyEncryptionAlgorithmIdentifier */ - if (GetSequence(pkiMsg, &localIdx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - localIdx = *idx; - if (GetAlgoId(pkiMsg, &localIdx, keyAgreeOID, oidCmsKeyAgreeType, - pkiMsgSz) < 0) { - return ASN_PARSE_E; - } - - if (localIdx < *idx + length) { - *idx = localIdx; - } - /* 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, byte* rid) -{ - int length; - byte tag; - - if (kari == NULL || pkiMsg == NULL || idx == NULL || recipFound == NULL || - rid == NULL) - return BAD_FUNC_ARG; - - /* remove RecipientKeyIdentifier IMPLICIT [0] */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) { - return ASN_PARSE_E; - } - - if (tag == (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 (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) { - return ASN_PARSE_E; - } - - if (tag != 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(rid, pkiMsg + (*idx), KEYID_SIZE); - (*idx) += length; - - /* subject key id should match if recipient found */ - if (XMEMCMP(rid, 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, byte* rid) -{ - int length, ret; -#ifdef WOLFSSL_SMALL_STACK - mp_int* serial; - mp_int* recipSerial; -#else - mp_int serial[1]; - mp_int recipSerial[1]; -#endif - - if (rid == NULL) { - return BAD_FUNC_ARG; - } - - /* remove IssuerAndSerialNumber */ - if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetNameHash(pkiMsg, idx, rid, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* if we found correct recipient, issuer hashes will match */ - if (XMEMCMP(rid, 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, byte* rid) -{ - int length; - int ret = 0; - byte tag; - word32 localIdx; - - 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 */ - localIdx = *idx; - if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - /* try to get RecipientKeyIdentifier */ - ret = wc_PKCS7_KariGetSubjectKeyIdentifier(kari, pkiMsg, pkiMsgSz, - idx, recipFound, rid); - } else { - /* try to get IssuerAndSerialNumber */ - ret = wc_PKCS7_KariGetIssuerAndSerialNumber(kari, pkiMsg, pkiMsgSz, - idx, recipFound, rid); - } - - /* if we don't have either option, malformed CMS */ - if (ret != 0) - return ret; - - /* remove EncryptedKey */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != 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 */ - - -int wc_PKCS7_SetOriEncryptCtx(PKCS7* pkcs7, void* ctx) -{ - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - pkcs7->oriEncryptCtx = ctx; - - return 0; -} - - -int wc_PKCS7_SetOriDecryptCtx(PKCS7* pkcs7, void* ctx) -{ - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - pkcs7->oriDecryptCtx = ctx; - - return 0; -} - - -int wc_PKCS7_SetOriDecryptCb(PKCS7* pkcs7, CallbackOriDecrypt cb) -{ - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - pkcs7->oriDecryptCb = cb; - - return 0; -} - - -/* return 0 on success */ -int wc_PKCS7_SetWrapCEKCb(PKCS7* pkcs7, CallbackWrapCEK cb) -{ - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - pkcs7->wrapCEKCb = cb; - - return 0; -} - -/* Decrypt ASN.1 OtherRecipientInfo (ori), as defined by: - * - * OtherRecipientInfo ::= SEQUENCE { - * oriType OBJECT IDENTIFIER, - * oriValue ANY DEFINED BY oriType } - * - * pkcs7 - pointer to initialized PKCS7 structure - * pkiMsg - pointer to encoded CMS bundle - * pkiMsgSz - size of pkiMsg, bytes - * idx - [IN/OUT] pointer to index into pkiMsg - * decryptedKey - [OUT] output buf for decrypted content encryption key - * decryptedKeySz - [IN/OUT] size of buffer, size of decrypted key - * recipFound - [OUT] 1 if recipient has been found, 0 if not - * - * Return 0 on success, negative upon error. - */ -static int wc_PKCS7_DecryptOri(PKCS7* pkcs7, byte* in, word32 inSz, - word32* idx, byte* decryptedKey, - word32* decryptedKeySz, int* recipFound) -{ - int ret, seqSz, oriOIDSz; - word32 oriValueSz, tmpIdx; - byte* oriValue; - byte oriOID[MAX_OID_SZ]; - - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; -#ifndef NO_PKCS7_STREAM - word32 stateIdx = *idx; - long rc; -#endif - - if (pkcs7->oriDecryptCb == NULL) { - WOLFSSL_MSG("You must register an ORI Decrypt callback"); - return BAD_FUNC_ARG; - } - - switch (pkcs7->state) { - - case WC_PKCS7_DECRYPT_ORI: - #ifndef NO_PKCS7_STREAM - /* @TODO for now just get full buffer, needs divided up */ - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - (pkcs7->stream->maxLen - pkcs7->stream->totalRd) + - pkcs7->stream->length, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - /* get OtherRecipientInfo sequence length */ - if (GetLength(pkiMsg, idx, &seqSz, pkiMsgSz) < 0) - return ASN_PARSE_E; - - tmpIdx = *idx; - - /* remove and store oriType OBJECT IDENTIFIER */ - if (GetASNObjectId(pkiMsg, idx, &oriOIDSz, pkiMsgSz) != 0) - return ASN_PARSE_E; - - XMEMCPY(oriOID, pkiMsg + *idx, oriOIDSz); - *idx += oriOIDSz; - - /* get oriValue, increment idx */ - oriValue = pkiMsg + *idx; - oriValueSz = seqSz - (*idx - tmpIdx); - *idx += oriValueSz; - - /* pass oriOID and oriValue to user callback, expect back - decryptedKey and size */ - ret = pkcs7->oriDecryptCb(pkcs7, oriOID, (word32)oriOIDSz, oriValue, - oriValueSz, decryptedKey, decryptedKeySz, - pkcs7->oriDecryptCtx); - - if (ret != 0 || decryptedKey == NULL || *decryptedKeySz == 0) { - /* decrypt operation failed */ - *recipFound = 0; - return PKCS7_RECIP_E; - } - - /* mark recipFound, since we only support one RecipientInfo for now */ - *recipFound = 1; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, idx)) != 0) { - break; - } - #endif - ret = 0; /* success */ - break; - - default: - WOLFSSL_MSG("PKCS7 ORI unknown state"); - ret = BAD_FUNC_ARG; - - } - - return ret; -} - -#if !defined(NO_PWDBASED) && !defined(NO_SHA) - -/* decode ASN.1 PasswordRecipientInfo (pwri), return 0 on success, - * < 0 on error */ -static int wc_PKCS7_DecryptPwri(PKCS7* pkcs7, byte* in, word32 inSz, - word32* idx, byte* decryptedKey, - word32* decryptedKeySz, int* recipFound) -{ - byte* salt; - byte* cek; - byte* kek; - - byte tmpIv[MAX_CONTENT_IV_SIZE]; - - int ret = 0, length, saltSz, iterations, blockSz, kekKeySz; - int hashOID = WC_SHA; /* default to SHA1 */ - word32 kdfAlgoId, pwriEncAlgoId, keyEncAlgoId, cekSz; - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - byte tag; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = *idx; - long rc; -#endif - - switch (pkcs7->state) { - case WC_PKCS7_DECRYPT_PWRI: - #ifndef NO_PKCS7_STREAM - /*@TODO for now just get full buffer, needs divided up */ - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - (pkcs7->stream->maxLen - pkcs7->stream->totalRd) + - pkcs7->stream->length, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - /* remove KeyDerivationAlgorithmIdentifier */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get KeyDerivationAlgorithmIdentifier */ - if (wc_GetContentType(pkiMsg, idx, &kdfAlgoId, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get KDF params SEQ */ - if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get KDF salt OCTET STRING */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &saltSz, pkiMsgSz) < 0) - return ASN_PARSE_E; - - salt = (byte*)XMALLOC(saltSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (salt == NULL) - return MEMORY_E; - - XMEMCPY(salt, pkiMsg + (*idx), saltSz); - *idx += saltSz; - - /* get KDF iterations */ - if (GetMyVersion(pkiMsg, idx, &iterations, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - /* get KeyEncAlgoId SEQ */ - if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - /* get KeyEncAlgoId */ - if (wc_GetContentType(pkiMsg, idx, &keyEncAlgoId, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - /* get pwriEncAlgoId */ - if (GetAlgoId(pkiMsg, idx, &pwriEncAlgoId, oidBlkType, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - blockSz = wc_PKCS7_GetOIDBlockSize(pwriEncAlgoId); - if (blockSz < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return blockSz; - } - - /* get content-encryption key size, based on algorithm */ - kekKeySz = wc_PKCS7_GetOIDKeySize(pwriEncAlgoId); - if (kekKeySz < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return kekKeySz; - } - - /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if (tag != ASN_OCTET_STRING) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if (length != blockSz) { - WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - XMEMCPY(tmpIv, pkiMsg + (*idx), length); - *idx += length; - - /* get EncryptedKey */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if (tag != ASN_OCTET_STRING) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - /* allocate temporary space for decrypted key */ - cekSz = length; - cek = (byte*)XMALLOC(cekSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (cek == NULL) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - /* generate KEK */ - kek = (byte*)XMALLOC(kekKeySz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (kek == NULL) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - ret = wc_PKCS7_GenerateKEK_PWRI(pkcs7, pkcs7->pass, pkcs7->passSz, - salt, saltSz, kdfAlgoId, hashOID, - iterations, kek, kekKeySz); - if (ret < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - /* decrypt CEK with KEK */ - ret = wc_PKCS7_PwriKek_KeyUnWrap(pkcs7, kek, kekKeySz, - pkiMsg + (*idx), length, cek, - cekSz, tmpIv, blockSz, - pwriEncAlgoId); - if (ret < 0) { - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - cekSz = ret; - - if (*decryptedKeySz < cekSz) { - WOLFSSL_MSG("Decrypted key buffer too small for CEK"); - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - XMEMCPY(decryptedKey, cek, cekSz); - *decryptedKeySz = cekSz; - - XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - /* mark recipFound, since we only support one RecipientInfo for now */ - *recipFound = 1; - *idx += length; - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - ret = 0; /* success */ - break; - - default: - WOLFSSL_MSG("PKCS7 PWRI unknown state"); - ret = BAD_FUNC_ARG; - } - - return ret; -} - -#endif /* NO_PWDBASED | NO_SHA */ - -/* decode ASN.1 KEKRecipientInfo (kekri), return 0 on success, - * < 0 on error */ -static int wc_PKCS7_DecryptKekri(PKCS7* pkcs7, byte* in, word32 inSz, - word32* idx, byte* decryptedKey, - word32* decryptedKeySz, int* recipFound) -{ - int length, keySz, dateLen, direction; - byte* keyId = NULL; - const byte* datePtr = NULL; - byte dateFormat, tag; - word32 keyIdSz, kekIdSz, keyWrapOID, localIdx; - - int ret = 0; - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = *idx; - long rc; -#endif - - WOLFSSL_ENTER("wc_PKCS7_DecryptKekri"); - switch (pkcs7->state) { - case WC_PKCS7_DECRYPT_KEKRI: - #ifndef NO_PKCS7_STREAM - /* @TODO for now just get full buffer, needs divided up */ - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - (pkcs7->stream->maxLen - pkcs7->stream->totalRd) + - pkcs7->stream->length, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - /* remove KEKIdentifier */ - if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - kekIdSz = length; - - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* save keyIdentifier and length */ - keyId = pkiMsg + *idx; - keyIdSz = length; - *idx += keyIdSz; - - /* may have OPTIONAL GeneralizedTime */ - localIdx = *idx; - if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag, - pkiMsgSz) == 0 && tag == ASN_GENERALIZED_TIME) { - if (wc_GetDateInfo(pkiMsg + *idx, pkiMsgSz, &datePtr, &dateFormat, - &dateLen) != 0) { - return ASN_PARSE_E; - } - *idx += (dateLen + 1); - } - - /* may have OPTIONAL OtherKeyAttribute */ - localIdx = *idx; - if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag, - pkiMsgSz) == 0 && tag == (ASN_SEQUENCE | - ASN_CONSTRUCTED)) { - if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* skip it */ - *idx += length; - } - - /* get KeyEncryptionAlgorithmIdentifier */ - if (GetAlgoId(pkiMsg, idx, &keyWrapOID, oidKeyWrapType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get EncryptedKey */ - if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - #ifndef NO_AES - direction = AES_DECRYPTION; - #else - direction = DES_DECRYPTION; - #endif - - /* decrypt CEK with KEK */ - if (pkcs7->wrapCEKCb) { - keySz = pkcs7->wrapCEKCb(pkcs7, pkiMsg + *idx, length, keyId, - keyIdSz, NULL, 0, decryptedKey, - *decryptedKeySz, keyWrapOID, - (int)PKCS7_KEKRI, direction); - } - else { - keySz = wc_PKCS7_KeyWrap(pkiMsg + *idx, length, pkcs7->privateKey, - pkcs7->privateKeySz, decryptedKey, *decryptedKeySz, - keyWrapOID, direction); - } - if (keySz <= 0) - return keySz; - - *decryptedKeySz = (word32)keySz; - - /* mark recipFound, since we only support one RecipientInfo for now */ - *recipFound = 1; - *idx += length; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - ret = 0; /* success */ - break; - - default: - WOLFSSL_MSG("PKCS7 KEKRI unknown state"); - ret = BAD_FUNC_ARG; - - } - - (void)keyId; - return ret; -} - - -/* decode ASN.1 KeyAgreeRecipientInfo (kari), return 0 on success, - * < 0 on error */ -static int wc_PKCS7_DecryptKari(PKCS7* pkcs7, byte* in, word32 inSz, - word32* idx, byte* decryptedKey, - word32* decryptedKeySz, int* recipFound) -{ -#ifdef HAVE_ECC - int ret, keySz; - int encryptedKeySz; - int direction = 0; - word32 keyAgreeOID, keyWrapOID; - byte rid[KEYID_SIZE]; - -#ifdef WOLFSSL_SMALL_STACK - byte* encryptedKey; -#else - byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; -#endif - - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = (idx) ? *idx : 0; - long rc; -#endif - - WOLFSSL_ENTER("wc_PKCS7_DecryptKari"); - if (pkcs7 == NULL || pkiMsg == NULL || - ((pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0) && - pkcs7->wrapCEKCb == NULL) || - idx == NULL || decryptedKey == NULL || decryptedKeySz == NULL) { - return BAD_FUNC_ARG; - } - - switch (pkcs7->state) { - case WC_PKCS7_DECRYPT_KARI: { - #ifndef NO_PKCS7_STREAM - /* @TODO for now just get full buffer, needs divided up */ - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - (pkcs7->stream->maxLen - pkcs7->stream->totalRd) + - pkcs7->stream->length, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - WC_PKCS7_KARI* kari; - - 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 */ - if (pkcs7->singleCert != NULL) { - 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: - WOLFSSL_MSG("AES key wrap algorithm unsupported"); - if (pkcs7->wrapCEKCb) { - WOLFSSL_MSG("Direction not set!"); - break; /* if unwrapping callback is set then do not - * force restriction of supported wrap - * algorithms */ - } - - wc_PKCS7_KariFree(kari); - #ifdef WOLFSSL_SMALL_STACK - XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - #endif - return BAD_KEYWRAP_ALG_E; - } - - /* remove RecipientEncryptedKeys */ - ret = wc_PKCS7_KariGetRecipientEncryptedKeys(kari, pkiMsg, pkiMsgSz, - idx, recipFound, encryptedKey, &encryptedKeySz, rid); - 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 */ - if (pkcs7->wrapCEKCb) { - word32 tmpKeySz = 0; - byte* tmpKeyDer = NULL; - - ret = wc_ecc_export_x963(kari->senderKey, NULL, &tmpKeySz); - if (ret != LENGTH_ONLY_E) { - return ret; - } - - /* buffer space for algorithm/curve */ - tmpKeySz += MAX_SEQ_SZ; - tmpKeySz += 2 * MAX_ALGO_SZ; - - /* buffer space for public key sequence */ - tmpKeySz += MAX_SEQ_SZ; - tmpKeySz += TRAILING_ZERO; - - tmpKeyDer = (byte*)XMALLOC(tmpKeySz, pkcs7->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (tmpKeyDer == NULL) { - return MEMORY_E; - } - - ret = wc_EccPublicKeyToDer(kari->senderKey, tmpKeyDer, - tmpKeySz, 1); - if (ret < 0) { - XFREE(tmpKeyDer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - tmpKeySz = (word32)ret; - - keySz = pkcs7->wrapCEKCb(pkcs7, encryptedKey, encryptedKeySz, - rid, KEYID_SIZE, tmpKeyDer, tmpKeySz, - decryptedKey, *decryptedKeySz, - keyWrapOID, (int)PKCS7_KARI, direction); - XFREE(tmpKeyDer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - - if (keySz > 0) { - /* If unwrapping was successful then consider recipient - * found. Checking for NULL singleCert to confirm previous - * SID check was not done */ - if (pkcs7->singleCert == NULL) - *recipFound = 1; - } - } - else { - /* 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_KeyWrap(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 - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - ret = 0; /* success */ - } - break; - - default: - WOLFSSL_MSG("PKCS7 kari unknown state"); - ret = BAD_FUNC_ARG; - - } - - (void)pkiMsg; - (void)pkiMsgSz; - - return ret; -#else - (void)in; - (void)inSz; - (void)pkcs7; - (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_DecryptRecipientInfos(PKCS7* pkcs7, byte* in, - word32 inSz, word32* idx, byte* decryptedKey, - word32* decryptedKeySz, int* recipFound) -{ - word32 savedIdx; - int version, ret = 0, length; - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - byte tag; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx; - long rc; -#endif - - if (pkcs7 == NULL || pkiMsg == NULL || idx == NULL || - decryptedKey == NULL || decryptedKeySz == NULL || - recipFound == NULL) { - return BAD_FUNC_ARG; - } - - WOLFSSL_ENTER("wc_PKCS7_DecryptRecipientInfos"); -#ifndef NO_PKCS7_STREAM - tmpIdx = *idx; -#endif - - /* check if in the process of decrypting */ - switch (pkcs7->state) { - case WC_PKCS7_DECRYPT_KTRI: - case WC_PKCS7_DECRYPT_KTRI_2: - case WC_PKCS7_DECRYPT_KTRI_3: - #ifndef NO_RSA - ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, recipFound); - #else - return NOT_COMPILED_IN; - #endif - break; - - case WC_PKCS7_DECRYPT_KARI: - ret = wc_PKCS7_DecryptKari(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, recipFound); - break; - - case WC_PKCS7_DECRYPT_KEKRI: - ret = wc_PKCS7_DecryptKekri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, recipFound); - break; - - case WC_PKCS7_DECRYPT_PWRI: - #if !defined(NO_PWDBASED) && !defined(NO_SHA) - ret = wc_PKCS7_DecryptPwri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, recipFound); - #else - return NOT_COMPILED_IN; - #endif - break; - - case WC_PKCS7_DECRYPT_ORI: - ret = wc_PKCS7_DecryptOri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, recipFound); - break; - - default: - /* not in decrypting state */ - break; - } - - if (ret < 0) { - return ret; - } - - savedIdx = *idx; -#ifndef NO_PKCS7_STREAM - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz); - if (rc < 0) { - return (int)rc; - } - pkiMsgSz = (word32)rc; - if (pkcs7->stream->length > 0) - pkiMsg = pkcs7->stream->buffer; -#endif - - /* 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) { - - #ifndef NO_RSA - /* found ktri */ - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI); - ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, - recipFound); - if (ret != 0) - return ret; - #else - return NOT_COMPILED_IN; - #endif - } - else { - word32 localIdx; - /* kari is IMPLICIT[1] */ - *idx = savedIdx; - localIdx = *idx; - - if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0) { - /* no room for recipient info */ - break; - } - - if (tag == (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 */ - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KARI); - ret = wc_PKCS7_DecryptKari(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, - recipFound); - if (ret != 0) - return ret; - - /* kekri is IMPLICIT[2] */ - } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2)) { - (*idx)++; - - if (GetLength(pkiMsg, idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) { - *idx = savedIdx; - break; - } - - if (version != 4) - return ASN_VERSION_E; - - /* found kekri */ - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KEKRI); - ret = wc_PKCS7_DecryptKekri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, - recipFound); - if (ret != 0) - return ret; - - /* pwri is IMPLICIT[3] */ - } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 3)) { - #if !defined(NO_PWDBASED) && !defined(NO_SHA) - (*idx)++; - - if (GetLength(pkiMsg, idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) { - *idx = savedIdx; - break; - } - - if (version != 0) - return ASN_VERSION_E; - - /* found pwri */ - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_PWRI); - ret = wc_PKCS7_DecryptPwri(pkcs7, in, inSz, idx, - decryptedKey, decryptedKeySz, - recipFound); - if (ret != 0) - return ret; - #else - return NOT_COMPILED_IN; - #endif - - /* ori is IMPLICIT[4] */ - } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 4)) { - (*idx)++; - - /* found ori */ - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_ORI); - ret = wc_PKCS7_DecryptOri(pkcs7, in, inSz, 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 ret; -} - - -/* Parse encoded EnvelopedData bundle up to RecipientInfo set. - * - * return size of RecipientInfo SET on success, negative upon error */ -static int wc_PKCS7_ParseToRecipientInfoSet(PKCS7* pkcs7, byte* in, - word32 inSz, word32* idx, - int type) -{ - int version = 0, length, ret = 0; - word32 contentType; - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - byte tag; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = 0; - long rc; -#endif - - if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 || idx == NULL) - return BAD_FUNC_ARG; - - if ((type != ENVELOPED_DATA) && (type != AUTH_ENVELOPED_DATA) && - pkcs7->contentOID != FIRMWARE_PKG_DATA) - return BAD_FUNC_ARG; - -#ifndef NO_PKCS7_STREAM - if (pkcs7->stream == NULL) { - if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) { - return ret; - } - } -#endif - - switch (pkcs7->state) { - case WC_PKCS7_INFOSET_START: - case WC_PKCS7_INFOSET_BER: - case WC_PKCS7_INFOSET_STAGE1: - case WC_PKCS7_INFOSET_STAGE2: - case WC_PKCS7_INFOSET_END: - break; - - default: - WOLFSSL_MSG("Warning, setting PKCS7 info state to start"); - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_START); - } - - switch (pkcs7->state) { - case WC_PKCS7_INFOSET_START: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ + - ASN_TAG_SZ, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - /* read past ContentInfo, verify type is envelopedData */ - if (ret == 0 && GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - { - ret = ASN_PARSE_E; - } - - if (ret == 0 && length == 0 && pkiMsg[(*idx)-1] == 0x80) { - #ifdef ASN_BER_TO_DER - word32 len; - - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_BER); - FALL_THROUGH; - - /* full buffer is needed for conversion */ - case WC_PKCS7_INFOSET_BER: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->maxLen - pkcs7->stream->length, - &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, - in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - - 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 = in = pkcs7->der; - pkiMsgSz = pkcs7->derSz = len; - *idx = 0; - - if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - #else - return BER_INDEF_E; - #endif - } - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_STAGE1); - FALL_THROUGH; - - case WC_PKCS7_INFOSET_STAGE1: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_OID_SZ + - MAX_LENGTH_SZ + ASN_TAG_SZ, &pkiMsg, idx)) != 0) { - return ret; - } - - pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz; - #endif - if (pkcs7->contentOID != FIRMWARE_PKG_DATA || - type == AUTH_ENVELOPED_DATA) { - if (ret == 0 && wc_GetContentType(pkiMsg, idx, &contentType, - pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0) { - if (type == ENVELOPED_DATA && contentType != ENVELOPED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData"); - ret = PKCS7_OID_E; - } else if (type == AUTH_ENVELOPED_DATA && - contentType != AUTH_ENVELOPED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type AuthEnvelopedData"); - ret = PKCS7_OID_E; - } - } - - if (ret == 0 && GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) != 0) - ret = ASN_PARSE_E; - - if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC - | 0)) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength_ex(pkiMsg, idx, &length, pkiMsgSz, - NO_USER_CHECK) < 0) - ret = ASN_PARSE_E; - } - - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_STAGE2); - FALL_THROUGH; - - case WC_PKCS7_INFOSET_STAGE2: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ + - MAX_VERSION_SZ, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - /* remove EnvelopedData and version */ - if (pkcs7->contentOID != FIRMWARE_PKG_DATA || - type == AUTH_ENVELOPED_DATA) { - if (ret == 0 && GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - - pkcs7->stream->varOne = version; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_END); - FALL_THROUGH; - - case WC_PKCS7_INFOSET_END: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - MAX_SET_SZ, &pkiMsg, idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - version = pkcs7->stream->varOne; - #endif - - if (type == ENVELOPED_DATA) { - /* TODO :: make this more accurate */ - if ((pkcs7->publicKeyOID == RSAk && - (version != 0 && version != 2)) - #ifdef HAVE_ECC - || (pkcs7->publicKeyOID == ECDSAk && - (version != 0 && version != 2 && version != 3)) - #endif - ) { - WOLFSSL_MSG("PKCS#7 envelopedData version incorrect"); - ret = ASN_VERSION_E; - } - } else { - /* AuthEnvelopedData version MUST be 0 */ - if (version != 0) { - WOLFSSL_MSG("PKCS#7 AuthEnvelopedData needs to be of version 0"); - ret = ASN_VERSION_E; - } - } - - /* remove RecipientInfo set, get length of set */ - if (ret == 0 && GetSet(pkiMsg, idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) { - break; - } - #endif - - if (ret == 0) - ret = length; - - break; - - default: - WOLFSSL_MSG("Bad PKCS7 info set state"); - ret = BAD_FUNC_ARG; - break; - } - - return ret; -} - - -/* Import secret/private key into a PKCS7 structure. Used for setting - * the secret key for decryption a EnvelopedData KEKRI RecipientInfo. - * - * Returns 0 on success, negative upon error */ -WOLFSSL_API int wc_PKCS7_SetKey(PKCS7* pkcs7, byte* key, word32 keySz) -{ - if (pkcs7 == NULL || key == NULL || keySz == 0) - return BAD_FUNC_ARG; - - pkcs7->privateKey = key; - pkcs7->privateKeySz = keySz; - - return 0; -} - - -/* append data to encrypted content cache in PKCS7 structure - * return 0 on success, negative on error */ -static int PKCS7_CacheEncryptedContent(PKCS7* pkcs7, byte* in, word32 inSz) -{ - byte* oldCache; - word32 oldCacheSz; - - if (pkcs7 == NULL || in == NULL) - return BAD_FUNC_ARG; - - /* save pointer to old cache */ - oldCache = pkcs7->cachedEncryptedContent; - oldCacheSz = pkcs7->cachedEncryptedContentSz; - - /* re-allocate new buffer to fit appended data */ - pkcs7->cachedEncryptedContent = (byte*)XMALLOC(oldCacheSz + inSz, - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7->cachedEncryptedContent == NULL) { - pkcs7->cachedEncryptedContentSz = 0; - XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - if (oldCache != NULL) { - XMEMCPY(pkcs7->cachedEncryptedContent, oldCache, oldCacheSz); - } - XMEMCPY(pkcs7->cachedEncryptedContent + oldCacheSz, in, inSz); - pkcs7->cachedEncryptedContentSz += inSz; - - XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return 0; -} - - -/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ -WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, - word32 inSz, byte* output, - word32 outputSz) -{ - int recipFound = 0; - int ret, length = 0; - word32 idx = 0; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = 0; - long rc; -#endif - word32 contentType, encOID = 0; - word32 decryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - - int expBlockSz = 0, blockKeySz = 0; - byte tmpIvBuf[MAX_CONTENT_IV_SIZE]; - byte* tmpIv = tmpIvBuf; - - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - byte* decryptedKey = NULL; - int encryptedContentTotalSz = 0; - int encryptedContentSz = 0; - byte padLen; - byte* encryptedContent = NULL; - int explicitOctet = 0; - word32 localIdx; - byte tag; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - if (pkiMsg == NULL || pkiMsgSz == 0 || - output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - -#ifndef NO_PKCS7_STREAM - (void)tmpIv; /* help out static analysis */ - if (pkcs7->stream == NULL) { - if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) { - return ret; - } - } -#endif - - switch (pkcs7->state) { - case WC_PKCS7_START: - case WC_PKCS7_INFOSET_START: - case WC_PKCS7_INFOSET_BER: - case WC_PKCS7_INFOSET_STAGE1: - case WC_PKCS7_INFOSET_STAGE2: - case WC_PKCS7_INFOSET_END: - ret = wc_PKCS7_ParseToRecipientInfoSet(pkcs7, pkiMsg, pkiMsgSz, - &idx, ENVELOPED_DATA); - if (ret < 0) { - break; - } - - #ifdef ASN_BER_TO_DER - /* check if content was BER and has been converted to DER */ - if (pkcs7->derSz > 0) - pkiMsg = in = pkcs7->der; - #endif - - decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (decryptedKey == NULL) - return MEMORY_E; - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2); - #ifndef NO_PKCS7_STREAM - tmpIdx = idx; - pkcs7->stream->aad = decryptedKey; - #endif - FALL_THROUGH; - - case WC_PKCS7_ENV_2: - #ifndef NO_PKCS7_STREAM - /* store up enough buffer for initial info set decode */ - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ + - MAX_VERSION_SZ + ASN_TAG_SZ, &pkiMsg, &idx)) != 0) { - return ret; - } - #endif - FALL_THROUGH; - - case WC_PKCS7_DECRYPT_KTRI: - case WC_PKCS7_DECRYPT_KTRI_2: - case WC_PKCS7_DECRYPT_KTRI_3: - case WC_PKCS7_DECRYPT_KARI: - case WC_PKCS7_DECRYPT_KEKRI: - case WC_PKCS7_DECRYPT_PWRI: - case WC_PKCS7_DECRYPT_ORI: - #ifndef NO_PKCS7_STREAM - decryptedKey = pkcs7->stream->aad; - decryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - #endif - - ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx, - decryptedKey, &decryptedKeySz, - &recipFound); - if (ret == 0 && recipFound == 0) { - WOLFSSL_MSG("No recipient found in envelopedData that matches input"); - ret = PKCS7_RECIP_E; - } - - if (ret != 0) - break; - #ifndef NO_PKCS7_STREAM - tmpIdx = idx; - pkcs7->stream->aadSz = decryptedKeySz; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_3); - FALL_THROUGH; - - case WC_PKCS7_ENV_3: - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ + - MAX_VERSION_SZ + ASN_TAG_SZ + - MAX_LENGTH_SZ, &pkiMsg, &idx)) - != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #else - ret = 0; - #endif - - /* remove EncryptedContentInfo */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType, - pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, - pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); - if (ret == 0 && blockKeySz < 0) { - ret = blockKeySz; - } - - expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); - if (ret == 0 && expBlockSz < 0) { - ret = expBlockSz; - } - - /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) != 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && tag != ASN_OCTET_STRING) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && length != expBlockSz) { - WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); - ret = ASN_PARSE_E; - } - - if (ret != 0) - break; - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, length); - pkcs7->stream->contentSz = blockKeySz; - pkcs7->stream->expected = length + MAX_LENGTH_SZ + MAX_LENGTH_SZ + - ASN_TAG_SZ + ASN_TAG_SZ; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_4); - FALL_THROUGH; - - case WC_PKCS7_ENV_4: - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - wc_PKCS7_StreamGetVar(pkcs7, 0, 0, &length); - tmpIv = pkcs7->stream->tmpIv; - if (tmpIv == NULL) { - /* check added to help out static analysis tool */ - ret = MEMORY_E; - break; - } - #else - ret = 0; - #endif - - XMEMCPY(tmpIv, &pkiMsg[idx], length); - idx += length; - - explicitOctet = 0; - localIdx = idx; - if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 && - tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) { - explicitOctet = 1; - } - - /* read encryptedContent, cont[0] */ - if (tag != (ASN_CONTEXT_SPECIFIC | 0) && - tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) { - ret = ASN_PARSE_E; - } - idx++; - - if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentTotalSz, - pkiMsgSz) <= 0) { - ret = ASN_PARSE_E; - } - - if (ret != 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - pkcs7->stream->expected = encryptedContentTotalSz; - wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, 0); - wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5); - FALL_THROUGH; - - case WC_PKCS7_ENV_5: - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - return ret; - } - - wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, &explicitOctet); - tmpIv = pkcs7->stream->tmpIv; - encryptedContentTotalSz = pkcs7->stream->expected; - - /* restore decrypted key */ - decryptedKey = pkcs7->stream->aad; - decryptedKeySz = pkcs7->stream->aadSz; - blockKeySz = pkcs7->stream->contentSz; - #else - ret = 0; - #endif - - if (explicitOctet) { - /* encrypted content may be fragmented into multiple - * consecutive OCTET STRINGs, if so loop through - * collecting and caching encrypted content bytes */ - localIdx = idx; - while (idx < (localIdx + encryptedContentTotalSz)) { - - if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && (tag != ASN_OCTET_STRING)) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetLength(pkiMsg, &idx, - &encryptedContentSz, pkiMsgSz) <= 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0) { - ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx], - encryptedContentSz); - } - - if (ret != 0) { - break; - } - - /* advance idx past encrypted content */ - idx += encryptedContentSz; - } - - if (ret != 0) { - break; - } - - } else { - /* cache encrypted content, no OCTET STRING */ - ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx], - encryptedContentTotalSz); - if (ret != 0) { - break; - } - idx += encryptedContentTotalSz; - } - - /* use cached content */ - encryptedContent = pkcs7->cachedEncryptedContent; - encryptedContentSz = pkcs7->cachedEncryptedContentSz; - - /* decrypt encryptedContent */ - ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey, - blockKeySz, tmpIv, expBlockSz, NULL, 0, NULL, 0, - encryptedContent, encryptedContentSz, encryptedContent); - if (ret != 0) { - break; - } - - padLen = encryptedContent[encryptedContentSz-1]; - - /* copy plaintext to output */ - if (padLen > encryptedContentSz || - (word32)(encryptedContentSz - padLen) > outputSz) { - ret = BUFFER_E; - break; - } - XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); - - /* free memory, zero out keys */ - ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7->cachedEncryptedContent != NULL) { - XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - pkcs7->cachedEncryptedContent = NULL; - pkcs7->cachedEncryptedContentSz = 0; - } - - ret = encryptedContentSz - padLen; - #ifndef NO_PKCS7_STREAM - pkcs7->stream->aad = NULL; - pkcs7->stream->aadSz = 0; - wc_PKCS7_ResetStream(pkcs7); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - break; - - default: - WOLFSSL_MSG("PKCS#7 unknown decode enveloped state"); - ret = BAD_FUNC_ARG; - } - -#ifndef NO_PKCS7_STREAM - if (ret < 0 && ret != WC_PKCS7_WANT_READ_E) { - wc_PKCS7_ResetStream(pkcs7); - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - if (pkcs7->cachedEncryptedContent != NULL) { - XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - pkcs7->cachedEncryptedContent = NULL; - pkcs7->cachedEncryptedContentSz = 0; - } - } -#else - if (decryptedKey != NULL && ret < 0) { - ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - if (pkcs7->cachedEncryptedContent != NULL && ret < 0) { - XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - pkcs7->cachedEncryptedContent = NULL; - pkcs7->cachedEncryptedContentSz = 0; - } -#endif - return ret; -} - - -/* build PKCS#7 authEnvelopedData content type, return enveloped size */ -int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output, - word32 outputSz) -{ -#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) - int ret, idx = 0; - int totalSz, 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 blockSz, blockKeySz; - byte* encryptedContent; - - Pkcs7EncodedRecip* tmpRecip = NULL; - int recipSz, recipSetSz; - byte recipSet[MAX_SET_SZ]; - - int encContentOctetSz, encContentSeqSz, contentTypeSz; - int contentEncAlgoSz, nonceOctetStringSz, macOctetStringSz; - byte encContentSeq[MAX_SEQ_SZ]; - byte contentType[MAX_ALGO_SZ]; - byte contentEncAlgo[MAX_ALGO_SZ]; - byte nonceOctetString[MAX_OCTET_STR_SZ]; - byte encContentOctet[MAX_OCTET_STR_SZ]; - byte macOctetString[MAX_OCTET_STR_SZ]; - - byte authTag[AES_BLOCK_SIZE]; - byte nonce[GCM_NONCE_MID_SZ]; /* GCM nonce is larger than CCM */ - byte macInt[MAX_VERSION_SZ]; - word32 nonceSz = 0, macIntSz = 0; - - /* authAttribs */ - byte* flatAuthAttribs = NULL; - byte authAttribSet[MAX_SET_SZ]; - EncodedAttrib authAttribs[MAX_AUTH_ATTRIBS_SZ]; - word32 authAttribsSz = 0, authAttribsCount = 0; - word32 authAttribsSetSz = 0; - - byte* aadBuffer = NULL; - word32 aadBufferSz = 0; - byte authAttribAadSet[MAX_SET_SZ]; - word32 authAttribsAadSetSz = 0; - - /* unauthAttribs */ - byte* flatUnauthAttribs = NULL; - byte unauthAttribSet[MAX_SET_SZ]; - EncodedAttrib unauthAttribs[MAX_UNAUTH_ATTRIBS_SZ]; - word32 unauthAttribsSz = 0, unauthAttribsCount = 0; - word32 unauthAttribsSetSz = 0; - - - PKCS7Attrib contentTypeAttrib; - byte contentTypeValue[MAX_OID_SZ]; - /* contentType OID (1.2.840.113549.1.9.3) */ - const byte contentTypeOid[] = - { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, - 0x09, 0x03 }; - - if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0) - return BAD_FUNC_ARG; - - if (output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - - switch (pkcs7->encryptOID) { -#ifdef HAVE_AESGCM - #ifdef WOLFSSL_AES_128 - case AES128GCMb: - break; - #endif - #ifdef WOLFSSL_AES_192 - case AES192GCMb: - break; - #endif - #ifdef WOLFSSL_AES_256 - case AES256GCMb: - break; - #endif -#endif -#ifdef HAVE_AESCCM - #ifdef WOLFSSL_AES_128 - case AES128CCMb: - break; - #endif - #ifdef WOLFSSL_AES_192 - case AES192CCMb: - break; - #endif - #ifdef WOLFSSL_AES_256 - case AES256CCMb: - break; - #endif -#endif - default: - WOLFSSL_MSG("CMS AuthEnvelopedData must use AES-GCM or AES-CCM"); - 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 */ - ret = wc_SetContentType(AUTH_ENVELOPED_DATA, outerContentType, - sizeof(outerContentType)); - if (ret < 0) - return ret; - - outerContentTypeSz = ret; - - /* version, defined as 0 in RFC 5083 */ - verSz = SetMyVersion(0, ver, 0); - - /* generate random content encryption key */ - ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz); - if (ret != 0) { - return ret; - } - - /* build RecipientInfo, only if user manually set singleCert and size */ - if (pkcs7->singleCert != NULL && pkcs7->singleCertSz > 0) { - switch (pkcs7->publicKeyOID) { - #ifndef NO_RSA - case RSAk: - ret = wc_PKCS7_AddRecipient_KTRI(pkcs7, pkcs7->singleCert, - pkcs7->singleCertSz, 0); - break; - #endif - #ifdef HAVE_ECC - case ECDSAk: - ret = wc_PKCS7_AddRecipient_KARI(pkcs7, pkcs7->singleCert, - pkcs7->singleCertSz, - pkcs7->keyWrapOID, - pkcs7->keyAgreeOID, pkcs7->ukm, - pkcs7->ukmSz, 0); - break; - #endif - - default: - WOLFSSL_MSG("Unsupported RecipientInfo public key type"); - return BAD_FUNC_ARG; - }; - - if (ret < 0) { - WOLFSSL_MSG("Failed to create RecipientInfo"); - return ret; - } - } - - recipSz = wc_PKCS7_GetRecipientListSize(pkcs7); - if (recipSz < 0) { - return ret; - - } else if (recipSz == 0) { - WOLFSSL_MSG("You must add at least one CMS recipient"); - return PKCS7_RECIP_E; - } - recipSetSz = SetSet(recipSz, recipSet); - - /* generate random nonce and IV for encryption */ - switch (pkcs7->encryptOID) { -#ifdef HAVE_AESGCM - #ifdef WOLFSSL_AES_128 - case AES128GCMb: - FALL_THROUGH; - #endif - #ifdef WOLFSSL_AES_192 - case AES192GCMb: - FALL_THROUGH; - #endif - #ifdef WOLFSSL_AES_256 - case AES256GCMb: - #endif - #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \ - defined(WOLFSSL_AES_256) - /* GCM nonce is GCM_NONCE_MID_SZ (12) */ - nonceSz = GCM_NONCE_MID_SZ; - break; - #endif -#endif /* HAVE_AESGCM */ -#ifdef HAVE_AESCCM - #ifdef WOLFSSL_AES_128 - case AES128CCMb: - FALL_THROUGH; - #endif - #ifdef WOLFSSL_AES_192 - case AES192CCMb: - FALL_THROUGH; - #endif - #ifdef WOLFSSL_AES_256 - case AES256CCMb: - #endif - #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \ - defined(WOLFSSL_AES_256) - /* CCM nonce is CCM_NONCE_MIN_SZ (7) */ - nonceSz = CCM_NONCE_MIN_SZ; - break; - #endif -#endif /* HAVE_AESCCM */ - } - - ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId); - if (ret != 0) - return ret; - - ret = wc_PKCS7_GenerateBlock(pkcs7, &rng, nonce, nonceSz); - wc_FreeRng(&rng); - if (ret != 0) { - return ret; - } - - - /* authAttribs: add contentType attrib if needed */ - if (pkcs7->contentOID != DATA) { - - /* if type is not id-data, contentType attribute MUST be added */ - contentTypeAttrib.oid = contentTypeOid; - contentTypeAttrib.oidSz = sizeof(contentTypeOid); - - /* try to set from contentOID first, known types */ - ret = wc_SetContentType(pkcs7->contentOID, contentTypeValue, - sizeof(contentTypeValue)); - if (ret > 0) { - contentTypeAttrib.value = contentTypeValue; - contentTypeAttrib.valueSz = ret; - - /* otherwise, try to set from custom content type */ - } else { - if (pkcs7->contentTypeSz == 0) { - WOLFSSL_MSG("CMS pkcs7->contentType must be set if " - "contentOID is not"); - return BAD_FUNC_ARG; - } - contentTypeAttrib.value = pkcs7->contentType; - contentTypeAttrib.valueSz = pkcs7->contentTypeSz; - } - - authAttribsSz += EncodeAttributes(authAttribs, 1, - &contentTypeAttrib, 1); - authAttribsCount += 1; - } - - /* authAttribs: add in user authenticated attributes */ - if (pkcs7->authAttribs != NULL && pkcs7->authAttribsSz > 0) { - authAttribsSz += EncodeAttributes(authAttribs + authAttribsCount, - MAX_AUTH_ATTRIBS_SZ - authAttribsCount, - pkcs7->authAttribs, - pkcs7->authAttribsSz); - authAttribsCount += pkcs7->authAttribsSz; - } - - /* authAttribs: flatten authAttribs */ - if (authAttribsSz > 0 && authAttribsCount > 0) { - flatAuthAttribs = (byte*)XMALLOC(authAttribsSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (flatAuthAttribs == NULL) { - return MEMORY_E; - } - - FlattenAttributes(pkcs7, flatAuthAttribs, authAttribs, - authAttribsCount); - - authAttribsSetSz = SetImplicit(ASN_SET, 1, authAttribsSz, - authAttribSet); - - /* From RFC5083, "For the purpose of constructing the AAD, the - * IMPLICIT [1] tag in the authAttrs field is not used for the - * DER encoding: rather a universal SET OF tag is used. */ - authAttribsAadSetSz = SetSet(authAttribsSz, authAttribAadSet); - - /* allocate temp buffer to hold alternate attrib encoding for aad */ - aadBuffer = (byte*)XMALLOC(authAttribsSz + authAttribsAadSetSz, - pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (aadBuffer == NULL) { - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - /* build up alternate attrib encoding for aad */ - aadBufferSz = 0; - XMEMCPY(aadBuffer + aadBufferSz, authAttribAadSet, authAttribsAadSetSz); - aadBufferSz += authAttribsAadSetSz; - XMEMCPY(aadBuffer + aadBufferSz, flatAuthAttribs, authAttribsSz); - aadBufferSz += authAttribsSz; - } - - /* build up unauthenticated attributes (unauthAttrs) */ - if (pkcs7->unauthAttribsSz > 0) { - unauthAttribsSz = EncodeAttributes(unauthAttribs + unauthAttribsCount, - MAX_UNAUTH_ATTRIBS_SZ - unauthAttribsCount, - pkcs7->unauthAttribs, - pkcs7->unauthAttribsSz); - unauthAttribsCount = pkcs7->unauthAttribsSz; - - flatUnauthAttribs = (byte*)XMALLOC(unauthAttribsSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (flatUnauthAttribs == NULL) { - if (aadBuffer) - XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (flatAuthAttribs) - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - FlattenAttributes(pkcs7, flatUnauthAttribs, unauthAttribs, - unauthAttribsCount); - unauthAttribsSetSz = SetImplicit(ASN_SET, 2, unauthAttribsSz, - unauthAttribSet); - } - - /* allocate encrypted content buffer */ - encryptedOutSz = pkcs7->contentSz; - encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (encryptedContent == NULL) { - if (aadBuffer) - XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (flatUnauthAttribs) - XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (flatAuthAttribs) - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - - /* encrypt content */ - ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->cek, - pkcs7->cekSz, nonce, nonceSz, aadBuffer, aadBufferSz, authTag, - sizeof(authTag), pkcs7->content, encryptedOutSz, encryptedContent); - - if (aadBuffer) { - XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER); - aadBuffer = NULL; - } - - if (ret != 0) { - if (flatUnauthAttribs) - XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (flatAuthAttribs) - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - /* EncryptedContentInfo */ - ret = wc_SetContentType(pkcs7->contentOID, contentType, - sizeof(contentType)); - if (ret < 0) { - if (flatUnauthAttribs) - XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (flatAuthAttribs) - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - contentTypeSz = ret; - - /* put together nonce OCTET STRING */ - nonceOctetStringSz = SetOctetString(nonceSz, nonceOctetString); - - /* put together aes-ICVlen INTEGER */ - macIntSz = SetMyVersion(sizeof(authTag), macInt, 0); - - /* build up our ContentEncryptionAlgorithmIdentifier sequence, - * adding (nonceOctetStringSz + blockSz + macIntSz) for nonce OCTET STRING - * and tag size */ - contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, - oidBlkType, nonceOctetStringSz + nonceSz + - macIntSz); - - if (contentEncAlgoSz == 0) { - if (flatUnauthAttribs) - XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (flatAuthAttribs) - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BAD_FUNC_ARG; - } - - encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz, - encContentOctet); - - encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz + - nonceOctetStringSz + nonceSz + macIntSz + - encContentOctetSz + encryptedOutSz, - encContentSeq); - - macOctetStringSz = SetOctetString(sizeof(authTag), macOctetString); - - /* keep track of sizes for outer wrapper layering */ - totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz + - contentEncAlgoSz + nonceOctetStringSz + nonceSz + macIntSz + - encContentOctetSz + encryptedOutSz + authAttribsSz + - authAttribsSetSz + macOctetStringSz + sizeof(authTag) + - unauthAttribsSz + unauthAttribsSetSz; - - /* 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"); - if (flatUnauthAttribs) - XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (flatAuthAttribs) - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(encryptedContent, 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, envDataSeq, envDataSeqSz); - idx += envDataSeqSz; - XMEMCPY(output + idx, ver, verSz); - idx += verSz; - XMEMCPY(output + idx, recipSet, recipSetSz); - idx += recipSetSz; - /* copy in recipients from list */ - tmpRecip = pkcs7->recipList; - while (tmpRecip != NULL) { - XMEMCPY(output + idx, tmpRecip->recip, tmpRecip->recipSz); - idx += tmpRecip->recipSz; - tmpRecip = tmpRecip->next; - } - wc_PKCS7_FreeEncodedRecipientSet(pkcs7); - XMEMCPY(output + idx, encContentSeq, encContentSeqSz); - idx += encContentSeqSz; - XMEMCPY(output + idx, contentType, contentTypeSz); - idx += contentTypeSz; - XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz); - idx += contentEncAlgoSz; - XMEMCPY(output + idx, nonceOctetString, nonceOctetStringSz); - idx += nonceOctetStringSz; - XMEMCPY(output + idx, nonce, nonceSz); - idx += nonceSz; - XMEMCPY(output + idx, macInt, macIntSz); - idx += macIntSz; - XMEMCPY(output + idx, encContentOctet, encContentOctetSz); - idx += encContentOctetSz; - XMEMCPY(output + idx, encryptedContent, encryptedOutSz); - idx += encryptedOutSz; - - /* authenticated attributes */ - if (flatAuthAttribs && authAttribsSz > 0) { - XMEMCPY(output + idx, authAttribSet, authAttribsSetSz); - idx += authAttribsSetSz; - XMEMCPY(output + idx, flatAuthAttribs, authAttribsSz); - idx += authAttribsSz; - XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - - XMEMCPY(output + idx, macOctetString, macOctetStringSz); - idx += macOctetStringSz; - XMEMCPY(output + idx, authTag, sizeof(authTag)); - idx += sizeof(authTag); - - /* unauthenticated attributes */ - if (unauthAttribsSz > 0) { - XMEMCPY(output + idx, unauthAttribSet, unauthAttribsSetSz); - idx += unauthAttribsSetSz; - XMEMCPY(output + idx, flatUnauthAttribs, unauthAttribsSz); - idx += unauthAttribsSz; - } - - if (flatUnauthAttribs != NULL) { - XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return idx; - -#else - WOLFSSL_MSG("AuthEnvelopedData requires AES-GCM or AES-CCM to be enabled"); - (void)pkcs7; - (void)output; - (void)outputSz; - - return NOT_COMPILED_IN; -#endif /* HAVE_AESGCM | HAVE_AESCCM */ -} - - -/* unwrap and decrypt PKCS#7 AuthEnvelopedData object, return decoded size */ -WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* in, - word32 inSz, byte* output, - word32 outputSz) -{ -#if defined(HAVE_AESGCM) || defined(HAVE_AESCCM) - int recipFound = 0; - int ret = 0, length; - word32 idx = 0; -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = 0; - long rc; -#endif - word32 contentType, encOID = 0; - word32 decryptedKeySz = 0; - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - - int expBlockSz = 0, blockKeySz = 0; - byte authTag[AES_BLOCK_SIZE]; - byte nonce[GCM_NONCE_MID_SZ]; /* GCM nonce is larger than CCM */ - int nonceSz = 0, authTagSz = 0, macSz = 0; - -#ifdef WOLFSSL_SMALL_STACK - byte* decryptedKey = NULL; -#else - byte decryptedKey[MAX_ENCRYPTED_KEY_SZ]; -#endif - int encryptedContentSz = 0; - byte* encryptedContent = NULL; - int explicitOctet = 0; - - byte authAttribSetByte = 0; - byte* encodedAttribs = NULL; - word32 encodedAttribIdx = 0, encodedAttribSz = 0; - byte* authAttrib = NULL; - int authAttribSz = 0; - word32 localIdx; - byte tag; - - if (pkcs7 == NULL) - return BAD_FUNC_ARG; - - if (pkiMsg == NULL || pkiMsgSz == 0 || - output == NULL || outputSz == 0) - return BAD_FUNC_ARG; -#ifndef NO_PKCS7_STREAM - if (pkcs7->stream == NULL) { - if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) { - return ret; - } - } -#endif - - switch (pkcs7->state) { - case WC_PKCS7_START: - case WC_PKCS7_INFOSET_START: - case WC_PKCS7_INFOSET_STAGE1: - case WC_PKCS7_INFOSET_STAGE2: - case WC_PKCS7_INFOSET_END: - ret = wc_PKCS7_ParseToRecipientInfoSet(pkcs7, pkiMsg, pkiMsgSz, - &idx, AUTH_ENVELOPED_DATA); - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - tmpIdx = idx; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_2); - FALL_THROUGH; - - case WC_PKCS7_AUTHENV_2: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ + - MAX_VERSION_SZ + ASN_TAG_SZ, &pkiMsg, &idx)) != 0) { - break; - } - #endif - #ifdef WOLFSSL_SMALL_STACK - decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (decryptedKey == NULL) { - ret = MEMORY_E; - break; - } - #ifndef NO_PKCS7_STREAM - pkcs7->stream->key = decryptedKey; - #endif - #endif - FALL_THROUGH; - - case WC_PKCS7_DECRYPT_KTRI: - case WC_PKCS7_DECRYPT_KTRI_2: - case WC_PKCS7_DECRYPT_KTRI_3: - case WC_PKCS7_DECRYPT_KARI: - case WC_PKCS7_DECRYPT_KEKRI: - case WC_PKCS7_DECRYPT_PWRI: - case WC_PKCS7_DECRYPT_ORI: - - decryptedKeySz = MAX_ENCRYPTED_KEY_SZ; - #ifdef WOLFSSL_SMALL_STACK - #ifndef NO_PKCS7_STREAM - decryptedKey = pkcs7->stream->key; - #endif - #endif - - ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx, - decryptedKey, &decryptedKeySz, - &recipFound); - if (ret != 0) { - break; - } - - if (recipFound == 0) { - WOLFSSL_MSG("No recipient found in envelopedData that matches input"); - ret = PKCS7_RECIP_E; - break; - } - - #ifndef NO_PKCS7_STREAM - tmpIdx = idx; - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_3); - FALL_THROUGH; - - case WC_PKCS7_AUTHENV_3: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ + - MAX_ALGO_SZ + MAX_ALGO_SZ + ASN_TAG_SZ, - &pkiMsg, &idx)) != 0) { - break; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, - in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - - /* remove EncryptedContentInfo */ - if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType, - pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, - pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - blockKeySz = wc_PKCS7_GetOIDKeySize(encOID); - if (ret == 0 && blockKeySz < 0) { - ret = blockKeySz; - } - - expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID); - if (ret == 0 && expBlockSz < 0) { - ret = expBlockSz; - } - - /* get nonce, stored in OPTIONAL parameter of AlgoID */ - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && tag != ASN_OCTET_STRING) { - ret = ASN_PARSE_E; - } - - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - wc_PKCS7_StreamStoreVar(pkcs7, encOID, blockKeySz, 0); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_4); - FALL_THROUGH; - - case WC_PKCS7_AUTHENV_4: - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ + - MAX_VERSION_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ, - &pkiMsg, &idx)) != 0) { - break; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - #endif - if (ret == 0 && GetLength(pkiMsg, &idx, &nonceSz, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && nonceSz > (int)sizeof(nonce)) { - WOLFSSL_MSG("AuthEnvelopedData nonce too large for buffer"); - ret = ASN_PARSE_E; - } - - if (ret == 0) { - XMEMCPY(nonce, &pkiMsg[idx], nonceSz); - idx += nonceSz; - } - - /* get mac size, also stored in OPTIONAL parameter of AlgoID */ - if (ret == 0 && GetMyVersion(pkiMsg, &idx, &macSz, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0) { - explicitOctet = 0; - localIdx = idx; - if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 && - tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) - explicitOctet = 1; - - /* read encryptedContent, cont[0] */ - ret = GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz); - } - - if (ret == 0 && - tag != (ASN_CONTEXT_SPECIFIC | 0) && - tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, - pkiMsgSz) <= 0) { - ret = ASN_PARSE_E; - } - - if (explicitOctet) { - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - if (ret == 0 && tag != ASN_OCTET_STRING) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, - pkiMsgSz) <= 0) { - ret = ASN_PARSE_E; - } - } - - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - - /* store nonce for later */ - if (nonceSz > 0) { - pkcs7->stream->nonceSz = nonceSz; - pkcs7->stream->nonce = (byte*)XMALLOC(nonceSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream->nonce == NULL) { - ret = MEMORY_E; - break; - } - else { - XMEMCPY(pkcs7->stream->nonce, nonce, nonceSz); - } - } - - pkcs7->stream->expected = encryptedContentSz; - wc_PKCS7_StreamStoreVar(pkcs7, encOID, blockKeySz, - encryptedContentSz); - #endif - - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_5); - FALL_THROUGH; - - case WC_PKCS7_AUTHENV_5: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ + - ASN_TAG_SZ + ASN_TAG_SZ + pkcs7->stream->expected, - &pkiMsg, &idx)) != 0) { - break; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - encryptedContentSz = pkcs7->stream->expected; - #endif - - encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (ret == 0 && encryptedContent == NULL) { - ret = MEMORY_E; - } - - if (ret == 0) { - XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - idx += encryptedContentSz; - } - #ifndef NO_PKCS7_STREAM - pkcs7->stream->bufferPt = encryptedContent; - #endif - - /* may have IMPLICIT [1] authenticatedAttributes */ - localIdx = idx; - if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 && - tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { - encodedAttribIdx = idx; - encodedAttribs = pkiMsg + idx; - idx++; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - #ifndef NO_PKCS7_STREAM - pkcs7->stream->expected = length; - #endif - encodedAttribSz = length + (idx - encodedAttribIdx); - - if (ret != 0) - break; - - #ifndef NO_PKCS7_STREAM - if (encodedAttribSz > 0) { - pkcs7->stream->aadSz = encodedAttribSz; - pkcs7->stream->aad = (byte*)XMALLOC(encodedAttribSz, - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream->aad == NULL) { - ret = MEMORY_E; - break; - } - else { - XMEMCPY(pkcs7->stream->aad, encodedAttribs, - (idx - encodedAttribIdx)); - } - } - - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRB); - } - else { - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - #endif - goto authenv_atrbend; /* jump over attribute cases */ - } - FALL_THROUGH; - - case WC_PKCS7_AUTHENV_ATRB: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - return ret; - } - - length = pkcs7->stream->expected; - encodedAttribs = pkcs7->stream->aad; - #else - length = 0; - #endif - - /* save pointer and length */ - authAttrib = &pkiMsg[idx]; - authAttribSz = length; - - if (ret == 0 && wc_PKCS7_ParseAttribs(pkcs7, authAttrib, authAttribSz) < 0) { - WOLFSSL_MSG("Error parsing authenticated attributes"); - ret = ASN_PARSE_E; - break; - } - - idx += length; - - #ifndef NO_PKCS7_STREAM - if (encodedAttribSz > 0) { - XMEMCPY(pkcs7->stream->aad + (encodedAttribSz - length), - authAttrib, authAttribSz); - } - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRBEND); - FALL_THROUGH; - -authenv_atrbend: - case WC_PKCS7_AUTHENV_ATRBEND: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ + - ASN_TAG_SZ, &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, - in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - if (pkcs7->stream->aadSz > 0) { - encodedAttribSz = pkcs7->stream->aadSz; - encodedAttribs = pkcs7->stream->aad; - } - #endif - - - /* get authTag OCTET STRING */ - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - if (ret == 0 && tag != ASN_OCTET_STRING) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && GetLength(pkiMsg, &idx, &authTagSz, pkiMsgSz) < 0) { - ret = ASN_PARSE_E; - } - - if (ret == 0 && authTagSz > (int)sizeof(authTag)) { - WOLFSSL_MSG("AuthEnvelopedData authTag too large for buffer"); - ret = ASN_PARSE_E; - } - - if (ret == 0) { - XMEMCPY(authTag, &pkiMsg[idx], authTagSz); - idx += authTagSz; - } - - if (ret == 0 && authAttrib != NULL) { - /* temporarily swap authAttribs byte[0] to SET OF instead of - * IMPLICIT [1], for aad calculation */ - authAttribSetByte = encodedAttribs[0]; - - encodedAttribs[0] = ASN_SET | ASN_CONSTRUCTED; - } - - if (ret < 0) - break; - - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - pkcs7->stream->expected = (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length; - - - /* store tag for later */ - if (authTagSz > 0) { - pkcs7->stream->tagSz = authTagSz; - pkcs7->stream->tag = (byte*)XMALLOC(authTagSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (pkcs7->stream->tag == NULL) { - ret = MEMORY_E; - break; - } - else { - XMEMCPY(pkcs7->stream->tag, authTag, authTagSz); - } - } - - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_6); - FALL_THROUGH; - - case WC_PKCS7_AUTHENV_6: - #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - break; - } - - /* restore all variables needed */ - if (pkcs7->stream->nonceSz > 0) { - nonceSz = pkcs7->stream->nonceSz; - if (nonceSz > GCM_NONCE_MID_SZ) { - WOLFSSL_MSG("PKCS7 saved nonce is too large"); - ret = BUFFER_E; - break; - } - else { - XMEMCPY(nonce, pkcs7->stream->nonce, nonceSz); - } - } - - if (pkcs7->stream->tagSz > 0) { - authTagSz = pkcs7->stream->tagSz; - if (authTagSz > AES_BLOCK_SIZE) { - WOLFSSL_MSG("PKCS7 saved tag is too large"); - ret = BUFFER_E; - break; - } - else { - XMEMCPY(authTag, pkcs7->stream->tag, authTagSz); - } - } - - if (pkcs7->stream->aadSz > 0) { - encodedAttribSz = pkcs7->stream->aadSz; - encodedAttribs = pkcs7->stream->aad; - } - - wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz, - &encryptedContentSz); - encryptedContent = pkcs7->stream->bufferPt; - #ifdef WOLFSSL_SMALL_STACK - decryptedKey = pkcs7->stream->key; - #endif - #endif - - /* decrypt encryptedContent */ - ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey, - blockKeySz, nonce, nonceSz, encodedAttribs, encodedAttribSz, - authTag, authTagSz, encryptedContent, encryptedContentSz, - encryptedContent); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - if (authAttrib != NULL) { - /* restore authAttrib IMPLICIT [1] */ - encodedAttribs[0] = authAttribSetByte; - } - - /* copy plaintext to output */ - XMEMCPY(output, encryptedContent, encryptedContentSz); - - /* free memory, zero out keys */ - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); - #ifdef WOLFSSL_SMALL_STACK - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - decryptedKey = NULL; - #ifdef WOLFSSL_SMALL_STACK - #ifndef NO_PKCS7_STREAM - pkcs7->stream->key = NULL; - #endif - #endif - #endif - ret = encryptedContentSz; - #ifndef NO_PKCS7_STREAM - wc_PKCS7_ResetStream(pkcs7); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - break; - default: - WOLFSSL_MSG("Unknown PKCS7 state"); - ret = BAD_FUNC_ARG; - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) { - if (decryptedKey != NULL) { - ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ); - } - XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } -#endif -#ifndef NO_PKCS7_STREAM - if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) { - wc_PKCS7_ResetStream(pkcs7); - } -#endif - - return ret; - -#else - WOLFSSL_MSG("AuthEnvelopedData requires AES-GCM or AES-CCM to be enabled"); - (void)pkcs7; - (void)in; - (void)inSz; - (void)output; - (void)outputSz; - - return NOT_COMPILED_IN; -#endif /* HAVE_AESGCM | HAVE_AESCCM */ -} - - -#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_OID_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; - - if (pkcs7->version == 3) { - verSz = SetMyVersion(0, ver, 0); - outerContentTypeSz = 0; - } - else { - /* outer content type */ - ret = wc_SetContentType(ENCRYPTED_DATA, outerContentType, - sizeof(outerContentType)); - if (ret < 0) - return ret; - - outerContentTypeSz = ret; - - /* version, 2 if unprotectedAttrs present, 0 if absent */ - if (pkcs7->unprotectedAttribsSz > 0) { - verSz = SetMyVersion(2, ver, 0); - } else { - verSz = SetMyVersion(0, ver, 0); - } - } - - /* EncryptedContentInfo */ - ret = wc_SetContentType(pkcs7->contentOID, contentType, - sizeof(contentType)); - if (ret < 0) - return ret; - - contentTypeSz = ret; - - /* 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 */ - WOLFSSL_MSG("Encrypting the content"); - ret = wc_PKCS7_GenerateBlock(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, NULL, 0, NULL, 0, - 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(pkcs7, 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; - - if (pkcs7->version != 3) { - /* outer content */ - outerContentSz = SetExplicit(0, totalSz, outerContent); - totalSz += outerContentTypeSz; - totalSz += outerContentSz; - /* ContentInfo */ - contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); - totalSz += contentInfoSeqSz; - } else { - contentInfoSeqSz = 0; - outerContentSz = 0; - } - - 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; - byte tag; - - if (pkcs7 == NULL || pkiMsg == NULL || - pkiMsgSz == 0 || inOutIdx == NULL) - return BAD_FUNC_ARG; - - idx = *inOutIdx; - - if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) - return ASN_PARSE_E; - - 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* in, word32 inSz, - byte* output, word32 outputSz) -{ - int ret = 0, version, length = 0, haveAttribs = 0; - word32 idx = 0; - -#ifndef NO_PKCS7_STREAM - word32 tmpIdx = 0; - long rc; -#endif - word32 contentType, encOID; - - int expBlockSz = 0; - byte tmpIvBuf[MAX_CONTENT_IV_SIZE]; - byte *tmpIv = tmpIvBuf; - - int encryptedContentSz = 0; - byte padLen; - byte* encryptedContent = NULL; - - byte* pkiMsg = in; - word32 pkiMsgSz = inSz; - byte tag; - - if (pkcs7 == NULL || - ((pkcs7->encryptionKey == NULL || pkcs7->encryptionKeySz == 0) && - pkcs7->decryptionCb == NULL)) - return BAD_FUNC_ARG; - - if (pkiMsg == NULL || pkiMsgSz == 0 || - output == NULL || outputSz == 0) - return BAD_FUNC_ARG; - -#ifndef NO_PKCS7_STREAM - (void)tmpIv; /* help out static analysis */ - if (pkcs7->stream == NULL) { - if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) { - return ret; - } - } -#endif - - switch (pkcs7->state) { - case WC_PKCS7_START: -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ + - MAX_ALGO_SZ, &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; -#endif - - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (pkcs7->version != 3) { /* ContentInfo not in firmware bundles */ - /* read past ContentInfo, verify type is encrypted-data */ - if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType, - pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && contentType != ENCRYPTED_DATA) { - WOLFSSL_MSG("PKCS#7 input not of type EncryptedData"); - ret = PKCS7_OID_E; - } - } - if (ret != 0) break; -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } -#endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE2); - FALL_THROUGH; - /* end of stage 1 */ - - case WC_PKCS7_STAGE2: -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - MAX_LENGTH_SZ + MAX_SEQ_SZ + ASN_TAG_SZ, &pkiMsg, - &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; -#endif - if (pkcs7->version != 3) { - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - if (ret == 0 && tag != - (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - /* remove EncryptedData and version */ - if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - } - - if (ret != 0) break; -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } -#endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE3); - FALL_THROUGH; - /* end of stage 2 */ - - case WC_PKCS7_STAGE3: -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_ALGO_SZ * 2, - &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; -#endif - /* get version, check later */ - haveAttribs = 0; - if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - /* remove EncryptedContentInfo */ - if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType, - pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && (ret = GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, - pkiMsgSz)) < 0) - ret = ASN_PARSE_E; - if (ret == 0 && (expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID)) < 0) - ret = expBlockSz; - - if (ret != 0) break; -#ifndef NO_PKCS7_STREAM - /* store expBlockSz for later */ - pkcs7->stream->varOne = expBlockSz; - pkcs7->stream->varTwo = encOID; - - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - - /* store version for later */ - pkcs7->stream->vers = version; -#endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE4); - FALL_THROUGH; - /* end of stage 3 */ - - /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ - case WC_PKCS7_STAGE4: -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - ASN_TAG_SZ + MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - /* restore saved variables */ - expBlockSz = pkcs7->stream->varOne; -#endif - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - if (ret == 0 && tag != ASN_OCTET_STRING) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - - if (ret == 0 && length != expBlockSz) { - WOLFSSL_MSG("Incorrect IV length, must be of content alg block size"); - ret = ASN_PARSE_E; - } - - if (ret != 0) break; -#ifndef NO_PKCS7_STREAM - /* next chunk of data expected should have the IV */ - pkcs7->stream->expected = length; - - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } -#endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE5); - FALL_THROUGH; - /* end of stage 4 */ - - case WC_PKCS7_STAGE5: -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected + ASN_TAG_SZ + - MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - /* use IV buffer from stream structure */ - tmpIv = pkcs7->stream->tmpIv; - length = pkcs7->stream->expected; -#endif - XMEMCPY(tmpIv, &pkiMsg[idx], length); - idx += length; - /* read encryptedContent, cont[0] */ - if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - ret = ASN_PARSE_E; - if (ret == 0 && tag != (ASN_CONTEXT_SPECIFIC | 0)) - ret = ASN_PARSE_E; - - if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz, - pkiMsgSz) <= 0) - ret = ASN_PARSE_E; - - if (ret < 0) - break; -#ifndef NO_PKCS7_STREAM - /* next chunk of data should contain encrypted content */ - pkcs7->stream->varThree = encryptedContentSz; - if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) { - break; - } - - if (pkcs7->stream->totalRd + encryptedContentSz < pkiMsgSz) { - pkcs7->stream->flagOne = 1; - } - - pkcs7->stream->expected = (pkcs7->stream->maxLen - - pkcs7->stream->totalRd) + pkcs7->stream->length; - -#endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE6); - FALL_THROUGH; - /* end of stage 5 */ - - case WC_PKCS7_STAGE6: -#ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, - pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { - return ret; - } - - rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, - inSz); - if (rc < 0) { - ret = (int)rc; - break; - } - pkiMsgSz = (word32)rc; - - /* restore saved variables */ - expBlockSz = pkcs7->stream->varOne; - encOID = pkcs7->stream->varTwo; - encryptedContentSz = pkcs7->stream->varThree; - version = pkcs7->stream->vers; - tmpIv = pkcs7->stream->tmpIv; -#else - encOID = 0; -#endif - if (ret == 0 && (encryptedContent = (byte*)XMALLOC( - encryptedContentSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7)) == NULL) { - ret = MEMORY_E; - break; - } - - if (ret == 0) { - XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); - idx += encryptedContentSz; - - /* decrypt encryptedContent */ - ret = wc_PKCS7_DecryptContent(pkcs7, encOID, - pkcs7->encryptionKey, pkcs7->encryptionKeySz, tmpIv, - expBlockSz, NULL, 0, NULL, 0, encryptedContent, - encryptedContentSz, encryptedContent); - if (ret != 0) { - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - } - } - - if (ret == 0) { - padLen = encryptedContent[encryptedContentSz-1]; - - if (padLen > encryptedContentSz) { - WOLFSSL_MSG("Bad padding size found"); - ret = BUFFER_E; - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - break; - } - - /* copy plaintext to output */ - XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); - - /* get implicit[1] unprotected attributes, optional */ - wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap); - pkcs7->decodedAttrib = NULL; - #ifndef NO_PKCS7_STREAM - if (pkcs7->stream->flagOne) - #else - if (idx < pkiMsgSz) - #endif - { - haveAttribs = 1; - - ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg, - pkiMsgSz, &idx); - if (ret != 0) { - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - ret = ASN_PARSE_E; - } - } - } - - if (ret == 0) { - ForceZero(encryptedContent, encryptedContentSz); - XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - /* go back and check the version now that attribs have been processed */ - if (pkcs7->version == 3 && version != 0) { - WOLFSSL_MSG("Wrong PKCS#7 FirmwareEncryptedData version"); - return ASN_VERSION_E; - } - - if (pkcs7->version != 3 && - ((haveAttribs == 0 && version != 0) || - (haveAttribs == 1 && version != 2))) { - WOLFSSL_MSG("Wrong PKCS#7 EncryptedData version"); - return ASN_VERSION_E; - } - ret = encryptedContentSz - padLen; - } - - if (ret != 0) break; - #ifndef NO_PKCS7_STREAM - wc_PKCS7_ResetStream(pkcs7); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - break; - - default: - WOLFSSL_MSG("Error in unknown PKCS#7 Decode Encrypted Data state"); - return BAD_STATE_E; - } - - if (ret != 0) { - #ifndef NO_PKCS7_STREAM - /* restart in error case */ - wc_PKCS7_ResetStream(pkcs7); - #endif - wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START); - } - return ret; -} - - -/* Function to set callback during decryption, this overrides the default - * decryption function and can be used for choosing a key at run time based - * on the parsed bundle so far. - * returns 0 on success - */ -int wc_PKCS7_SetDecodeEncryptedCb(PKCS7* pkcs7, - CallbackDecryptContent decryptionCb) -{ - if (pkcs7 != NULL) { - pkcs7->decryptionCb = decryptionCb; - } - return 0; -} - - -/* Set an optional user context that gets passed to callback - * returns 0 on success - */ -int wc_PKCS7_SetDecodeEncryptedCtx(PKCS7* pkcs7, void* ctx) -{ - if (pkcs7 != NULL) { - pkcs7->decryptionCtx = ctx; - } - return 0; -} -#endif /* NO_PKCS7_ENCRYPTED_DATA */ - -#if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA) - -/* build PKCS#7 compressedData content type, return encrypted size */ -int wc_PKCS7_EncodeCompressedData(PKCS7* pkcs7, byte* output, word32 outputSz) -{ - byte contentInfoSeq[MAX_SEQ_SZ]; - byte contentInfoTypeOid[MAX_OID_SZ]; - byte contentInfoContentSeq[MAX_SEQ_SZ]; /* EXPLICIT [0] */ - byte compressedDataSeq[MAX_SEQ_SZ]; - byte cmsVersion[MAX_VERSION_SZ]; - byte compressAlgId[MAX_ALGO_SZ]; - byte encapContentInfoSeq[MAX_SEQ_SZ]; - byte contentTypeOid[MAX_OID_SZ]; - byte contentSeq[MAX_SEQ_SZ]; /* EXPLICIT [0] */ - byte contentOctetStr[MAX_OCTET_STR_SZ]; - - int ret; - word32 totalSz, idx; - word32 contentInfoSeqSz, contentInfoContentSeqSz, contentInfoTypeOidSz; - word32 compressedDataSeqSz, cmsVersionSz, compressAlgIdSz; - word32 encapContentInfoSeqSz, contentTypeOidSz, contentSeqSz; - word32 contentOctetStrSz; - - byte* compressed; - word32 compressedSz; - - if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 || - output == NULL || outputSz == 0) { - return BAD_FUNC_ARG; - } - - /* allocate space for compressed content. The libz code says the compressed - * buffer should be srcSz + 0.1% + 12. */ - compressedSz = (pkcs7->contentSz + (word32)(pkcs7->contentSz * 0.001) + 12); - compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (compressed == NULL) { - WOLFSSL_MSG("Error allocating memory for CMS compressed content"); - return MEMORY_E; - } - - /* compress content */ - ret = wc_Compress(compressed, compressedSz, pkcs7->content, - pkcs7->contentSz, 0); - if (ret < 0) { - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - compressedSz = (word32)ret; - - /* eContent OCTET STRING, working backwards */ - contentOctetStrSz = SetOctetString(compressedSz, contentOctetStr); - totalSz = contentOctetStrSz + compressedSz; - - /* EXPLICIT [0] eContentType */ - contentSeqSz = SetExplicit(0, totalSz, contentSeq); - totalSz += contentSeqSz; - - /* eContentType OBJECT IDENTIFIER */ - ret = wc_SetContentType(pkcs7->contentOID, contentTypeOid, - sizeof(contentTypeOid)); - if (ret < 0) { - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - contentTypeOidSz = ret; - totalSz += contentTypeOidSz; - - /* EncapsulatedContentInfo SEQUENCE */ - encapContentInfoSeqSz = SetSequence(totalSz, encapContentInfoSeq); - totalSz += encapContentInfoSeqSz; - - /* compressionAlgorithm AlgorithmIdentifier */ - /* Only supports zlib for compression currently: - * id-alg-zlibCompress (1.2.840.113549.1.9.16.3.8) */ - compressAlgIdSz = SetAlgoID(ZLIBc, compressAlgId, oidCompressType, 0); - totalSz += compressAlgIdSz; - - /* version */ - cmsVersionSz = SetMyVersion(0, cmsVersion, 0); - totalSz += cmsVersionSz; - - /* CompressedData SEQUENCE */ - compressedDataSeqSz = SetSequence(totalSz, compressedDataSeq); - totalSz += compressedDataSeqSz; - - /* ContentInfo content EXPLICIT SEQUENCE */ - contentInfoContentSeqSz = SetExplicit(0, totalSz, contentInfoContentSeq); - totalSz += contentInfoContentSeqSz; - - /* ContentInfo ContentType (compressedData) */ - if (pkcs7->version == 3) { - contentInfoTypeOidSz = 0; - } - else { - ret = wc_SetContentType(COMPRESSED_DATA, contentInfoTypeOid, - sizeof(contentInfoTypeOid)); - if (ret < 0) { - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - - contentInfoTypeOidSz = ret; - totalSz += contentInfoTypeOidSz; - } - - /* ContentInfo SEQUENCE */ - contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq); - totalSz += contentInfoSeqSz; - - if (outputSz < totalSz) { - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - idx = 0; - XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz); - idx += contentInfoSeqSz; - XMEMCPY(output + idx, contentInfoTypeOid, contentInfoTypeOidSz); - idx += contentInfoTypeOidSz; - XMEMCPY(output + idx, contentInfoContentSeq, contentInfoContentSeqSz); - idx += contentInfoContentSeqSz; - XMEMCPY(output + idx, compressedDataSeq, compressedDataSeqSz); - idx += compressedDataSeqSz; - XMEMCPY(output + idx, cmsVersion, cmsVersionSz); - idx += cmsVersionSz; - XMEMCPY(output + idx, compressAlgId, compressAlgIdSz); - idx += compressAlgIdSz; - XMEMCPY(output + idx, encapContentInfoSeq, encapContentInfoSeqSz); - idx += encapContentInfoSeqSz; - XMEMCPY(output + idx, contentTypeOid, contentTypeOidSz); - idx += contentTypeOidSz; - XMEMCPY(output + idx, contentSeq, contentSeqSz); - idx += contentSeqSz; - XMEMCPY(output + idx, contentOctetStr, contentOctetStrSz); - idx += contentOctetStrSz; - XMEMCPY(output + idx, compressed, compressedSz); - idx += compressedSz; - - XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return idx; -} - -/* unwrap and decompress PKCS#7/CMS compressedData object, - * returned decoded size */ -int wc_PKCS7_DecodeCompressedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, - byte* output, word32 outputSz) -{ - int length, version, ret; - word32 idx = 0, algOID, contentType; - byte tag; - - byte* decompressed; - word32 decompressedSz; - - if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 || - output == NULL || outputSz == 0) { - return BAD_FUNC_ARG; - } - - /* get ContentInfo SEQUENCE */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (pkcs7->version != 3) { - /* get ContentInfo contentType */ - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (contentType != COMPRESSED_DATA) - return ASN_PARSE_E; - } - - /* get ContentInfo content EXPLICIT SEQUENCE */ - if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get CompressedData SEQUENCE */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get version */ - if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (version != 0) { - WOLFSSL_MSG("CMS CompressedData version MUST be 0, but is not"); - return ASN_PARSE_E; - } - - /* get CompressionAlgorithmIdentifier */ - if (GetAlgoId(pkiMsg, &idx, &algOID, oidIgnoreType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* Only supports zlib for compression currently: - * id-alg-zlibCompress (1.2.840.113549.1.9.16.3.8) */ - if (algOID != ZLIBc) { - WOLFSSL_MSG("CMS CompressedData only supports zlib algorithm"); - return ASN_PARSE_E; - } - - /* get EncapsulatedContentInfo SEQUENCE */ - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get ContentType OID */ - if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) - return ASN_PARSE_E; - - pkcs7->contentOID = contentType; - - /* get eContent EXPLICIT SEQUENCE */ - if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* get content OCTET STRING */ - if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) - return ASN_PARSE_E; - - if (tag != ASN_OCTET_STRING) - return ASN_PARSE_E; - - if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - /* allocate space for decompressed data */ - decompressed = (byte*)XMALLOC(length, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (decompressed == NULL) { - WOLFSSL_MSG("Error allocating memory for CMS decompression buffer"); - return MEMORY_E; - } - - /* decompress content */ - ret = wc_DeCompress(decompressed, length, &pkiMsg[idx], length); - if (ret < 0) { - XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ret; - } - decompressedSz = (word32)ret; - - /* get content */ - if (outputSz < decompressedSz) { - WOLFSSL_MSG("CMS output buffer too small to hold decompressed data"); - XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return BUFFER_E; - } - - XMEMCPY(output, decompressed, decompressedSz); - XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - - return decompressedSz; -} - -#endif /* HAVE_LIBZ && !NO_PKCS7_COMPRESSED_DATA */ - -#else /* HAVE_PKCS7 */ - - -#ifdef _MSC_VER - /* 4206 warning for blank file */ - #pragma warning(disable: 4206) -#endif - - -#endif /* HAVE_PKCS7 */ - |