aboutsummaryrefslogtreecommitdiff
path: root/client/wolfssl/wolfcrypt/src/pkcs7.c
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-22 08:40:38 -0700
committerauth12 <[email protected]>2020-07-22 08:40:38 -0700
commit4ff89e85e74884e8f04edb5c31a94b4323e895e9 (patch)
tree65f98ebf9af0d0947e44bf397b1fac0f107d7a2f /client/wolfssl/wolfcrypt/src/pkcs7.c
parentClient injection. (diff)
downloadloader-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.c12523
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 */
-