summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c')
-rw-r--r--FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c12701
1 files changed, 11683 insertions, 1018 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c
index 2f66ea216..e420cad37 100644
--- a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c
+++ b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pkcs7.c
@@ -1,8 +1,8 @@
/* pkcs7.c
*
- * Copyright (C) 2006-2015 wolfSSL Inc.
+ * Copyright (C) 2006-2020 wolfSSL Inc.
*
- * This file is part of wolfSSL. (formerly known as CyaSSL)
+ * 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
@@ -16,9 +16,10 @@
*
* 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-1301, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -30,45 +31,512 @@
#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
-#ifndef WOLFSSL_HAVE_MIN
-#define WOLFSSL_HAVE_MIN
+/* 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 */
+};
+
- static INLINE word32 min(word32 a, word32 b)
- {
- return a > b ? b : a;
+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;
+}
+
-#endif /* WOLFSSL_HAVE_MIN */
+/* 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 */
-WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output)
+static int wc_SetContentType(int pkcs7TypeOID, byte* output, word32 outputSz)
{
/* PKCS#7 content types, RFC 2315, section 14 */
- static const byte pkcs7[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ const byte pkcs7[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x07 };
- static const byte data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ const byte data[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x07, 0x01 };
- static const byte signedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ const byte signedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x07, 0x02};
- static const byte envelopedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ const byte envelopedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x07, 0x03 };
- static const byte signedAndEnveloped[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ 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 };
- static const byte digestedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+ const byte digestedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x07, 0x05 };
- static const byte encryptedData[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
+#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
- int idSz;
- int typeSz = 0, idx = 0;
+#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];
@@ -87,12 +555,17 @@ WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output)
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;
@@ -103,16 +576,45 @@ WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output)
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);
@@ -121,82 +623,384 @@ WOLFSSL_LOCAL int wc_SetContentType(int pkcs7TypeOID, byte* output)
idx += typeSz;
return idx;
-
}
/* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */
-int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid,
- word32 maxIdx)
+static int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid,
+ word32 maxIdx)
{
- int length;
- word32 i = *inOutIdx;
- byte b;
- *oid = 0;
-
WOLFSSL_ENTER("wc_GetContentType");
+ if (GetObjectId(input, inOutIdx, oid, oidIgnoreType, maxIdx) < 0)
+ return ASN_PARSE_E;
- b = input[i++];
- if (b != ASN_OBJECT_ID)
- return ASN_OBJECT_ID_E;
+ return 0;
+}
- if (GetLength(input, &i, &length, maxIdx) < 0)
- return ASN_PARSE_E;
- while(length--) {
- *oid += input[i];
- i++;
+/* 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;
+}
- *inOutIdx = i;
+
+/* 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;
}
-/* init PKCS7 struct with recipient cert, decode into DecodedCert */
-int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz)
+/* 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;
- XMEMSET(pkcs7, 0, sizeof(PKCS7));
- if (cert != NULL && certSz > 0) {
+ 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), NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
+ dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
+ DYNAMIC_TYPE_DCERT);
if (dCert == NULL)
return MEMORY_E;
#else
- DecodedCert stack_dCert;
- DecodedCert* dCert = &stack_dCert;
+ DecodedCert dCert[1];
#endif
- pkcs7->singleCert = cert;
- pkcs7->singleCertSz = certSz;
- InitDecodedCert(dCert, cert, certSz, 0);
+ 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
#endif
}
@@ -204,10 +1008,265 @@ int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz)
}
+/* 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)
{
- (void)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;
}
@@ -224,6 +1283,10 @@ int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz)
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);
@@ -253,10 +1316,11 @@ typedef struct EncodedAttrib {
typedef struct ESD {
- Sha sha;
- byte contentDigest[SHA_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */
- byte contentAttribsDigest[SHA_DIGEST_SIZE];
- byte encContentDigest[512];
+ 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];
@@ -274,20 +1338,24 @@ typedef struct ESD {
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[6];
+ 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,
- signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz;
+ issuerSnSeqSz, issuerNameSz, issuerSnSz, issuerSKIDSz,
+ issuerSKIDSeqSz, signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz;
word32 encContentDigestSz, signedAttribsSz, signedAttribsCount,
signedAttribSetSz;
} ESD;
@@ -322,12 +1390,112 @@ static int EncodeAttributes(EncodedAttrib* ea, int eaSz,
}
-static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz)
+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)
{
- int i, idx;
+ 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;
+ }
- idx = 0;
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);
@@ -335,293 +1503,893 @@ static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz)
XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz);
idx += ea[i].valueSetSz;
XMEMCPY(output + idx, ea[i].value, ea[i].valueSz);
- idx += ea[i].valueSz;
+
+ fa = derArr[i];
+ fa->data = output;
+ fa->dataSz = sz;
}
+
return 0;
}
-/* build PKCS#7 signedData content type */
-int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz)
+/* Sort and Flatten EncodedAttrib attributes into output buffer */
+static int FlattenAttributes(PKCS7* pkcs7, byte* output, EncodedAttrib* ea,
+ int eaSz)
{
- static const byte outerOid[] =
- { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
- 0x07, 0x02 };
- static const byte innerOid[] =
- { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
- 0x07, 0x01 };
+ 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
- ESD* esd = NULL;
+ RsaKey* privKey;
#else
- ESD stack_esd;
- ESD* esd = &stack_esd;
+ RsaKey privKey[1];
#endif
- word32 signerInfoSz = 0;
- word32 totalSz = 0;
- int idx = 0, ret = 0;
- byte* flatSignedAttribs = NULL;
- word32 flatSignedAttribsSz = 0;
- word32 innerOidSz = sizeof(innerOid);
- word32 outerOidSz = sizeof(outerOid);
+ if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) {
+ return BAD_FUNC_ARG;
+ }
- if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
- pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 ||
- pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 ||
- pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0 ||
- output == NULL || outputSz == 0)
+#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
- esd = (ESD*)XMALLOC(sizeof(ESD), NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (esd == NULL)
+ privKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
+ if (privKey == NULL)
return MEMORY_E;
#endif
- XMEMSET(esd, 0, sizeof(ESD));
- ret = wc_InitSha(&esd->sha);
- if (ret != 0) {
+ 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(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ret;
+
+ 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->contentSz != 0)
- {
- wc_ShaUpdate(&esd->sha, pkcs7->content, pkcs7->contentSz);
- esd->contentDigest[0] = ASN_OCTET_STRING;
- esd->contentDigest[1] = SHA_DIGEST_SIZE;
- wc_ShaFinal(&esd->sha, &esd->contentDigest[2]);
- }
-
- esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets);
- esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz + pkcs7->contentSz,
- esd->innerContSeq);
- esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz + esd->innerOctetsSz +
- innerOidSz + esd->innerContSeqSz,
- esd->contentInfoSeq);
-
- esd->issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz,
- esd->issuerSn);
- signerInfoSz += esd->issuerSnSz;
- esd->issuerNameSz = SetSequence(pkcs7->issuerSz, esd->issuerName);
- signerInfoSz += esd->issuerNameSz + pkcs7->issuerSz;
- esd->issuerSnSeqSz = SetSequence(signerInfoSz, esd->issuerSnSeq);
- signerInfoSz += esd->issuerSnSeqSz;
- esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0);
- signerInfoSz += esd->signerVersionSz;
- esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId,
- hashType, 0);
- signerInfoSz += esd->signerDigAlgoIdSz;
- esd->digEncAlgoIdSz = SetAlgoID(pkcs7->encryptOID, esd->digEncAlgoId,
- keyType, 0);
- signerInfoSz += esd->digEncAlgoIdSz;
-
- if (pkcs7->signedAttribsSz != 0) {
- byte contentTypeOid[] =
- { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
- 0x09, 0x03 };
- byte contentType[] =
- { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x07, 0x01 };
- byte messageDigestOid[] =
- { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
- 0x09, 0x04 };
-
- PKCS7Attrib cannedAttribs[2] =
- {
- { contentTypeOid, sizeof(contentTypeOid),
- contentType, sizeof(contentType) },
- { messageDigestOid, sizeof(messageDigestOid),
- esd->contentDigest, sizeof(esd->contentDigest) }
- };
- word32 cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib);
+ 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], 2,
+ 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
+ }
- flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, 0, NULL);
- flatSignedAttribsSz = esd->signedAttribsSz;
- if (flatSignedAttribs == NULL) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return MEMORY_E;
+#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
}
- FlattenAttributes(flatSignedAttribs,
- esd->signedAttribs, esd->signedAttribsCount);
- esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz,
- esd->signedAttribSet);
+
}
- /* Calculate the final hash and encrypt it. */
- {
- int result;
- word32 scratch = 0;
+#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;
- RsaKey* privKey;
+ byte* digestInfo;
#else
- RsaKey stack_privKey;
- RsaKey* privKey = &stack_privKey;
- byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ +
- MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE];
+ byte digestInfo[MAX_PKCS7_DIGEST_SZ];
#endif
- byte digestInfoSeq[MAX_SEQ_SZ];
- byte digestStr[MAX_OCTET_STR_SZ];
- word32 digestInfoSeqSz, digestStrSz;
- int digIdx = 0;
- if (pkcs7->signedAttribsSz != 0) {
- byte attribSet[MAX_SET_SZ];
- word32 attribSetSz;
+ if (pkcs7 == NULL || esd == NULL)
+ return BAD_FUNC_ARG;
- attribSetSz = SetSet(flatSignedAttribsSz, attribSet);
+#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_InitSha(&esd->sha);
- if (ret < 0) {
- XFREE(flatSignedAttribs, 0, NULL);
+ ret = wc_PKCS7_BuildDigestInfo(pkcs7, flatSignedAttribs,
+ flatSignedAttribsSz, esd, digestInfo,
+ &digestInfoSz);
+ if (ret < 0) {
#ifdef WOLFSSL_SMALL_STACK
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ret;
- }
- wc_ShaUpdate(&esd->sha, attribSet, attribSetSz);
- wc_ShaUpdate(&esd->sha, flatSignedAttribs, flatSignedAttribsSz);
- }
- wc_ShaFinal(&esd->sha, esd->contentAttribsDigest);
+ return ret;
+ }
- digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr);
- digestInfoSeqSz = SetSequence(esd->signerDigAlgoIdSz +
- digestStrSz + SHA_DIGEST_SIZE,
- digestInfoSeq);
+#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
-#ifdef WOLFSSL_SMALL_STACK
- digestInfo = (byte*)XMALLOC(MAX_SEQ_SZ + MAX_ALGO_SZ +
- MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE,
- NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (digestInfo == NULL) {
- if (pkcs7->signedAttribsSz != 0)
- XFREE(flatSignedAttribs, 0, NULL);
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- return MEMORY_E;
- }
+ /* 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
- XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
- digIdx += digestInfoSeqSz;
- XMEMCPY(digestInfo + digIdx,
- esd->signerDigAlgoId, esd->signerDigAlgoIdSz);
- digIdx += esd->signerDigAlgoIdSz;
- XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
- digIdx += digestStrSz;
- XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest,
- SHA_DIGEST_SIZE);
- digIdx += SHA_DIGEST_SIZE;
+ default:
+ WOLFSSL_MSG("Unsupported public key type");
+ ret = BAD_FUNC_ARG;
+ }
#ifdef WOLFSSL_SMALL_STACK
- privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (privKey == NULL) {
- if (pkcs7->signedAttribsSz != 0)
- XFREE(flatSignedAttribs, 0, NULL);
- XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- return MEMORY_E;
- }
+ XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- result = wc_InitRsaKey(privKey, NULL);
- if (result == 0)
- result = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &scratch, privKey,
- pkcs7->privateKeySz);
- if (result < 0) {
- if (pkcs7->signedAttribsSz != 0)
- XFREE(flatSignedAttribs, 0, NULL);
+ 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
- XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (esd == NULL)
+ return MEMORY_E;
#endif
- return PUBLIC_KEY_E;
- }
- result = wc_RsaSSL_Sign(digestInfo, digIdx,
- esd->encContentDigest,
- sizeof(esd->encContentDigest),
- privKey, pkcs7->rng);
+ XMEMSET(esd, 0, sizeof(ESD));
- wc_FreeRsaKey(privKey);
+ /* 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(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
+ return ret;
+ }
+ pkcs7->contentTypeSz = ret;
+ }
- if (result < 0) {
- if (pkcs7->signedAttribsSz != 0)
- XFREE(flatSignedAttribs, 0, NULL);
+ /* set signedData outer content type */
+ ret = wc_SetContentType(SIGNED_DATA, signedDataOid, sizeof(signedDataOid));
+ if (ret < 0) {
#ifdef WOLFSSL_SMALL_STACK
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return result;
+ 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;
}
- esd->encContentDigestSz = (word32)result;
+
+ /* include hash */
+ esd->contentDigest[0] = ASN_OCTET_STRING;
+ esd->contentDigest[1] = (byte)hashSz;
+ XMEMCPY(&esd->contentDigest[2], hashBuf, hashSz);
}
- signerInfoSz += flatSignedAttribsSz + esd->signedAttribSetSz;
- esd->signerDigestSz = SetOctetString(esd->encContentDigestSz,
- esd->signerDigest);
- signerInfoSz += esd->signerDigestSz + esd->encContentDigestSz;
+ 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);
+ }
- esd->signerInfoSeqSz = SetSequence(signerInfoSz, esd->signerInfoSeq);
- signerInfoSz += esd->signerInfoSeqSz;
+ /* 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;
- esd->certsSetSz = SetImplicit(ASN_SET, 0, pkcs7->singleCertSz,
- esd->certsSet);
+ /* certificates [0] IMPLICIT CertificateSet */
+ /* get total certificates size */
+ certPtr = pkcs7->certList;
+ while (certPtr != NULL) {
+ certSetSz += certPtr->derSz;
+ certPtr = certPtr->next;
+ }
+ certPtr = NULL;
- esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId,
- hashType, 0);
- esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet);
+ 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);
- esd->versionSz = SetMyVersion(1, esd->version, 0);
+ 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 + esd->certsSetSz + pkcs7->singleCertSz +
- esd->innerOctetsSz + esd->innerContSeqSz +
- innerOidSz + pkcs7->contentSz +
- signerInfoSz;
- esd->innerSeqSz = SetSequence(totalSz, esd->innerSeq);
+ 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, esd->outerContent);
- totalSz += esd->outerContentSz + outerOidSz;
- esd->outerSeqSz = SetSequence(totalSz, esd->outerSeq);
+ esd->outerContentSz = SetExplicit(0, totalSz + total2Sz, esd->outerContent);
+ totalSz += esd->outerContentSz + signedDataOidSz;
+ esd->outerSeqSz = SetSequence(totalSz + total2Sz, esd->outerSeq);
totalSz += esd->outerSeqSz;
- if (outputSz < totalSz) {
+ /* 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, 0, NULL);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
+ XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
return BUFFER_E;
}
idx = 0;
XMEMCPY(output + idx, esd->outerSeq, esd->outerSeqSz);
idx += esd->outerSeqSz;
- XMEMCPY(output + idx, outerOid, outerOidSz);
- idx += outerOidSz;
+ XMEMCPY(output + idx, signedDataOid, signedDataOidSz);
+ idx += signedDataOidSz;
XMEMCPY(output + idx, esd->outerContent, esd->outerContentSz);
idx += esd->outerContentSz;
XMEMCPY(output + idx, esd->innerSeq, esd->innerSeqSz);
@@ -634,326 +2402,3617 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz)
idx += esd->singleDigAlgoIdSz;
XMEMCPY(output + idx, esd->contentInfoSeq, esd->contentInfoSeqSz);
idx += esd->contentInfoSeqSz;
- XMEMCPY(output + idx, innerOid, innerOidSz);
- idx += innerOidSz;
+ 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;
- XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
- idx += pkcs7->contentSz;
- XMEMCPY(output + idx, esd->certsSet, esd->certsSetSz);
+
+ /* 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;
- XMEMCPY(output + idx, pkcs7->singleCert, pkcs7->singleCertSz);
- idx += pkcs7->singleCertSz;
- XMEMCPY(output + idx, esd->signerInfoSet, esd->signerInfoSetSz);
+ 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(output + idx, esd->signerInfoSeq, esd->signerInfoSeqSz);
+ XMEMCPY(output2 + idx, esd->signerInfoSeq, esd->signerInfoSeqSz);
idx += esd->signerInfoSeqSz;
- XMEMCPY(output + idx, esd->signerVersion, esd->signerVersionSz);
+ XMEMCPY(output2 + idx, esd->signerVersion, esd->signerVersionSz);
idx += esd->signerVersionSz;
- XMEMCPY(output + idx, esd->issuerSnSeq, esd->issuerSnSeqSz);
- idx += esd->issuerSnSeqSz;
- XMEMCPY(output + idx, esd->issuerName, esd->issuerNameSz);
- idx += esd->issuerNameSz;
- XMEMCPY(output + idx, pkcs7->issuer, pkcs7->issuerSz);
- idx += pkcs7->issuerSz;
- XMEMCPY(output + idx, esd->issuerSn, esd->issuerSnSz);
- idx += esd->issuerSnSz;
- XMEMCPY(output + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz);
+ /* 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 (pkcs7->signedAttribsSz != 0) {
- XMEMCPY(output + idx, esd->signedAttribSet, esd->signedAttribSetSz);
+ if (flatSignedAttribsSz > 0) {
+ XMEMCPY(output2 + idx, esd->signedAttribSet, esd->signedAttribSetSz);
idx += esd->signedAttribSetSz;
- XMEMCPY(output + idx, flatSignedAttribs, flatSignedAttribsSz);
+ XMEMCPY(output2 + idx, flatSignedAttribs, flatSignedAttribsSz);
idx += flatSignedAttribsSz;
- XFREE(flatSignedAttribs, 0, NULL);
+ XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
}
- XMEMCPY(output + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz);
+ XMEMCPY(output2 + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz);
idx += esd->digEncAlgoIdSz;
- XMEMCPY(output + idx, esd->signerDigest, esd->signerDigestSz);
+ XMEMCPY(output2 + idx, esd->signerDigest, esd->signerDigestSz);
idx += esd->signerDigestSz;
- XMEMCPY(output + idx, esd->encContentDigest, esd->encContentDigestSz);
+ 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
-/* Finds the certificates in the message and saves it. */
-int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
+ /* 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)
{
- word32 idx, contentType;
- int length, version, ret;
- byte* content = NULL;
- byte* sig = NULL;
- byte* cert = NULL;
- int contentSz = 0, sigSz = 0, certSz = 0;
+ if (pkcs7 == NULL || (flag != 0 && flag != 1))
+ return BAD_FUNC_ARG;
+
+ pkcs7->detached = flag;
+
+ return 0;
+}
- if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 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;
- idx = 0;
+ pkcs7->skipDefaultSignedAttribs = 1;
- /* Get the contentInfo sequence */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ return 0;
+}
- /* Get the contentInfo contentType */
- if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+/* 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
- if (contentType != SIGNED_DATA) {
- WOLFSSL_MSG("PKCS#7 input not of type SignedData");
- return PKCS7_OID_E;
+ /* other args checked in wc_PKCS7_EncodeSigned_ex */
+ if (pkcs7 == NULL || pkcs7->contentSz == 0 || pkcs7->content == NULL) {
+ return BAD_FUNC_ARG;
}
- /* get the ContentInfo content */
- if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
- return ASN_PARSE_E;
+ /* get hash type and size, validate hashOID */
+ hashType = wc_OidGetHash(pkcs7->hashOID);
+ hashSz = wc_HashGetDigestSize(hashType);
+ if (hashSz < 0)
+ return hashSz;
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+#ifdef WOLFSSL_SMALL_STACK
+ esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (esd == NULL)
+ return MEMORY_E;
+#endif
- /* Get the signedData sequence */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ 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);
+ }
- /* Get the version */
- if (GetMyVersion(pkiMsg, &idx, &version) < 0)
- return ASN_PARSE_E;
+ 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;
- if (version != 1) {
- WOLFSSL_MSG("PKCS#7 signedData needs to be of version 1");
- return ASN_VERSION_E;
+ 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");
}
- /* Get the set of DigestAlgorithmIdentifiers */
- if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ pkcs7->rng = NULL;
+ wc_FreeRng(&rng);
- /* Skip the set. */
- idx += length;
+ return ret;
+}
- /* Get the inner ContentInfo sequence */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+#ifndef NO_PKCS7_ENCRYPTED_DATA
- /* Get the inner ContentInfo contentType */
- if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+/* 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);
- if (contentType != DATA) {
- WOLFSSL_MSG("PKCS#7 inner input not of type Data");
- return PKCS7_OID_E;
+
+ /* 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;
+}
- if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 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;
+ }
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+ /* advance past attrib->value ASN.1 header and length */
+ if (attrib->value == NULL || attrib->valueSz == 0)
return ASN_PARSE_E;
- if (pkiMsg[idx++] != ASN_OCTET_STRING)
+ if (attrib->value[idx++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+ if (GetLength(attrib->value, &idx, &innerAttribSz, attrib->valueSz) < 0)
return ASN_PARSE_E;
- /* Save the inner data as the content. */
- if (length > 0) {
- /* Local pointer for calculating hashes later */
- pkcs7->content = content = &pkiMsg[idx];
- pkcs7->contentSz = contentSz = length;
- idx += length;
+ /* 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;
}
- /* Get the implicit[0] set of certificates */
- if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
- idx++;
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ /* build content hash if needed, or use existing hash value */
+ if (hashBuf == NULL) {
- 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. */
+#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);
- word32 certIdx = idx;
+ 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;
+ }
- if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
- if (GetLength(pkiMsg, &certIdx, &certSz, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ 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
+ }
- cert = &pkiMsg[idx];
- certSz += (certIdx - idx);
+ 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;
}
- wc_PKCS7_InitWithCert(pkcs7, cert, certSz);
+ 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;
}
- idx += length;
}
- /* Get the implicit[1] set of crls */
- if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
- idx++;
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
- /* Skip the set */
- idx += length;
+
+ 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;
}
- /* Get the set of signerInfos */
- if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+ return ret;
+}
- if (length > 0) {
- /* Get the sequence of the first signerInfo */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
- /* Get the version */
- if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+/* 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;
- if (version != 1) {
- WOLFSSL_MSG("PKCS#7 signerInfo needs to be of version 1");
- return ASN_VERSION_E;
+ attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib),
+ pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ if (attrib == NULL) {
+ return MEMORY_E;
}
+ XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib));
- /* Get the sequence of IssuerAndSerialNumber */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+ 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);
- /* Skip it */
- idx += length;
+ /* 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;
+ }
- /* Get the sequence of digestAlgorithm */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+ if ((inSz - idx) < (word32)length) {
+ XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
return ASN_PARSE_E;
+ }
- /* Skip it */
+ 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 */
- if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
+ localIdx = idx;
+ if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
+ tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
idx++;
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ 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 the sequence of digestEncryptionAlgorithm */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ /* Get digestEncryptionAlgorithm */
+ if (ret == 0 && GetAlgoId(in, &idx, &sigOID, oidSigType, inSz) < 0) {
+ ret = ASN_PARSE_E;
+ }
- /* Skip it */
- idx += length;
+ /* 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;
+ }
+ }
+ }
- /* Get the signature */
- if (pkiMsg[idx] == ASN_OCTET_STRING) {
- idx++;
+ /* update index on success */
+ if (ret == 0) {
+ *idxIn = idx;
+ }
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ return ret;
+}
- /* save pointer and length */
- sig = &pkiMsg[idx];
- sigSz = length;
+/* 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;
}
- pkcs7->content = content;
- pkcs7->contentSz = contentSz;
+ return 0;
+ }
- {
- word32 scratch = 0;
- int plainSz = 0;
- int digestSz = MAX_SEQ_SZ + MAX_ALGO_SZ +
- MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE;
+ /* allocate space for cek */
+ tmpKey = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ if (tmpKey == NULL)
+ return MEMORY_E;
-#ifdef WOLFSSL_SMALL_STACK
- byte* digest;
- RsaKey* key;
+ XMEMSET(tmpKey, 0, len);
- digest = (byte*)XMALLOC(digestSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
+ if (ret != 0) {
+ XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return ret;
+ }
- if (digest == NULL)
- return MEMORY_E;
+ ret = wc_RNG_GenerateBlock(&rng, tmpKey, len);
+ if (ret != 0) {
+ wc_FreeRng(&rng);
+ XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return ret;
+ }
- key = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (key == NULL) {
- XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- return MEMORY_E;
+ /* 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 digest[digestSz];
- RsaKey stack_key;
- RsaKey* key = &stack_key;
+ byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
#endif
- XMEMSET(digest, 0, digestSz);
+ /* 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));
- ret = wc_InitRsaKey(key, NULL);
- if (ret != 0) {
+ /* get key size for content-encryption key based on algorithm */
+ blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
+ if (blockKeySz < 0) {
#ifdef WOLFSSL_SMALL_STACK
- XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ret;
- }
- if (wc_RsaPublicKeyDecode(pkcs7->publicKey, &scratch, key,
- pkcs7->publicKeySz) < 0) {
- WOLFSSL_MSG("ASN RSA key decode error");
+ 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(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return PUBLIC_KEY_E;
- }
+ XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return ret;
+ }
- plainSz = wc_RsaSSL_Verify(sig, sigSz, digest, digestSz, key);
- wc_FreeRsaKey(key);
+ /* 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(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
+ XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return MEMORY_E;
+ }
- if (plainSz < 0)
- return plainSz;
+ /* 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;
}
- return 0;
+ (void)options;
+
+ return idx;
}
+#endif /* HAVE_ECC */
+
+#ifndef NO_RSA
-/* create ASN.1 fomatted RecipientInfo structure, returns sequence size */
-WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz,
- int keyEncAlgo, int blockKeySz,
- RNG* rng, byte* contentKeyPlain,
- byte* contentKeyEnc,
- int* keyEncSz, byte* out, word32 outSz)
+/* 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;
- int ret = 0, totalSz = 0;
- int verSz, issuerSz, snSz, keyEncAlgSz;
- int issuerSeqSz, recipSeqSz, issuerSerialSeqSz;
+ 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];
@@ -961,241 +6020,1696 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz,
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* serial;
+ byte* keyAlgArray;
+ byte* encryptedKey;
RsaKey* pubKey;
DecodedCert* decoded;
- serial = (byte*)XMALLOC(MAX_SN_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- keyAlgArray = (byte*)XMALLOC(MAX_SN_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
-
- if (decoded == NULL || serial == NULL || keyAlgArray == NULL) {
- if (serial) XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (keyAlgArray) XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (decoded) XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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];
-
- RsaKey stack_pubKey;
- RsaKey* pubKey = &stack_pubKey;
- DecodedCert stack_decoded;
- DecodedCert* decoded = &stack_decoded;
+ 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, 0);
+ 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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;
}
- /* version */
- verSz = SetMyVersion(0, ver, 0);
+ if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
- /* IssuerAndSerialNumber */
- if (decoded->issuerRaw == NULL || decoded->issuerRawLen == 0) {
- WOLFSSL_MSG("DecodedCert lacks raw issuer pointer and length");
- FreeDecodedCert(decoded);
+ /* 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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
- return -1;
- }
- issuerSz = decoded->issuerRawLen;
- issuerSeqSz = SetSequence(issuerSz, issuerSeq);
+ 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");
+ 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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
- return -1;
+ XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return PKCS7_RECIP_E;
}
- snSz = SetSerialNumber(decoded->serial, decoded->serialSz, serial);
- issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz,
- issuerSerialSeq);
+ pkcs7->publicKeyOID = decoded->keyOID;
/* KeyEncryptionAlgorithmIdentifier, only support RSA now */
- if (keyEncAlgo != RSAk) {
+ if (pkcs7->publicKeyOID != RSAk) {
FreeDecodedCert(decoded);
#ifdef WOLFSSL_SMALL_STACK
- XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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 ALGO_ID_E;
}
- keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0);
+ keyEncAlgSz = SetAlgoID(pkcs7->publicKeyOID, keyAlgArray, oidKeyType, 0);
if (keyEncAlgSz == 0) {
FreeDecodedCert(decoded);
#ifdef WOLFSSL_SMALL_STACK
- XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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 BAD_FUNC_ARG;
}
#ifdef WOLFSSL_SMALL_STACK
- pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
+ DYNAMIC_TYPE_TMP_BUFFER);
if (pubKey == NULL) {
FreeDecodedCert(decoded);
- XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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);
+ XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
return MEMORY_E;
}
#endif
/* EncryptedKey */
- ret = wc_InitRsaKey(pubKey, 0);
+ ret = wc_InitRsaKey_ex(pubKey, pkcs7->heap, INVALID_DEVID);
if (ret != 0) {
FreeDecodedCert(decoded);
#ifdef WOLFSSL_SMALL_STACK
- XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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) {
+ decoded->pubKeySize) < 0) {
WOLFSSL_MSG("ASN RSA key decode error");
wc_FreeRsaKey(pubKey);
FreeDecodedCert(decoded);
#ifdef WOLFSSL_SMALL_STACK
- XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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;
}
- *keyEncSz = wc_RsaPublicEncrypt(contentKeyPlain, blockKeySz, contentKeyEnc,
- MAX_ENCRYPTED_KEY_SZ, pubKey, rng);
+ 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- if (*keyEncSz < 0) {
+ if (ret < 0) {
WOLFSSL_MSG("RSA Public Encrypt failed");
FreeDecodedCert(decoded);
#ifdef WOLFSSL_SMALL_STACK
- XFREE(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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
- return *keyEncSz;
+ XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return ret;
}
+ encryptedKeySz = ret;
- encKeyOctetStrSz = SetOctetString(*keyEncSz, encKeyOctetStr);
+ encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr);
/* RecipientInfo */
- recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz +
- issuerSz + snSz + keyEncAlgSz + encKeyOctetStrSz +
- *keyEncSz, recipSeq);
+ 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;
+ }
- if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz +
- keyEncAlgSz + encKeyOctetStrSz + *keyEncSz > (int)outSz) {
- WOLFSSL_MSG("RecipientInfo output buffer too small");
- FreeDecodedCert(decoded);
+ } 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, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, 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 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);
}
- XMEMCPY(out + totalSz, recipSeq, recipSeqSz);
+ 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;
- XMEMCPY(out + totalSz, ver, verSz);
+
+ 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;
- XMEMCPY(out + totalSz, issuerSerialSeq, issuerSerialSeqSz);
- totalSz += issuerSerialSeqSz;
- XMEMCPY(out + totalSz, issuerSeq, issuerSeqSz);
- totalSz += issuerSeqSz;
- XMEMCPY(out + totalSz, decoded->issuerRaw, issuerSz);
- totalSz += issuerSz;
- XMEMCPY(out + totalSz, serial, snSz);
- totalSz += snSz;
- XMEMCPY(out + totalSz, keyAlgArray, keyEncAlgSz);
- totalSz += keyEncAlgSz;
- XMEMCPY(out + totalSz, encKeyOctetStr, encKeyOctetStrSz);
- totalSz += encKeyOctetStrSz;
- XMEMCPY(out + totalSz, contentKeyEnc, *keyEncSz);
- totalSz += *keyEncSz;
+ recip->recipVersion = 4;
- FreeDecodedCert(decoded);
+ /* 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(serial, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(keyAlgArray, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(decoded, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
#endif
- return totalSz;
+ /* 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 i, ret = 0, idx = 0;
- int totalSz = 0, padSz = 0, desOutSz = 0;
+ int ret, idx = 0;
+ int totalSz, padSz, encryptedOutSz;
- int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
+ 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];
- RNG rng;
- int contentKeyEncSz, blockKeySz;
- int dynamicFlag = 0;
- byte contentKeyPlain[MAX_CONTENT_KEY_LEN];
-#ifdef WOLFSSL_SMALL_STACK
- byte* contentKeyEnc;
-#else
- byte contentKeyEnc[MAX_ENCRYPTED_KEY_SZ];
-#endif
+ WC_RNG rng;
+ int blockSz, blockKeySz;
byte* plain;
byte* encryptedContent;
+ Pkcs7EncodedRecip* tmpRecip = NULL;
int recipSz, recipSetSz;
-#ifdef WOLFSSL_SMALL_STACK
- byte* recip;
-#else
- byte recip[MAX_RECIP_SZ];
-#endif
byte recipSet[MAX_SET_SZ];
int encContentOctetSz, encContentSeqSz, contentTypeSz;
@@ -1203,204 +7717,3109 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz)
byte encContentSeq[MAX_SEQ_SZ];
byte contentType[MAX_ALGO_SZ];
byte contentEncAlgo[MAX_ALGO_SZ];
- byte tmpIv[DES_BLOCK_SIZE];
+ byte tmpIv[MAX_CONTENT_IV_SIZE];
byte ivOctetString[MAX_OCTET_STR_SZ];
byte encContentOctet[MAX_OCTET_STR_SZ];
- if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
- pkcs7->encryptOID == 0 || pkcs7->singleCert == NULL)
+ if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0)
return BAD_FUNC_ARG;
if (output == NULL || outputSz == 0)
return BAD_FUNC_ARG;
- /* PKCS#7 only supports DES, 3DES for now */
- switch (pkcs7->encryptOID) {
- case DESb:
- blockKeySz = DES_KEYLEN;
- break;
+ blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
+ if (blockKeySz < 0)
+ return blockKeySz;
- case DES3b:
- blockKeySz = DES3_KEYLEN;
+ 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("Unsupported content cipher type");
- return ALGO_ID_E;
- };
+ WOLFSSL_MSG("PKCS7 Unknown KTRI decrypt state");
+ ret = BAD_FUNC_ARG;
+ }
- /* outer content type */
- outerContentTypeSz = wc_SetContentType(ENVELOPED_DATA, outerContentType);
+ return ret;
+}
+#endif /* !NO_RSA */
- /* version, defined as 0 in RFC 2315 */
- verSz = SetMyVersion(0, ver, 0);
+#ifdef HAVE_ECC
- /* generate random content encryption key */
- ret = wc_InitRng(&rng);
+/* 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;
- ret = wc_RNG_GenerateBlock(&rng, contentKeyPlain, blockKeySz);
+ 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) {
- wc_FreeRng(&rng);
- return ret;
+ 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
- recip = (byte*)XMALLOC(MAX_RECIP_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- contentKeyEnc = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (contentKeyEnc == NULL || recip == NULL) {
- if (recip) XFREE(recip, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (contentKeyEnc) XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- wc_FreeRng(&rng);
+ 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
- /* build RecipientInfo, only handle 1 for now */
- recipSz = wc_CreateRecipientInfo(pkcs7->singleCert, pkcs7->singleCertSz, RSAk,
- blockKeySz, &rng, contentKeyPlain,
- contentKeyEnc, &contentKeyEncSz, recip,
- MAX_RECIP_SZ);
-
- ForceZero(contentKeyEnc, MAX_ENCRYPTED_KEY_SZ);
-
+ if (GetInt(serial, pkiMsg, idx, pkiMsgSz) < 0) {
#ifdef WOLFSSL_SMALL_STACK
- XFREE(contentKeyEnc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
+ return ASN_PARSE_E;
+ }
- if (recipSz < 0) {
- WOLFSSL_MSG("Failed to create RecipientInfo");
- wc_FreeRng(&rng);
+ 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(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return recipSz;
+ return ret;
}
- recipSetSz = SetSet(recipSz, recipSet);
- /* generate IV for block cipher */
- ret = wc_RNG_GenerateBlock(&rng, tmpIv, DES_BLOCK_SIZE);
- wc_FreeRng(&rng);
- if (ret != 0) {
+ 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(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ret;
+ return PKCS7_RECIP_E;
}
- /* EncryptedContentInfo */
- contentTypeSz = wc_SetContentType(pkcs7->contentOID, contentType);
- if (contentTypeSz == 0) {
+ mp_clear(serial);
+ mp_clear(recipSerial);
+
#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ 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);
}
- /* allocate encrypted content buffer, pad if necessary, PKCS#7 padding */
- padSz = DES_BLOCK_SIZE - (pkcs7->contentSz % DES_BLOCK_SIZE);
- desOutSz = pkcs7->contentSz + padSz;
+ /* 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];
- if (padSz != 0) {
- plain = (byte*)XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (plain == NULL) {
#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ byte* encryptedKey;
+#else
+ byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
#endif
- return MEMORY_E;
- }
- XMEMCPY(plain, pkcs7->content, pkcs7->contentSz);
- dynamicFlag = 1;
- for (i = 0; i < padSz; i++) {
- plain[pkcs7->contentSz + i] = padSz;
+ 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;
- } else {
- plain = pkcs7->content;
- desOutSz = pkcs7->contentSz;
}
- encryptedContent = (byte*)XMALLOC(desOutSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (encryptedContent == NULL) {
- if (dynamicFlag)
- XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ (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
- return MEMORY_E;
+
+ if (pkcs7 == NULL || pkiMsg == NULL || idx == NULL ||
+ decryptedKey == NULL || decryptedKeySz == NULL ||
+ recipFound == NULL) {
+ return BAD_FUNC_ARG;
}
- /* put together IV OCTET STRING */
- ivOctetStringSz = SetOctetString(DES_BLOCK_SIZE, ivOctetString);
+ WOLFSSL_ENTER("wc_PKCS7_DecryptRecipientInfos");
+#ifndef NO_PKCS7_STREAM
+ tmpIdx = *idx;
+#endif
- /* build up our ContentEncryptionAlgorithmIdentifier sequence,
- * adding (ivOctetStringSz + DES_BLOCK_SIZE) for IV OCTET STRING */
- contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
- blkType, ivOctetStringSz + DES_BLOCK_SIZE);
+ /* 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;
- if (contentEncAlgoSz == 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (dynamicFlag)
- XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ 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
- /* encrypt content */
- if (pkcs7->encryptOID == DESb) {
- Des des;
+ 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;
- ret = wc_Des_SetKey(&des, contentKeyPlain, tmpIv, DES_ENCRYPTION);
+ default:
+ WOLFSSL_MSG("Warning, setting PKCS7 info state to start");
+ wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_START);
+ }
- if (ret == 0)
- wc_Des_CbcEncrypt(&des, encryptedContent, plain, desOutSz);
+ 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;
+ }
- if (ret != 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (dynamicFlag)
- XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ 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;
}
}
- else if (pkcs7->encryptOID == DES3b) {
- Des3 des3;
+#endif
- ret = wc_Des3_SetKey(&des3, contentKeyPlain, tmpIv, DES_ENCRYPTION);
+ 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;
+ }
- if (ret == 0)
- ret = wc_Des3_CbcEncrypt(&des3, encryptedContent, plain, desOutSz);
+ #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
- if (ret != 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (dynamicFlag)
- XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
+ 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;
}
}
- encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0,
- desOutSz, encContentOctet);
+ 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 +
- ivOctetStringSz + DES_BLOCK_SIZE +
- encContentOctetSz + desOutSz, encContentSeq);
+ 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 + ivOctetStringSz + DES_BLOCK_SIZE +
- encContentOctetSz + desOutSz;
+ contentEncAlgoSz + nonceOctetStringSz + nonceSz + macIntSz +
+ encContentOctetSz + encryptedOutSz + authAttribsSz +
+ authAttribsSetSz + macOctetStringSz + sizeof(authTag) +
+ unauthAttribsSz + unauthAttribsSetSz;
/* EnvelopedData */
envDataSeqSz = SetSequence(totalSz, envDataSeq);
@@ -1417,12 +10836,11 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz)
if (totalSz > (int)outputSz) {
WOLFSSL_MSG("Pkcs7_encrypt output buffer too small");
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (dynamicFlag)
- XFREE(plain, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
-#endif
+ 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;
}
@@ -1438,412 +10856,1659 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz)
idx += verSz;
XMEMCPY(output + idx, recipSet, recipSetSz);
idx += recipSetSz;
- XMEMCPY(output + idx, recip, recipSz);
- idx += recipSz;
+ /* 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, DES_BLOCK_SIZE);
- idx += DES_BLOCK_SIZE;
+ 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, desOutSz);
- idx += desOutSz;
+ 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);
+ }
- ForceZero(contentKeyPlain, MAX_CONTENT_KEY_LEN);
+ 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 (dynamicFlag)
- XFREE(plain, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(recip, NULL, DYNAMMIC_TYPE_TMP_BUFFER);
-#endif
+ 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 envelopedData object, return decoded size */
-WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
- word32 pkiMsgSz, byte* output,
- word32 outputSz)
+
+/* 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, version, length;
- word32 savedIdx = 0, idx = 0;
- word32 contentType, encOID;
- byte issuerHash[SHA_DIGEST_SIZE];
+ 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 encryptedKeySz, keySz;
- byte tmpIv[DES_BLOCK_SIZE];
- byte* decryptedKey = NULL;
+ 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
- mp_int* serialNum;
- byte* encryptedKey;
- RsaKey* privKey;
+ byte* decryptedKey = NULL;
#else
- mp_int stack_serialNum;
- mp_int* serialNum = &stack_serialNum;
- byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
-
- RsaKey stack_privKey;
- RsaKey* privKey = &stack_privKey;
+ byte decryptedKey[MAX_ENCRYPTED_KEY_SZ];
#endif
- int encryptedContentSz;
- byte padLen;
+ 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 || pkcs7->singleCert == NULL ||
- pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL ||
- pkcs7->privateKeySz == 0)
+ 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
- /* read past ContentInfo, verify type is envelopedData */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ 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 (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ if (recipFound == 0) {
+ WOLFSSL_MSG("No recipient found in envelopedData that matches input");
+ ret = PKCS7_RECIP_E;
+ break;
+ }
- if (contentType != ENVELOPED_DATA) {
- WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData");
- return PKCS7_OID_E;
- }
+ #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;
+ }
- if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
- return ASN_PARSE_E;
+ rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
+ in, inSz);
+ if (rc < 0) {
+ ret = (int)rc;
+ break;
+ }
+ pkiMsgSz = (word32)rc;
+ #endif
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ /* remove EncryptedContentInfo */
+ if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+ ret = ASN_PARSE_E;
+ }
- /* remove EnvelopedData and version */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
+ if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
+ pkiMsgSz) < 0) {
+ ret = ASN_PARSE_E;
+ }
- if (GetMyVersion(pkiMsg, &idx, &version) < 0)
- return ASN_PARSE_E;
+ if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
+ pkiMsgSz) < 0) {
+ ret = ASN_PARSE_E;
+ }
- if (version != 0) {
- WOLFSSL_MSG("PKCS#7 envelopedData needs to be of version 0");
- return ASN_VERSION_E;
- }
+ blockKeySz = wc_PKCS7_GetOIDKeySize(encOID);
+ if (ret == 0 && blockKeySz < 0) {
+ ret = blockKeySz;
+ }
- /* walk through RecipientInfo set, find correct recipient */
- if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
- return ASN_PARSE_E;
-
-#ifdef WOLFSSL_SMALL_STACK
- encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (encryptedKey == NULL)
- return MEMORY_E;
-#endif
-
- savedIdx = idx;
- recipFound = 0;
+ expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID);
+ if (ret == 0 && expBlockSz < 0) {
+ ret = expBlockSz;
+ }
- /* when looking for next recipient, use first sequence and version to
- * indicate there is another, if not, move on */
- while(recipFound == 0) {
+ /* get nonce, stored in OPTIONAL parameter of AlgoID */
+ if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
+ ret = ASN_PARSE_E;
+ }
- /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to
- * last good saved one */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
- idx = savedIdx;
- break;
- }
+ if (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
- if (GetMyVersion(pkiMsg, &idx, &version) < 0) {
- idx = savedIdx;
+ 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;
+ }
- if (version != 0) {
#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return ASN_VERSION_E;
+ if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) {
+ if (decryptedKey != NULL) {
+ ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
}
-
- /* remove IssuerAndSerialNumber */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ }
#endif
- return ASN_PARSE_E;
- }
-
- if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifndef NO_PKCS7_STREAM
+ if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) {
+ wc_PKCS7_ResetStream(pkcs7);
+ }
#endif
- return ASN_PARSE_E;
+
+ 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);
}
-
- /* if we found correct recipient, issuer hashes will match */
- if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) {
- recipFound = 1;
+ }
+
+ /* 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;
}
-
-#ifdef WOLFSSL_SMALL_STACK
- serialNum = (mp_int*)XMALLOC(sizeof(mp_int), NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (serialNum == NULL) {
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+ 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;
}
-#endif
-
- if (GetInt(serialNum, pkiMsg, &idx, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return ASN_PARSE_E;
+
+ 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;
}
-
- mp_clear(serialNum);
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-
- if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return ASN_PARSE_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);
}
-
- /* key encryption algorithm must be RSA for now */
- if (encOID != RSAk) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
- return ALGO_ID_E;
+ 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;
}
-
- /* read encryptedKey */
- if (pkiMsg[idx++] != ASN_OCTET_STRING) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ }
#endif
- return ASN_PARSE_E;
- }
-
- if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+ 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
- return ASN_PARSE_E;
- }
-
- if (recipFound == 1)
- XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz);
- idx += encryptedKeySz;
- /* update good idx */
- savedIdx = idx;
- }
+ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
+ ret = ASN_PARSE_E;
- if (recipFound == 0) {
- WOLFSSL_MSG("No recipient found in envelopedData that matches input");
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
- return PKCS7_RECIP_E;
- }
+ 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;
+ }
- /* remove EncryptedContentInfo */
- if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
+ inSz);
+ if (rc < 0) {
+ ret = (int)rc;
+ break;
+ }
+ pkiMsgSz = (word32)rc;
#endif
- return ASN_PARSE_E;
- }
-
- if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
- return ASN_PARSE_E;
- }
+ 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;
+ }
- if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
+ inSz);
+ if (rc < 0) {
+ ret = (int)rc;
+ break;
+ }
+ pkiMsgSz = (word32)rc;
#endif
- return ASN_PARSE_E;
- }
-
- /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
- if (pkiMsg[idx++] != ASN_OCTET_STRING) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ /* 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
- return ASN_PARSE_E;
- }
-
- if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
- return ASN_PARSE_E;
- }
-
- if (length != DES_BLOCK_SIZE) {
- WOLFSSL_MSG("Incorrect IV length, must be of DES_BLOCK_SIZE");
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
- return ASN_PARSE_E;
- }
+ 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;
+ }
- XMEMCPY(tmpIv, &pkiMsg[idx], length);
- idx += length;
+ rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
+ inSz);
+ if (rc < 0) {
+ ret = (int)rc;
+ break;
+ }
+ pkiMsgSz = (word32)rc;
- /* read encryptedContent, cont[0] */
- if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ /* use IV buffer from stream structure */
+ tmpIv = pkcs7->stream->tmpIv;
+ length = pkcs7->stream->expected;
#endif
- return ASN_PARSE_E;
- }
+ 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;
- if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ASN_PARSE_E;
- }
-
- encryptedContent = (byte*)XMALLOC(encryptedContentSz, NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (encryptedContent == NULL) {
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ 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
- return MEMORY_E;
- }
+ if (ret == 0 && (encryptedContent = (byte*)XMALLOC(
+ encryptedContentSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7)) == NULL) {
+ ret = MEMORY_E;
+ break;
+ }
- XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz);
+ 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);
+ }
+ }
- /* load private key */
-#ifdef WOLFSSL_SMALL_STACK
- privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (privKey == NULL) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E;
+ 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;
}
-#endif
- ret = wc_InitRsaKey(privKey, 0);
if (ret != 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return ret;
+ #ifndef NO_PKCS7_STREAM
+ /* restart in error case */
+ wc_PKCS7_ResetStream(pkcs7);
+ #endif
+ wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
}
+ return ret;
+}
- idx = 0;
- ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey,
- pkcs7->privateKeySz);
- if (ret != 0) {
- WOLFSSL_MSG("Failed to decode RSA private key");
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
+/* 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;
- /* decrypt encryptedKey */
- keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz,
- &decryptedKey, privKey);
- wc_FreeRsaKey(privKey);
+ /* eContent OCTET STRING, working backwards */
+ contentOctetStrSz = SetOctetString(compressedSz, contentOctetStr);
+ totalSz = contentOctetStrSz + compressedSz;
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
+ /* EXPLICIT [0] eContentType */
+ contentSeqSz = SetExplicit(0, totalSz, contentSeq);
+ totalSz += contentSeqSz;
- if (keySz <= 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return keySz;
+ /* eContentType OBJECT IDENTIFIER */
+ ret = wc_SetContentType(pkcs7->contentOID, contentTypeOid,
+ sizeof(contentTypeOid));
+ if (ret < 0) {
+ XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return ret;
}
- /* decrypt encryptedContent */
- if (encOID == DESb) {
- Des des;
- ret = wc_Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION);
+ contentTypeOidSz = ret;
+ totalSz += contentTypeOidSz;
- if (ret == 0)
- wc_Des_CbcDecrypt(&des, encryptedContent, encryptedContent,
- encryptedContentSz);
+ /* EncapsulatedContentInfo SEQUENCE */
+ encapContentInfoSeqSz = SetSequence(totalSz, encapContentInfoSeq);
+ totalSz += encapContentInfoSeqSz;
- if (ret != 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
+ /* 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;
}
- else if (encOID == DES3b) {
- Des3 des;
- ret = wc_Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION);
- if (ret == 0)
- ret = wc_Des3_CbcDecrypt(&des, encryptedContent, encryptedContent,
- encryptedContentSz);
- if (ret != 0) {
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return ret;
- }
- } else {
- WOLFSSL_MSG("Unsupported content encryption OID type");
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
- return ALGO_ID_E;
+ /* ContentInfo SEQUENCE */
+ contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
+ totalSz += contentInfoSeqSz;
+
+ if (outputSz < totalSz) {
+ XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ return BUFFER_E;
}
- padLen = encryptedContent[encryptedContentSz-1];
+ 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);
- /* copy plaintext to output */
- XMEMCPY(output, encryptedContent, encryptedContentSz - padLen);
+ return idx;
+}
- /* free memory, zero out keys */
- ForceZero(encryptedKey, MAX_ENCRYPTED_KEY_SZ);
- ForceZero(encryptedContent, encryptedContentSz);
- XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-#endif
-
- return encryptedContentSz - padLen;
+/* 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 */