wolf SSL / wolfSSL

Dependents:   CyaSSL-Twitter-OAuth4Tw Example-client-tls-cert TwitterReader TweetTest ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pkcs7.c Source File

pkcs7.c

00001 /* pkcs7.c
00002  *
00003  * Copyright (C) 2006-2020 wolfSSL Inc.
00004  *
00005  * This file is part of wolfSSL.
00006  *
00007  * wolfSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * wolfSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
00020  */
00021 
00022 
00023 #ifdef HAVE_CONFIG_H
00024     #include <config.h>
00025 #endif
00026 
00027 #include <wolfssl/wolfcrypt/settings.h>
00028 
00029 #ifdef HAVE_PKCS7
00030 
00031 #include <wolfssl/wolfcrypt/pkcs7.h >
00032 #include <wolfssl/wolfcrypt/error-crypt.h >
00033 #include <wolfssl/wolfcrypt/logging.h >
00034 #include <wolfssl/wolfcrypt/hash.h >
00035 #ifndef NO_RSA
00036     #include <wolfssl/wolfcrypt/rsa.h >
00037 #endif
00038 #ifdef HAVE_ECC
00039     #include <wolfssl/wolfcrypt/ecc.h >
00040 #endif
00041 #ifdef HAVE_LIBZ
00042     #include <wolfssl/wolfcrypt/compress.h >
00043 #endif
00044 #ifndef NO_PWDBASED
00045     #include <wolfssl/wolfcrypt/pwdbased.h >
00046 #endif
00047 #ifdef NO_INLINE
00048     #include <wolfssl/wolfcrypt/misc.h>
00049 #else
00050     #define WOLFSSL_MISC_INCLUDED
00051     #include <wolfcrypt/src/misc.c>
00052 #endif
00053 
00054 /* direction for processing, encoding or decoding */
00055 typedef enum {
00056     WC_PKCS7_ENCODE,
00057     WC_PKCS7_DECODE
00058 } pkcs7Direction;
00059 
00060 #define NO_USER_CHECK 0
00061 
00062 /* holds information about the signers */
00063 struct PKCS7SignerInfo {
00064     int version;
00065     byte  *sid;
00066     word32 sidSz;
00067 };
00068 
00069 
00070 #ifndef NO_PKCS7_STREAM
00071 
00072 #define MAX_PKCS7_STREAM_BUFFER 256
00073 struct PKCS7State {
00074     byte* tmpCert;
00075     byte* bufferPt;
00076     byte* key;
00077     byte* nonce;    /* stored nonce */
00078     byte* aad;      /* additional data for AEAD algos */
00079     byte* tag;      /* tag data for AEAD algos */
00080     byte* content;
00081     byte* buffer;   /* main internal read buffer */
00082 
00083     /* stack variables to store for when returning */
00084     word32 varOne;
00085     int    varTwo;
00086     int    varThree;
00087 
00088     word32 vers;
00089     word32 idx;      /* index read into current input buffer */
00090     word32 maxLen;   /* sanity cap on maximum amount of data to allow
00091                       * needed for GetSequence and other calls */
00092     word32 length;   /* amount of data stored */
00093     word32 bufferSz; /* size of internal buffer */
00094     word32 expected; /* next amount of data expected, if needed */
00095     word32 totalRd;  /* total amount of bytes read */
00096     word32 nonceSz;  /* size of nonce stored */
00097     word32 aadSz;    /* size of additional AEAD data */
00098     word32 tagSz;    /* size of tag for AEAD */
00099     word32 contentSz;
00100     byte tmpIv[MAX_CONTENT_IV_SIZE]; /* store IV if needed */
00101 #ifdef WC_PKCS7_STREAM_DEBUG
00102     word32 peakUsed; /* most bytes used for struct at any one time */
00103     word32 peakRead; /* most bytes used by read buffer */
00104 #endif
00105     byte   multi:1;  /* flag for if content is in multiple parts */
00106     byte   flagOne:1;
00107     byte   detached:1; /* flag to indicate detached signature is present */
00108 };
00109 
00110 
00111 enum PKCS7_MaxLen {
00112     PKCS7_DEFAULT_PEEK = 0,
00113     PKCS7_SEQ_PEEK
00114 };
00115 
00116 /* creates a PKCS7State structure and returns 0 on success */
00117 static int wc_PKCS7_CreateStream(PKCS7* pkcs7)
00118 {
00119     WOLFSSL_MSG("creating PKCS7 stream structure");
00120     pkcs7->stream = (PKCS7State*)XMALLOC(sizeof(PKCS7State), pkcs7->heap,
00121         DYNAMIC_TYPE_PKCS7);
00122     if (pkcs7->stream == NULL) {
00123         return MEMORY_E;
00124     }
00125     XMEMSET(pkcs7->stream, 0, sizeof(PKCS7State));
00126 #ifdef WC_PKCS7_STREAM_DEBUG
00127     printf("\nCreating new PKCS#7 stream %p\n", pkcs7->stream);
00128 #endif
00129     return 0;
00130 }
00131 
00132 
00133 static void wc_PKCS7_ResetStream(PKCS7* pkcs7)
00134 {
00135     if (pkcs7 != NULL && pkcs7->stream != NULL) {
00136 #ifdef WC_PKCS7_STREAM_DEBUG
00137         /* collect final data point in case more was read right before reset */
00138         if (pkcs7->stream->length > pkcs7->stream->peakRead) {
00139             pkcs7->stream->peakRead = pkcs7->stream->length;
00140         }
00141         if (pkcs7->stream->bufferSz + pkcs7->stream->aadSz +
00142                 pkcs7->stream->nonceSz + pkcs7->stream->tagSz >
00143                 pkcs7->stream->peakUsed) {
00144             pkcs7->stream->peakUsed = pkcs7->stream->bufferSz +
00145                 pkcs7->stream->aadSz + pkcs7->stream->nonceSz +
00146                 pkcs7->stream->tagSz;
00147         }
00148 
00149         /* print out debugging statistics */
00150         if (pkcs7->stream->peakUsed > 0 || pkcs7->stream->peakRead > 0) {
00151             printf("PKCS#7 STREAM:\n\tPeak heap used by struct = %d"
00152                                  "\n\tPeak read buffer bytes   = %d"
00153                                  "\n\tTotal bytes read         = %d"
00154                                  "\n",
00155                    pkcs7->stream->peakUsed, pkcs7->stream->peakRead,
00156                    pkcs7->stream->totalRd);
00157         }
00158         printf("PKCS#7 stream reset : Address [%p]\n", pkcs7->stream);
00159     #endif
00160 
00161         /* free any buffers that may be allocated */
00162         XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00163         XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00164         XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00165         XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00166         XFREE(pkcs7->stream->key, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00167         pkcs7->stream->aad    = NULL;
00168         pkcs7->stream->tag    = NULL;
00169         pkcs7->stream->nonce  = NULL;
00170         pkcs7->stream->buffer = NULL;
00171         pkcs7->stream->key    = NULL;
00172 
00173         /* reset values, note that content and tmpCert are saved */
00174         pkcs7->stream->maxLen   = 0;
00175         pkcs7->stream->length   = 0;
00176         pkcs7->stream->idx      = 0;
00177         pkcs7->stream->expected = 0;
00178         pkcs7->stream->totalRd  = 0;
00179         pkcs7->stream->bufferSz = 0;
00180 
00181         pkcs7->stream->multi    = 0;
00182         pkcs7->stream->flagOne  = 0;
00183         pkcs7->stream->detached = 0;
00184         pkcs7->stream->varOne   = 0;
00185         pkcs7->stream->varTwo   = 0;
00186         pkcs7->stream->varThree = 0;
00187     }
00188 }
00189 
00190 
00191 static void wc_PKCS7_FreeStream(PKCS7* pkcs7)
00192 {
00193     if (pkcs7 != NULL && pkcs7->stream != NULL) {
00194         wc_PKCS7_ResetStream(pkcs7);
00195 
00196         XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00197         XFREE(pkcs7->stream->tmpCert, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00198         pkcs7->stream->content = NULL;
00199         pkcs7->stream->tmpCert = NULL;
00200 
00201         XFREE(pkcs7->stream, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00202         pkcs7->stream = NULL;
00203     }
00204 }
00205 
00206 
00207 /* used to increase the max size for internal buffer
00208  * returns 0 on success  */
00209 static int wc_PKCS7_GrowStream(PKCS7* pkcs7, word32 newSz)
00210 {
00211     byte* pt;
00212 
00213     pt = (byte*)XMALLOC(newSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00214     if (pt == NULL) {
00215         return MEMORY_E;
00216     }
00217     XMEMCPY(pt, pkcs7->stream->buffer, pkcs7->stream->bufferSz);
00218 
00219 #ifdef WC_PKCS7_STREAM_DEBUG
00220     printf("PKCS7 increasing internal stream buffer %d -> %d\n",
00221             pkcs7->stream->bufferSz, newSz);
00222 #endif
00223     pkcs7->stream->bufferSz = newSz;
00224     XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00225     pkcs7->stream->buffer = pt;
00226     return 0;
00227 }
00228 
00229 
00230 /* pt gets set to the buffer that is holding data in the case that stream struct
00231  *    is used.
00232  *
00233  * Sets idx to be the current offset into "pt" buffer
00234  * returns 0 on success
00235  */
00236 static int wc_PKCS7_AddDataToStream(PKCS7* pkcs7, byte* in, word32 inSz,
00237         word32 expected, byte** pt, word32* idx)
00238 {
00239     word32 rdSz = pkcs7->stream->idx;
00240 
00241     /* If the input size minus current index into input buffer is greater than
00242      * the expected size then use the input buffer. If data is already stored
00243      * in stream buffer or if there is not enough input data available then use
00244      * the stream buffer. */
00245     if (inSz - rdSz >= expected && pkcs7->stream->length == 0) {
00246         /* storing input buffer is not needed */
00247         *pt  = in; /* reset in case previously used internal buffer */
00248         *idx = rdSz;
00249         return 0;
00250     }
00251 
00252     /* is there enough stored in buffer already? */
00253     if (pkcs7->stream->length >= expected) {
00254         *idx = 0; /* start reading from beginning of stream buffer */
00255         *pt  = pkcs7->stream->buffer;
00256         return 0;
00257     }
00258 
00259     /* check if all data has been read from input */
00260     if (rdSz >= inSz) {
00261         /* no more input to read, reset input index and request more data */
00262         pkcs7->stream->idx = 0;
00263         return WC_PKCS7_WANT_READ_E;
00264     }
00265 
00266     /* try to store input data into stream buffer */
00267     if (inSz - rdSz > 0 && pkcs7->stream->length < expected) {
00268         int len = min(inSz - rdSz, expected - pkcs7->stream->length);
00269 
00270         /* sanity check that the input buffer is not internal buffer */
00271         if (in == pkcs7->stream->buffer) {
00272             return WC_PKCS7_WANT_READ_E;
00273         }
00274 
00275         /* check if internal buffer size needs to be increased */
00276         if (len + pkcs7->stream->length > pkcs7->stream->bufferSz) {
00277             int ret = wc_PKCS7_GrowStream(pkcs7, expected);
00278             if (ret < 0) {
00279                 return ret;
00280             }
00281         }
00282         XMEMCPY(pkcs7->stream->buffer + pkcs7->stream->length, in + rdSz, len);
00283         pkcs7->stream->length  += len;
00284         pkcs7->stream->idx     += len;
00285         pkcs7->stream->totalRd += len;
00286     }
00287 
00288 #ifdef WC_PKCS7_STREAM_DEBUG
00289     /* collects memory usage for debugging */
00290     if (pkcs7->stream->length > pkcs7->stream->peakRead) {
00291         pkcs7->stream->peakRead = pkcs7->stream->length;
00292     }
00293     if (pkcs7->stream->bufferSz + pkcs7->stream->aadSz + pkcs7->stream->nonceSz +
00294         pkcs7->stream->tagSz > pkcs7->stream->peakUsed) {
00295         pkcs7->stream->peakUsed = pkcs7->stream->bufferSz +
00296            pkcs7->stream->aadSz + pkcs7->stream->nonceSz + pkcs7->stream->tagSz;
00297     }
00298 #endif
00299 
00300     /* if not enough data was read in then request more */
00301     if (pkcs7->stream->length < expected) {
00302         pkcs7->stream->idx = 0;
00303         return WC_PKCS7_WANT_READ_E;
00304     }
00305 
00306     /* adjust pointer to read from stored buffer */
00307     *idx = 0;
00308     *pt  = pkcs7->stream->buffer;
00309     return 0;
00310 }
00311 
00312 
00313 /* Does two things
00314  *  1) Tries to get the length from current buffer and set it as max length
00315  *  2) Retrieves the set max length
00316  *
00317  * if no flag value is set then the stored max length is returned.
00318  * returns length found on success and defSz if no stored data is found
00319  */
00320 static long wc_PKCS7_GetMaxStream(PKCS7* pkcs7, byte flag, byte* in,
00321         word32 defSz)
00322 {
00323     /* check there is a buffer to read from */
00324     if (pkcs7) {
00325         int     length = 0, ret;
00326         word32  idx = 0, maxIdx;
00327         byte*   pt;
00328 
00329         if (flag != PKCS7_DEFAULT_PEEK) {
00330             if (pkcs7->stream->length > 0) {
00331                 length = pkcs7->stream->length;
00332                 pt     = pkcs7->stream->buffer;
00333             }
00334             else {
00335                 length = defSz;
00336                 pt     = in;
00337             }
00338             maxIdx = (word32)length;
00339 
00340             if (length < MAX_SEQ_SZ) {
00341                 WOLFSSL_MSG("PKCS7 Error not enough data for SEQ peek\n");
00342                 return 0;
00343             }
00344             if (flag == PKCS7_SEQ_PEEK) {
00345                 if ((ret = GetSequence_ex(pt, &idx, &length, maxIdx,
00346                                 NO_USER_CHECK)) < 0) {
00347                     return ret;
00348                 }
00349 
00350             #ifdef ASN_BER_TO_DER
00351                 if (length == 0 && ret == 0) {
00352                     idx = 0;
00353                     if ((ret = wc_BerToDer(pt, defSz, NULL,
00354                                     (word32*)&length)) != LENGTH_ONLY_E) {
00355                         return ret;
00356                     }
00357                 }
00358             #endif /* ASN_BER_TO_DER */
00359                 pkcs7->stream->maxLen = length + idx;
00360             }
00361         }
00362 
00363         if (pkcs7->stream->maxLen == 0) {
00364             pkcs7->stream->maxLen = defSz;
00365         }
00366 
00367         return pkcs7->stream->maxLen;
00368     }
00369 
00370     return defSz;
00371 }
00372 
00373 
00374 /* setter function for stored variables */
00375 static void wc_PKCS7_StreamStoreVar(PKCS7* pkcs7, word32 var1, int var2,
00376         int var3)
00377 {
00378     if (pkcs7 != NULL && pkcs7->stream != NULL) {
00379         pkcs7->stream->varOne   = var1;
00380         pkcs7->stream->varTwo   = var2;
00381         pkcs7->stream->varThree = var3;
00382     }
00383 }
00384 
00385 /* getter function for stored variables */
00386 static void wc_PKCS7_StreamGetVar(PKCS7* pkcs7, word32* var1, int* var2,
00387         int* var3)
00388 {
00389     if (pkcs7 != NULL && pkcs7->stream != NULL) {
00390         if (var1 != NULL) *var1 = pkcs7->stream->varOne;
00391         if (var2 != NULL) *var2 = pkcs7->stream->varTwo;
00392         if (var3 != NULL) *var3 = pkcs7->stream->varThree;
00393     }
00394 }
00395 
00396 
00397 /* common update of index and total read after section complete
00398  * returns 0 on success */
00399 static int wc_PKCS7_StreamEndCase(PKCS7* pkcs7, word32* tmpIdx, word32* idx)
00400 {
00401     int ret = 0;
00402 
00403     if (pkcs7->stream->length > 0) {
00404         if (pkcs7->stream->length < *idx) {
00405             WOLFSSL_MSG("PKCS7 read too much data from internal buffer");
00406             ret = BUFFER_E;
00407         }
00408         else {
00409             XMEMMOVE(pkcs7->stream->buffer, pkcs7->stream->buffer + *idx,
00410                  pkcs7->stream->length - *idx);
00411             pkcs7->stream->length -= *idx;
00412         }
00413     }
00414     else {
00415         pkcs7->stream->totalRd += *idx - *tmpIdx;
00416         pkcs7->stream->idx = *idx; /* adjust index into input buffer */
00417         *tmpIdx = *idx;
00418     }
00419 
00420     return ret;
00421 }
00422 #endif /* NO_PKCS7_STREAM */
00423 
00424 #ifdef WC_PKCS7_STREAM_DEBUG
00425 /* used to print out human readable state for debugging */
00426 static const char* wc_PKCS7_GetStateName(int in)
00427 {
00428     switch (in) {
00429         case WC_PKCS7_START: return "WC_PKCS7_START";
00430 
00431         case WC_PKCS7_STAGE2: return "WC_PKCS7_STAGE2";
00432         case WC_PKCS7_STAGE3: return "WC_PKCS7_STAGE3";
00433         case WC_PKCS7_STAGE4: return "WC_PKCS7_STAGE4";
00434         case WC_PKCS7_STAGE5: return "WC_PKCS7_STAGE5";
00435         case WC_PKCS7_STAGE6: return "WC_PKCS7_STAGE6";
00436 
00437         /* parse info set */
00438         case WC_PKCS7_INFOSET_START:  return "WC_PKCS7_INFOSET_START";
00439         case WC_PKCS7_INFOSET_BER:    return "WC_PKCS7_INFOSET_BER";
00440         case WC_PKCS7_INFOSET_STAGE1: return "WC_PKCS7_INFOSET_STAGE1";
00441         case WC_PKCS7_INFOSET_STAGE2: return "WC_PKCS7_INFOSET_STAGE2";
00442         case WC_PKCS7_INFOSET_END:    return "WC_PKCS7_INFOSET_END";
00443 
00444         /* decode enveloped data */
00445         case WC_PKCS7_ENV_2: return "WC_PKCS7_ENV_2";
00446         case WC_PKCS7_ENV_3: return "WC_PKCS7_ENV_3";
00447         case WC_PKCS7_ENV_4: return "WC_PKCS7_ENV_4";
00448         case WC_PKCS7_ENV_5: return "WC_PKCS7_ENV_5";
00449 
00450         /* decode auth enveloped */
00451         case WC_PKCS7_AUTHENV_2: return "WC_PKCS7_AUTHENV_2";
00452         case WC_PKCS7_AUTHENV_3: return "WC_PKCS7_AUTHENV_3";
00453         case WC_PKCS7_AUTHENV_4: return "WC_PKCS7_AUTHENV_4";
00454         case WC_PKCS7_AUTHENV_5: return "WC_PKCS7_AUTHENV_5";
00455         case WC_PKCS7_AUTHENV_6: return "WC_PKCS7_AUTHENV_6";
00456         case WC_PKCS7_AUTHENV_ATRB: return "WC_PKCS7_AUTHENV_ATRB";
00457         case WC_PKCS7_AUTHENV_ATRBEND: return "WC_PKCS7_AUTHENV_ATRBEND";
00458         case WC_PKCS7_AUTHENV_7: return "WC_PKCS7_AUTHENV_7";
00459 
00460         /* decryption state types */
00461         case WC_PKCS7_DECRYPT_KTRI:   return "WC_PKCS7_DECRYPT_KTRI";
00462         case WC_PKCS7_DECRYPT_KTRI_2: return "WC_PKCS7_DECRYPT_KTRI_2";
00463         case WC_PKCS7_DECRYPT_KTRI_3: return "WC_PKCS7_DECRYPT_KTRI_3";
00464 
00465         case WC_PKCS7_DECRYPT_KARI:  return "WC_PKCS7_DECRYPT_KARI";
00466         case WC_PKCS7_DECRYPT_KEKRI: return "WC_PKCS7_DECRYPT_KEKRI";
00467         case WC_PKCS7_DECRYPT_PWRI:  return "WC_PKCS7_DECRYPT_PWRI";
00468         case WC_PKCS7_DECRYPT_ORI:   return "WC_PKCS7_DECRYPT_ORI";
00469         case WC_PKCS7_DECRYPT_DONE:  return "WC_PKCS7_DECRYPT_DONE";
00470 
00471         case WC_PKCS7_VERIFY_STAGE2: return "WC_PKCS7_VERIFY_STAGE2";
00472         case WC_PKCS7_VERIFY_STAGE3: return "WC_PKCS7_VERIFY_STAGE3";
00473         case WC_PKCS7_VERIFY_STAGE4: return "WC_PKCS7_VERIFY_STAGE4";
00474         case WC_PKCS7_VERIFY_STAGE5: return "WC_PKCS7_VERIFY_STAGE5";
00475         case WC_PKCS7_VERIFY_STAGE6: return "WC_PKCS7_VERIFY_STAGE6";
00476 
00477         default:
00478             return "Unknown state";
00479     }
00480 }
00481 #endif
00482 
00483 /* Used to change the PKCS7 state. Having state change as a function allows
00484  * for easier debugging */
00485 static void wc_PKCS7_ChangeState(PKCS7* pkcs7, int newState)
00486 {
00487 #ifdef WC_PKCS7_STREAM_DEBUG
00488     printf("\tChanging from state [%02d] %s to [%02d] %s\n",
00489             pkcs7->state, wc_PKCS7_GetStateName(pkcs7->state),
00490             newState, wc_PKCS7_GetStateName(newState));
00491 #endif
00492     pkcs7->state = newState;
00493 }
00494 
00495 #define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ + \
00496                              MAX_OCTET_STR_SZ + WC_MAX_DIGEST_SIZE)
00497 
00498 
00499 /* placed ASN.1 contentType OID into *output, return idx on success,
00500  * 0 upon failure */
00501 static int wc_SetContentType(int pkcs7TypeOID, byte* output, word32 outputSz)
00502 {
00503     /* PKCS#7 content types, RFC 2315, section 14 */
00504     const byte pkcs7[]              = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00505                                                0x0D, 0x01, 0x07 };
00506     const byte data[]               = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00507                                                0x0D, 0x01, 0x07, 0x01 };
00508     const byte signedData[]         = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00509                                                0x0D, 0x01, 0x07, 0x02};
00510     const byte envelopedData[]      = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00511                                                0x0D, 0x01, 0x07, 0x03 };
00512     const byte authEnvelopedData[]  = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00513                                         0x0D, 0x01, 0x09, 0x10, 0x01, 0x17};
00514     const byte signedAndEnveloped[] = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00515                                                0x0D, 0x01, 0x07, 0x04 };
00516     const byte digestedData[]       = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00517                                                0x0D, 0x01, 0x07, 0x05 };
00518 #ifndef NO_PKCS7_ENCRYPTED_DATA
00519     const byte encryptedData[]      = { 0x2A, 0x86, 0x48, 0x86, 0xF7,
00520                                                0x0D, 0x01, 0x07, 0x06 };
00521 #endif
00522     /* FirmwarePkgData (1.2.840.113549.1.9.16.1.16), RFC 4108 */
00523     const byte firmwarePkgData[]    = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
00524                                         0x01, 0x09, 0x10, 0x01, 0x10 };
00525 #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
00526     /* id-ct-compressedData (1.2.840.113549.1.9.16.1.9), RFC 3274 */
00527     const byte compressedData[]     = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
00528                                         0x01, 0x09, 0x10, 0x01, 0x09 };
00529 #endif
00530 
00531 #if !defined(NO_PWDBASED) && !defined(NO_SHA)
00532     const byte pwriKek[]            = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
00533                                         0x01, 0x09, 0x10, 0x03, 0x09 };
00534     const byte pbkdf2[]             = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
00535                                         0x01, 0x05, 0x0C };
00536 #endif
00537 
00538     int idSz, idx = 0;
00539     word32 typeSz = 0;
00540     const byte* typeName = 0;
00541     byte ID_Length[MAX_LENGTH_SZ];
00542 
00543     switch (pkcs7TypeOID) {
00544         case PKCS7_MSG:
00545             typeSz = sizeof(pkcs7);
00546             typeName = pkcs7;
00547             break;
00548 
00549         case DATA:
00550             typeSz = sizeof(data);
00551             typeName = data;
00552             break;
00553 
00554         case SIGNED_DATA:
00555             typeSz = sizeof(signedData);
00556             typeName = signedData;
00557             break;
00558 
00559         case ENVELOPED_DATA:
00560             typeSz = sizeof(envelopedData);
00561             typeName = envelopedData;
00562             break;
00563 
00564         case AUTH_ENVELOPED_DATA:
00565             typeSz = sizeof(authEnvelopedData);
00566             typeName = authEnvelopedData;
00567             break;
00568 
00569         case SIGNED_AND_ENVELOPED_DATA:
00570             typeSz = sizeof(signedAndEnveloped);
00571             typeName = signedAndEnveloped;
00572             break;
00573 
00574         case DIGESTED_DATA:
00575             typeSz = sizeof(digestedData);
00576             typeName = digestedData;
00577             break;
00578 
00579 #ifndef NO_PKCS7_ENCRYPTED_DATA
00580         case ENCRYPTED_DATA:
00581             typeSz = sizeof(encryptedData);
00582             typeName = encryptedData;
00583             break;
00584 #endif
00585 #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
00586         case COMPRESSED_DATA:
00587             typeSz = sizeof(compressedData);
00588             typeName = compressedData;
00589             break;
00590 #endif
00591         case FIRMWARE_PKG_DATA:
00592             typeSz = sizeof(firmwarePkgData);
00593             typeName = firmwarePkgData;
00594             break;
00595 
00596 #if !defined(NO_PWDBASED) && !defined(NO_SHA)
00597         case PWRI_KEK_WRAP:
00598             typeSz = sizeof(pwriKek);
00599             typeName = pwriKek;
00600             break;
00601 
00602         case PBKDF2_OID:
00603             typeSz = sizeof(pbkdf2);
00604             typeName = pbkdf2;
00605             break;
00606 #endif
00607 
00608         default:
00609             WOLFSSL_MSG("Unknown PKCS#7 Type");
00610             return 0;
00611     };
00612 
00613     if (outputSz < (MAX_LENGTH_SZ + 1 + typeSz)) {
00614         WOLFSSL_MSG("CMS content type buffer too small");
00615         return BAD_FUNC_ARG;
00616     }
00617 
00618     idSz  = SetLength(typeSz, ID_Length);
00619     output[idx++] = ASN_OBJECT_ID;
00620     XMEMCPY(output + idx, ID_Length, idSz);
00621     idx += idSz;
00622     XMEMCPY(output + idx, typeName, typeSz);
00623     idx += typeSz;
00624 
00625     return idx;
00626 }
00627 
00628 
00629 /* get ASN.1 contentType OID sum, return 0 on success, <0 on failure */
00630 static int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid,
00631                              word32 maxIdx)
00632 {
00633     WOLFSSL_ENTER("wc_GetContentType");
00634     if (GetObjectId(input, inOutIdx, oid, oidIgnoreType, maxIdx) < 0)
00635         return ASN_PARSE_E;
00636 
00637     return 0;
00638 }
00639 
00640 
00641 /* return block size for algorithm represented by oid, or <0 on error */
00642 static int wc_PKCS7_GetOIDBlockSize(int oid)
00643 {
00644     int blockSz;
00645 
00646     switch (oid) {
00647 #ifndef NO_AES
00648     #ifdef WOLFSSL_AES_128
00649         case AES128CBCb:
00650         case AES128GCMb:
00651         case AES128CCMb:
00652     #endif
00653     #ifdef WOLFSSL_AES_192
00654         case AES192CBCb:
00655         case AES192GCMb:
00656         case AES192CCMb:
00657     #endif
00658     #ifdef WOLFSSL_AES_256
00659         case AES256CBCb:
00660         case AES256GCMb:
00661         case AES256CCMb:
00662     #endif
00663             blockSz = AES_BLOCK_SIZE;
00664             break;
00665 #endif
00666 #ifndef NO_DES3
00667         case DESb:
00668         case DES3b:
00669             blockSz = DES_BLOCK_SIZE;
00670             break;
00671 #endif
00672         default:
00673             WOLFSSL_MSG("Unsupported content cipher type");
00674             return ALGO_ID_E;
00675     };
00676 
00677     return blockSz;
00678 }
00679 
00680 
00681 /* get key size for algorithm represented by oid, or <0 on error */
00682 static int wc_PKCS7_GetOIDKeySize(int oid)
00683 {
00684     int blockKeySz;
00685 
00686     switch (oid) {
00687 #ifndef NO_AES
00688     #ifdef WOLFSSL_AES_128
00689         case AES128CBCb:
00690         case AES128GCMb:
00691         case AES128CCMb:
00692         case AES128_WRAP:
00693             blockKeySz = 16;
00694             break;
00695     #endif
00696     #ifdef WOLFSSL_AES_192
00697         case AES192CBCb:
00698         case AES192GCMb:
00699         case AES192CCMb:
00700         case AES192_WRAP:
00701             blockKeySz = 24;
00702             break;
00703     #endif
00704     #ifdef WOLFSSL_AES_256
00705         case AES256CBCb:
00706         case AES256GCMb:
00707         case AES256CCMb:
00708         case AES256_WRAP:
00709             blockKeySz = 32;
00710             break;
00711     #endif
00712 #endif
00713 #ifndef NO_DES3
00714         case DESb:
00715             blockKeySz = DES_KEYLEN;
00716             break;
00717 
00718         case DES3b:
00719             blockKeySz = DES3_KEYLEN;
00720             break;
00721 #endif
00722         default:
00723             WOLFSSL_MSG("Unsupported content cipher type");
00724             return ALGO_ID_E;
00725     };
00726 
00727     return blockKeySz;
00728 }
00729 
00730 
00731 PKCS7* wc_PKCS7_New(void* heap, int devId)
00732 {
00733     PKCS7* pkcs7 = (PKCS7*)XMALLOC(sizeof(PKCS7), heap, DYNAMIC_TYPE_PKCS7);
00734     if (pkcs7) {
00735         XMEMSET(pkcs7, 0, sizeof(PKCS7));
00736         if (wc_PKCS7_Init(pkcs7, heap, devId) == 0) {
00737             pkcs7->isDynamic = 1;
00738         }
00739         else {
00740             XFREE(pkcs7, heap, DYNAMIC_TYPE_PKCS7);
00741             pkcs7 = NULL;
00742         }
00743     }
00744     return pkcs7;
00745 }
00746 
00747 /* This is to initialize a PKCS7 structure. It sets all values to 0 and can be
00748  * used to set the heap hint.
00749  *
00750  * pkcs7 PKCS7 structure to initialize
00751  * heap  memory heap hint for PKCS7 structure to use
00752  * devId currently not used but a place holder for async operations
00753  *
00754  * returns 0 on success or a negative value for failure
00755  */
00756 int wc_PKCS7_Init(PKCS7* pkcs7, void* heap, int devId)
00757 {
00758     word16 isDynamic;
00759 
00760     WOLFSSL_ENTER("wc_PKCS7_Init");
00761 
00762     if (pkcs7 == NULL) {
00763         return BAD_FUNC_ARG;
00764     }
00765 
00766     isDynamic = pkcs7->isDynamic;
00767     XMEMSET(pkcs7, 0, sizeof(PKCS7));
00768     pkcs7->isDynamic = isDynamic;
00769 #ifdef WOLFSSL_HEAP_TEST
00770     pkcs7->heap = (void*)WOLFSSL_HEAP_TEST;
00771 #else
00772     pkcs7->heap = heap;
00773 #endif
00774     pkcs7->devId = devId;
00775 
00776     return 0;
00777 }
00778 
00779 
00780 /* Certificate structure holding der pointer, size, and pointer to next
00781  * Pkcs7Cert struct. Used when creating SignedData types with multiple
00782  * certificates. */
00783 struct Pkcs7Cert {
00784     byte*  der;
00785     word32 derSz;
00786     Pkcs7Cert* next;
00787 };
00788 
00789 
00790 /* Linked list of ASN.1 encoded RecipientInfos */
00791 struct Pkcs7EncodedRecip {
00792     byte recip[MAX_RECIP_SZ];
00793     word32 recipSz;
00794     int recipType;
00795     int recipVersion;
00796     Pkcs7EncodedRecip* next;
00797 };
00798 
00799 
00800 /* free all members of Pkcs7Cert linked list */
00801 static void wc_PKCS7_FreeCertSet(PKCS7* pkcs7)
00802 {
00803     Pkcs7Cert* curr = NULL;
00804     Pkcs7Cert* next = NULL;
00805 
00806     if (pkcs7 == NULL)
00807         return;
00808 
00809     curr = pkcs7->certList;
00810     pkcs7->certList = NULL;
00811 
00812     while (curr != NULL) {
00813         next = curr->next;
00814         curr->next = NULL;
00815         XFREE(curr, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00816         curr = next;
00817     }
00818 
00819     return;
00820 }
00821 
00822 
00823 /* Get total size of all recipients in recipient list.
00824  *
00825  * Returns total size of recipients, or negative upon error */
00826 static int wc_PKCS7_GetRecipientListSize(PKCS7* pkcs7)
00827 {
00828     int totalSz = 0;
00829     Pkcs7EncodedRecip* tmp = NULL;
00830 
00831     if (pkcs7 == NULL)
00832         return BAD_FUNC_ARG;
00833 
00834     tmp = pkcs7->recipList;
00835 
00836     while (tmp != NULL) {
00837         totalSz += tmp->recipSz;
00838         tmp = tmp->next;
00839     }
00840 
00841     return totalSz;
00842 }
00843 
00844 
00845 /* free all members of Pkcs7EncodedRecip linked list */
00846 static void wc_PKCS7_FreeEncodedRecipientSet(PKCS7* pkcs7)
00847 {
00848     Pkcs7EncodedRecip* curr = NULL;
00849     Pkcs7EncodedRecip* next = NULL;
00850 
00851     if (pkcs7 == NULL)
00852         return;
00853 
00854     curr = pkcs7->recipList;
00855     pkcs7->recipList = NULL;
00856 
00857     while (curr != NULL) {
00858         next = curr->next;
00859         curr->next = NULL;
00860         XFREE(curr, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
00861         curr = next;
00862     }
00863 
00864     return;
00865 }
00866 
00867 
00868 /* search through RecipientInfo list for specific type.
00869  * return 1 if ANY recipient of type specified is present, otherwise
00870  * return 0 */
00871 static int wc_PKCS7_RecipientListIncludesType(PKCS7* pkcs7, int type)
00872 {
00873     Pkcs7EncodedRecip* tmp = NULL;
00874 
00875     if (pkcs7 == NULL)
00876         return BAD_FUNC_ARG;
00877 
00878     tmp = pkcs7->recipList;
00879 
00880     while (tmp != NULL) {
00881         if (tmp->recipType == type)
00882             return 1;
00883 
00884         tmp = tmp->next;
00885     }
00886 
00887     return 0;
00888 }
00889 
00890 
00891 /* searches through RecipientInfo list, returns 1 if all structure
00892  * versions are set to 0, otherwise returns 0 */
00893 static int wc_PKCS7_RecipientListVersionsAllZero(PKCS7* pkcs7)
00894 {
00895     Pkcs7EncodedRecip* tmp = NULL;
00896 
00897     if (pkcs7 == NULL)
00898         return BAD_FUNC_ARG;
00899 
00900     tmp = pkcs7->recipList;
00901 
00902     while (tmp != NULL) {
00903         if (tmp->recipVersion != 0)
00904             return 0;
00905 
00906         tmp = tmp->next;
00907     }
00908 
00909     return 1;
00910 }
00911 
00912 
00913 /* Init PKCS7 struct with recipient cert, decode into DecodedCert
00914  * NOTE: keeps previously set pkcs7 heap hint, devId and isDynamic */
00915 int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* derCert, word32 derCertSz)
00916 {
00917     int ret = 0;
00918     void* heap;
00919     int devId;
00920     Pkcs7Cert* cert;
00921     Pkcs7Cert* lastCert;
00922 
00923     if (pkcs7 == NULL || (derCert == NULL && derCertSz != 0)) {
00924         return BAD_FUNC_ARG;
00925     }
00926 
00927     heap = pkcs7->heap;
00928     devId = pkcs7->devId;
00929     cert = pkcs7->certList;
00930     ret = wc_PKCS7_Init(pkcs7, heap, devId);
00931     if (ret != 0)
00932         return ret;
00933     pkcs7->certList = cert;
00934 
00935     if (derCert != NULL && derCertSz > 0) {
00936 #ifdef WOLFSSL_SMALL_STACK
00937         DecodedCert* dCert;
00938 
00939         dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
00940                                                        DYNAMIC_TYPE_DCERT);
00941         if (dCert == NULL)
00942             return MEMORY_E;
00943 #else
00944         DecodedCert dCert[1];
00945 #endif
00946 
00947         pkcs7->singleCert = derCert;
00948         pkcs7->singleCertSz = derCertSz;
00949         pkcs7->cert[0] = derCert;
00950         pkcs7->certSz[0] = derCertSz;
00951 
00952         /* create new Pkcs7Cert for recipient, freed during cleanup */
00953         cert = (Pkcs7Cert*)XMALLOC(sizeof(Pkcs7Cert), pkcs7->heap,
00954                                    DYNAMIC_TYPE_PKCS7);
00955         XMEMSET(cert, 0, sizeof(Pkcs7Cert));
00956         cert->der = derCert;
00957         cert->derSz = derCertSz;
00958         cert->next = NULL;
00959 
00960         /* free existing cert list if existing */
00961         wc_PKCS7_FreeCertSet(pkcs7);
00962 
00963         /* add cert to list */
00964         if (pkcs7->certList == NULL) {
00965             pkcs7->certList = cert;
00966         } else {
00967            lastCert = pkcs7->certList;
00968            while (lastCert->next != NULL) {
00969                lastCert = lastCert->next;
00970            }
00971            lastCert->next = cert;
00972         }
00973 
00974         InitDecodedCert(dCert, derCert, derCertSz, pkcs7->heap);
00975         ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
00976         if (ret < 0) {
00977             FreeDecodedCert(dCert);
00978 #ifdef WOLFSSL_SMALL_STACK
00979             XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
00980 #endif
00981             return ret;
00982         }
00983 
00984         XMEMCPY(pkcs7->publicKey, dCert->publicKey, dCert->pubKeySize);
00985         pkcs7->publicKeySz = dCert->pubKeySize;
00986         pkcs7->publicKeyOID = dCert->keyOID;
00987         XMEMCPY(pkcs7->issuerHash, dCert->issuerHash, KEYID_SIZE);
00988         pkcs7->issuer = dCert->issuerRaw;
00989         pkcs7->issuerSz = dCert->issuerRawLen;
00990         XMEMCPY(pkcs7->issuerSn, dCert->serial, dCert->serialSz);
00991         pkcs7->issuerSnSz = dCert->serialSz;
00992         XMEMCPY(pkcs7->issuerSubjKeyId, dCert->extSubjKeyId, KEYID_SIZE);
00993 
00994         /* default to IssuerAndSerialNumber for SignerIdentifier */
00995         pkcs7->sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
00996 
00997         /* free existing recipient list if existing */
00998         wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
00999 
01000         FreeDecodedCert(dCert);
01001 
01002 #ifdef WOLFSSL_SMALL_STACK
01003         XFREE(dCert, pkcs7->heap, DYNAMIC_TYPE_DCERT);
01004 #endif
01005     }
01006 
01007     return ret;
01008 }
01009 
01010 
01011 /* Adds one DER-formatted certificate to the internal PKCS7/CMS certificate
01012  * list, to be added as part of the certificates CertificateSet. Currently
01013  * used in SignedData content type.
01014  *
01015  * Must be called after wc_PKCS7_Init() or wc_PKCS7_InitWithCert().
01016  *
01017  * Does not represent the recipient/signer certificate, only certificates that
01018  * are part of the certificate chain used to build and verify signer
01019  * certificates.
01020  *
01021  * This API does not currently validate certificates.
01022  *
01023  * Returns 0 on success, negative upon error */
01024 int wc_PKCS7_AddCertificate(PKCS7* pkcs7, byte* derCert, word32 derCertSz)
01025 {
01026     Pkcs7Cert* cert;
01027 
01028     if (pkcs7 == NULL || derCert == NULL || derCertSz == 0)
01029         return BAD_FUNC_ARG;
01030 
01031     cert = (Pkcs7Cert*)XMALLOC(sizeof(Pkcs7Cert), pkcs7->heap,
01032                                DYNAMIC_TYPE_PKCS7);
01033     if (cert == NULL)
01034         return MEMORY_E;
01035 
01036     cert->der = derCert;
01037     cert->derSz = derCertSz;
01038 
01039     if (pkcs7->certList == NULL) {
01040         pkcs7->certList = cert;
01041     } else {
01042         cert->next = pkcs7->certList;
01043         pkcs7->certList = cert;
01044     }
01045 
01046     return 0;
01047 }
01048 
01049 
01050 /* free linked list of PKCS7DecodedAttrib structs */
01051 static void wc_PKCS7_FreeDecodedAttrib(PKCS7DecodedAttrib* attrib, void* heap)
01052 {
01053     PKCS7DecodedAttrib* current;
01054 
01055     if (attrib == NULL) {
01056         return;
01057     }
01058 
01059     current = attrib;
01060     while (current != NULL) {
01061         PKCS7DecodedAttrib* next = current->next;
01062         if (current->oid != NULL)  {
01063             XFREE(current->oid, heap, DYNAMIC_TYPE_PKCS7);
01064         }
01065         if (current->value != NULL) {
01066             XFREE(current->value, heap, DYNAMIC_TYPE_PKCS7);
01067         }
01068         XFREE(current, heap, DYNAMIC_TYPE_PKCS7);
01069         current = next;
01070     }
01071 
01072     (void)heap;
01073 }
01074 
01075 
01076 /* return 0 on success */
01077 static int wc_PKCS7_SignerInfoNew(PKCS7* pkcs7)
01078 {
01079     if (pkcs7->signerInfo != NULL) {
01080         XFREE(pkcs7->signerInfo, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01081         pkcs7->signerInfo = NULL;
01082     }
01083 
01084     pkcs7->signerInfo = (PKCS7SignerInfo*)XMALLOC(sizeof(PKCS7SignerInfo),
01085             pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01086     if (pkcs7->signerInfo == NULL) {
01087         WOLFSSL_MSG("Unable to malloc memory for signer info");
01088         return MEMORY_E;
01089     }
01090     XMEMSET(pkcs7->signerInfo, 0, sizeof(PKCS7SignerInfo));
01091     return 0;
01092 }
01093 
01094 
01095 static void wc_PKCS7_SignerInfoFree(PKCS7* pkcs7)
01096 {
01097     if (pkcs7->signerInfo != NULL) {
01098         if (pkcs7->signerInfo->sid != NULL) {
01099             XFREE(pkcs7->signerInfo->sid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01100             pkcs7->signerInfo->sid = NULL;
01101         }
01102         XFREE(pkcs7->signerInfo, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01103         pkcs7->signerInfo = NULL;
01104     }
01105 }
01106 
01107 
01108 /* free's any current SID and sets it to "in"
01109  * returns 0 on success
01110  */
01111 static int wc_PKCS7_SignerInfoSetSID(PKCS7* pkcs7, byte* in, int inSz)
01112 {
01113     if (pkcs7 == NULL || in == NULL || inSz < 0) {
01114         return BAD_FUNC_ARG;
01115     }
01116 
01117     if (pkcs7->signerInfo->sid != NULL) {
01118         XFREE(pkcs7->signerInfo->sid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01119         pkcs7->signerInfo->sid = NULL;
01120     }
01121     pkcs7->signerInfo->sid = (byte*)XMALLOC(inSz, pkcs7->heap,
01122             DYNAMIC_TYPE_PKCS7);
01123     if (pkcs7->signerInfo->sid == NULL) {
01124         return MEMORY_E;
01125     }
01126     XMEMCPY(pkcs7->signerInfo->sid, in, inSz);
01127     pkcs7->signerInfo->sidSz = inSz;
01128     return 0;
01129 }
01130 
01131 
01132 /* releases any memory allocated by a PKCS7 initializer */
01133 void wc_PKCS7_Free(PKCS7* pkcs7)
01134 {
01135     if (pkcs7 == NULL)
01136         return;
01137 
01138 #ifndef NO_PKCS7_STREAM
01139     wc_PKCS7_FreeStream(pkcs7);
01140 #endif
01141 
01142     wc_PKCS7_SignerInfoFree(pkcs7);
01143     wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap);
01144     wc_PKCS7_FreeCertSet(pkcs7);
01145 
01146 #ifdef ASN_BER_TO_DER
01147     if (pkcs7->der != NULL)
01148         XFREE(pkcs7->der, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01149 #endif
01150     if (pkcs7->contentDynamic != NULL)
01151         XFREE(pkcs7->contentDynamic, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01152 
01153     if (pkcs7->cek != NULL) {
01154         ForceZero(pkcs7->cek, pkcs7->cekSz);
01155         XFREE(pkcs7->cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01156     }
01157 
01158     pkcs7->contentTypeSz = 0;
01159 
01160     if (pkcs7->signature) {
01161         XFREE(pkcs7->signature, pkcs7->heap, DYNAMIC_TYPE_SIGNATURE);
01162         pkcs7->signature = NULL;
01163         pkcs7->signatureSz = 0;
01164     }
01165     if (pkcs7->plainDigest) {
01166         XFREE(pkcs7->plainDigest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
01167         pkcs7->plainDigest = NULL;
01168         pkcs7->plainDigestSz = 0;
01169     }
01170     if (pkcs7->pkcs7Digest) {
01171         XFREE(pkcs7->pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
01172         pkcs7->pkcs7Digest = NULL;
01173         pkcs7->pkcs7DigestSz = 0;
01174     }
01175     if (pkcs7->cachedEncryptedContent != NULL) {
01176         XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01177         pkcs7->cachedEncryptedContent = NULL;
01178         pkcs7->cachedEncryptedContentSz = 0;
01179     }
01180 
01181     if (pkcs7->isDynamic) {
01182         pkcs7->isDynamic = 0;
01183         XFREE(pkcs7, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
01184     }
01185 }
01186 
01187 
01188 /* helper function for parsing through attributes and finding a specific one.
01189  * returns PKCS7DecodedAttrib pointer on success */
01190 static PKCS7DecodedAttrib* findAttrib(PKCS7* pkcs7, const byte* oid, word32 oidSz)
01191 {
01192     PKCS7DecodedAttrib* list;
01193 
01194     if (pkcs7 == NULL || oid == NULL) {
01195         return NULL;
01196     }
01197 
01198     /* search attributes for pkiStatus */
01199     list = pkcs7->decodedAttrib;
01200     while (list != NULL) {
01201         word32 sz  = oidSz;
01202         word32 idx = 0;
01203         int    length = 0;
01204         byte   tag;
01205 
01206         if (GetASNTag(list->oid, &idx, &tag, list->oidSz) < 0) {
01207             return NULL;
01208         }
01209         if (tag != ASN_OBJECT_ID) {
01210             WOLFSSL_MSG("Bad attribute ASN1 syntax");
01211             return NULL;
01212         }
01213 
01214         if (GetLength(list->oid, &idx, &length, list->oidSz) < 0) {
01215             WOLFSSL_MSG("Bad attribute length");
01216             return NULL;
01217         }
01218 
01219         sz = (sz < (word32)length)? sz : (word32)length;
01220         if (XMEMCMP(oid, list->oid + idx, sz) == 0) {
01221             return list;
01222         }
01223         list = list->next;
01224     }
01225     return NULL;
01226 }
01227 
01228 
01229 /* Searches through decoded attributes and returns the value for the first one
01230  * matching the oid passed in. Note that this value includes the leading ASN1
01231  * syntax. So for a printable string of "3" this would be something like
01232  *
01233  * 0x13, 0x01, 0x33
01234  *  ID   SIZE  "3"
01235  *
01236  * pkcs7  structure to get value from
01237  * oid    OID value to search for with attributes
01238  * oidSz  size of oid buffer
01239  * out    buffer to hold result
01240  * outSz  size of out buffer (if out is NULL this is set to needed size and
01241           LENGTH_ONLY_E is returned)
01242  *
01243  * returns size of value on success
01244  */
01245 int wc_PKCS7_GetAttributeValue(PKCS7* pkcs7, const byte* oid, word32 oidSz,
01246         byte* out, word32* outSz)
01247 {
01248     PKCS7DecodedAttrib* attrib;
01249 
01250     if (pkcs7 == NULL || oid == NULL || outSz == NULL) {
01251         return BAD_FUNC_ARG;
01252     }
01253 
01254     attrib = findAttrib(pkcs7, oid, oidSz);
01255     if (attrib == NULL) {
01256         return ASN_PARSE_E;
01257     }
01258 
01259     if (out == NULL) {
01260         *outSz = attrib->valueSz;
01261         return LENGTH_ONLY_E;
01262     }
01263 
01264     if (*outSz < attrib->valueSz) {
01265         return BUFFER_E;
01266     }
01267 
01268     XMEMCPY(out, attrib->value, attrib->valueSz);
01269     return attrib->valueSz;
01270 }
01271 
01272 
01273 /* build PKCS#7 data content type */
01274 int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz)
01275 {
01276     static const byte oid[] =
01277         { ASN_OBJECT_ID, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
01278                          0x07, 0x01 };
01279     byte seq[MAX_SEQ_SZ];
01280     byte octetStr[MAX_OCTET_STR_SZ];
01281     word32 seqSz;
01282     word32 octetStrSz;
01283     word32 oidSz = (word32)sizeof(oid);
01284     int idx = 0;
01285 
01286     if (pkcs7 == NULL || output == NULL) {
01287         return BAD_FUNC_ARG;
01288     }
01289 
01290     octetStrSz = SetOctetString(pkcs7->contentSz, octetStr);
01291     seqSz = SetSequence(pkcs7->contentSz + octetStrSz + oidSz, seq);
01292 
01293     if (outputSz < pkcs7->contentSz + octetStrSz + oidSz + seqSz)
01294         return BUFFER_E;
01295 
01296     XMEMCPY(output, seq, seqSz);
01297     idx += seqSz;
01298     XMEMCPY(output + idx, oid, oidSz);
01299     idx += oidSz;
01300     XMEMCPY(output + idx, octetStr, octetStrSz);
01301     idx += octetStrSz;
01302     XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
01303     idx += pkcs7->contentSz;
01304 
01305     return idx;
01306 }
01307 
01308 
01309 typedef struct EncodedAttrib {
01310     byte valueSeq[MAX_SEQ_SZ];
01311         const byte* oid;
01312         byte valueSet[MAX_SET_SZ];
01313         const byte* value;
01314     word32 valueSeqSz, oidSz, idSz, valueSetSz, valueSz, totalSz;
01315 } EncodedAttrib;
01316 
01317 
01318 typedef struct ESD {
01319     wc_HashAlg  hash;
01320     enum wc_HashType hashType;
01321     byte contentDigest[WC_MAX_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */
01322     byte contentAttribsDigest[WC_MAX_DIGEST_SIZE];
01323     byte encContentDigest[MAX_ENCRYPTED_KEY_SZ];
01324 
01325     byte outerSeq[MAX_SEQ_SZ];
01326         byte outerContent[MAX_EXP_SZ];
01327             byte innerSeq[MAX_SEQ_SZ];
01328                 byte version[MAX_VERSION_SZ];
01329                 byte digAlgoIdSet[MAX_SET_SZ];
01330                     byte singleDigAlgoId[MAX_ALGO_SZ];
01331 
01332                 byte contentInfoSeq[MAX_SEQ_SZ];
01333                     byte innerContSeq[MAX_EXP_SZ];
01334                         byte innerOctets[MAX_OCTET_STR_SZ];
01335 
01336                 byte certsSet[MAX_SET_SZ];
01337 
01338                 byte signerInfoSet[MAX_SET_SZ];
01339                     byte signerInfoSeq[MAX_SEQ_SZ];
01340                         byte signerVersion[MAX_VERSION_SZ];
01341                         /* issuerAndSerialNumber ...*/
01342                         byte issuerSnSeq[MAX_SEQ_SZ];
01343                             byte issuerName[MAX_SEQ_SZ];
01344                             byte issuerSn[MAX_SN_SZ];
01345                         /* OR subjectKeyIdentifier */
01346                         byte issuerSKIDSeq[MAX_SEQ_SZ];
01347                             byte issuerSKID[MAX_OCTET_STR_SZ];
01348                         byte signerDigAlgoId[MAX_ALGO_SZ];
01349                         byte digEncAlgoId[MAX_ALGO_SZ];
01350                         byte signedAttribSet[MAX_SET_SZ];
01351                             EncodedAttrib signedAttribs[7];
01352                         byte signerDigest[MAX_OCTET_STR_SZ];
01353     word32 innerOctetsSz, innerContSeqSz, contentInfoSeqSz;
01354     word32 outerSeqSz, outerContentSz, innerSeqSz, versionSz, digAlgoIdSetSz,
01355            singleDigAlgoIdSz, certsSetSz;
01356     word32 signerInfoSetSz, signerInfoSeqSz, signerVersionSz,
01357            issuerSnSeqSz, issuerNameSz, issuerSnSz, issuerSKIDSz,
01358            issuerSKIDSeqSz, signerDigAlgoIdSz, digEncAlgoIdSz, signerDigestSz;
01359     word32 encContentDigestSz, signedAttribsSz, signedAttribsCount,
01360            signedAttribSetSz;
01361 } ESD;
01362 
01363 
01364 static int EncodeAttributes(EncodedAttrib* ea, int eaSz,
01365                                             PKCS7Attrib* attribs, int attribsSz)
01366 {
01367     int i;
01368     int maxSz = min(eaSz, attribsSz);
01369     int allAttribsSz = 0;
01370 
01371     for (i = 0; i < maxSz; i++)
01372     {
01373         int attribSz = 0;
01374 
01375         ea[i].value = attribs[i].value;
01376         ea[i].valueSz = attribs[i].valueSz;
01377         attribSz += ea[i].valueSz;
01378         ea[i].valueSetSz = SetSet(attribSz, ea[i].valueSet);
01379         attribSz += ea[i].valueSetSz;
01380         ea[i].oid = attribs[i].oid;
01381         ea[i].oidSz = attribs[i].oidSz;
01382         attribSz += ea[i].oidSz;
01383         ea[i].valueSeqSz = SetSequence(attribSz, ea[i].valueSeq);
01384         attribSz += ea[i].valueSeqSz;
01385         ea[i].totalSz = attribSz;
01386 
01387         allAttribsSz += attribSz;
01388     }
01389     return allAttribsSz;
01390 }
01391 
01392 
01393 typedef struct FlatAttrib {
01394     byte* data;
01395     word32 dataSz;
01396 } FlatAttrib;
01397 
01398 /* Returns a pointer to FlatAttrib whose members are initialized to 0.
01399 *  Caller is expected to free.
01400 */
01401 static FlatAttrib* NewAttrib(void* heap)
01402 {
01403     FlatAttrib* fb = (FlatAttrib*) XMALLOC(sizeof(FlatAttrib), heap,
01404                                                    DYNAMIC_TYPE_TMP_BUFFER);
01405     if (fb != NULL) {
01406         ForceZero(fb, sizeof(FlatAttrib));
01407     }
01408     (void)heap;
01409     return fb;
01410 }
01411 
01412 /* Free FlatAttrib array and memory allocated to internal struct members */
01413 static void FreeAttribArray(PKCS7* pkcs7, FlatAttrib** arr, int rows)
01414 {
01415     int i;
01416 
01417     if (arr) {
01418         for (i = 0; i < rows; i++) {
01419             if (arr[i]) {
01420                 if (arr[i]->data) {
01421                     ForceZero(arr[i]->data, arr[i]->dataSz);
01422                     XFREE(arr[i]->data, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
01423                 }
01424                 ForceZero(arr[i], sizeof(FlatAttrib));
01425                 XFREE(arr[i], pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
01426             }
01427         }
01428         ForceZero(arr, rows);
01429         XFREE(arr, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
01430     }
01431     (void)pkcs7;
01432 }
01433 
01434 
01435 /* Sort FlatAttrib array in ascending order */
01436 static int SortAttribArray(FlatAttrib** arr, int rows)
01437 {
01438     int i, j;
01439     word32 minSz, minIdx;
01440     FlatAttrib* a   = NULL;
01441     FlatAttrib* b   = NULL;
01442     FlatAttrib* tmp = NULL;
01443 
01444     if (arr == NULL) {
01445         return BAD_FUNC_ARG;
01446     }
01447 
01448     for (i = 0; i < rows; i++) {
01449         a = arr[i];
01450         minSz = a->dataSz;
01451         minIdx = i;
01452         for (j = i+1; j < rows; j++) {
01453             b = arr[j];
01454             if (b->dataSz < minSz) {
01455                 minSz = b->dataSz;
01456                 minIdx = j;
01457             }
01458         }
01459         if (minSz < a->dataSz) {
01460             /* swap array positions */
01461             tmp = arr[i];
01462             arr[i] = arr[minIdx];
01463             arr[minIdx] = tmp;
01464         }
01465     }
01466 
01467     return 0;
01468 }
01469 
01470 
01471 /* Build up array of FlatAttrib structs from EncodedAttrib ones. FlatAttrib
01472  * holds flattened DER encoding of each attribute */
01473 static int FlattenEncodedAttribs(PKCS7* pkcs7, FlatAttrib** derArr, int rows,
01474                                  EncodedAttrib* ea, int eaSz)
01475 {
01476     int i, idx, sz;
01477     byte* output   = NULL;
01478     FlatAttrib* fa = NULL;
01479 
01480     if (pkcs7 == NULL || derArr == NULL || ea == NULL) {
01481         WOLFSSL_MSG("Invalid arguments to FlattenEncodedAttribs");
01482         return BAD_FUNC_ARG;
01483     }
01484 
01485     if (rows != eaSz) {
01486         WOLFSSL_MSG("DER array not large enough to hold attribute count");
01487         return BAD_FUNC_ARG;
01488     }
01489 
01490     for (i = 0; i < eaSz; i++) {
01491         sz = ea[i].valueSeqSz + ea[i].oidSz + ea[i].valueSetSz + ea[i].valueSz;
01492 
01493         output = (byte*)XMALLOC(sz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
01494         if (output == NULL) {
01495             return MEMORY_E;
01496         }
01497 
01498         idx = 0;
01499         XMEMCPY(output + idx, ea[i].valueSeq, ea[i].valueSeqSz);
01500         idx += ea[i].valueSeqSz;
01501         XMEMCPY(output + idx, ea[i].oid, ea[i].oidSz);
01502         idx += ea[i].oidSz;
01503         XMEMCPY(output + idx, ea[i].valueSet, ea[i].valueSetSz);
01504         idx += ea[i].valueSetSz;
01505         XMEMCPY(output + idx, ea[i].value, ea[i].valueSz);
01506 
01507         fa = derArr[i];
01508         fa->data = output;
01509         fa->dataSz = sz;
01510     }
01511 
01512     return 0;
01513 }
01514 
01515 
01516 /* Sort and Flatten EncodedAttrib attributes into output buffer */
01517 static int FlattenAttributes(PKCS7* pkcs7, byte* output, EncodedAttrib* ea,
01518                              int eaSz)
01519 {
01520     int i, idx, ret;
01521     FlatAttrib** derArr = NULL;
01522     FlatAttrib*  fa     = NULL;
01523 
01524     if (pkcs7 == NULL || output == NULL || ea == NULL) {
01525         return BAD_FUNC_ARG;
01526     }
01527 
01528     /* create array of FlatAttrib struct pointers to hold DER attribs */
01529     derArr = (FlatAttrib**) XMALLOC(eaSz * sizeof(FlatAttrib*), pkcs7->heap,
01530                                     DYNAMIC_TYPE_TMP_BUFFER);
01531     if (derArr == NULL) {
01532         return MEMORY_E;
01533     }
01534     XMEMSET(derArr, 0, eaSz * sizeof(FlatAttrib*));
01535 
01536     for (i = 0; i < eaSz; i++) {
01537         derArr[i] = NewAttrib(pkcs7->heap);
01538         if (derArr[i] == NULL) {
01539             FreeAttribArray(pkcs7, derArr, eaSz);
01540             return MEMORY_E;
01541         }
01542         ForceZero(derArr[i], sizeof(FlatAttrib));
01543     }
01544 
01545     /* flatten EncodedAttrib into DER byte arrays */
01546     ret = FlattenEncodedAttribs(pkcs7, derArr, eaSz, ea, eaSz);
01547     if (ret != 0) {
01548         FreeAttribArray(pkcs7, derArr, eaSz);
01549         return ret;
01550     }
01551 
01552     /* SET OF DER signed attributes must be sorted in ascending order */
01553     ret = SortAttribArray(derArr, eaSz);
01554     if (ret != 0) {
01555         FreeAttribArray(pkcs7, derArr, eaSz);
01556         return ret;
01557     }
01558 
01559     /* copy sorted DER attribute arrays into output buffer */
01560     idx = 0;
01561     for (i = 0; i < eaSz; i++) {
01562         fa = derArr[i];
01563         XMEMCPY(output + idx, fa->data, fa->dataSz);
01564         idx += fa->dataSz;
01565     }
01566 
01567     FreeAttribArray(pkcs7, derArr, eaSz);
01568 
01569     return 0;
01570 }
01571 
01572 
01573 #ifndef NO_RSA
01574 
01575 /* returns size of signature put into out, negative on error */
01576 static int wc_PKCS7_RsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd)
01577 {
01578     int ret;
01579     word32 idx;
01580 #ifdef WOLFSSL_SMALL_STACK
01581     RsaKey* privKey;
01582 #else
01583     RsaKey  privKey[1];
01584 #endif
01585 
01586     if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) {
01587         return BAD_FUNC_ARG;
01588     }
01589 
01590 #ifdef WOLFSSL_SMALL_STACK
01591     privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
01592         DYNAMIC_TYPE_TMP_BUFFER);
01593     if (privKey == NULL)
01594         return MEMORY_E;
01595 #endif
01596 
01597     ret = wc_InitRsaKey_ex(privKey, pkcs7->heap, pkcs7->devId);
01598     if (ret == 0) {
01599         if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) {
01600             idx = 0;
01601             ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey,
01602                                          pkcs7->privateKeySz);
01603         }
01604         else if (pkcs7->devId == INVALID_DEVID) {
01605             ret = BAD_FUNC_ARG;
01606         }
01607     }
01608     if (ret == 0) {
01609     #ifdef WOLFSSL_ASYNC_CRYPT
01610         do {
01611             ret = wc_AsyncWait(ret, &privKey->asyncDev,
01612                 WC_ASYNC_FLAG_CALL_AGAIN);
01613             if (ret >= 0)
01614     #endif
01615             {
01616                 ret = wc_RsaSSL_Sign(in, inSz, esd->encContentDigest,
01617                                      sizeof(esd->encContentDigest),
01618                                      privKey, pkcs7->rng);
01619             }
01620     #ifdef WOLFSSL_ASYNC_CRYPT
01621         } while (ret == WC_PENDING_E);
01622     #endif
01623     }
01624 
01625     wc_FreeRsaKey(privKey);
01626 #ifdef WOLFSSL_SMALL_STACK
01627     XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
01628 #endif
01629 
01630     return ret;
01631 }
01632 
01633 #endif /* NO_RSA */
01634 
01635 
01636 #ifdef HAVE_ECC
01637 
01638 /* returns size of signature put into out, negative on error */
01639 static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd)
01640 {
01641     int ret;
01642     word32 outSz, idx;
01643 #ifdef WOLFSSL_SMALL_STACK
01644     ecc_key* privKey;
01645 #else
01646     ecc_key  privKey[1];
01647 #endif
01648 
01649     if (pkcs7 == NULL || pkcs7->rng == NULL || in == NULL || esd == NULL) {
01650         return BAD_FUNC_ARG;
01651     }
01652 
01653 #ifdef WOLFSSL_SMALL_STACK
01654     privKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
01655         DYNAMIC_TYPE_TMP_BUFFER);
01656     if (privKey == NULL)
01657         return MEMORY_E;
01658 #endif
01659 
01660     ret = wc_ecc_init_ex(privKey, pkcs7->heap, pkcs7->devId);
01661     if (ret == 0) {
01662         if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) {
01663             idx = 0;
01664             ret = wc_EccPrivateKeyDecode(pkcs7->privateKey, &idx, privKey,
01665                                          pkcs7->privateKeySz);
01666         }
01667         else if (pkcs7->devId == INVALID_DEVID) {
01668             ret = BAD_FUNC_ARG;
01669         }
01670     }
01671     if (ret == 0) {
01672         outSz = sizeof(esd->encContentDigest);
01673     #ifdef WOLFSSL_ASYNC_CRYPT
01674         do {
01675             ret = wc_AsyncWait(ret, &privKey->asyncDev,
01676                 WC_ASYNC_FLAG_CALL_AGAIN);
01677             if (ret >= 0)
01678     #endif
01679             {
01680                 ret = wc_ecc_sign_hash(in, inSz, esd->encContentDigest,
01681                                        &outSz, pkcs7->rng, privKey);
01682             }
01683     #ifdef WOLFSSL_ASYNC_CRYPT
01684         } while (ret == WC_PENDING_E);
01685     #endif
01686         if (ret == 0)
01687             ret = (int)outSz;
01688     }
01689 
01690     wc_ecc_free(privKey);
01691 #ifdef WOLFSSL_SMALL_STACK
01692     XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
01693 #endif
01694 
01695     return ret;
01696 }
01697 
01698 #endif /* HAVE_ECC */
01699 
01700 
01701 /* builds up SignedData signed attributes, including default ones.
01702  *
01703  * pkcs7 - pointer to initialized PKCS7 structure
01704  * esd   - pointer to initialized ESD structure, used for output
01705  *
01706  * return 0 on success, negative on error */
01707 static int wc_PKCS7_BuildSignedAttributes(PKCS7* pkcs7, ESD* esd,
01708                     const byte* contentType, word32 contentTypeSz,
01709                     const byte* contentTypeOid, word32 contentTypeOidSz,
01710                     const byte* messageDigestOid, word32 messageDigestOidSz,
01711                     const byte* signingTimeOid, word32 signingTimeOidSz,
01712                     byte* signingTime, word32 signingTimeSz)
01713 {
01714     int hashSz;
01715 #ifdef NO_ASN_TIME
01716     PKCS7Attrib cannedAttribs[2];
01717 #else
01718     time_t tm;
01719     int timeSz;
01720     PKCS7Attrib cannedAttribs[3];
01721 #endif
01722     word32 idx = 0;
01723     word32 cannedAttribsCount;
01724 
01725     if (pkcs7 == NULL || esd == NULL || contentType == NULL ||
01726         contentTypeOid == NULL || messageDigestOid == NULL ||
01727         signingTimeOid == NULL) {
01728         return BAD_FUNC_ARG;
01729     }
01730 
01731     if (pkcs7->skipDefaultSignedAttribs == 0) {
01732         hashSz = wc_HashGetDigestSize(esd->hashType);
01733         if (hashSz < 0)
01734             return hashSz;
01735 
01736     #ifndef NO_ASN_TIME
01737         if (signingTime == NULL || signingTimeSz == 0)
01738             return BAD_FUNC_ARG;
01739 
01740         tm = XTIME(0);
01741         timeSz = GetAsnTimeString(&tm, signingTime, signingTimeSz);
01742         if (timeSz < 0)
01743             return timeSz;
01744     #endif
01745 
01746         cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib);
01747 
01748         cannedAttribs[idx].oid     = contentTypeOid;
01749         cannedAttribs[idx].oidSz   = contentTypeOidSz;
01750         cannedAttribs[idx].value   = contentType;
01751         cannedAttribs[idx].valueSz = contentTypeSz;
01752         idx++;
01753     #ifndef NO_ASN_TIME
01754         cannedAttribs[idx].oid     = signingTimeOid;
01755         cannedAttribs[idx].oidSz   = signingTimeOidSz;
01756         cannedAttribs[idx].value   = signingTime;
01757         cannedAttribs[idx].valueSz = timeSz;
01758         idx++;
01759     #endif
01760         cannedAttribs[idx].oid     = messageDigestOid;
01761         cannedAttribs[idx].oidSz   = messageDigestOidSz;
01762         cannedAttribs[idx].value   = esd->contentDigest;
01763         cannedAttribs[idx].valueSz = hashSz + 2;  /* ASN.1 heading */
01764 
01765         esd->signedAttribsCount += cannedAttribsCount;
01766         esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[0], 3,
01767                                              cannedAttribs, cannedAttribsCount);
01768     } else {
01769         esd->signedAttribsCount = 0;
01770         esd->signedAttribsSz = 0;
01771     }
01772 
01773     /* add custom signed attributes if set */
01774     if (pkcs7->signedAttribsSz > 0 && pkcs7->signedAttribs != NULL) {
01775         esd->signedAttribsCount += pkcs7->signedAttribsSz;
01776     #ifdef NO_ASN_TIME
01777         esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[2], 4,
01778                                   pkcs7->signedAttribs, pkcs7->signedAttribsSz);
01779     #else
01780         esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[3], 4,
01781                                   pkcs7->signedAttribs, pkcs7->signedAttribsSz);
01782     #endif
01783     }
01784 
01785 #ifdef NO_ASN_TIME
01786     (void)signingTimeOidSz;
01787     (void)signingTime;
01788     (void)signingTimeSz;
01789 #endif
01790 
01791     return 0;
01792 }
01793 
01794 
01795 /* gets correct encryption algo ID for SignedData, either CTC_<hash>wRSA or
01796  * CTC_<hash>wECDSA, from pkcs7->publicKeyOID and pkcs7->hashOID.
01797  *
01798  * pkcs7          - pointer to PKCS7 structure
01799  * digEncAlgoId   - [OUT] output int to store correct algo ID in
01800  * digEncAlgoType - [OUT] output for algo ID type
01801  *
01802  * return 0 on success, negative on error */
01803 static int wc_PKCS7_SignedDataGetEncAlgoId(PKCS7* pkcs7, int* digEncAlgoId,
01804                                            int* digEncAlgoType)
01805 {
01806     int algoId   = 0;
01807     int algoType = 0;
01808 
01809     if (pkcs7 == NULL || digEncAlgoId == NULL || digEncAlgoType == NULL)
01810         return BAD_FUNC_ARG;
01811 
01812     if (pkcs7->publicKeyOID == RSAk) {
01813 
01814         algoType = oidSigType;
01815 
01816         switch (pkcs7->hashOID) {
01817         #ifndef NO_SHA
01818             case SHAh:
01819                 algoId = CTC_SHAwRSA;
01820                 break;
01821         #endif
01822         #ifdef WOLFSSL_SHA224
01823             case SHA224h:
01824                 algoId = CTC_SHA224wRSA;
01825                 break;
01826         #endif
01827         #ifndef NO_SHA256
01828             case SHA256h:
01829                 algoId = CTC_SHA256wRSA;
01830                 break;
01831         #endif
01832         #ifdef WOLFSSL_SHA384
01833             case SHA384h:
01834                 algoId = CTC_SHA384wRSA;
01835                 break;
01836         #endif
01837         #ifdef WOLFSSL_SHA512
01838             case SHA512h:
01839                 algoId = CTC_SHA512wRSA;
01840                 break;
01841         #endif
01842         }
01843 
01844     }
01845 #ifdef HAVE_ECC
01846     else if (pkcs7->publicKeyOID == ECDSAk) {
01847 
01848         algoType = oidSigType;
01849 
01850         switch (pkcs7->hashOID) {
01851         #ifndef NO_SHA
01852             case SHAh:
01853                 algoId = CTC_SHAwECDSA;
01854                 break;
01855         #endif
01856         #ifdef WOLFSSL_SHA224
01857             case SHA224h:
01858                 algoId = CTC_SHA224wECDSA;
01859                 break;
01860         #endif
01861         #ifndef NO_SHA256
01862             case SHA256h:
01863                 algoId = CTC_SHA256wECDSA;
01864                 break;
01865         #endif
01866         #ifdef WOLFSSL_SHA384
01867             case SHA384h:
01868                 algoId = CTC_SHA384wECDSA;
01869                 break;
01870         #endif
01871         #ifdef WOLFSSL_SHA512
01872             case SHA512h:
01873                 algoId = CTC_SHA512wECDSA;
01874                 break;
01875         #endif
01876         }
01877     }
01878 #endif /* HAVE_ECC */
01879 
01880     if (algoId == 0) {
01881         WOLFSSL_MSG("Invalid signature algorithm type");
01882         return BAD_FUNC_ARG;
01883     }
01884 
01885     *digEncAlgoId = algoId;
01886     *digEncAlgoType = algoType;
01887 
01888     return 0;
01889 }
01890 
01891 
01892 /* build SignedData DigestInfo for use with PKCS#7/RSA
01893  *
01894  * pkcs7 - pointer to initialized PKCS7 struct
01895  * flatSignedAttribs - flattened, signed attributes
01896  * flatSignedAttrbsSz - size of flatSignedAttribs, octets
01897  * esd - pointer to initialized ESD struct
01898  * digestInfo - [OUT] output array for DigestInfo
01899  * digestInfoSz - [IN/OUT] - input size of array, size of digestInfo
01900  *
01901  * return 0 on success, negative on error */
01902 static int wc_PKCS7_BuildDigestInfo(PKCS7* pkcs7, byte* flatSignedAttribs,
01903                                     word32 flatSignedAttribsSz, ESD* esd,
01904                                     byte* digestInfo, word32* digestInfoSz)
01905 {
01906     int ret, hashSz, digIdx = 0;
01907     byte digestInfoSeq[MAX_SEQ_SZ];
01908     byte digestStr[MAX_OCTET_STR_SZ];
01909     byte attribSet[MAX_SET_SZ];
01910     byte algoId[MAX_ALGO_SZ];
01911     word32 digestInfoSeqSz, digestStrSz, algoIdSz;
01912     word32 attribSetSz;
01913 
01914     if (pkcs7 == NULL || esd == NULL || digestInfo == NULL ||
01915         digestInfoSz == NULL) {
01916         return BAD_FUNC_ARG;
01917     }
01918 
01919     hashSz = wc_HashGetDigestSize(esd->hashType);
01920     if (hashSz < 0)
01921         return hashSz;
01922 
01923     if (flatSignedAttribsSz != 0) {
01924 
01925         if (flatSignedAttribs == NULL)
01926             return BAD_FUNC_ARG;
01927 
01928         attribSetSz = SetSet(flatSignedAttribsSz, attribSet);
01929 
01930         ret = wc_HashInit(&esd->hash, esd->hashType);
01931         if (ret < 0)
01932             return ret;
01933 
01934         ret = wc_HashUpdate(&esd->hash, esd->hashType,
01935                             attribSet, attribSetSz);
01936         if (ret == 0)
01937             ret = wc_HashUpdate(&esd->hash, esd->hashType,
01938                                 flatSignedAttribs, flatSignedAttribsSz);
01939         if (ret == 0)
01940             ret = wc_HashFinal(&esd->hash, esd->hashType,
01941                                esd->contentAttribsDigest);
01942         wc_HashFree(&esd->hash, esd->hashType);
01943 
01944         if (ret < 0)
01945             return ret;
01946 
01947     } else {
01948         /* when no attrs, digest is contentDigest without tag and length */
01949         XMEMCPY(esd->contentAttribsDigest, esd->contentDigest + 2, hashSz);
01950     }
01951 
01952     /* set algoID, with NULL attributes */
01953     algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0);
01954 
01955     digestStrSz = SetOctetString(hashSz, digestStr);
01956     digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz,
01957                                   digestInfoSeq);
01958 
01959     if (*digestInfoSz < (digestInfoSeqSz + algoIdSz + digestStrSz + hashSz)) {
01960         return BUFFER_E;
01961     }
01962 
01963     XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
01964     digIdx += digestInfoSeqSz;
01965     XMEMCPY(digestInfo + digIdx, algoId, algoIdSz);
01966     digIdx += algoIdSz;
01967     XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
01968     digIdx += digestStrSz;
01969     XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest, hashSz);
01970     digIdx += hashSz;
01971 
01972     *digestInfoSz = digIdx;
01973 
01974     return 0;
01975 }
01976 
01977 
01978 /* build SignedData signature over DigestInfo or content digest
01979  *
01980  * pkcs7 - pointer to initialized PKCS7 struct
01981  * flatSignedAttribs - flattened, signed attributes
01982  * flatSignedAttribsSz - size of flatSignedAttribs, octets
01983  * esd - pointer to initialized ESD struct
01984  *
01985  * returns length of signature on success, negative on error */
01986 static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7,
01987                                              byte* flatSignedAttribs,
01988                                              word32 flatSignedAttribsSz,
01989                                              ESD* esd)
01990 {
01991     int ret = 0;
01992 #if defined(HAVE_ECC) || \
01993     (defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA))
01994     int hashSz = 0;
01995 #endif
01996 #if defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA)
01997     int hashOID;
01998 #endif
01999     word32 digestInfoSz = MAX_PKCS7_DIGEST_SZ;
02000 #ifdef WOLFSSL_SMALL_STACK
02001     byte* digestInfo;
02002 #else
02003     byte  digestInfo[MAX_PKCS7_DIGEST_SZ];
02004 #endif
02005 
02006     if (pkcs7 == NULL || esd == NULL)
02007         return BAD_FUNC_ARG;
02008 
02009 #ifdef WOLFSSL_SMALL_STACK
02010     digestInfo = (byte*)XMALLOC(digestInfoSz, pkcs7->heap,
02011         DYNAMIC_TYPE_TMP_BUFFER);
02012     if (digestInfo == NULL) {
02013         return MEMORY_E;
02014     }
02015 #endif
02016     XMEMSET(digestInfo, 0, digestInfoSz);
02017 
02018     ret = wc_PKCS7_BuildDigestInfo(pkcs7, flatSignedAttribs,
02019                                    flatSignedAttribsSz, esd, digestInfo,
02020                                    &digestInfoSz);
02021     if (ret < 0) {
02022 #ifdef WOLFSSL_SMALL_STACK
02023         XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02024 #endif
02025         return ret;
02026     }
02027 
02028 #if defined(HAVE_ECC) || \
02029     (defined(HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK) && !defined(NO_RSA))
02030     /* get digest size from hash type */
02031     hashSz = wc_HashGetDigestSize(esd->hashType);
02032     if (hashSz < 0) {
02033     #ifdef WOLFSSL_SMALL_STACK
02034         XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02035     #endif
02036         return hashSz;
02037     }
02038 #endif
02039 
02040     /* sign digestInfo */
02041     switch (pkcs7->publicKeyOID) {
02042 
02043 #ifndef NO_RSA
02044         case RSAk:
02045         #ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
02046             if (pkcs7->rsaSignRawDigestCb != NULL) {
02047                 /* get hash OID */
02048                 hashOID = wc_HashGetOID(esd->hashType);
02049 
02050                 /* user signing plain digest, build DigestInfo themselves */
02051                 ret = pkcs7->rsaSignRawDigestCb(pkcs7,
02052                            esd->contentAttribsDigest, hashSz,
02053                            esd->encContentDigest, sizeof(esd->encContentDigest),
02054                            pkcs7->privateKey, pkcs7->privateKeySz, pkcs7->devId,
02055                            hashOID);
02056                 break;
02057             }
02058         #endif
02059             ret = wc_PKCS7_RsaSign(pkcs7, digestInfo, digestInfoSz, esd);
02060             break;
02061 #endif
02062 
02063 #ifdef HAVE_ECC
02064         case ECDSAk:
02065             /* CMS with ECDSA does not sign DigestInfo structure
02066              * like PKCS#7 with RSA does */
02067             ret = wc_PKCS7_EcdsaSign(pkcs7, esd->contentAttribsDigest,
02068                                      hashSz, esd);
02069             break;
02070 #endif
02071 
02072         default:
02073             WOLFSSL_MSG("Unsupported public key type");
02074             ret = BAD_FUNC_ARG;
02075     }
02076 
02077 #ifdef WOLFSSL_SMALL_STACK
02078     XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02079 #endif
02080 
02081     if (ret >= 0) {
02082         esd->encContentDigestSz = (word32)ret;
02083     }
02084 
02085     return ret;
02086 }
02087 
02088 
02089 /* build PKCS#7 signedData content type */
02090 static int PKCS7_EncodeSigned(PKCS7* pkcs7, ESD* esd,
02091     const byte* hashBuf, word32 hashSz, byte* output, word32* outputSz,
02092     byte* output2, word32* output2Sz)
02093 {
02094     /* contentType OID (1.2.840.113549.1.9.3) */
02095     const byte contentTypeOid[] =
02096             { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
02097                              0x09, 0x03 };
02098 
02099     /* messageDigest OID (1.2.840.113549.1.9.4) */
02100     const byte messageDigestOid[] =
02101             { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
02102                              0x09, 0x04 };
02103 
02104     /* signingTime OID () */
02105     byte signingTimeOid[] =
02106             { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
02107                              0x09, 0x05};
02108 
02109     Pkcs7Cert* certPtr = NULL;
02110     word32 certSetSz = 0;
02111 
02112     word32 signerInfoSz = 0;
02113     word32 totalSz, total2Sz;
02114     int idx = 0, ret = 0;
02115     int digEncAlgoId, digEncAlgoType;
02116     byte* flatSignedAttribs = NULL;
02117     word32 flatSignedAttribsSz = 0;
02118 
02119     byte signedDataOid[MAX_OID_SZ];
02120     word32 signedDataOidSz;
02121 
02122     byte signingTime[MAX_TIME_STRING_SZ];
02123 
02124     if (pkcs7 == NULL || pkcs7->contentSz == 0 ||
02125         pkcs7->encryptOID == 0 || pkcs7->hashOID == 0 || pkcs7->rng == 0 ||
02126         output == NULL || outputSz == NULL || *outputSz == 0 || hashSz == 0 ||
02127         hashBuf == NULL) {
02128         return BAD_FUNC_ARG;
02129     }
02130 
02131     /* verify the hash size matches */
02132 #ifdef WOLFSSL_SMALL_STACK
02133     esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02134     if (esd == NULL)
02135         return MEMORY_E;
02136 #endif
02137 
02138     XMEMSET(esd, 0, sizeof(ESD));
02139 
02140     /* set content type based on contentOID, unless user has set custom one
02141        with wc_PKCS7_SetContentType() */
02142     if (pkcs7->contentTypeSz == 0) {
02143 
02144         /* default to DATA content type if user has not set */
02145         if (pkcs7->contentOID == 0) {
02146             pkcs7->contentOID = DATA;
02147         }
02148 
02149         ret = wc_SetContentType(pkcs7->contentOID, pkcs7->contentType,
02150                                 sizeof(pkcs7->contentType));
02151         if (ret < 0) {
02152 #ifdef WOLFSSL_SMALL_STACK
02153         XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02154 #endif
02155             return ret;
02156         }
02157         pkcs7->contentTypeSz = ret;
02158     }
02159 
02160     /* set signedData outer content type */
02161     ret = wc_SetContentType(SIGNED_DATA, signedDataOid, sizeof(signedDataOid));
02162     if (ret < 0) {
02163 #ifdef WOLFSSL_SMALL_STACK
02164         XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02165 #endif
02166         return ret;
02167     }
02168     signedDataOidSz = ret;
02169 
02170     if (pkcs7->sidType != DEGENERATE_SID) {
02171         esd->hashType = wc_OidGetHash(pkcs7->hashOID);
02172         if (wc_HashGetDigestSize(esd->hashType) != (int)hashSz) {
02173             WOLFSSL_MSG("hashSz did not match hashOID");
02174     #ifdef WOLFSSL_SMALL_STACK
02175             XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02176     #endif
02177             return BUFFER_E;
02178         }
02179 
02180         /* include hash */
02181         esd->contentDigest[0] = ASN_OCTET_STRING;
02182         esd->contentDigest[1] = (byte)hashSz;
02183         XMEMCPY(&esd->contentDigest[2], hashBuf, hashSz);
02184     }
02185 
02186     if (pkcs7->detached == 1) {
02187         /* do not include content if generating detached signature */
02188         esd->innerOctetsSz = 0;
02189         esd->innerContSeqSz = 0;
02190         esd->contentInfoSeqSz = SetSequence(pkcs7->contentTypeSz,
02191                                             esd->contentInfoSeq);
02192     } else {
02193         esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets);
02194         esd->innerContSeqSz = SetExplicit(0, esd->innerOctetsSz +
02195                                     pkcs7->contentSz, esd->innerContSeq);
02196         esd->contentInfoSeqSz = SetSequence(pkcs7->contentSz +
02197                                     esd->innerOctetsSz + pkcs7->contentTypeSz +
02198                                     esd->innerContSeqSz, esd->contentInfoSeq);
02199     }
02200 
02201     /* SignerIdentifier */
02202     if (pkcs7->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
02203         /* IssuerAndSerialNumber */
02204         esd->issuerSnSz = SetSerialNumber(pkcs7->issuerSn, pkcs7->issuerSnSz,
02205                                           esd->issuerSn, MAX_SN_SZ, MAX_SN_SZ);
02206         signerInfoSz += esd->issuerSnSz;
02207         esd->issuerNameSz = SetSequence(pkcs7->issuerSz, esd->issuerName);
02208         signerInfoSz += esd->issuerNameSz + pkcs7->issuerSz;
02209         esd->issuerSnSeqSz = SetSequence(signerInfoSz, esd->issuerSnSeq);
02210         signerInfoSz += esd->issuerSnSeqSz;
02211 
02212         if (pkcs7->version == 3) {
02213             /* RFC 4108 version MUST be 3 for firmware package signer */
02214             esd->signerVersionSz = SetMyVersion(3, esd->signerVersion, 0);
02215         }
02216         else {
02217             /* version MUST be 1 otherwise*/
02218             esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0);
02219         }
02220 
02221     } else if (pkcs7->sidType == CMS_SKID) {
02222         /* SubjectKeyIdentifier */
02223         esd->issuerSKIDSz = SetOctetString(KEYID_SIZE, esd->issuerSKID);
02224         esd->issuerSKIDSeqSz = SetExplicit(0, esd->issuerSKIDSz + KEYID_SIZE,
02225                                            esd->issuerSKIDSeq);
02226         signerInfoSz += (esd->issuerSKIDSz + esd->issuerSKIDSeqSz +
02227                          KEYID_SIZE);
02228 
02229         /* version MUST be 3 */
02230         esd->signerVersionSz = SetMyVersion(3, esd->signerVersion, 0);
02231     } else if (pkcs7->sidType == DEGENERATE_SID) {
02232         /* no signer info added */
02233     } else {
02234     #ifdef WOLFSSL_SMALL_STACK
02235         XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02236     #endif
02237         return SKID_E;
02238     }
02239 
02240     if (pkcs7->sidType != DEGENERATE_SID) {
02241         signerInfoSz += esd->signerVersionSz;
02242         esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId,
02243                                           oidHashType, 0);
02244         signerInfoSz += esd->signerDigAlgoIdSz;
02245 
02246         /* set signatureAlgorithm */
02247         ret = wc_PKCS7_SignedDataGetEncAlgoId(pkcs7, &digEncAlgoId,
02248                                               &digEncAlgoType);
02249         if (ret < 0) {
02250     #ifdef WOLFSSL_SMALL_STACK
02251             XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02252     #endif
02253             return ret;
02254         }
02255         esd->digEncAlgoIdSz = SetAlgoID(digEncAlgoId, esd->digEncAlgoId,
02256                                         digEncAlgoType, 0);
02257         signerInfoSz += esd->digEncAlgoIdSz;
02258 
02259         /* build up signed attributes, include contentType, signingTime, and
02260            messageDigest by default */
02261         ret = wc_PKCS7_BuildSignedAttributes(pkcs7, esd, pkcs7->contentType,
02262                                      pkcs7->contentTypeSz,
02263                                      contentTypeOid, sizeof(contentTypeOid),
02264                                      messageDigestOid, sizeof(messageDigestOid),
02265                                      signingTimeOid, sizeof(signingTimeOid),
02266                                      signingTime, sizeof(signingTime));
02267         if (ret < 0) {
02268         #ifdef WOLFSSL_SMALL_STACK
02269             XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02270         #endif
02271             return ret;
02272         }
02273 
02274         if (esd->signedAttribsSz > 0) {
02275             flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, pkcs7->heap,
02276                                                              DYNAMIC_TYPE_PKCS7);
02277             flatSignedAttribsSz = esd->signedAttribsSz;
02278             if (flatSignedAttribs == NULL) {
02279             #ifdef WOLFSSL_SMALL_STACK
02280                 XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02281             #endif
02282                 return MEMORY_E;
02283             }
02284 
02285             FlattenAttributes(pkcs7, flatSignedAttribs,
02286                                        esd->signedAttribs, esd->signedAttribsCount);
02287             esd->signedAttribSetSz = SetImplicit(ASN_SET, 0, esd->signedAttribsSz,
02288                                                               esd->signedAttribSet);
02289         } else {
02290             esd->signedAttribSetSz = 0;
02291         }
02292 
02293         /* Calculate the final hash and encrypt it. */
02294         ret = wc_PKCS7_SignedDataBuildSignature(pkcs7, flatSignedAttribs,
02295                                                 flatSignedAttribsSz, esd);
02296         if (ret < 0) {
02297             if (pkcs7->signedAttribsSz != 0)
02298                 XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02299         #ifdef WOLFSSL_SMALL_STACK
02300             XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02301         #endif
02302             return ret;
02303         }
02304 
02305         signerInfoSz += flatSignedAttribsSz + esd->signedAttribSetSz;
02306 
02307         esd->signerDigestSz = SetOctetString(esd->encContentDigestSz,
02308                                                                  esd->signerDigest);
02309         signerInfoSz += esd->signerDigestSz + esd->encContentDigestSz;
02310 
02311         esd->signerInfoSeqSz = SetSequence(signerInfoSz, esd->signerInfoSeq);
02312         signerInfoSz += esd->signerInfoSeqSz;
02313     }
02314     esd->signerInfoSetSz = SetSet(signerInfoSz, esd->signerInfoSet);
02315     signerInfoSz += esd->signerInfoSetSz;
02316 
02317     /* certificates [0] IMPLICIT CertificateSet */
02318     /* get total certificates size */
02319     certPtr = pkcs7->certList;
02320     while (certPtr != NULL) {
02321         certSetSz += certPtr->derSz;
02322         certPtr = certPtr->next;
02323     }
02324     certPtr = NULL;
02325 
02326     if (certSetSz > 0)
02327         esd->certsSetSz = SetImplicit(ASN_SET, 0, certSetSz, esd->certsSet);
02328 
02329     if (pkcs7->sidType != DEGENERATE_SID) {
02330         esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId,
02331                                       oidHashType, 0);
02332     }
02333     esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet);
02334 
02335     if (pkcs7->version == 3) {
02336         /* RFC 4108 version MUST be 3 for firmware package signer */
02337         esd->versionSz = SetMyVersion(3, esd->version, 0);
02338     }
02339     else {
02340         esd->versionSz = SetMyVersion(1, esd->version, 0);
02341     }
02342 
02343     totalSz = esd->versionSz + esd->singleDigAlgoIdSz + esd->digAlgoIdSetSz +
02344               esd->contentInfoSeqSz + pkcs7->contentTypeSz +
02345               esd->innerContSeqSz + esd->innerOctetsSz + pkcs7->contentSz;
02346     total2Sz = esd->certsSetSz + certSetSz + signerInfoSz;
02347 
02348     if (pkcs7->detached) {
02349         totalSz -= pkcs7->contentSz;
02350     }
02351 
02352     esd->innerSeqSz = SetSequence(totalSz + total2Sz, esd->innerSeq);
02353     totalSz += esd->innerSeqSz;
02354     esd->outerContentSz = SetExplicit(0, totalSz + total2Sz, esd->outerContent);
02355     totalSz += esd->outerContentSz + signedDataOidSz;
02356     esd->outerSeqSz = SetSequence(totalSz + total2Sz, esd->outerSeq);
02357     totalSz += esd->outerSeqSz;
02358 
02359     /* if using header/footer, we are not returning the content */
02360     if (output2 && output2Sz) {
02361         if (total2Sz > *output2Sz) {
02362             if (pkcs7->signedAttribsSz != 0)
02363                 XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02364         #ifdef WOLFSSL_SMALL_STACK
02365             XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02366         #endif
02367             return BUFFER_E;
02368         }
02369 
02370         if (!pkcs7->detached) {
02371             totalSz -= pkcs7->contentSz;
02372         }
02373     }
02374     else {
02375         /* if using single output buffer include content and footer */
02376         totalSz += total2Sz;
02377     }
02378 
02379     if (totalSz > *outputSz) {
02380         if (pkcs7->signedAttribsSz != 0)
02381             XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02382     #ifdef WOLFSSL_SMALL_STACK
02383         XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02384     #endif
02385         return BUFFER_E;
02386     }
02387 
02388     idx = 0;
02389     XMEMCPY(output + idx, esd->outerSeq, esd->outerSeqSz);
02390     idx += esd->outerSeqSz;
02391     XMEMCPY(output + idx, signedDataOid, signedDataOidSz);
02392     idx += signedDataOidSz;
02393     XMEMCPY(output + idx, esd->outerContent, esd->outerContentSz);
02394     idx += esd->outerContentSz;
02395     XMEMCPY(output + idx, esd->innerSeq, esd->innerSeqSz);
02396     idx += esd->innerSeqSz;
02397     XMEMCPY(output + idx, esd->version, esd->versionSz);
02398     idx += esd->versionSz;
02399     XMEMCPY(output + idx, esd->digAlgoIdSet, esd->digAlgoIdSetSz);
02400     idx += esd->digAlgoIdSetSz;
02401     XMEMCPY(output + idx, esd->singleDigAlgoId, esd->singleDigAlgoIdSz);
02402     idx += esd->singleDigAlgoIdSz;
02403     XMEMCPY(output + idx, esd->contentInfoSeq, esd->contentInfoSeqSz);
02404     idx += esd->contentInfoSeqSz;
02405     XMEMCPY(output + idx, pkcs7->contentType, pkcs7->contentTypeSz);
02406     idx += pkcs7->contentTypeSz;
02407     XMEMCPY(output + idx, esd->innerContSeq, esd->innerContSeqSz);
02408     idx += esd->innerContSeqSz;
02409     XMEMCPY(output + idx, esd->innerOctets, esd->innerOctetsSz);
02410     idx += esd->innerOctetsSz;
02411 
02412     /* support returning header and footer without content */
02413     if (output2 && output2Sz) {
02414         *outputSz = idx;
02415         idx = 0;
02416     }
02417     else {
02418         if (!pkcs7->detached) {
02419             XMEMCPY(output + idx, pkcs7->content, pkcs7->contentSz);
02420             idx += pkcs7->contentSz;
02421         }
02422         output2 = output;
02423     }
02424 
02425     /* certificates */
02426     XMEMCPY(output2 + idx, esd->certsSet, esd->certsSetSz);
02427     idx += esd->certsSetSz;
02428     certPtr = pkcs7->certList;
02429     while (certPtr != NULL) {
02430         XMEMCPY(output2 + idx, certPtr->der, certPtr->derSz);
02431         idx += certPtr->derSz;
02432         certPtr = certPtr->next;
02433     }
02434     wc_PKCS7_FreeCertSet(pkcs7);
02435 
02436     XMEMCPY(output2 + idx, esd->signerInfoSet, esd->signerInfoSetSz);
02437     idx += esd->signerInfoSetSz;
02438     XMEMCPY(output2 + idx, esd->signerInfoSeq, esd->signerInfoSeqSz);
02439     idx += esd->signerInfoSeqSz;
02440     XMEMCPY(output2 + idx, esd->signerVersion, esd->signerVersionSz);
02441     idx += esd->signerVersionSz;
02442     /* SignerIdentifier */
02443     if (pkcs7->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
02444         /* IssuerAndSerialNumber */
02445         XMEMCPY(output2 + idx, esd->issuerSnSeq, esd->issuerSnSeqSz);
02446         idx += esd->issuerSnSeqSz;
02447         XMEMCPY(output2 + idx, esd->issuerName, esd->issuerNameSz);
02448         idx += esd->issuerNameSz;
02449         XMEMCPY(output2 + idx, pkcs7->issuer, pkcs7->issuerSz);
02450         idx += pkcs7->issuerSz;
02451         XMEMCPY(output2 + idx, esd->issuerSn, esd->issuerSnSz);
02452         idx += esd->issuerSnSz;
02453     } else if (pkcs7->sidType == CMS_SKID) {
02454         /* SubjectKeyIdentifier */
02455         XMEMCPY(output2 + idx, esd->issuerSKIDSeq, esd->issuerSKIDSeqSz);
02456         idx += esd->issuerSKIDSeqSz;
02457         XMEMCPY(output2 + idx, esd->issuerSKID, esd->issuerSKIDSz);
02458         idx += esd->issuerSKIDSz;
02459         XMEMCPY(output2 + idx, pkcs7->issuerSubjKeyId, KEYID_SIZE);
02460         idx += KEYID_SIZE;
02461     } else if (pkcs7->sidType == DEGENERATE_SID) {
02462         /* no signer infos in degenerate case */
02463     } else {
02464     #ifdef WOLFSSL_SMALL_STACK
02465         XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02466     #endif
02467         return SKID_E;
02468     }
02469     XMEMCPY(output2 + idx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz);
02470     idx += esd->signerDigAlgoIdSz;
02471 
02472     /* SignerInfo:Attributes */
02473     if (flatSignedAttribsSz > 0) {
02474         XMEMCPY(output2 + idx, esd->signedAttribSet, esd->signedAttribSetSz);
02475         idx += esd->signedAttribSetSz;
02476         XMEMCPY(output2 + idx, flatSignedAttribs, flatSignedAttribsSz);
02477         idx += flatSignedAttribsSz;
02478         XFREE(flatSignedAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02479     }
02480 
02481     XMEMCPY(output2 + idx, esd->digEncAlgoId, esd->digEncAlgoIdSz);
02482     idx += esd->digEncAlgoIdSz;
02483     XMEMCPY(output2 + idx, esd->signerDigest, esd->signerDigestSz);
02484     idx += esd->signerDigestSz;
02485     XMEMCPY(output2 + idx, esd->encContentDigest, esd->encContentDigestSz);
02486     idx += esd->encContentDigestSz;
02487 
02488     if (output2 && output2Sz) {
02489         *output2Sz = idx;
02490         idx = 0; /* success */
02491     }
02492     else {
02493         *outputSz = idx;
02494     }
02495 
02496 #ifdef WOLFSSL_SMALL_STACK
02497     XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02498 #endif
02499     return idx;
02500 }
02501 
02502 /* hashBuf: The computed digest for the pkcs7->content
02503  * hashSz: The size of computed digest for the pkcs7->content based on hashOID
02504  * outputHead: The PKCS7 header that goes on top of the raw data signed.
02505  * outputFoot: The PKCS7 footer that goes at the end of the raw data signed.
02506  * pkcs7->content: Not used
02507  * pkcs7->contentSz: Must be provided as actual sign of raw data
02508  * return codes: 0=success, negative=error
02509  */
02510 int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf,
02511     word32 hashSz, byte* outputHead, word32* outputHeadSz, byte* outputFoot,
02512     word32* outputFootSz)
02513 {
02514     int ret;
02515 #ifdef WOLFSSL_SMALL_STACK
02516     ESD* esd;
02517 #else
02518     ESD  esd[1];
02519 #endif
02520 
02521     /* other args checked in wc_PKCS7_EncodeSigned_ex */
02522     if (pkcs7 == NULL || outputFoot == NULL || outputFootSz == NULL) {
02523         return BAD_FUNC_ARG;
02524     }
02525 
02526 #ifdef WOLFSSL_SMALL_STACK
02527     esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02528     if (esd == NULL)
02529         return MEMORY_E;
02530 #endif
02531 
02532     XMEMSET(esd, 0, sizeof(ESD));
02533 
02534     ret = PKCS7_EncodeSigned(pkcs7, esd, hashBuf, hashSz,
02535         outputHead, outputHeadSz, outputFoot, outputFootSz);
02536 
02537 #ifdef WOLFSSL_SMALL_STACK
02538     XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02539 #endif
02540 
02541     return ret;
02542 }
02543 
02544 /* Toggle detached signature mode on/off for PKCS#7/CMS SignedData content type.
02545  * By default wolfCrypt includes the data to be signed in the SignedData
02546  * bundle. This data can be omitted in the case when a detached signature is
02547  * being created. To enable generation of detached signatures, set flag to "1",
02548  * otherwise set to "0":
02549  *
02550  *     flag 1 turns on support
02551  *     flag 0 turns off support
02552  *
02553  * pkcs7 - pointer to initialized PKCS7 structure
02554  * flag  - turn on/off detached signature generation (1 or 0)
02555  *
02556  * Returns 0 on success, negative upon error. */
02557 int wc_PKCS7_SetDetached(PKCS7* pkcs7, word16 flag)
02558 {
02559     if (pkcs7 == NULL || (flag != 0 && flag != 1))
02560         return BAD_FUNC_ARG;
02561 
02562     pkcs7->detached = flag;
02563 
02564     return 0;
02565 }
02566 
02567 /* By default, SignedData bundles have the following signed attributes attached:
02568  *     contentType (1.2.840.113549.1.9.3)
02569  *     signgingTime (1.2.840.113549.1.9.5)
02570  *     messageDigest (1.2.840.113549.1.9.4)
02571  *
02572  * Calling this API before wc_PKCS7_EncodeSignedData() will disable the
02573  * inclusion of those attributes.
02574  *
02575  * pkcs7 - pointer to initialized PKCS7 structure
02576  *
02577  * Returns 0 on success, negative upon error. */
02578 int wc_PKCS7_NoDefaultSignedAttribs(PKCS7* pkcs7)
02579 {
02580     if (pkcs7 == NULL)
02581         return BAD_FUNC_ARG;
02582 
02583     pkcs7->skipDefaultSignedAttribs = 1;
02584 
02585     return 0;
02586 }
02587 
02588 /* return codes: >0: Size of signed PKCS7 output buffer, negative: error */
02589 int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz)
02590 {
02591     int ret;
02592     int hashSz;
02593     enum wc_HashType hashType;
02594     byte hashBuf[WC_MAX_DIGEST_SIZE];
02595 #ifdef WOLFSSL_SMALL_STACK
02596     ESD* esd;
02597 #else
02598     ESD  esd[1];
02599 #endif
02600 
02601     /* other args checked in wc_PKCS7_EncodeSigned_ex */
02602     if (pkcs7 == NULL || pkcs7->contentSz == 0 || pkcs7->content == NULL) {
02603         return BAD_FUNC_ARG;
02604     }
02605 
02606     /* get hash type and size, validate hashOID */
02607     hashType = wc_OidGetHash(pkcs7->hashOID);
02608     hashSz = wc_HashGetDigestSize(hashType);
02609     if (hashSz < 0)
02610         return hashSz;
02611 
02612 #ifdef WOLFSSL_SMALL_STACK
02613     esd = (ESD*)XMALLOC(sizeof(ESD), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02614     if (esd == NULL)
02615         return MEMORY_E;
02616 #endif
02617 
02618     XMEMSET(esd, 0, sizeof(ESD));
02619     esd->hashType = hashType;
02620 
02621     /* calculate hash for content */
02622     ret = wc_HashInit(&esd->hash, esd->hashType);
02623     if (ret == 0) {
02624         ret = wc_HashUpdate(&esd->hash, esd->hashType,
02625                             pkcs7->content, pkcs7->contentSz);
02626         if (ret == 0) {
02627             ret = wc_HashFinal(&esd->hash, esd->hashType, hashBuf);
02628         }
02629         wc_HashFree(&esd->hash, esd->hashType);
02630     }
02631 
02632     if (ret == 0) {
02633         ret = PKCS7_EncodeSigned(pkcs7, esd, hashBuf, hashSz,
02634             output, &outputSz, NULL, NULL);
02635     }
02636 
02637 #ifdef WOLFSSL_SMALL_STACK
02638     XFREE(esd, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
02639 #endif
02640 
02641     return ret;
02642 }
02643 
02644 
02645 /* Single-shot API to generate a CMS SignedData bundle that encapsulates a
02646  * content of type FirmwarePkgData. Any recipient certificates should be
02647  * loaded into the PKCS7 structure prior to calling this function, using
02648  * wc_PKCS7_InitWithCert() and/or wc_PKCS7_AddCertificate().
02649  *
02650  * pkcs7                - pointer to initialized PKCS7 struct
02651  * privateKey           - private RSA/ECC key, used for signing SignedData
02652  * privateKeySz         - size of privateKey, octets
02653  * signOID              - public key algorithm OID, used for sign operation
02654  * hashOID              - hash algorithm OID, used for signature generation
02655  * content              - content to be encapsulated, of type FirmwarePkgData
02656  * contentSz            - size of content, octets
02657  * signedAttribs        - optional signed attributes
02658  * signedAttribsSz      - number of PKCS7Attrib members in signedAttribs
02659  * output               - output buffer for final bundle
02660  * outputSz             - size of output buffer, octets
02661  *
02662  * Returns length of generated bundle on success, negative upon error. */
02663 int wc_PKCS7_EncodeSignedFPD(PKCS7* pkcs7, byte* privateKey,
02664                              word32 privateKeySz, int signOID, int hashOID,
02665                              byte* content, word32 contentSz,
02666                              PKCS7Attrib* signedAttribs, word32 signedAttribsSz,
02667                              byte* output, word32 outputSz)
02668 {
02669     int ret = 0;
02670     WC_RNG rng;
02671 
02672     if (pkcs7 == NULL || privateKey == NULL || privateKeySz == 0 ||
02673         content == NULL || contentSz == 0 || output == NULL || outputSz == 0)
02674         return BAD_FUNC_ARG;
02675 
02676     ret = wc_InitRng(&rng);
02677     if (ret != 0)
02678         return ret;
02679 
02680     pkcs7->rng = &rng;
02681     pkcs7->content = content;
02682     pkcs7->contentSz = contentSz;
02683     pkcs7->contentOID = FIRMWARE_PKG_DATA;
02684     pkcs7->hashOID = hashOID;
02685     pkcs7->encryptOID = signOID;
02686     pkcs7->privateKey = privateKey;
02687     pkcs7->privateKeySz = privateKeySz;
02688     pkcs7->signedAttribs = signedAttribs;
02689     pkcs7->signedAttribsSz = signedAttribsSz;
02690     pkcs7->version = 3;
02691 
02692     ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
02693     if (ret <= 0) {
02694         WOLFSSL_MSG("Error encoding CMS SignedData content type");
02695     }
02696 
02697     pkcs7->rng = NULL;
02698     wc_FreeRng(&rng);
02699 
02700     return ret;
02701 }
02702 
02703 #ifndef NO_PKCS7_ENCRYPTED_DATA
02704 
02705 /* Single-shot API to generate a CMS SignedData bundle that encapsulates a
02706  * CMS EncryptedData bundle. Content of inner EncryptedData is set to that
02707  * of FirmwarePkgData. Any recipient certificates should be loaded into the
02708  * PKCS7 structure prior to calling this function, using wc_PKCS7_InitWithCert()
02709  * and/or wc_PKCS7_AddCertificate().
02710  *
02711  * pkcs7                - pointer to initialized PKCS7 struct
02712  * encryptKey           - encryption key used for encrypting EncryptedData
02713  * encryptKeySz         - size of encryptKey, octets
02714  * privateKey           - private RSA/ECC key, used for signing SignedData
02715  * privateKeySz         - size of privateKey, octets
02716  * encryptOID           - encryption algorithm OID, to be used as encryption
02717  *                        algorithm for EncryptedData
02718  * signOID              - public key algorithm OID, to be used for sign
02719  *                        operation in SignedData generation
02720  * hashOID              - hash algorithm OID, to be used for signature in
02721  *                        SignedData generation
02722  * content              - content to be encapsulated
02723  * contentSz            - size of content, octets
02724  * unprotectedAttribs   - optional unprotected attributes, for EncryptedData
02725  * unprotectedAttribsSz - number of PKCS7Attrib members in unprotectedAttribs
02726  * signedAttribs        - optional signed attributes, for SignedData
02727  * signedAttribsSz      - number of PKCS7Attrib members in signedAttribs
02728  * output               - output buffer for final bundle
02729  * outputSz             - size of output buffer, octets
02730  *
02731  * Returns length of generated bundle on success, negative upon error. */
02732 int wc_PKCS7_EncodeSignedEncryptedFPD(PKCS7* pkcs7, byte* encryptKey,
02733                                       word32 encryptKeySz, byte* privateKey,
02734                                       word32 privateKeySz, int encryptOID,
02735                                       int signOID, int hashOID,
02736                                       byte* content, word32 contentSz,
02737                                       PKCS7Attrib* unprotectedAttribs,
02738                                       word32 unprotectedAttribsSz,
02739                                       PKCS7Attrib* signedAttribs,
02740                                       word32 signedAttribsSz,
02741                                       byte* output, word32 outputSz)
02742 {
02743     int ret = 0, encryptedSz = 0;
02744     byte* encrypted = NULL;
02745     WC_RNG rng;
02746 
02747     if (pkcs7 == NULL || encryptKey == NULL || encryptKeySz == 0 ||
02748         privateKey == NULL || privateKeySz == 0 || content == NULL ||
02749         contentSz == 0 || output == NULL || outputSz == 0) {
02750         return BAD_FUNC_ARG;
02751     }
02752 
02753     /* 1: build up EncryptedData using FirmwarePkgData type, use output
02754      *    buffer as tmp for storage and to get size */
02755 
02756     /* set struct elements, inner content type is FirmwarePkgData */
02757     pkcs7->content = content;
02758     pkcs7->contentSz = contentSz;
02759     pkcs7->contentOID = FIRMWARE_PKG_DATA;
02760     pkcs7->encryptOID = encryptOID;
02761     pkcs7->encryptionKey = encryptKey;
02762     pkcs7->encryptionKeySz = encryptKeySz;
02763     pkcs7->unprotectedAttribs = unprotectedAttribs;
02764     pkcs7->unprotectedAttribsSz = unprotectedAttribsSz;
02765     pkcs7->version = 3;
02766 
02767     encryptedSz = wc_PKCS7_EncodeEncryptedData(pkcs7, output, outputSz);
02768     if (encryptedSz < 0) {
02769         WOLFSSL_MSG("Error encoding CMS EncryptedData content type");
02770         return encryptedSz;
02771     }
02772 
02773     /* save encryptedData, reset output buffer and struct */
02774     encrypted = (byte*)XMALLOC(encryptedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02775     if (encrypted == NULL) {
02776         ForceZero(output, outputSz);
02777         return MEMORY_E;
02778     }
02779 
02780     XMEMCPY(encrypted, output, encryptedSz);
02781     ForceZero(output, outputSz);
02782 
02783     ret = wc_InitRng(&rng);
02784     if (ret != 0) {
02785         ForceZero(encrypted, encryptedSz);
02786         XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02787         return ret;
02788     }
02789 
02790     /* 2: build up SignedData, encapsulating EncryptedData */
02791     pkcs7->rng = &rng;
02792     pkcs7->content = encrypted;
02793     pkcs7->contentSz = encryptedSz;
02794     pkcs7->contentOID = ENCRYPTED_DATA;
02795     pkcs7->hashOID = hashOID;
02796     pkcs7->encryptOID = signOID;
02797     pkcs7->privateKey = privateKey;
02798     pkcs7->privateKeySz = privateKeySz;
02799     pkcs7->signedAttribs = signedAttribs;
02800     pkcs7->signedAttribsSz = signedAttribsSz;
02801 
02802     ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
02803     if (ret <= 0) {
02804         WOLFSSL_MSG("Error encoding CMS SignedData content type");
02805     }
02806 
02807     ForceZero(encrypted, encryptedSz);
02808     XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02809     pkcs7->rng = NULL;
02810     wc_FreeRng(&rng);
02811 
02812     return ret;
02813 }
02814 
02815 #endif /* NO_PKCS7_ENCRYPTED_DATA */
02816 
02817 #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
02818 /* Single-shot API to generate a CMS SignedData bundle that encapsulates a
02819  * CMS CompressedData bundle. Content of inner CompressedData is set to that
02820  * of FirmwarePkgData. Any recipient certificates should be loaded into the
02821  * PKCS7 structure prior to calling this function, using wc_PKCS7_InitWithCert()
02822  * and/or wc_PKCS7_AddCertificate().
02823  *
02824  * pkcs7                - pointer to initialized PKCS7 struct
02825  * privateKey           - private RSA/ECC key, used for signing SignedData
02826  * privateKeySz         - size of privateKey, octets
02827  * signOID              - public key algorithm OID, to be used for sign
02828  *                        operation in SignedData generation
02829  * hashOID              - hash algorithm OID, to be used for signature in
02830  *                        SignedData generation
02831  * content              - content to be encapsulated
02832  * contentSz            - size of content, octets
02833  * signedAttribs        - optional signed attributes, for SignedData
02834  * signedAttribsSz      - number of PKCS7Attrib members in signedAttribs
02835  * output               - output buffer for final bundle
02836  * outputSz             - size of output buffer, octets
02837  *
02838  * Returns length of generated bundle on success, negative upon error. */
02839 int wc_PKCS7_EncodeSignedCompressedFPD(PKCS7* pkcs7, byte* privateKey,
02840                                        word32 privateKeySz, int signOID,
02841                                        int hashOID, byte* content,
02842                                        word32 contentSz,
02843                                        PKCS7Attrib* signedAttribs,
02844                                        word32 signedAttribsSz, byte* output,
02845                                        word32 outputSz)
02846 {
02847     int ret = 0, compressedSz = 0;
02848     byte* compressed = NULL;
02849     WC_RNG rng;
02850 
02851     if (pkcs7 == NULL || privateKey == NULL || privateKeySz == 0 ||
02852         content == NULL || contentSz == 0 || output == NULL || outputSz == 0) {
02853         return BAD_FUNC_ARG;
02854     }
02855 
02856     /* 1: build up CompressedData using FirmwarePkgData type, use output
02857      *    buffer as tmp for storage and to get size */
02858 
02859     /* set struct elements, inner content type is FirmwarePkgData */
02860     pkcs7->content = content;
02861     pkcs7->contentSz = contentSz;
02862     pkcs7->contentOID = FIRMWARE_PKG_DATA;
02863     pkcs7->version = 3;
02864 
02865     compressedSz = wc_PKCS7_EncodeCompressedData(pkcs7, output, outputSz);
02866     if (compressedSz < 0) {
02867         WOLFSSL_MSG("Error encoding CMS CompressedData content type");
02868         return compressedSz;
02869     }
02870 
02871     /* save compressedData, reset output buffer and struct */
02872     compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02873     if (compressed == NULL) {
02874         ForceZero(output, outputSz);
02875         return MEMORY_E;
02876     }
02877 
02878     XMEMCPY(compressed, output, compressedSz);
02879     ForceZero(output, outputSz);
02880 
02881     ret = wc_InitRng(&rng);
02882     if (ret != 0) {
02883         ForceZero(compressed, compressedSz);
02884         XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02885         return ret;
02886     }
02887 
02888     /* 2: build up SignedData, encapsulating EncryptedData */
02889     pkcs7->rng = &rng;
02890     pkcs7->content = compressed;
02891     pkcs7->contentSz = compressedSz;
02892     pkcs7->contentOID = COMPRESSED_DATA;
02893     pkcs7->hashOID = hashOID;
02894     pkcs7->encryptOID = signOID;
02895     pkcs7->privateKey = privateKey;
02896     pkcs7->privateKeySz = privateKeySz;
02897     pkcs7->signedAttribs = signedAttribs;
02898     pkcs7->signedAttribsSz = signedAttribsSz;
02899 
02900     ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
02901     if (ret <= 0) {
02902         WOLFSSL_MSG("Error encoding CMS SignedData content type");
02903     }
02904 
02905     ForceZero(compressed, compressedSz);
02906     XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02907     pkcs7->rng = NULL;
02908     wc_FreeRng(&rng);
02909 
02910     return ret;
02911 }
02912 
02913 #ifndef NO_PKCS7_ENCRYPTED_DATA
02914 
02915 /* Single-shot API to generate a CMS SignedData bundle that encapsulates a
02916  * CMS EncryptedData bundle, which then encapsulates a CMS CompressedData
02917  * bundle. Content of inner CompressedData is set to that of FirmwarePkgData.
02918  * Any recipient certificates should be loaded into the PKCS7 structure prior
02919  * to calling this function, using wc_PKCS7_InitWithCert() and/or
02920  * wc_PKCS7_AddCertificate().
02921  *
02922  * pkcs7                - pointer to initialized PKCS7 struct
02923  * encryptKey           - encryption key used for encrypting EncryptedData
02924  * encryptKeySz         - size of encryptKey, octets
02925  * privateKey           - private RSA/ECC key, used for signing SignedData
02926  * privateKeySz         - size of privateKey, octets
02927  * encryptOID           - encryption algorithm OID, to be used as encryption
02928  *                        algorithm for EncryptedData
02929  * signOID              - public key algorithm OID, to be used for sign
02930  *                        operation in SignedData generation
02931  * hashOID              - hash algorithm OID, to be used for signature in
02932  *                        SignedData generation
02933  * content              - content to be encapsulated
02934  * contentSz            - size of content, octets
02935  * unprotectedAttribs   - optional unprotected attributes, for EncryptedData
02936  * unprotectedAttribsSz - number of PKCS7Attrib members in unprotectedAttribs
02937  * signedAttribs        - optional signed attributes, for SignedData
02938  * signedAttribsSz      - number of PKCS7Attrib members in signedAttribs
02939  * output               - output buffer for final bundle
02940  * outputSz             - size of output buffer, octets
02941  *
02942  * Returns length of generated bundle on success, negative upon error. */
02943 int  wc_PKCS7_EncodeSignedEncryptedCompressedFPD(PKCS7* pkcs7, byte* encryptKey,
02944                                        word32 encryptKeySz, byte* privateKey,
02945                                        word32 privateKeySz, int encryptOID,
02946                                        int signOID, int hashOID, byte* content,
02947                                        word32 contentSz,
02948                                        PKCS7Attrib* unprotectedAttribs,
02949                                        word32 unprotectedAttribsSz,
02950                                        PKCS7Attrib* signedAttribs,
02951                                        word32 signedAttribsSz,
02952                                        byte* output, word32 outputSz)
02953 {
02954     int ret = 0, compressedSz = 0, encryptedSz = 0;
02955     byte* compressed = NULL;
02956     byte* encrypted = NULL;
02957     WC_RNG rng;
02958 
02959     if (pkcs7 == NULL || encryptKey == NULL || encryptKeySz == 0 ||
02960         privateKey == NULL || privateKeySz == 0 || content == NULL ||
02961         contentSz == 0 || output == NULL || outputSz == 0) {
02962         return BAD_FUNC_ARG;
02963     }
02964 
02965     /* 1: build up CompressedData using FirmwarePkgData type, use output
02966      *    buffer as tmp for storage and to get size */
02967     pkcs7->content = content;
02968     pkcs7->contentSz = contentSz;
02969     pkcs7->contentOID = FIRMWARE_PKG_DATA;
02970     pkcs7->version = 3;
02971 
02972     compressedSz = wc_PKCS7_EncodeCompressedData(pkcs7, output, outputSz);
02973     if (compressedSz < 0) {
02974         WOLFSSL_MSG("Error encoding CMS CompressedData content type");
02975         return compressedSz;
02976     }
02977 
02978     /* save compressedData, reset output buffer and struct */
02979     compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
02980     if (compressed == NULL)
02981         return MEMORY_E;
02982 
02983     XMEMCPY(compressed, output, compressedSz);
02984     ForceZero(output, outputSz);
02985 
02986     /* 2: build up EncryptedData using CompressedData, use output
02987      *    buffer as tmp for storage and to get size */
02988     pkcs7->content = compressed;
02989     pkcs7->contentSz = compressedSz;
02990     pkcs7->contentOID = COMPRESSED_DATA;
02991     pkcs7->encryptOID = encryptOID;
02992     pkcs7->encryptionKey = encryptKey;
02993     pkcs7->encryptionKeySz = encryptKeySz;
02994     pkcs7->unprotectedAttribs = unprotectedAttribs;
02995     pkcs7->unprotectedAttribsSz = unprotectedAttribsSz;
02996 
02997     encryptedSz = wc_PKCS7_EncodeEncryptedData(pkcs7, output, outputSz);
02998     if (encryptedSz < 0) {
02999         WOLFSSL_MSG("Error encoding CMS EncryptedData content type");
03000         XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03001         return encryptedSz;
03002     }
03003 
03004     /* save encryptedData, reset output buffer and struct */
03005     encrypted = (byte*)XMALLOC(encryptedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03006     if (encrypted == NULL) {
03007         ForceZero(compressed, compressedSz);
03008         XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03009         return MEMORY_E;
03010     }
03011 
03012     XMEMCPY(encrypted, output, encryptedSz);
03013     ForceZero(compressed, compressedSz);
03014     XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03015     ForceZero(output, outputSz);
03016 
03017     ret = wc_InitRng(&rng);
03018     if (ret != 0) {
03019         ForceZero(encrypted, encryptedSz);
03020         XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03021         return ret;
03022     }
03023 
03024     /* 3: build up SignedData, encapsulating EncryptedData */
03025     pkcs7->rng = &rng;
03026     pkcs7->content = encrypted;
03027     pkcs7->contentSz = encryptedSz;
03028     pkcs7->contentOID = ENCRYPTED_DATA;
03029     pkcs7->hashOID = hashOID;
03030     pkcs7->encryptOID = signOID;
03031     pkcs7->privateKey = privateKey;
03032     pkcs7->privateKeySz = privateKeySz;
03033     pkcs7->signedAttribs = signedAttribs;
03034     pkcs7->signedAttribsSz = signedAttribsSz;
03035 
03036     ret = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz);
03037     if (ret <= 0) {
03038         WOLFSSL_MSG("Error encoding CMS SignedData content type");
03039     }
03040 
03041     ForceZero(encrypted, encryptedSz);
03042     XFREE(encrypted, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03043     pkcs7->rng = NULL;
03044     wc_FreeRng(&rng);
03045 
03046     return ret;
03047 }
03048 
03049 #endif /* !NO_PKCS7_ENCRYPTED_DATA */
03050 #endif /* HAVE_LIBZ && !NO_PKCS7_COMPRESSED_DATA */
03051 
03052 
03053 #ifndef NO_RSA
03054 
03055 #ifdef HAVE_PKCS7_RSA_RAW_SIGN_CALLBACK
03056 /* register raw RSA sign digest callback */
03057 int wc_PKCS7_SetRsaSignRawDigestCb(PKCS7* pkcs7, CallbackRsaSignRawDigest cb)
03058 {
03059     if (pkcs7 == NULL || cb == NULL) {
03060         return BAD_FUNC_ARG;
03061     }
03062 
03063     pkcs7->rsaSignRawDigestCb = cb;
03064 
03065     return 0;
03066 }
03067 #endif
03068 
03069 /* returns size of signature put into out, negative on error */
03070 static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz,
03071                               byte* hash, word32 hashSz)
03072 {
03073     int ret = 0, i;
03074     word32 scratch = 0, verified = 0;
03075 #ifdef WOLFSSL_SMALL_STACK
03076     byte* digest;
03077     RsaKey* key;
03078     DecodedCert* dCert;
03079 #else
03080     byte digest[MAX_PKCS7_DIGEST_SZ];
03081     RsaKey key[1];
03082     DecodedCert stack_dCert;
03083     DecodedCert* dCert = &stack_dCert;
03084 #endif
03085 
03086     if (pkcs7 == NULL || sig == NULL || hash == NULL) {
03087         return BAD_FUNC_ARG;
03088     }
03089 
03090 #ifdef WOLFSSL_SMALL_STACK
03091     digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
03092                             DYNAMIC_TYPE_TMP_BUFFER);
03093     if (digest == NULL)
03094         return MEMORY_E;
03095 
03096     key = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03097     if (key == NULL) {
03098         XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03099         return MEMORY_E;
03100     }
03101 
03102     dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
03103                                   DYNAMIC_TYPE_DCERT);
03104     if (dCert == NULL) {
03105         XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03106         XFREE(key, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03107         return MEMORY_E;
03108     }
03109 #endif
03110 
03111     XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
03112 
03113     /* loop over certs received in certificates set, try to find one
03114      * that will validate signature */
03115     for (i = 0; i < MAX_PKCS7_CERTS; i++) {
03116 
03117         verified = 0;
03118         scratch  = 0;
03119 
03120         if (pkcs7->certSz[i] == 0)
03121             continue;
03122 
03123         ret = wc_InitRsaKey_ex(key, pkcs7->heap, pkcs7->devId);
03124         if (ret != 0) {
03125 #ifdef WOLFSSL_SMALL_STACK
03126             XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03127             XFREE(key,    pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03128             XFREE(dCert,  pkcs7->heap, DYNAMIC_TYPE_DCERT);
03129 #endif
03130             return ret;
03131         }
03132 
03133         InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap);
03134         /* not verifying, only using this to extract public key */
03135         ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
03136         if (ret < 0) {
03137             WOLFSSL_MSG("ASN RSA cert parse error");
03138             FreeDecodedCert(dCert);
03139             wc_FreeRsaKey(key);
03140             continue;
03141         }
03142 
03143         if (wc_RsaPublicKeyDecode(dCert->publicKey, &scratch, key,
03144                                   dCert->pubKeySize) < 0) {
03145             WOLFSSL_MSG("ASN RSA key decode error");
03146             FreeDecodedCert(dCert);
03147             wc_FreeRsaKey(key);
03148             continue;
03149         }
03150 
03151     #ifdef WOLFSSL_ASYNC_CRYPT
03152         do {
03153             ret = wc_AsyncWait(ret, &key->asyncDev,
03154                 WC_ASYNC_FLAG_CALL_AGAIN);
03155     #endif
03156             if (ret >= 0) {
03157                 ret = wc_RsaSSL_Verify(sig, sigSz, digest, MAX_PKCS7_DIGEST_SZ,
03158                     key);
03159             }
03160     #ifdef WOLFSSL_ASYNC_CRYPT
03161         } while (ret == WC_PENDING_E);
03162     #endif
03163         FreeDecodedCert(dCert);
03164         wc_FreeRsaKey(key);
03165 
03166         if ((ret > 0) && (hashSz == (word32)ret)) {
03167             if (XMEMCMP(digest, hash, hashSz) == 0) {
03168                 /* found signer that successfully verified signature */
03169                 verified = 1;
03170                 break;
03171             }
03172         }
03173     }
03174 
03175     if (verified == 0) {
03176         ret = SIG_VERIFY_E;
03177     }
03178 
03179 #ifdef WOLFSSL_SMALL_STACK
03180     XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03181     XFREE(key,    pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03182     XFREE(dCert,  pkcs7->heap, DYNAMIC_TYPE_DCERT);
03183 #endif
03184 
03185     return ret;
03186 }
03187 
03188 #endif /* NO_RSA */
03189 
03190 
03191 #ifdef HAVE_ECC
03192 
03193 /* returns size of signature put into out, negative on error */
03194 static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz,
03195                                 byte* hash, word32 hashSz)
03196 {
03197     int ret = 0, i;
03198     int res = 0;
03199     int verified = 0;
03200 #ifdef WOLFSSL_SMALL_STACK
03201     byte* digest;
03202     ecc_key* key;
03203     DecodedCert* dCert;
03204 #else
03205     byte digest[MAX_PKCS7_DIGEST_SZ];
03206     ecc_key key[1];
03207     DecodedCert stack_dCert;
03208     DecodedCert* dCert = &stack_dCert;
03209 #endif
03210     word32 idx = 0;
03211 
03212     if (pkcs7 == NULL || sig == NULL)
03213         return BAD_FUNC_ARG;
03214 
03215 #ifdef WOLFSSL_SMALL_STACK
03216     digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
03217                             DYNAMIC_TYPE_TMP_BUFFER);
03218     if (digest == NULL)
03219         return MEMORY_E;
03220 
03221     key = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03222     if (key == NULL) {
03223         XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03224         return MEMORY_E;
03225     }
03226 
03227     dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
03228                                   DYNAMIC_TYPE_DCERT);
03229     if (dCert == NULL) {
03230         XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03231         XFREE(key,    pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03232         return MEMORY_E;
03233     }
03234 #endif
03235 
03236     XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
03237 
03238     /* loop over certs received in certificates set, try to find one
03239      * that will validate signature */
03240     for (i = 0; i < MAX_PKCS7_CERTS; i++) {
03241 
03242         verified = 0;
03243 
03244         if (pkcs7->certSz[i] == 0)
03245             continue;
03246 
03247         ret = wc_ecc_init_ex(key, pkcs7->heap, pkcs7->devId);
03248         if (ret != 0) {
03249 #ifdef WOLFSSL_SMALL_STACK
03250             XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03251             XFREE(key,    pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03252             XFREE(dCert,  pkcs7->heap, DYNAMIC_TYPE_DCERT);
03253 #endif
03254             return ret;
03255         }
03256 
03257         InitDecodedCert(dCert, pkcs7->cert[i], pkcs7->certSz[i], pkcs7->heap);
03258         /* not verifying, only using this to extract public key */
03259         ret = ParseCert(dCert, CA_TYPE, NO_VERIFY, 0);
03260         if (ret < 0) {
03261             WOLFSSL_MSG("ASN ECC cert parse error");
03262             FreeDecodedCert(dCert);
03263             wc_ecc_free(key);
03264             continue;
03265         }
03266 
03267         if (wc_EccPublicKeyDecode(pkcs7->publicKey, &idx, key,
03268                                   pkcs7->publicKeySz) < 0) {
03269             WOLFSSL_MSG("ASN ECC key decode error");
03270             FreeDecodedCert(dCert);
03271             wc_ecc_free(key);
03272             continue;
03273         }
03274 
03275     #ifdef WOLFSSL_ASYNC_CRYPT
03276         do {
03277             ret = wc_AsyncWait(ret, &key->asyncDev,
03278                 WC_ASYNC_FLAG_CALL_AGAIN);
03279     #endif
03280             if (ret >= 0) {
03281                 ret = wc_ecc_verify_hash(sig, sigSz, hash, hashSz, &res, key);
03282             }
03283     #ifdef WOLFSSL_ASYNC_CRYPT
03284         } while (ret == WC_PENDING_E);
03285     #endif
03286 
03287         FreeDecodedCert(dCert);
03288         wc_ecc_free(key);
03289 
03290         if (ret == 0 && res == 1) {
03291             /* found signer that successfully verified signature */
03292             verified = 1;
03293             break;
03294         }
03295     }
03296 
03297     if (verified == 0) {
03298         ret = SIG_VERIFY_E;
03299     }
03300 
03301 #ifdef WOLFSSL_SMALL_STACK
03302     XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03303     XFREE(key,    pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03304     XFREE(dCert,  pkcs7->heap, DYNAMIC_TYPE_DCERT);
03305 #endif
03306 
03307     return ret;
03308 }
03309 
03310 #endif /* HAVE_ECC */
03311 
03312 
03313 /* build SignedData digest, both in PKCS#7 DigestInfo format and
03314  * as plain digest for CMS.
03315  *
03316  * pkcs7          - pointer to initialized PKCS7 struct
03317  * signedAttrib   - signed attributes
03318  * signedAttribSz - size of signedAttrib, octets
03319  * pkcs7Digest    - [OUT] PKCS#7 DigestInfo
03320  * pkcs7DigestSz  - [IN/OUT] size of pkcs7Digest
03321  * plainDigest    - [OUT] pointer to plain digest, offset into pkcs7Digest
03322  * plainDigestSz  - [OUT] size of digest at plainDigest
03323  *
03324  * returns 0 on success, negative on error */
03325 static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib,
03326                                       word32 signedAttribSz, byte* pkcs7Digest,
03327                                       word32* pkcs7DigestSz, byte** plainDigest,
03328                                       word32* plainDigestSz,
03329                                       const byte* hashBuf, word32 hashBufSz)
03330 {
03331     int ret = 0, digIdx = 0;
03332     word32 attribSetSz = 0, hashSz = 0;
03333     byte attribSet[MAX_SET_SZ];
03334     byte digest[WC_MAX_DIGEST_SIZE];
03335     byte digestInfoSeq[MAX_SEQ_SZ];
03336     byte digestStr[MAX_OCTET_STR_SZ];
03337     byte algoId[MAX_ALGO_SZ];
03338     word32 digestInfoSeqSz, digestStrSz, algoIdSz;
03339 #ifdef WOLFSSL_SMALL_STACK
03340     byte* digestInfo;
03341 #else
03342     byte  digestInfo[MAX_PKCS7_DIGEST_SZ];
03343 #endif
03344 
03345     wc_HashAlg hash;
03346     enum wc_HashType hashType;
03347 
03348     /* check arguments */
03349     if (pkcs7 == NULL || pkcs7Digest == NULL ||
03350         pkcs7DigestSz == NULL || plainDigest == NULL) {
03351         return BAD_FUNC_ARG;
03352     }
03353 
03354     hashType = wc_OidGetHash(pkcs7->hashOID);
03355     ret = wc_HashGetDigestSize(hashType);
03356     if (ret < 0)
03357         return ret;
03358     hashSz = ret;
03359 
03360     if (signedAttribSz > 0) {
03361         if (signedAttrib == NULL)
03362             return BAD_FUNC_ARG;
03363     }
03364     else {
03365         if (hashBuf && hashBufSz > 0) {
03366             if (hashSz != hashBufSz)
03367                 return BAD_FUNC_ARG;
03368         }
03369         else if (pkcs7->content == NULL)
03370             return BAD_FUNC_ARG;
03371     }
03372 
03373 #ifdef WOLFSSL_SMALL_STACK
03374     digestInfo = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
03375         DYNAMIC_TYPE_TMP_BUFFER);
03376     if (digestInfo == NULL)
03377         return MEMORY_E;
03378 #endif
03379 
03380     XMEMSET(pkcs7Digest, 0, *pkcs7DigestSz);
03381     XMEMSET(digest,      0, WC_MAX_DIGEST_SIZE);
03382     XMEMSET(digestInfo,  0, MAX_PKCS7_DIGEST_SZ);
03383 
03384 
03385     /* calculate digest */
03386     if (hashBuf && hashBufSz > 0 && signedAttribSz == 0) {
03387         XMEMCPY(digest, hashBuf, hashBufSz);
03388     }
03389     else {
03390         ret = wc_HashInit(&hash, hashType);
03391         if (ret < 0) {
03392     #ifdef WOLFSSL_SMALL_STACK
03393             XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03394     #endif
03395             return ret;
03396         }
03397 
03398         if (signedAttribSz > 0) {
03399             attribSetSz = SetSet(signedAttribSz, attribSet);
03400 
03401             /* calculate digest */
03402             ret = wc_HashUpdate(&hash, hashType, attribSet, attribSetSz);
03403             if (ret == 0)
03404                 ret = wc_HashUpdate(&hash, hashType, signedAttrib, signedAttribSz);
03405             if (ret == 0)
03406                 ret = wc_HashFinal(&hash, hashType, digest);
03407         } else {
03408             ret = wc_HashUpdate(&hash, hashType, pkcs7->content, pkcs7->contentSz);
03409             if (ret == 0)
03410                 ret = wc_HashFinal(&hash, hashType, digest);
03411         }
03412 
03413         wc_HashFree(&hash, hashType);
03414         if (ret < 0) {
03415     #ifdef WOLFSSL_SMALL_STACK
03416             XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03417     #endif
03418             return ret;
03419         }
03420     }
03421 
03422     /* Set algoID, with NULL attributes */
03423     algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0);
03424 
03425     digestStrSz = SetOctetString(hashSz, digestStr);
03426     digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz,
03427                                   digestInfoSeq);
03428 
03429     XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz);
03430     digIdx += digestInfoSeqSz;
03431     XMEMCPY(digestInfo + digIdx, algoId, algoIdSz);
03432     digIdx += algoIdSz;
03433     XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz);
03434     digIdx += digestStrSz;
03435     XMEMCPY(digestInfo + digIdx, digest, hashSz);
03436     digIdx += hashSz;
03437 
03438     XMEMCPY(pkcs7Digest, digestInfo, digIdx);
03439     *pkcs7DigestSz = digIdx;
03440 
03441     /* set plain digest pointer */
03442     *plainDigest = pkcs7Digest + digIdx - hashSz;
03443     *plainDigestSz = hashSz;
03444 
03445 #ifdef WOLFSSL_SMALL_STACK
03446     XFREE(digestInfo, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03447 #endif
03448     return 0;
03449 }
03450 
03451 
03452 /* Verifies CMS/PKCS7 SignedData content digest matches that which is
03453  * included in the messageDigest signed attribute. Only called when
03454  * signed attributes are present, otherwise original signature verification
03455  * is done over content.
03456  *
03457  * pkcs7          - pointer to initialized PKCS7 struct
03458  * hashBuf        - pointer to user-provided hash buffer, used with
03459  *                  wc_PKCS7_VerifySignedData_ex()
03460  * hashBufSz      - size of hashBuf, octets
03461  *
03462  * return 0 on success, negative on error */
03463 static int wc_PKCS7_VerifyContentMessageDigest(PKCS7* pkcs7,
03464                                                const byte* hashBuf,
03465                                                word32 hashSz)
03466 {
03467     int ret = 0, digestSz = 0, innerAttribSz = 0;
03468     word32 idx = 0;
03469     byte* digestBuf = NULL;
03470 #ifdef WOLFSSL_SMALL_STACK
03471     byte* digest = NULL;
03472 #else
03473     byte  digest[MAX_PKCS7_DIGEST_SZ];
03474 #endif
03475     PKCS7DecodedAttrib* attrib;
03476     enum wc_HashType hashType;
03477 
03478     /* messageDigest OID (1.2.840.113549.1.9.4) */
03479     const byte mdOid[] =
03480             { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04 };
03481 
03482     if (pkcs7 == NULL)
03483         return BAD_FUNC_ARG;
03484 
03485     if ((pkcs7->content == NULL || pkcs7->contentSz == 0) &&
03486         (hashBuf == NULL || hashSz == 0)) {
03487         WOLFSSL_MSG("SignedData bundle has no content or hash to verify");
03488         return BAD_FUNC_ARG;
03489     }
03490 
03491     /* lookup messageDigest attribute */
03492     attrib = findAttrib(pkcs7, mdOid, sizeof(mdOid));
03493     if (attrib == NULL) {
03494         WOLFSSL_MSG("messageDigest attribute not in bundle, must be when "
03495                     "signed attribs are present");
03496         return ASN_PARSE_E;
03497     }
03498 
03499     /* advance past attrib->value ASN.1 header and length */
03500     if (attrib->value == NULL || attrib->valueSz == 0)
03501         return ASN_PARSE_E;
03502 
03503     if (attrib->value[idx++] != ASN_OCTET_STRING)
03504         return ASN_PARSE_E;
03505 
03506     if (GetLength(attrib->value, &idx, &innerAttribSz, attrib->valueSz) < 0)
03507         return ASN_PARSE_E;
03508 
03509     /* get hash type and size */
03510     hashType = wc_OidGetHash(pkcs7->hashOID);
03511     if (hashType == WC_HASH_TYPE_NONE) {
03512         WOLFSSL_MSG("Error getting hash type for PKCS7 content verification");
03513         return BAD_FUNC_ARG;
03514     }
03515 
03516     /* build content hash if needed, or use existing hash value */
03517     if (hashBuf == NULL) {
03518 
03519 #ifdef WOLFSSL_SMALL_STACK
03520         digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, pkcs7->heap,
03521                                 DYNAMIC_TYPE_TMP_BUFFER);
03522         if (digest == NULL)
03523             return MEMORY_E;
03524 #endif
03525         XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ);
03526 
03527         ret = wc_Hash(hashType, pkcs7->content, pkcs7->contentSz, digest,
03528                       MAX_PKCS7_DIGEST_SZ);
03529         if (ret < 0) {
03530             WOLFSSL_MSG("Error hashing PKCS7 content for verification");
03531 #ifdef WOLFSSL_SMALL_STACK
03532             XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03533 #endif
03534             return ret;
03535         }
03536 
03537         digestBuf = digest;
03538         digestSz = wc_HashGetDigestSize(hashType);
03539         if (digestSz < 0) {
03540             WOLFSSL_MSG("Invalid hash type");
03541 #ifdef WOLFSSL_SMALL_STACK
03542             XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03543 #endif
03544             return digestSz;
03545         }
03546     } else {
03547 
03548         /* user passed in pre-computed hash */
03549         digestBuf = (byte*)hashBuf;
03550         digestSz  = (int)hashSz;
03551     }
03552 
03553     /* compare generated to hash in messageDigest attribute */
03554     if ((innerAttribSz != digestSz) ||
03555         (XMEMCMP(attrib->value + idx, digestBuf, (word32)digestSz) != 0)) {
03556         WOLFSSL_MSG("Content digest does not match messageDigest attrib value");
03557 #ifdef WOLFSSL_SMALL_STACK
03558         XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03559 #endif
03560         return SIG_VERIFY_E;
03561     }
03562 
03563     if (hashBuf == NULL) {
03564 #ifdef WOLFSSL_SMALL_STACK
03565         XFREE(digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03566 #endif
03567     }
03568 
03569     return 0;
03570 }
03571 
03572 
03573 /* verifies SignedData signature, over either PKCS#7 DigestInfo or
03574  * content digest.
03575  *
03576  * pkcs7          - pointer to initialized PKCS7 struct
03577  * sig            - signature to verify
03578  * sigSz          - size of sig
03579  * signedAttrib   - signed attributes, or null if empty
03580  * signedAttribSz - size of signedAttributes
03581  *
03582  * return 0 on success, negative on error */
03583 static int wc_PKCS7_SignedDataVerifySignature(PKCS7* pkcs7, byte* sig,
03584                                              word32 sigSz, byte* signedAttrib,
03585                                              word32 signedAttribSz,
03586                                              const byte* hashBuf, word32 hashSz)
03587 {
03588     int ret = 0;
03589     word32 plainDigestSz = 0, pkcs7DigestSz;
03590     byte* plainDigest = NULL; /* offset into pkcs7Digest */
03591 #ifdef WOLFSSL_SMALL_STACK
03592     byte* pkcs7Digest;
03593 #else
03594     byte  pkcs7Digest[MAX_PKCS7_DIGEST_SZ];
03595 #endif
03596 
03597     if (pkcs7 == NULL)
03598         return BAD_FUNC_ARG;
03599 
03600     /* allocate space to build hash */
03601     pkcs7DigestSz = MAX_PKCS7_DIGEST_SZ;
03602 #ifdef WOLFSSL_SMALL_STACK
03603     pkcs7Digest = (byte*)XMALLOC(pkcs7DigestSz, pkcs7->heap,
03604                                  DYNAMIC_TYPE_TMP_BUFFER);
03605     if (pkcs7Digest == NULL)
03606         return MEMORY_E;
03607 #endif
03608 
03609     XMEMSET(pkcs7Digest, 0, pkcs7DigestSz);
03610 
03611     /* verify signed attrib digest matches that of content */
03612     if (signedAttrib != NULL) {
03613         ret = wc_PKCS7_VerifyContentMessageDigest(pkcs7, hashBuf, hashSz);
03614         if (ret != 0) {
03615 #ifdef WOLFSSL_SMALL_STACK
03616             XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03617 #endif
03618             return ret;
03619         }
03620     }
03621 
03622     /* build hash to verify against */
03623     ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib,
03624                                          signedAttribSz, pkcs7Digest,
03625                                          &pkcs7DigestSz, &plainDigest,
03626                                          &plainDigestSz, hashBuf, hashSz);
03627     if (ret < 0) {
03628 #ifdef WOLFSSL_SMALL_STACK
03629         XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03630 #endif
03631         return ret;
03632     }
03633 
03634     /* If no certificates are available then store the signature and hash for
03635      * user to verify. Make sure that different return value than success is
03636      * returned because the signature was not verified here. */
03637     if (ret == 0) {
03638         byte haveCert = 0;
03639         int  i;
03640 
03641         for (i = 0; i < MAX_PKCS7_CERTS; i++) {
03642             if (pkcs7->certSz[i] == 0)
03643                 continue;
03644             haveCert = 1;
03645         }
03646 
03647         if (!haveCert) {
03648             WOLFSSL_MSG("No certificates in bundle to verify signature");
03649 
03650             /* store signature */
03651             XFREE(pkcs7->signature, pkcs7->heap, DYNAMIC_TYPE_SIGNATURE);
03652             pkcs7->signature = NULL;
03653             pkcs7->signatureSz = 0;
03654             pkcs7->signature = (byte*)XMALLOC(sigSz, pkcs7->heap,
03655                     DYNAMIC_TYPE_SIGNATURE);
03656             if (pkcs7->signature == NULL) {
03657             #ifdef WOLFSSL_SMALL_STACK
03658                 XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03659             #endif
03660                 return MEMORY_E;
03661             }
03662             XMEMCPY(pkcs7->signature, sig, sigSz);
03663             pkcs7->signatureSz = sigSz;
03664 
03665             /* store plain digest (CMS and ECC) */
03666             XFREE(pkcs7->plainDigest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
03667             pkcs7->plainDigest = NULL;
03668             pkcs7->plainDigestSz = 0;
03669             pkcs7->plainDigest = (byte*)XMALLOC(plainDigestSz, pkcs7->heap,
03670                     DYNAMIC_TYPE_DIGEST);
03671             if (pkcs7->plainDigest == NULL) {
03672             #ifdef WOLFSSL_SMALL_STACK
03673                 XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03674             #endif
03675                 return MEMORY_E;
03676             }
03677             XMEMCPY(pkcs7->plainDigest, plainDigest, plainDigestSz);
03678             pkcs7->plainDigestSz = plainDigestSz;
03679 
03680             /* store pkcs7 digest (default RSA) */
03681             XFREE(pkcs7->pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_DIGEST);
03682             pkcs7->pkcs7Digest = NULL;
03683             pkcs7->pkcs7DigestSz = 0;
03684             pkcs7->pkcs7Digest = (byte*)XMALLOC(pkcs7DigestSz, pkcs7->heap,
03685                     DYNAMIC_TYPE_DIGEST);
03686             if (pkcs7->pkcs7Digest == NULL) {
03687             #ifdef WOLFSSL_SMALL_STACK
03688                 XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03689             #endif
03690                 return MEMORY_E;
03691             }
03692             XMEMCPY(pkcs7->pkcs7Digest, pkcs7Digest, pkcs7DigestSz);
03693             pkcs7->pkcs7DigestSz = pkcs7DigestSz;
03694 
03695             #ifdef WOLFSSL_SMALL_STACK
03696             XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03697             #endif
03698             return PKCS7_SIGNEEDS_CHECK;
03699         }
03700     }
03701 
03702 
03703 
03704     switch (pkcs7->publicKeyOID) {
03705 
03706 #ifndef NO_RSA
03707         case RSAk:
03708             ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, pkcs7Digest,
03709                                      pkcs7DigestSz);
03710             if (ret < 0) {
03711                 WOLFSSL_MSG("PKCS#7 verification failed, trying CMS");
03712                 ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, plainDigest,
03713                                          plainDigestSz);
03714             }
03715             break;
03716 #endif
03717 
03718 #ifdef HAVE_ECC
03719         case ECDSAk:
03720             ret = wc_PKCS7_EcdsaVerify(pkcs7, sig, sigSz, plainDigest,
03721                                        plainDigestSz);
03722             break;
03723 #endif
03724 
03725         default:
03726             WOLFSSL_MSG("Unsupported public key type");
03727             ret = BAD_FUNC_ARG;
03728     }
03729 
03730 #ifdef WOLFSSL_SMALL_STACK
03731      XFREE(pkcs7Digest, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
03732 #endif
03733     return ret;
03734 }
03735 
03736 
03737 /* set correct public key OID based on signature OID, stores in
03738  * pkcs7->publicKeyOID and returns same value */
03739 static int wc_PKCS7_SetPublicKeyOID(PKCS7* pkcs7, int sigOID)
03740 {
03741     if (pkcs7 == NULL)
03742         return BAD_FUNC_ARG;
03743 
03744     pkcs7->publicKeyOID = 0;
03745 
03746     switch (sigOID) {
03747 
03748     #ifndef NO_RSA
03749         /* RSA signature types */
03750         case CTC_MD2wRSA:
03751         case CTC_MD5wRSA:
03752         case CTC_SHAwRSA:
03753         case CTC_SHA224wRSA:
03754         case CTC_SHA256wRSA:
03755         case CTC_SHA384wRSA:
03756         case CTC_SHA512wRSA:
03757             pkcs7->publicKeyOID = RSAk;
03758             break;
03759 
03760         /* if sigOID is already RSAk */
03761         case RSAk:
03762             pkcs7->publicKeyOID = sigOID;
03763             break;
03764     #endif
03765 
03766     #ifndef NO_DSA
03767         /* DSA signature types */
03768         case CTC_SHAwDSA:
03769             pkcs7->publicKeyOID = DSAk;
03770             break;
03771 
03772         /* if sigOID is already DSAk */
03773         case DSAk:
03774             pkcs7->publicKeyOID = sigOID;
03775             break;
03776     #endif
03777 
03778     #ifdef HAVE_ECC
03779         /* ECDSA signature types */
03780         case CTC_SHAwECDSA:
03781         case CTC_SHA224wECDSA:
03782         case CTC_SHA256wECDSA:
03783         case CTC_SHA384wECDSA:
03784         case CTC_SHA512wECDSA:
03785             pkcs7->publicKeyOID = ECDSAk;
03786             break;
03787 
03788         /* if sigOID is already ECDSAk */
03789         case ECDSAk:
03790             pkcs7->publicKeyOID = sigOID;
03791             break;
03792     #endif
03793 
03794         default:
03795             WOLFSSL_MSG("Unsupported public key algorithm");
03796             return ASN_SIG_KEY_E;
03797     }
03798 
03799     return pkcs7->publicKeyOID;
03800 }
03801 
03802 
03803 /* Parses through the attributes and adds them to the PKCS7 structure
03804  * Creates dynamic attribute structures that are free'd with calling
03805  * wc_PKCS7_Free()
03806  *
03807  * NOTE: An attribute has the ASN1 format of
03808  ** Sequence
03809  ****** Object ID
03810  ****** Set
03811  ********** {PritnableString, UTCTime, OCTET STRING ...}
03812  *
03813  * pkcs7  the PKCS7 structure to put the parsed attributes into
03814  * in     buffer holding all attributes
03815  * inSz   size of in buffer
03816  *
03817  * returns the number of attributes parsed on success
03818  */
03819 static int wc_PKCS7_ParseAttribs(PKCS7* pkcs7, byte* in, int inSz)
03820 {
03821     int    found = 0;
03822     word32 idx   = 0;
03823     word32 oid;
03824 
03825     if (pkcs7 == NULL || in == NULL || inSz < 0) {
03826         return BAD_FUNC_ARG;
03827     }
03828 
03829     while (idx < (word32)inSz) {
03830         int length  = 0;
03831         int oidIdx;
03832         PKCS7DecodedAttrib* attrib;
03833 
03834         if (GetSequence(in, &idx, &length, inSz) < 0)
03835             return ASN_PARSE_E;
03836 
03837         attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib),
03838                 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03839         if (attrib == NULL) {
03840             return MEMORY_E;
03841         }
03842         XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib));
03843 
03844         oidIdx = idx;
03845         if (GetObjectId(in, &idx, &oid, oidIgnoreType, inSz)
03846                 < 0) {
03847             XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03848             return ASN_PARSE_E;
03849         }
03850         attrib->oidSz = idx - oidIdx;
03851         attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap,
03852                                      DYNAMIC_TYPE_PKCS7);
03853         if (attrib->oid == NULL) {
03854             XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03855             return MEMORY_E;
03856         }
03857         XMEMCPY(attrib->oid, in + oidIdx, attrib->oidSz);
03858 
03859         /* Get Set that contains the printable string value */
03860         if (GetSet(in, &idx, &length, inSz) < 0) {
03861             XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03862             XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03863             return ASN_PARSE_E;
03864         }
03865 
03866         if ((inSz - idx) < (word32)length) {
03867             XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03868             XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03869             return ASN_PARSE_E;
03870         }
03871 
03872         attrib->valueSz = (word32)length;
03873         attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap,
03874                                        DYNAMIC_TYPE_PKCS7);
03875         if (attrib->value == NULL) {
03876             XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03877             XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
03878             return MEMORY_E;
03879         }
03880         XMEMCPY(attrib->value, in + idx, attrib->valueSz);
03881         idx += length;
03882 
03883         /* store attribute in linked list */
03884         if (pkcs7->decodedAttrib != NULL) {
03885             attrib->next = pkcs7->decodedAttrib;
03886             pkcs7->decodedAttrib = attrib;
03887         } else {
03888             pkcs7->decodedAttrib = attrib;
03889         }
03890         found++;
03891     }
03892 
03893     return found;
03894 }
03895 
03896 
03897 /* option to turn off support for degenerate cases
03898  * flag 0 turns off support
03899  * flag 1 turns on support
03900  *
03901  * by default support for SignedData degenerate cases is on
03902  */
03903 void wc_PKCS7_AllowDegenerate(PKCS7* pkcs7, word16 flag)
03904 {
03905     if (pkcs7) {
03906         if (flag) { /* flag of 1 turns on support for degenerate */
03907             pkcs7->noDegenerate = 0;
03908         }
03909         else { /* flag of 0 turns off support */
03910             pkcs7->noDegenerate = 1;
03911         }
03912     }
03913 }
03914 
03915 /* Parses through a signerInfo set. Reads buffer "in" from "idxIn" to "idxIn" +
03916  * length treating the current "idxIn" plus the length of set as max possible
03917  * index.
03918  *
03919  * In the case that signed attributes are found "signedAttrib" gets set to point
03920  *  at their location in the buffer "in". Also in this case signedAttribSz gets
03921  *  set to the size of the signedAttrib buffer.
03922  *
03923  * returns 0 on success
03924  */
03925 static int wc_PKCS7_ParseSignerInfo(PKCS7* pkcs7, byte* in, word32 inSz,
03926         word32* idxIn, int degenerate, byte** signedAttrib, int* signedAttribSz)
03927 {
03928     int ret = 0;
03929     int length;
03930     int version;
03931     word32 sigOID = 0, hashOID = 0;
03932     word32 idx = *idxIn, localIdx;
03933     byte tag;
03934 
03935     WOLFSSL_ENTER("wc_PKCS7_ParseSignerInfo");
03936     /* require a signer if degenerate case not allowed */
03937     if (inSz == 0 && pkcs7->noDegenerate == 1) {
03938         WOLFSSL_MSG("Set to not allow degenerate cases");
03939         return PKCS7_NO_SIGNER_E;
03940     }
03941 
03942     if (inSz == 0 && degenerate == 0) {
03943         WOLFSSL_MSG("PKCS7 signers expected");
03944         return PKCS7_NO_SIGNER_E;
03945     }
03946 
03947     /* not a degenerate case and there is elements in the set */
03948     if (inSz > 0 && degenerate == 0) {
03949         ret = wc_PKCS7_SignerInfoNew(pkcs7);
03950 
03951         /* Get the sequence of the first signerInfo */
03952         if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0)
03953             ret = ASN_PARSE_E;
03954 
03955         /* Get the version */
03956         if (ret == 0 && GetMyVersion(in, &idx, &version, inSz) < 0)
03957             ret = ASN_PARSE_E;
03958 
03959         if (ret == 0) {
03960             pkcs7->signerInfo->version = version;
03961         }
03962 
03963         if (ret == 0 && version == 1) {
03964             /* Get the sequence of IssuerAndSerialNumber */
03965             if (GetSequence(in, &idx, &length, inSz) < 0)
03966                 ret = ASN_PARSE_E;
03967 
03968             if (ret == 0) {
03969                 ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length);
03970                 idx += length;
03971             }
03972 
03973         } else if (ret == 0 && version == 3) {
03974             /* Get the sequence of SubjectKeyIdentifier */
03975             if (idx + 1 > inSz)
03976                 ret = BUFFER_E;
03977 
03978             localIdx = idx;
03979             if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
03980                    tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
03981                 idx++;
03982 
03983                 if (GetLength(in, &idx, &length, inSz) <= 0)
03984                     ret = ASN_PARSE_E;
03985 
03986                 if (ret == 0 && idx + 1 > inSz)
03987                     ret = BUFFER_E;
03988 
03989                 if (ret == 0 && GetASNTag(in, &idx, &tag, inSz) < 0)
03990                     ret = ASN_PARSE_E;
03991 
03992                 if (ret == 0 && tag != ASN_OCTET_STRING)
03993                     ret = ASN_PARSE_E;
03994 
03995                 if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0)
03996                     ret = ASN_PARSE_E;
03997             }
03998             else {
03999                 /* check if SKID with ASN_CONTEXT_SPECIFIC otherwise in version
04000                  * 3 try to get issuerAndSerial */
04001                 localIdx = idx;
04002                 if (GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
04003                         tag == ASN_CONTEXT_SPECIFIC) {
04004                     idx++;
04005                     if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0)
04006                         ret = ASN_PARSE_E;
04007                 }
04008                 else {
04009                     if (pkcs7->version != 3) {
04010                         WOLFSSL_MSG("Unexpected signer info found with version");
04011                         ret = ASN_PARSE_E;
04012                     }
04013 
04014                     if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0)
04015                         ret = ASN_PARSE_E;
04016                 }
04017             }
04018 
04019             if (ret == 0) {
04020                 ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length);
04021                 idx += length;
04022             }
04023 
04024         } else {
04025             WOLFSSL_MSG("PKCS#7 signerInfo version must be 1 or 3");
04026             ret = ASN_VERSION_E;
04027         }
04028 
04029         /* Get the sequence of digestAlgorithm */
04030         if (ret == 0 && GetAlgoId(in, &idx, &hashOID, oidHashType, inSz) < 0) {
04031             ret = ASN_PARSE_E;
04032         }
04033         pkcs7->hashOID = (int)hashOID;
04034 
04035         /* Get the IMPLICIT[0] SET OF signedAttributes */
04036         localIdx = idx;
04037         if (ret == 0 && GetASNTag(in, &localIdx, &tag, inSz) == 0 &&
04038                 tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
04039             idx++;
04040 
04041             if (GetLength(in, &idx, &length, inSz) < 0)
04042                 ret = ASN_PARSE_E;
04043 
04044             /* save pointer and length */
04045             *signedAttrib = &in[idx];
04046             *signedAttribSz = length;
04047 
04048             if (ret == 0 && wc_PKCS7_ParseAttribs(pkcs7, *signedAttrib,
04049                         *signedAttribSz) < 0) {
04050                 WOLFSSL_MSG("Error parsing signed attributes");
04051                 ret = ASN_PARSE_E;
04052             }
04053 
04054             idx += length;
04055         }
04056 
04057         /* Get digestEncryptionAlgorithm */
04058         if (ret == 0 && GetAlgoId(in, &idx, &sigOID, oidSigType, inSz) < 0) {
04059             ret = ASN_PARSE_E;
04060         }
04061 
04062         /* store public key type based on digestEncryptionAlgorithm */
04063         if (ret == 0) {
04064             ret = wc_PKCS7_SetPublicKeyOID(pkcs7, sigOID);
04065             if (ret < 0) {
04066                 WOLFSSL_MSG("Failed to set public key OID from signature");
04067             }
04068             else {
04069                 /* if previous return was positive then was success */
04070                 ret = 0;
04071             }
04072         }
04073     }
04074 
04075     /* update index on success */
04076     if (ret == 0) {
04077         *idxIn = idx;
04078     }
04079 
04080     return ret;
04081 }
04082 
04083 
04084 /* Finds the certificates in the message and saves it. By default allows
04085  * degenerate cases which can have no signer.
04086  *
04087  * By default expects type SIGNED_DATA (SignedData) which can have any number of
04088  * elements in signerInfos collection, including zero. (RFC2315 section 9.1)
04089  * When adding support for the case of SignedAndEnvelopedData content types a
04090  * signer is required. In this case the PKCS7 flag noDegenerate could be set.
04091  */
04092 static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf,
04093     word32 hashSz, byte* in, word32 inSz,
04094     byte* in2, word32 in2Sz)
04095 {
04096     word32 idx, maxIdx = inSz, outerContentType, contentTypeSz = 0, totalSz = 0;
04097     int length = 0, version = 0, ret = 0;
04098     byte* content = NULL;
04099     byte* contentDynamic = NULL;
04100     byte* sig = NULL;
04101     byte* cert = NULL;
04102     byte* signedAttrib = NULL;
04103     byte* contentType = NULL;
04104     int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0;
04105     word32 localIdx, start;
04106     byte degenerate = 0;
04107     byte detached = 0;
04108     byte tag = 0;
04109 #ifdef ASN_BER_TO_DER
04110     byte* der;
04111 #endif
04112     int multiPart = 0, keepContent;
04113     int contentLen = 0;
04114 
04115     byte* pkiMsg    = in;
04116     word32 pkiMsgSz = inSz;
04117 #ifndef NO_PKCS7_STREAM
04118     word32 stateIdx = 0;
04119     long rc;
04120 #endif
04121 
04122     byte* pkiMsg2 = in2;
04123     word32 pkiMsg2Sz = in2Sz;
04124 
04125     if (pkcs7 == NULL)
04126         return BAD_FUNC_ARG;
04127 
04128 #ifndef NO_PKCS7_STREAM
04129     /* allow for 0 size inputs with stream mode */
04130     if (pkiMsg == NULL && pkiMsgSz > 0)
04131         return BAD_FUNC_ARG;
04132 
04133 #else
04134     if (pkiMsg == NULL || pkiMsgSz == 0)
04135         return BAD_FUNC_ARG;
04136 #endif
04137 
04138     if ((hashSz > 0 && hashBuf == NULL) || (pkiMsg2Sz > 0 && pkiMsg2 == NULL)) {
04139         return BAD_FUNC_ARG;
04140     }
04141     idx = 0;
04142 
04143 #ifdef ASN_BER_TO_DER
04144     if (pkcs7->derSz > 0 && pkcs7->der) {
04145         pkiMsg = in = pkcs7->der;
04146     }
04147 #endif
04148 
04149 #ifndef NO_PKCS7_STREAM
04150     if (pkcs7->stream == NULL) {
04151         if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
04152             return ret;
04153         }
04154     }
04155 #endif
04156 
04157     switch (pkcs7->state) {
04158         case WC_PKCS7_START:
04159         #ifndef NO_PKCS7_STREAM
04160             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
04161                             MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ +
04162                             ASN_TAG_SZ + MAX_OID_SZ + MAX_SEQ_SZ,
04163                             &pkiMsg, &idx)) != 0) {
04164                 break;
04165             }
04166 
04167             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz);
04168             if (rc < 0) {
04169                 ret = (int)rc;
04170                 break;
04171             }
04172             pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz;
04173         #endif
04174 
04175             /* determine total message size */
04176             totalSz = pkiMsgSz;
04177             if (pkiMsg2 && pkiMsg2Sz > 0) {
04178                 totalSz += pkiMsg2Sz + pkcs7->contentSz;
04179             }
04180 
04181             /* Get the contentInfo sequence */
04182             if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, totalSz,
04183                         NO_USER_CHECK) < 0)
04184                 ret = ASN_PARSE_E;
04185 
04186             if (ret == 0 && length == 0 && pkiMsg[idx-1] == 0x80) {
04187         #ifdef ASN_BER_TO_DER
04188                 word32 len = 0;
04189 
04190                 ret = wc_BerToDer(pkiMsg, pkiMsgSz, NULL, &len);
04191                 if (ret != LENGTH_ONLY_E)
04192                     return ret;
04193                 pkcs7->der = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
04194                 if (pkcs7->der == NULL)
04195                     return MEMORY_E;
04196                 ret = wc_BerToDer(pkiMsg, pkiMsgSz, pkcs7->der, &len);
04197                 if (ret < 0)
04198                     return ret;
04199 
04200                 pkiMsg   = in = pkcs7->der;
04201                 pkiMsgSz = pkcs7->derSz = len;
04202                 idx = 0;
04203                 if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
04204                             NO_USER_CHECK) < 0)
04205                     return ASN_PARSE_E;
04206 
04207             #ifndef NO_PKCS7_STREAM
04208                 rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK,
04209                     pkiMsg, pkiMsgSz);
04210                 if (rc < 0) {
04211                     ret = (int)rc;
04212                     break;
04213                 }
04214             #endif
04215         #else
04216                 ret = BER_INDEF_E;
04217         #endif
04218             }
04219 
04220             /* Get the contentInfo contentType */
04221             if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &outerContentType,
04222                         pkiMsgSz) < 0)
04223                 ret = ASN_PARSE_E;
04224 
04225             if (ret == 0 && outerContentType != SIGNED_DATA) {
04226                 WOLFSSL_MSG("PKCS#7 input not of type SignedData");
04227                 ret = PKCS7_OID_E;
04228             }
04229 
04230             /* get the ContentInfo content */
04231             if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, totalSz) != 0)
04232                 ret = ASN_PARSE_E;
04233 
04234             if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
04235                 ret = ASN_PARSE_E;
04236 
04237             if (ret == 0 && GetLength_ex(pkiMsg, &idx, &length, totalSz,
04238                         NO_USER_CHECK) < 0)
04239                 ret = ASN_PARSE_E;
04240 
04241             /* Get the signedData sequence */
04242             if (ret == 0 && GetSequence_ex(pkiMsg, &idx, &length, totalSz,
04243                         NO_USER_CHECK) < 0)
04244                 ret = ASN_PARSE_E;
04245 
04246             /* Get the version */
04247             if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
04248                 ret = ASN_PARSE_E;
04249 
04250 
04251             /* version 1 follows RFC 2315 */
04252             /* version 3 follows RFC 4108 */
04253             if (ret == 0 && (version != 1 && version != 3)) {
04254                 WOLFSSL_MSG("PKCS#7 signedData needs to be version 1 or 3");
04255                 ret = ASN_VERSION_E;
04256             }
04257             pkcs7->version = version;
04258 
04259             /* Get the set of DigestAlgorithmIdentifiers */
04260             if (ret == 0 && GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0)
04261                 ret = ASN_PARSE_E;
04262 
04263             /* Skip the set. */
04264             idx += length;
04265             degenerate = (length == 0)? 1 : 0;
04266             if (pkcs7->noDegenerate == 1 && degenerate == 1) {
04267                 ret = PKCS7_NO_SIGNER_E;
04268             }
04269 
04270             if (ret != 0)
04271                 break;
04272 
04273         #ifndef NO_PKCS7_STREAM
04274             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
04275                 break;
04276             }
04277             if (pkiMsg2 && pkiMsg2Sz > 0) {
04278                 pkcs7->stream->maxLen += pkiMsg2Sz + pkcs7->contentSz;
04279             }
04280             wc_PKCS7_StreamStoreVar(pkcs7, totalSz, 0, 0);
04281         #endif
04282 
04283             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE2);
04284             FALL_THROUGH;
04285 
04286         case WC_PKCS7_VERIFY_STAGE2:
04287         #ifndef NO_PKCS7_STREAM
04288             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz,
04289                            MAX_SEQ_SZ + MAX_OID_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ
04290                            + ASN_TAG_SZ + MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) {
04291                 break;
04292             }
04293 
04294             wc_PKCS7_StreamGetVar(pkcs7, &totalSz, 0, 0);
04295             if (pkcs7->stream->length > 0)
04296                 pkiMsgSz = pkcs7->stream->length;
04297         #ifdef ASN_BER_TO_DER
04298             else if (pkcs7->der)
04299                 pkiMsgSz = pkcs7->derSz;
04300         #endif
04301             else
04302                 pkiMsgSz = inSz;
04303 
04304         #endif
04305             /* Get the inner ContentInfo sequence */
04306             if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz,
04307                         NO_USER_CHECK) < 0)
04308                 ret = ASN_PARSE_E;
04309 
04310             /* Get the inner ContentInfo contentType */
04311             if (ret == 0) {
04312                 word32 tmpIdx = idx;
04313 
04314                 if (GetASNObjectId(pkiMsg, &idx, &length, pkiMsgSz) != 0)
04315                     ret = ASN_PARSE_E;
04316 
04317                 contentType = pkiMsg + tmpIdx;
04318                 contentTypeSz = length + (idx - tmpIdx);
04319 
04320                 idx += length;
04321             }
04322 
04323             if (ret != 0)
04324                 break;
04325 
04326             /* Check for content info, it could be omitted when degenerate */
04327             localIdx = idx;
04328             ret = 0;
04329             if (localIdx + 1 > pkiMsgSz) {
04330                 ret = BUFFER_E;
04331                 break;
04332             }
04333 
04334             if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0)
04335                 ret = ASN_PARSE_E;
04336 
04337             if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
04338                 ret = ASN_PARSE_E;
04339 
04340             if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz,
04341                         NO_USER_CHECK) <= 0)
04342                 ret = ASN_PARSE_E;
04343 
04344             if (localIdx >= pkiMsgSz) {
04345                 ret = BUFFER_E;
04346             }
04347 
04348             /* get length of content in the case that there is multiple parts */
04349             if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
04350                 ret = ASN_PARSE_E;
04351 
04352             if (ret == 0 && tag == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) {
04353                 multiPart = 1;
04354 
04355                 /* Get length of all OCTET_STRINGs. */
04356                 if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz,
04357                             NO_USER_CHECK) < 0)
04358                     ret = ASN_PARSE_E;
04359 
04360                 /* Check whether there is one OCTET_STRING inside. */
04361                 start = localIdx;
04362                 if (localIdx >= pkiMsgSz) {
04363                     ret = BUFFER_E;
04364                 }
04365 
04366                 if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz)
04367                         != 0)
04368                     ret = ASN_PARSE_E;
04369 
04370                 if (ret == 0 && tag != ASN_OCTET_STRING)
04371                     ret = ASN_PARSE_E;
04372 
04373                 if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz,
04374                             NO_USER_CHECK) < 0)
04375                     ret = ASN_PARSE_E;
04376 
04377                 if (ret == 0) {
04378                     /* Use single OCTET_STRING directly. */
04379                     if (localIdx - start + length == (word32)contentLen)
04380                         multiPart = 0;
04381                     localIdx = start;
04382                 }
04383             }
04384 
04385             /* get length of content in case of single part */
04386             if (ret == 0 && !multiPart) {
04387                 if (tag != ASN_OCTET_STRING)
04388                     ret = ASN_PARSE_E;
04389 
04390                 if (ret == 0 && GetLength_ex(pkiMsg, &localIdx,
04391                             &length, pkiMsgSz, NO_USER_CHECK) < 0)
04392                     ret = ASN_PARSE_E;
04393             }
04394 
04395             /* update idx if successful */
04396             if (ret == 0) {
04397                 /* support using header and footer without content */
04398                 if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) {
04399                     localIdx = 0;
04400                 }
04401                 idx = localIdx;
04402             }
04403             else {
04404 
04405                 /* if pkcs7->content and pkcs7->contentSz are set, try to
04406                    process as a detached signature */
04407                 if (!degenerate &&
04408                     (pkcs7->content != NULL && pkcs7->contentSz != 0)) {
04409                     detached = 1;
04410                 }
04411 
04412                 if (!degenerate && !detached && ret != 0)
04413                     break;
04414 
04415                 length = 0; /* no content to read */
04416                 pkiMsg2   = pkiMsg;
04417                 pkiMsg2Sz = pkiMsgSz;
04418             }
04419 
04420         #ifndef NO_PKCS7_STREAM
04421             /* save detached flag value */
04422             pkcs7->stream->detached = detached;
04423 
04424             /* save contentType */
04425             pkcs7->stream->nonce = (byte*)XMALLOC(contentTypeSz, pkcs7->heap,
04426                     DYNAMIC_TYPE_PKCS7);
04427             if (pkcs7->stream->nonce == NULL) {
04428                 ret = MEMORY_E;
04429                 break;
04430             }
04431             else {
04432                 pkcs7->stream->nonceSz = contentTypeSz;
04433                 XMEMCPY(pkcs7->stream->nonce, contentType, contentTypeSz);
04434             }
04435 
04436             /* content expected? */
04437             if ((ret == 0 && length > 0) &&
04438                 !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0)) {
04439                 pkcs7->stream->expected = length + ASN_TAG_SZ + MAX_LENGTH_SZ;
04440             }
04441             else {
04442                 pkcs7->stream->expected = ASN_TAG_SZ + MAX_LENGTH_SZ;
04443             }
04444 
04445             if (pkcs7->stream->expected > (pkcs7->stream->maxLen - idx)) {
04446                 pkcs7->stream->expected = pkcs7->stream->maxLen - idx;
04447             }
04448 
04449             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
04450                 break;
04451             }
04452             wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, localIdx, length);
04453 
04454             /* content length is in multiple parts */
04455             if (multiPart) {
04456                 pkcs7->stream->expected = contentLen + ASN_TAG_SZ;
04457             }
04458             pkcs7->stream->multi = multiPart;
04459 
04460         #endif
04461             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE3);
04462             FALL_THROUGH;
04463 
04464         case WC_PKCS7_VERIFY_STAGE3:
04465         #ifndef NO_PKCS7_STREAM
04466             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz,
04467                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
04468                 break;
04469             }
04470 
04471             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
04472                     pkiMsg, pkiMsgSz);
04473             if (rc < 0) {
04474                 ret = (int)rc;
04475                 break;
04476             }
04477         #ifdef ASN_BER_TO_DER
04478             if (pkcs7->derSz != 0)
04479                 pkiMsgSz = pkcs7->derSz;
04480             else
04481         #endif
04482                 pkiMsgSz = (word32)rc;
04483             wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, (int*)&localIdx, &length);
04484 
04485             if (pkcs7->stream->length > 0) {
04486                 localIdx = 0;
04487             }
04488             multiPart = pkcs7->stream->multi;
04489             detached  = pkcs7->stream->detached;
04490             maxIdx = idx + pkcs7->stream->expected;
04491         #endif
04492 
04493             /* Break out before content because it can be optional in degenerate
04494              * cases. */
04495             if (ret != 0 && !degenerate)
04496                 break;
04497 
04498             /* get parts of content */
04499             if (ret == 0 && multiPart) {
04500                 int i = 0;
04501                 keepContent = !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0);
04502 
04503                 if (keepContent) {
04504                     /* Create a buffer to hold content of OCTET_STRINGs. */
04505                     pkcs7->contentDynamic = (byte*)XMALLOC(contentLen, pkcs7->heap,
04506                                                             DYNAMIC_TYPE_PKCS7);
04507                     if (pkcs7->contentDynamic == NULL)
04508                         ret = MEMORY_E;
04509                 }
04510 
04511                 start = localIdx;
04512                 /* Use the data from each OCTET_STRING. */
04513                 while (ret == 0 && localIdx < start + contentLen) {
04514                     if (GetASNTag(pkiMsg, &localIdx, &tag, totalSz) < 0)
04515                         ret = ASN_PARSE_E;
04516                     if (ret == 0 && tag != ASN_OCTET_STRING)
04517                         ret = ASN_PARSE_E;
04518 
04519                     if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0)
04520                         ret = ASN_PARSE_E;
04521                     if (ret == 0 && length + localIdx > start + contentLen)
04522                         ret = ASN_PARSE_E;
04523 
04524                     if (ret == 0) {
04525                         if (keepContent) {
04526                             XMEMCPY(pkcs7->contentDynamic + i, pkiMsg + localIdx,
04527                                                                         length);
04528                         }
04529                         i += length;
04530                         localIdx += length;
04531                     }
04532                 }
04533                 localIdx = start; /* reset for sanity check, increment later */
04534                 length = i;
04535             }
04536 
04537             /* Save the inner data as the content. */
04538             if (ret == 0 && length > 0) {
04539                 contentSz = length;
04540 
04541                 /* support using header and footer without content */
04542                 if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) {
04543                     /* Content not provided, use provided pkiMsg2 footer */
04544                     content = NULL;
04545                     localIdx = 0;
04546                     if (contentSz != (int)pkcs7->contentSz) {
04547                         WOLFSSL_MSG("Data signed does not match contentSz provided");
04548                         ret = BUFFER_E;
04549                     }
04550                 }
04551                 else {
04552                     if ((word32)length > pkiMsgSz - localIdx) {
04553                         ret = BUFFER_E;
04554                     }
04555 
04556                     /* Content pointer for calculating hashes later */
04557                     if (ret == 0 && !multiPart) {
04558                         content = &pkiMsg[localIdx];
04559                     }
04560                     if (ret == 0 && multiPart) {
04561                         content = pkcs7->contentDynamic;
04562                     }
04563 
04564                     if (ret == 0) {
04565                         idx += length;
04566 
04567                         pkiMsg2   = pkiMsg;
04568                         pkiMsg2Sz = pkiMsgSz;
04569                     #ifndef NO_PKCS7_STREAM
04570                         pkcs7->stream->varOne = pkiMsg2Sz;
04571                         pkcs7->stream->flagOne = 1;
04572                     #endif
04573                     }
04574                 }
04575             }
04576             else {
04577                 pkiMsg2 = pkiMsg;
04578                 pkiMsg2Sz = pkiMsgSz;
04579             #ifndef NO_PKCS7_STREAM
04580                 pkcs7->stream->varOne = pkiMsg2Sz;
04581                 pkcs7->stream->flagOne = 1;
04582             #endif
04583             }
04584 
04585             /* If getting the content info failed with non degenerate then return the
04586              * error case. Otherwise with a degenerate it is ok if the content
04587              * info was omitted */
04588             if (!degenerate && !detached && (ret != 0)) {
04589                 break;
04590             }
04591             else {
04592                 ret = 0; /* reset ret state on degenerate case */
04593             }
04594 
04595         #ifndef NO_PKCS7_STREAM
04596             /* save content */
04597             if (detached == 1) {
04598                 /* if detached, use content from user in pkcs7 struct */
04599                 content = pkcs7->content;
04600                 contentSz = pkcs7->contentSz;
04601             }
04602 
04603             if (content != NULL) {
04604                 XFREE(pkcs7->stream->content, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
04605                 pkcs7->stream->content = (byte*)XMALLOC(contentSz, pkcs7->heap,
04606                         DYNAMIC_TYPE_PKCS7);
04607                 if (pkcs7->stream->content == NULL) {
04608                     ret = MEMORY_E;
04609                     break;
04610                 }
04611                 else {
04612                     XMEMCPY(pkcs7->stream->content, content, contentSz);
04613                     pkcs7->stream->contentSz = contentSz;
04614                 }
04615             }
04616         #endif /* !NO_PKCS7_STREAM */
04617 
04618             /* Get the implicit[0] set of certificates */
04619             if (ret == 0 && idx >= pkiMsg2Sz)
04620                 ret = BUFFER_E;
04621 
04622             length = 0; /* set length to 0 to check if reading in any certs */
04623             localIdx = idx;
04624             if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz) == 0
04625                     && tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
04626                 idx++;
04627                 if (GetLength_ex(pkiMsg2, &idx, &length, maxIdx, NO_USER_CHECK)
04628                         < 0)
04629                     ret = ASN_PARSE_E;
04630             }
04631 
04632             if (ret != 0) {
04633                 break;
04634             }
04635         #ifndef NO_PKCS7_STREAM
04636             if (in2 && in2Sz > 0 && hashBuf && hashSz > 0) {
04637                 stateIdx = idx; /* case where all data was read from in2 */
04638             }
04639 
04640             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
04641                 break;
04642             }
04643             wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length);
04644             if (length > 0) {
04645                 pkcs7->stream->expected = length;
04646             }
04647             else {
04648                 pkcs7->stream->expected = MAX_SEQ_SZ;
04649                 if (pkcs7->stream->expected > (pkcs7->stream->maxLen -
04650                                 pkcs7->stream->totalRd) + pkcs7->stream->length) {
04651                     pkcs7->stream->expected = (pkcs7->stream->maxLen -
04652                                 pkcs7->stream->totalRd) + pkcs7->stream->length;
04653                 }
04654             }
04655         #endif
04656             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE4);
04657             FALL_THROUGH;
04658 
04659         case WC_PKCS7_VERIFY_STAGE4:
04660         #ifndef NO_PKCS7_STREAM
04661             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz,
04662                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
04663                 break;
04664             }
04665 
04666             wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length);
04667             if (pkcs7->stream->flagOne) {
04668                 pkiMsg2 = pkiMsg;
04669             }
04670 
04671             /* restore content */
04672             content   = pkcs7->stream->content;
04673             contentSz = pkcs7->stream->contentSz;
04674 
04675             /* restore detached flag */
04676             detached = pkcs7->stream->detached;
04677 
04678             /* store certificate if needed */
04679             if (length > 0 && in2Sz == 0) {
04680                 /* free tmpCert if not NULL */
04681                 XFREE(pkcs7->stream->tmpCert, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
04682                 pkcs7->stream->tmpCert = (byte*)XMALLOC(length,
04683                         pkcs7->heap, DYNAMIC_TYPE_PKCS7);
04684                 if ((pkiMsg2 == NULL) || (pkcs7->stream->tmpCert == NULL)) {
04685                     ret = MEMORY_E;
04686                     break;
04687                 }
04688                 XMEMCPY(pkcs7->stream->tmpCert, pkiMsg2 + idx, length);
04689                 pkiMsg2 = pkcs7->stream->tmpCert;
04690                 pkiMsg2Sz = length;
04691                 idx = 0;
04692             }
04693         #endif
04694 
04695                 if (length > 0) {
04696                     /* At this point, idx is at the first certificate in
04697                      * a set of certificates. There may be more than one,
04698                      * or none, or they may be a PKCS 6 extended
04699                      * certificate. We want to save the first cert if it
04700                      * is X.509. */
04701 
04702                     word32 certIdx = idx;
04703 
04704                     if (length < MAX_LENGTH_SZ + ASN_TAG_SZ)
04705                         ret = BUFFER_E;
04706 
04707                     if (ret == 0)
04708                         ret = GetASNTag(pkiMsg2, &certIdx, &tag, pkiMsg2Sz);
04709 
04710                     if (ret == 0 && tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
04711                         if (GetLength(pkiMsg2, &certIdx, &certSz, pkiMsg2Sz) < 0)
04712                             ret = ASN_PARSE_E;
04713 
04714                         cert = &pkiMsg2[idx];
04715                         certSz += (certIdx - idx);
04716                         if (certSz > length) {
04717                             ret = BUFFER_E;
04718                             break;
04719                         }
04720                     }
04721         #ifdef ASN_BER_TO_DER
04722                     der = pkcs7->der;
04723         #endif
04724                     contentDynamic = pkcs7->contentDynamic;
04725                     version = pkcs7->version;
04726 
04727 
04728                     if (ret == 0) {
04729                     #ifndef NO_PKCS7_STREAM
04730                         PKCS7State* stream = pkcs7->stream;
04731                     #endif
04732                         /* This will reset PKCS7 structure and then set the
04733                          * certificate */
04734                         ret = wc_PKCS7_InitWithCert(pkcs7, cert, certSz);
04735                     #ifndef NO_PKCS7_STREAM
04736                         pkcs7->stream = stream;
04737                     #endif
04738                     }
04739                     pkcs7->contentDynamic = contentDynamic;
04740                     pkcs7->version = version;
04741         #ifdef ASN_BER_TO_DER
04742                     pkcs7->der = der;
04743         #endif
04744                     if (ret != 0)
04745                         break;
04746 
04747                     /* iterate through any additional certificates */
04748                     if (ret == 0 && MAX_PKCS7_CERTS > 0) {
04749                         int sz = 0;
04750                         int i;
04751 
04752                         pkcs7->cert[0]   = cert;
04753                         pkcs7->certSz[0] = certSz;
04754                         certIdx = idx + certSz;
04755 
04756                         for (i = 1; i < MAX_PKCS7_CERTS &&
04757                                 certIdx + 1 < pkiMsg2Sz &&
04758                                 certIdx + 1 < (word32)length; i++) {
04759                             localIdx = certIdx;
04760 
04761                             if (ret == 0 && GetASNTag(pkiMsg2, &certIdx, &tag,
04762                                         pkiMsg2Sz) < 0) {
04763                                 ret = ASN_PARSE_E;
04764                                 break;
04765                             }
04766 
04767                             if (ret == 0 &&
04768                                     tag == (ASN_CONSTRUCTED | ASN_SEQUENCE)) {
04769                                 if (GetLength(pkiMsg2, &certIdx, &sz,
04770                                             pkiMsg2Sz) < 0) {
04771                                     ret = ASN_PARSE_E;
04772                                     break;
04773                                 }
04774 
04775                                 pkcs7->cert[i]   = &pkiMsg2[localIdx];
04776                                 pkcs7->certSz[i] = sz + (certIdx - localIdx);
04777                                 certIdx += sz;
04778                             }
04779                         }
04780                     }
04781                 }
04782                 idx += length;
04783 
04784             if (!detached) {
04785                 /* set content and size after init of PKCS7 structure */
04786                 pkcs7->content   = content;
04787                 pkcs7->contentSz = contentSz;
04788             }
04789         #ifndef NO_PKCS7_STREAM
04790             else {
04791                 /* save content if detached and using streaming API */
04792                 if (pkcs7->content != NULL) {
04793                     XFREE(pkcs7->stream->content, pkcs7->heap,
04794                           DYNAMIC_TYPE_PKCS7);
04795                     pkcs7->stream->content = (byte*)XMALLOC(pkcs7->contentSz,
04796                                                             pkcs7->heap,
04797                                                             DYNAMIC_TYPE_PKCS7);
04798                     if (pkcs7->stream->content == NULL) {
04799                         ret = MEMORY_E;
04800                         break;
04801                     }
04802                     else {
04803                         XMEMCPY(pkcs7->stream->content, pkcs7->content,
04804                                 contentSz);
04805                         pkcs7->stream->contentSz = pkcs7->contentSz;
04806                     }
04807                 }
04808             }
04809         #endif
04810 
04811             if (ret != 0) {
04812                 break;
04813             }
04814         #ifndef NO_PKCS7_STREAM
04815             /* factor in that recent idx was in cert buffer. If in2 buffer was
04816              * used then don't advance idx. */
04817             if (length > 0 && pkcs7->stream->flagOne &&
04818                     pkcs7->stream->length == 0) {
04819                 idx = stateIdx + idx;
04820                 if (idx > inSz) {
04821                     /* index is more than input size */
04822                     ret = BUFFER_E;
04823                     break;
04824                 }
04825             }
04826             else {
04827                 stateIdx = idx; /* didn't read any from internal buffer */
04828             }
04829 
04830             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
04831                 break;
04832             }
04833             if (pkcs7->stream->flagOne && pkcs7->stream->length > 0) {
04834                 idx = stateIdx + idx;
04835             }
04836 
04837             pkcs7->stream->expected = MAX_OID_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ +
04838                                       MAX_SET_SZ;
04839 
04840             if (pkcs7->stream->expected > (pkcs7->stream->maxLen -
04841                                 pkcs7->stream->totalRd) + pkcs7->stream->length)
04842                 pkcs7->stream->expected = (pkcs7->stream->maxLen -
04843                                 pkcs7->stream->totalRd) + pkcs7->stream->length;
04844 
04845             wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz,  0, 0);
04846             wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length);
04847         #endif
04848             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE5);
04849             FALL_THROUGH;
04850 
04851         case WC_PKCS7_VERIFY_STAGE5:
04852         #ifndef NO_PKCS7_STREAM
04853             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz,
04854                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
04855                 break;
04856             }
04857             wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length);
04858             if (pkcs7->stream->flagOne) {
04859                 pkiMsg2 = pkiMsg;
04860             }
04861 
04862             /* restore content type */
04863             contentType   = pkcs7->stream->nonce;
04864             contentTypeSz = pkcs7->stream->nonceSz;
04865 
04866             maxIdx = idx + pkcs7->stream->expected;
04867             if (maxIdx > pkiMsg2Sz) {
04868                 ret = BUFFER_E;
04869                 break;
04870             }
04871             stateIdx = idx;
04872         #endif
04873 
04874             /* set contentType and size after init of PKCS7 structure */
04875             if (ret == 0 && wc_PKCS7_SetContentType(pkcs7, contentType,
04876                         contentTypeSz) < 0)
04877                 ret = ASN_PARSE_E;
04878 
04879             /* Get the implicit[1] set of crls */
04880             if (ret == 0 && idx >= maxIdx)
04881                 ret = BUFFER_E;
04882 
04883             localIdx = idx;
04884             if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag, pkiMsg2Sz) == 0
04885                     && tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
04886                 idx++;
04887                 if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0)
04888                     ret = ASN_PARSE_E;
04889 
04890                 /* Skip the set */
04891                 idx += length;
04892             }
04893 
04894             /* Get the set of signerInfos */
04895             if (ret == 0 && GetSet_ex(pkiMsg2, &idx, &length, maxIdx,
04896                         NO_USER_CHECK) < 0)
04897                 ret = ASN_PARSE_E;
04898 
04899             if (ret != 0)
04900                 break;
04901         #ifndef NO_PKCS7_STREAM
04902             if (!pkcs7->stream->flagOne) {
04903                 stateIdx = idx; /* didn't read any from internal buffer */
04904             }
04905             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, &idx)) != 0) {
04906                 break;
04907             }
04908             wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length);
04909 
04910             if (in2 && in2Sz > 0 && hashBuf && hashSz > 0) {
04911                 if (length > 0) {
04912                     pkcs7->stream->expected = length;
04913                 }
04914                 else {
04915                     pkcs7->stream->expected = 0;
04916                 }
04917             }
04918             else {
04919                 /* last state expect the reset of the buffer */
04920                 pkcs7->stream->expected = (pkcs7->stream->maxLen -
04921                     pkcs7->stream->totalRd) + pkcs7->stream->length;
04922             }
04923 
04924         #endif
04925             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE6);
04926             FALL_THROUGH;
04927 
04928         case WC_PKCS7_VERIFY_STAGE6:
04929         #ifndef NO_PKCS7_STREAM
04930             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz,
04931                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
04932                 break;
04933             }
04934 
04935             wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, &length);
04936             if (pkcs7->stream->flagOne) {
04937                 pkiMsg2 = pkiMsg;
04938             }
04939 
04940             /* restore content */
04941             content   = pkcs7->stream->content;
04942             contentSz = pkcs7->stream->contentSz;
04943         #endif
04944 
04945             ret = wc_PKCS7_ParseSignerInfo(pkcs7, pkiMsg2, pkiMsg2Sz, &idx,
04946                     degenerate, &signedAttrib, &signedAttribSz);
04947 
04948             /* parse out the signature if present and verify it */
04949             if (ret == 0 && length > 0 && degenerate == 0) {
04950                 WOLFSSL_MSG("Parsing signature and verifying");
04951                 if (idx >= pkiMsg2Sz)
04952                     ret = BUFFER_E;
04953 
04954                 /* Get the signature */
04955                 localIdx = idx;
04956                 if (ret == 0 && GetASNTag(pkiMsg2, &localIdx, &tag,
04957                             pkiMsg2Sz) == 0 && tag == ASN_OCTET_STRING) {
04958                     idx++;
04959 
04960                     if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0)
04961                         ret = ASN_PARSE_E;
04962 
04963                     /* save pointer and length */
04964                     sig = &pkiMsg2[idx];
04965                     sigSz = length;
04966 
04967                     idx += length;
04968                 }
04969 
04970                 pkcs7->content = content;
04971                 pkcs7->contentSz = contentSz;
04972 
04973                 if (ret == 0) {
04974                     ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz,
04975                                                    signedAttrib, signedAttribSz,
04976                                                    hashBuf, hashSz);
04977                 }
04978             }
04979 
04980             if (ret < 0)
04981                 break;
04982 
04983             ret = 0; /* success */
04984         #ifndef NO_PKCS7_STREAM
04985             wc_PKCS7_ResetStream(pkcs7);
04986         #endif
04987             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
04988             break;
04989 
04990         default:
04991             WOLFSSL_MSG("PKCS7 Unknown verify state");
04992             ret = BAD_FUNC_ARG;
04993     }
04994 
04995     if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) {
04996     #ifndef NO_PKCS7_STREAM
04997         wc_PKCS7_ResetStream(pkcs7);
04998     #endif
04999         wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
05000     }
05001     return ret;
05002 }
05003 
05004 
05005 /* Gets a copy of the SID parsed from signerInfo. This can be called after
05006  * wc_PKCS7_VerifySignedData has been called. SID can be SKID in version 3 case
05007  * or issuerAndSerialNumber.
05008  *
05009  * return 0 on success and LENGTH_ONLY_E if just setting "outSz" for buffer
05010  *  length needed.
05011  */
05012 int wc_PKCS7_GetSignerSID(PKCS7* pkcs7, byte* out, word32* outSz)
05013 {
05014     if (outSz == NULL || pkcs7 == NULL) {
05015         return BAD_FUNC_ARG;
05016     }
05017 
05018     if (pkcs7->signerInfo == NULL) {
05019         WOLFSSL_MSG("Either the bundle had no signers or"
05020                 "wc_PKCS7_VerifySignedData needs called yet");
05021         return PKCS7_NO_SIGNER_E;
05022     }
05023 
05024     if (pkcs7->signerInfo->sidSz == 0) {
05025         WOLFSSL_MSG("Bundle had no signer SID set");
05026         return PKCS7_NO_SIGNER_E;
05027     }
05028 
05029     if (out == NULL) {
05030         *outSz = pkcs7->signerInfo->sidSz;
05031         return LENGTH_ONLY_E;
05032     }
05033 
05034     if (*outSz < pkcs7->signerInfo->sidSz) {
05035         WOLFSSL_MSG("Buffer being passed in is not large enough for SKID");
05036         return BUFFER_E;
05037     }
05038     XMEMCPY(out, pkcs7->signerInfo->sid, pkcs7->signerInfo->sidSz);
05039     *outSz = pkcs7->signerInfo->sidSz;
05040     return 0;
05041 }
05042 
05043 
05044 /* variant that allows computed data hash and header/foot,
05045  * which is useful for large data signing */
05046 int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf,
05047     word32 hashSz, byte* pkiMsgHead, word32 pkiMsgHeadSz, byte* pkiMsgFoot,
05048     word32 pkiMsgFootSz)
05049 {
05050     return PKCS7_VerifySignedData(pkcs7, hashBuf, hashSz,
05051         pkiMsgHead, pkiMsgHeadSz, pkiMsgFoot, pkiMsgFootSz);
05052 }
05053 
05054 int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
05055 {
05056     return PKCS7_VerifySignedData(pkcs7, NULL, 0, pkiMsg, pkiMsgSz, NULL, 0);
05057 }
05058 
05059 
05060 /* Generate random content encryption key, store into pkcs7->cek and
05061  * pkcs7->cekSz.
05062  *
05063  * pkcs7 - pointer to initialized PKCS7 structure
05064  * len   - length of key to be generated
05065  *
05066  * Returns 0 on success, negative upon error */
05067 static int PKCS7_GenerateContentEncryptionKey(PKCS7* pkcs7, word32 len)
05068 {
05069     int ret;
05070     WC_RNG rng;
05071     byte* tmpKey;
05072 
05073     if (pkcs7 == NULL || len == 0)
05074         return BAD_FUNC_ARG;
05075 
05076     /* if key already exists, don't need to re-generate */
05077     if (pkcs7->cek != NULL && pkcs7->cekSz != 0) {
05078 
05079         /* if key exists, but is different size, return error */
05080         if (pkcs7->cekSz != len) {
05081             WOLFSSL_MSG("Random content-encryption key size is inconsistent "
05082                         "between CMS recipients");
05083             return WC_KEY_SIZE_E;
05084         }
05085 
05086         return 0;
05087     }
05088 
05089     /* allocate space for cek */
05090     tmpKey = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05091     if (tmpKey == NULL)
05092         return MEMORY_E;
05093 
05094     XMEMSET(tmpKey, 0, len);
05095 
05096     ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
05097     if (ret != 0) {
05098         XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05099         return ret;
05100     }
05101 
05102     ret = wc_RNG_GenerateBlock(&rng, tmpKey, len);
05103     if (ret != 0) {
05104         wc_FreeRng(&rng);
05105         XFREE(tmpKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05106         return ret;
05107     }
05108 
05109     /* store into PKCS7, memory freed during final cleanup */
05110     pkcs7->cek = tmpKey;
05111     pkcs7->cekSz = len;
05112 
05113     wc_FreeRng(&rng);
05114 
05115     return 0;
05116 }
05117 
05118 
05119 /* wrap CEK (content encryption key) with KEK, 0 on success, < 0 on error */
05120 static int wc_PKCS7_KeyWrap(byte* cek, word32 cekSz, byte* kek,
05121                             word32 kekSz, byte* out, word32 outSz,
05122                             int keyWrapAlgo, int direction)
05123 {
05124     int ret = 0;
05125 
05126     if (cek == NULL || kek == NULL || out == NULL)
05127         return BAD_FUNC_ARG;
05128 
05129     switch (keyWrapAlgo) {
05130 #ifndef NO_AES
05131     #ifdef WOLFSSL_AES_128
05132         case AES128_WRAP:
05133     #endif
05134     #ifdef WOLFSSL_AES_192
05135         case AES192_WRAP:
05136     #endif
05137     #ifdef WOLFSSL_AES_256
05138         case AES256_WRAP:
05139     #endif
05140 
05141             if (direction == AES_ENCRYPTION) {
05142 
05143                 ret = wc_AesKeyWrap(kek, kekSz, cek, cekSz,
05144                                     out, outSz, NULL);
05145 
05146             } else if (direction == AES_DECRYPTION) {
05147 
05148                 ret = wc_AesKeyUnWrap(kek, kekSz, cek, cekSz,
05149                                       out, outSz, NULL);
05150             } else {
05151                 WOLFSSL_MSG("Bad key un/wrap direction");
05152                 return BAD_FUNC_ARG;
05153             }
05154 
05155             if (ret <= 0)
05156                 return ret;
05157             break;
05158 #endif /* NO_AES */
05159 
05160         default:
05161             WOLFSSL_MSG("Unsupported key wrap algorithm");
05162             return BAD_KEYWRAP_ALG_E;
05163     };
05164 
05165     (void)cekSz;
05166     (void)kekSz;
05167     (void)outSz;
05168     (void)direction;
05169     return ret;
05170 }
05171 
05172 
05173 #ifdef HAVE_ECC
05174 
05175 /* KARI == KeyAgreeRecipientInfo (key agreement) */
05176 typedef struct WC_PKCS7_KARI {
05177     DecodedCert* decoded;          /* decoded recip cert */
05178     void*    heap;                 /* user heap, points to PKCS7->heap */
05179     int      devId;                /* device ID for HW based private key */
05180     ecc_key* recipKey;             /* recip key  (pub | priv) */
05181     ecc_key* senderKey;            /* sender key (pub | priv) */
05182     byte*    senderKeyExport;      /* sender ephemeral key DER */
05183     byte*    kek;                  /* key encryption key */
05184     byte*    ukm;                  /* OPTIONAL user keying material */
05185     byte*    sharedInfo;           /* ECC-CMS-SharedInfo ASN.1 encoded blob */
05186     word32   senderKeyExportSz;    /* size of sender ephemeral key DER */
05187     word32   kekSz;                /* size of key encryption key */
05188     word32   ukmSz;                /* size of user keying material */
05189     word32   sharedInfoSz;         /* size of ECC-CMS-SharedInfo encoded */
05190     byte     ukmOwner;             /* do we own ukm buffer? 1:yes, 0:no */
05191     byte     direction;            /* WC_PKCS7_ENCODE | WC_PKCS7_DECODE */
05192     byte     decodedInit : 1;      /* indicates decoded was initialized */
05193     byte     recipKeyInit : 1;     /* indicates recipKey was initialized */
05194     byte     senderKeyInit : 1;    /* indicates senderKey was initialized */
05195 } WC_PKCS7_KARI;
05196 
05197 
05198 /* allocate and create new WC_PKCS7_KARI struct,
05199  * returns struct pointer on success, NULL on failure */
05200 static WC_PKCS7_KARI* wc_PKCS7_KariNew(PKCS7* pkcs7, byte direction)
05201 {
05202     WC_PKCS7_KARI* kari = NULL;
05203 
05204     if (pkcs7 == NULL)
05205         return NULL;
05206 
05207     kari = (WC_PKCS7_KARI*)XMALLOC(sizeof(WC_PKCS7_KARI), pkcs7->heap,
05208                                    DYNAMIC_TYPE_PKCS7);
05209     if (kari == NULL) {
05210         WOLFSSL_MSG("Failed to allocate WC_PKCS7_KARI");
05211         return NULL;
05212     }
05213 
05214     kari->decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
05215                                           DYNAMIC_TYPE_PKCS7);
05216     if (kari->decoded == NULL) {
05217         WOLFSSL_MSG("Failed to allocate DecodedCert");
05218         XFREE(kari, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05219         return NULL;
05220     }
05221 
05222     kari->recipKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
05223                                        DYNAMIC_TYPE_PKCS7);
05224     if (kari->recipKey == NULL) {
05225         WOLFSSL_MSG("Failed to allocate recipient ecc_key");
05226         XFREE(kari->decoded, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05227         XFREE(kari, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05228         return NULL;
05229     }
05230 
05231     kari->senderKey = (ecc_key*)XMALLOC(sizeof(ecc_key), pkcs7->heap,
05232                                         DYNAMIC_TYPE_PKCS7);
05233     if (kari->senderKey == NULL) {
05234         WOLFSSL_MSG("Failed to allocate sender ecc_key");
05235         XFREE(kari->recipKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05236         XFREE(kari->decoded, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05237         XFREE(kari, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05238         return NULL;
05239     }
05240 
05241     kari->senderKeyExport = NULL;
05242     kari->senderKeyExportSz = 0;
05243     kari->kek = NULL;
05244     kari->kekSz = 0;
05245     kari->ukm = NULL;
05246     kari->ukmSz = 0;
05247     kari->ukmOwner = 0;
05248     kari->sharedInfo = NULL;
05249     kari->sharedInfoSz = 0;
05250     kari->direction = direction;
05251     kari->decodedInit = 0;
05252     kari->recipKeyInit = 0;
05253     kari->senderKeyInit = 0;
05254 
05255     kari->heap = pkcs7->heap;
05256     kari->devId = pkcs7->devId;
05257 
05258     return kari;
05259 }
05260 
05261 
05262 /* free WC_PKCS7_KARI struct, return 0 on success */
05263 static int wc_PKCS7_KariFree(WC_PKCS7_KARI* kari)
05264 {
05265     void* heap;
05266 
05267     if (kari) {
05268         heap = kari->heap;
05269 
05270         if (kari->decoded) {
05271             if (kari->decodedInit)
05272                 FreeDecodedCert(kari->decoded);
05273             XFREE(kari->decoded, heap, DYNAMIC_TYPE_PKCS7);
05274         }
05275         if (kari->senderKey) {
05276             if (kari->senderKeyInit)
05277                 wc_ecc_free(kari->senderKey);
05278             XFREE(kari->senderKey, heap, DYNAMIC_TYPE_PKCS7);
05279         }
05280         if (kari->recipKey) {
05281             if (kari->recipKeyInit)
05282                 wc_ecc_free(kari->recipKey);
05283             XFREE(kari->recipKey, heap, DYNAMIC_TYPE_PKCS7);
05284         }
05285         if (kari->senderKeyExport) {
05286             ForceZero(kari->senderKeyExport, kari->senderKeyExportSz);
05287             XFREE(kari->senderKeyExport, heap, DYNAMIC_TYPE_PKCS7);
05288             kari->senderKeyExportSz = 0;
05289         }
05290         if (kari->kek) {
05291             ForceZero(kari->kek, kari->kekSz);
05292             XFREE(kari->kek, heap, DYNAMIC_TYPE_PKCS7);
05293             kari->kekSz = 0;
05294         }
05295         if (kari->ukm) {
05296             if (kari->ukmOwner == 1) {
05297                 XFREE(kari->ukm, heap, DYNAMIC_TYPE_PKCS7);
05298             }
05299             kari->ukmSz = 0;
05300         }
05301         if (kari->sharedInfo) {
05302             ForceZero(kari->sharedInfo, kari->sharedInfoSz);
05303             XFREE(kari->sharedInfo, heap, DYNAMIC_TYPE_PKCS7);
05304             kari->sharedInfoSz = 0;
05305         }
05306         XFREE(kari, heap, DYNAMIC_TYPE_PKCS7);
05307     }
05308 
05309     (void)heap;
05310 
05311     return 0;
05312 }
05313 
05314 
05315 /* parse recipient cert/key, return 0 on success, negative on error
05316  * key/keySz only needed during decoding (WC_PKCS7_DECODE) */
05317 static int wc_PKCS7_KariParseRecipCert(WC_PKCS7_KARI* kari, const byte* cert,
05318                                        word32 certSz, const byte* key,
05319                                        word32 keySz)
05320 {
05321     int ret;
05322     word32 idx;
05323 
05324     if (kari == NULL || kari->decoded == NULL ||
05325         cert == NULL || certSz == 0)
05326         return BAD_FUNC_ARG;
05327 
05328     /* decode certificate */
05329     InitDecodedCert(kari->decoded, (byte*)cert, certSz, kari->heap);
05330     kari->decodedInit = 1;
05331     ret = ParseCert(kari->decoded, CA_TYPE, NO_VERIFY, 0);
05332     if (ret < 0)
05333         return ret;
05334 
05335     /* only supports ECDSA for now */
05336     if (kari->decoded->keyOID != ECDSAk) {
05337         WOLFSSL_MSG("CMS KARI only supports ECDSA key types");
05338         return BAD_FUNC_ARG;
05339     }
05340 
05341     /* make sure subject key id was read from cert */
05342     if (kari->decoded->extSubjKeyIdSet == 0) {
05343         WOLFSSL_MSG("Failed to read subject key ID from recipient cert");
05344         return BAD_FUNC_ARG;
05345     }
05346 
05347     ret = wc_ecc_init_ex(kari->recipKey, kari->heap, kari->devId);
05348     if (ret != 0)
05349         return ret;
05350 
05351     kari->recipKeyInit = 1;
05352 
05353     /* get recip public key */
05354     if (kari->direction == WC_PKCS7_ENCODE) {
05355 
05356         idx = 0;
05357         ret = wc_EccPublicKeyDecode(kari->decoded->publicKey, &idx,
05358                                     kari->recipKey, kari->decoded->pubKeySize);
05359         if (ret != 0)
05360             return ret;
05361     }
05362     /* get recip private key */
05363     else if (kari->direction == WC_PKCS7_DECODE) {
05364         if (key != NULL && keySz > 0) {
05365             idx = 0;
05366             ret = wc_EccPrivateKeyDecode(key, &idx, kari->recipKey, keySz);
05367         }
05368         else if (kari->devId == INVALID_DEVID) {
05369             ret = BAD_FUNC_ARG;
05370         }
05371         if (ret != 0)
05372             return ret;
05373 
05374     } else {
05375         /* bad direction */
05376         return BAD_FUNC_ARG;
05377     }
05378 
05379     (void)idx;
05380 
05381     return 0;
05382 }
05383 
05384 
05385 /* create ephemeral ECC key, places ecc_key in kari->senderKey,
05386  * DER encoded in kari->senderKeyExport. return 0 on success,
05387  * negative on error */
05388 static int wc_PKCS7_KariGenerateEphemeralKey(WC_PKCS7_KARI* kari)
05389 {
05390     int ret;
05391     WC_RNG rng;
05392 
05393     if (kari == NULL || kari->decoded == NULL ||
05394         kari->recipKey == NULL || kari->recipKey->dp == NULL)
05395         return BAD_FUNC_ARG;
05396 
05397     kari->senderKeyExport = (byte*)XMALLOC(kari->decoded->pubKeySize,
05398                                            kari->heap, DYNAMIC_TYPE_PKCS7);
05399     if (kari->senderKeyExport == NULL)
05400         return MEMORY_E;
05401 
05402     kari->senderKeyExportSz = kari->decoded->pubKeySize;
05403 
05404     ret = wc_ecc_init_ex(kari->senderKey, kari->heap, kari->devId);
05405     if (ret != 0) {
05406         XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
05407         return ret;
05408     }
05409 
05410     kari->senderKeyInit = 1;
05411 
05412     ret = wc_InitRng_ex(&rng, kari->heap, kari->devId);
05413     if (ret != 0) {
05414         XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
05415         return ret;
05416     }
05417 
05418     ret = wc_ecc_make_key_ex(&rng, kari->recipKey->dp->size,
05419                              kari->senderKey, kari->recipKey->dp->id);
05420     if (ret != 0) {
05421         XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
05422         wc_FreeRng(&rng);
05423         return ret;
05424     }
05425 
05426     wc_FreeRng(&rng);
05427 
05428     /* dump generated key to X.963 DER for output in CMS bundle */
05429     ret = wc_ecc_export_x963(kari->senderKey, kari->senderKeyExport,
05430                              &kari->senderKeyExportSz);
05431     if (ret != 0) {
05432         XFREE(kari->senderKeyExport, kari->heap, DYNAMIC_TYPE_PKCS7);
05433         return ret;
05434     }
05435 
05436     return 0;
05437 }
05438 
05439 
05440 /* create ASN.1 encoded ECC-CMS-SharedInfo using specified key wrap algorithm,
05441  * place in kari->sharedInfo. returns 0 on success, negative on error */
05442 static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID)
05443 {
05444     int idx = 0;
05445     int sharedInfoSeqSz = 0;
05446     int keyInfoSz = 0;
05447     int suppPubInfoSeqSz = 0;
05448     int entityUInfoOctetSz = 0;
05449     int entityUInfoExplicitSz = 0;
05450     int kekOctetSz = 0;
05451     int sharedInfoSz = 0;
05452 
05453     word32 kekBitSz = 0;
05454 
05455     byte sharedInfoSeq[MAX_SEQ_SZ];
05456     byte keyInfo[MAX_ALGO_SZ];
05457     byte suppPubInfoSeq[MAX_SEQ_SZ];
05458     byte entityUInfoOctet[MAX_OCTET_STR_SZ];
05459     byte entityUInfoExplicitSeq[MAX_SEQ_SZ];
05460     byte kekOctet[MAX_OCTET_STR_SZ];
05461 
05462     if (kari == NULL)
05463         return BAD_FUNC_ARG;
05464 
05465     if ((kari->ukmSz > 0) && (kari->ukm == NULL))
05466         return BAD_FUNC_ARG;
05467 
05468     /* kekOctet */
05469     kekOctetSz = SetOctetString(sizeof(word32), kekOctet);
05470     sharedInfoSz += (kekOctetSz + sizeof(word32));
05471 
05472     /* suppPubInfo */
05473     suppPubInfoSeqSz = SetImplicit(ASN_SEQUENCE, 2,
05474                                    kekOctetSz + sizeof(word32),
05475                                    suppPubInfoSeq);
05476     sharedInfoSz += suppPubInfoSeqSz;
05477 
05478     /* optional ukm/entityInfo */
05479     if (kari->ukmSz > 0) {
05480         entityUInfoOctetSz = SetOctetString(kari->ukmSz, entityUInfoOctet);
05481         sharedInfoSz += (entityUInfoOctetSz + kari->ukmSz);
05482 
05483         entityUInfoExplicitSz = SetExplicit(0, entityUInfoOctetSz +
05484                                             kari->ukmSz,
05485                                             entityUInfoExplicitSeq);
05486         sharedInfoSz += entityUInfoExplicitSz;
05487     }
05488 
05489     /* keyInfo */
05490     keyInfoSz = SetAlgoID(keyWrapOID, keyInfo, oidKeyWrapType, 0);
05491     sharedInfoSz += keyInfoSz;
05492 
05493     /* sharedInfo */
05494     sharedInfoSeqSz = SetSequence(sharedInfoSz, sharedInfoSeq);
05495     sharedInfoSz += sharedInfoSeqSz;
05496 
05497     kari->sharedInfo = (byte*)XMALLOC(sharedInfoSz, kari->heap,
05498                                       DYNAMIC_TYPE_PKCS7);
05499     if (kari->sharedInfo == NULL)
05500         return MEMORY_E;
05501 
05502     kari->sharedInfoSz = sharedInfoSz;
05503 
05504     XMEMCPY(kari->sharedInfo + idx, sharedInfoSeq, sharedInfoSeqSz);
05505     idx += sharedInfoSeqSz;
05506     XMEMCPY(kari->sharedInfo + idx, keyInfo, keyInfoSz);
05507     idx += keyInfoSz;
05508     if (kari->ukmSz > 0) {
05509         XMEMCPY(kari->sharedInfo + idx, entityUInfoExplicitSeq,
05510                 entityUInfoExplicitSz);
05511         idx += entityUInfoExplicitSz;
05512         XMEMCPY(kari->sharedInfo + idx, entityUInfoOctet, entityUInfoOctetSz);
05513         idx += entityUInfoOctetSz;
05514         XMEMCPY(kari->sharedInfo + idx, kari->ukm, kari->ukmSz);
05515         idx += kari->ukmSz;
05516     }
05517     XMEMCPY(kari->sharedInfo + idx, suppPubInfoSeq, suppPubInfoSeqSz);
05518     idx += suppPubInfoSeqSz;
05519     XMEMCPY(kari->sharedInfo + idx, kekOctet, kekOctetSz);
05520     idx += kekOctetSz;
05521 
05522     kekBitSz = (kari->kekSz) * 8;              /* convert to bits */
05523 #ifdef LITTLE_ENDIAN_ORDER
05524     kekBitSz = ByteReverseWord32(kekBitSz);    /* network byte order */
05525 #endif
05526     XMEMCPY(kari->sharedInfo + idx, &kekBitSz, sizeof(kekBitSz));
05527 
05528     return 0;
05529 }
05530 
05531 
05532 /* create key encryption key (KEK) using key wrap algorithm and key encryption
05533  * algorithm, place in kari->kek. return 0 on success, <0 on error. */
05534 static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari,
05535                                     int keyWrapOID, int keyEncOID)
05536 {
05537     int ret;
05538     int kSz;
05539     enum wc_HashType kdfType;
05540     byte*  secret;
05541     word32 secretSz;
05542 
05543     if (kari == NULL || kari->recipKey == NULL ||
05544         kari->senderKey == NULL || kari->senderKey->dp == NULL)
05545         return BAD_FUNC_ARG;
05546 
05547     /* get KEK size, allocate buff */
05548     kSz = wc_PKCS7_GetOIDKeySize(keyWrapOID);
05549     if (kSz < 0)
05550         return kSz;
05551 
05552     kari->kek = (byte*)XMALLOC(kSz, kari->heap, DYNAMIC_TYPE_PKCS7);
05553     if (kari->kek == NULL)
05554         return MEMORY_E;
05555 
05556     kari->kekSz = (word32)kSz;
05557 
05558     /* generate ECC-CMS-SharedInfo */
05559     ret = wc_PKCS7_KariGenerateSharedInfo(kari, keyWrapOID);
05560     if (ret != 0)
05561         return ret;
05562 
05563     /* generate shared secret */
05564     secretSz = kari->senderKey->dp->size;
05565     secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7);
05566     if (secret == NULL)
05567         return MEMORY_E;
05568 
05569     if (kari->direction == WC_PKCS7_ENCODE) {
05570 
05571         ret = wc_ecc_shared_secret(kari->senderKey, kari->recipKey,
05572                                    secret, &secretSz);
05573 
05574     } else if (kari->direction == WC_PKCS7_DECODE) {
05575 
05576         ret = wc_ecc_shared_secret(kari->recipKey, kari->senderKey,
05577                                    secret, &secretSz);
05578 
05579     } else {
05580         /* bad direction */
05581         XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
05582         return BAD_FUNC_ARG;
05583     }
05584 
05585     if (ret != 0) {
05586         XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
05587         return ret;
05588     }
05589 
05590     /* run through KDF */
05591     switch (keyEncOID) {
05592 
05593     #ifndef NO_SHA
05594         case dhSinglePass_stdDH_sha1kdf_scheme:
05595             kdfType = WC_HASH_TYPE_SHA;
05596             break;
05597     #endif
05598     #ifndef WOLFSSL_SHA224
05599         case dhSinglePass_stdDH_sha224kdf_scheme:
05600             kdfType = WC_HASH_TYPE_SHA224;
05601             break;
05602     #endif
05603     #ifndef NO_SHA256
05604         case dhSinglePass_stdDH_sha256kdf_scheme:
05605             kdfType = WC_HASH_TYPE_SHA256;
05606             break;
05607     #endif
05608     #ifdef WOLFSSL_SHA384
05609         case dhSinglePass_stdDH_sha384kdf_scheme:
05610             kdfType = WC_HASH_TYPE_SHA384;
05611             break;
05612     #endif
05613     #ifdef WOLFSSL_SHA512
05614         case dhSinglePass_stdDH_sha512kdf_scheme:
05615             kdfType = WC_HASH_TYPE_SHA512;
05616             break;
05617     #endif
05618         default:
05619             WOLFSSL_MSG("Unsupported key agreement algorithm");
05620             XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
05621             return BAD_FUNC_ARG;
05622     };
05623 
05624     ret = wc_X963_KDF(kdfType, secret, secretSz, kari->sharedInfo,
05625                       kari->sharedInfoSz, kari->kek, kari->kekSz);
05626     if (ret != 0) {
05627         XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
05628         return ret;
05629     }
05630 
05631     XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
05632 
05633     return 0;
05634 }
05635 
05636 
05637 /* Encode and add CMS EnvelopedData KARI (KeyAgreeRecipientInfo) RecipientInfo
05638  * to CMS/PKCS#7 EnvelopedData structure.
05639  *
05640  * Returns 0 on success, negative upon error */
05641 int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz,
05642                                int keyWrapOID, int keyAgreeOID, byte* ukm,
05643                                word32 ukmSz, int options)
05644 {
05645     Pkcs7EncodedRecip* recip;
05646     Pkcs7EncodedRecip* lastRecip = NULL;
05647     WC_PKCS7_KARI* kari = NULL;
05648 
05649     word32 idx = 0;
05650     word32 encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
05651 
05652     int ret = 0;
05653     int keySz, direction = 0;
05654     int blockKeySz = 0;
05655 
05656     /* ASN.1 layout */
05657     int totalSz = 0;
05658     int kariSeqSz = 0;
05659     byte kariSeq[MAX_SEQ_SZ];           /* IMPLICIT [1] */
05660     int verSz = 0;
05661     byte ver[MAX_VERSION_SZ];
05662 
05663     int origIdOrKeySeqSz = 0;
05664     byte origIdOrKeySeq[MAX_SEQ_SZ];    /* IMPLICIT [0] */
05665     int origPubKeySeqSz = 0;
05666     byte origPubKeySeq[MAX_SEQ_SZ];     /* IMPLICIT [1] */
05667     int origAlgIdSz = 0;
05668     byte origAlgId[MAX_ALGO_SZ];
05669     int origPubKeyStrSz = 0;
05670     byte origPubKeyStr[MAX_OCTET_STR_SZ];
05671 
05672     /* optional user keying material */
05673     int ukmOctetSz = 0;
05674     byte ukmOctetStr[MAX_OCTET_STR_SZ];
05675     int ukmExplicitSz = 0;
05676     byte ukmExplicitSeq[MAX_SEQ_SZ];
05677 
05678     int keyEncryptAlgoIdSz = 0;
05679     byte keyEncryptAlgoId[MAX_ALGO_SZ];
05680     int keyWrapAlgSz = 0;
05681     byte keyWrapAlg[MAX_ALGO_SZ];
05682 
05683     int recipEncKeysSeqSz = 0;
05684     byte recipEncKeysSeq[MAX_SEQ_SZ];
05685     int recipEncKeySeqSz = 0;
05686     byte recipEncKeySeq[MAX_SEQ_SZ];
05687     int recipKeyIdSeqSz = 0;
05688     byte recipKeyIdSeq[MAX_SEQ_SZ];     /* IMPLICIT [0] */
05689     int subjKeyIdOctetSz = 0;
05690     byte subjKeyIdOctet[MAX_OCTET_STR_SZ];
05691     int encryptedKeyOctetSz = 0;
05692     byte encryptedKeyOctet[MAX_OCTET_STR_SZ];
05693 
05694 #ifdef WOLFSSL_SMALL_STACK
05695     byte* encryptedKey;
05696 
05697     encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
05698                                   DYNAMIC_TYPE_TMP_BUFFER);
05699     if (encryptedKey == NULL) {
05700         return MEMORY_E;
05701     }
05702 #else
05703     byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
05704 #endif
05705 
05706     /* allocate and init memory for recipient */
05707     recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap,
05708                                  DYNAMIC_TYPE_PKCS7);
05709     if (recip == NULL) {
05710 #ifdef WOLFSSL_SMALL_STACK
05711         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05712 #endif
05713         return MEMORY_E;
05714     }
05715     XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
05716 
05717     /* get key size for content-encryption key based on algorithm */
05718     blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
05719     if (blockKeySz < 0) {
05720 #ifdef WOLFSSL_SMALL_STACK
05721         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05722 #endif
05723         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05724         return blockKeySz;
05725     }
05726 
05727     /* generate random content encryption key, if needed */
05728     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz);
05729     if (ret < 0) {
05730 #ifdef WOLFSSL_SMALL_STACK
05731         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05732 #endif
05733         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05734         return ret;
05735     }
05736 
05737     /* set direction based on keyWrapAlgo */
05738     switch (keyWrapOID) {
05739 #ifndef NO_AES
05740     #ifdef WOLFSSL_AES_128
05741         case AES128_WRAP:
05742     #endif
05743     #ifdef WOLFSSL_AES_192
05744         case AES192_WRAP:
05745     #endif
05746     #ifdef WOLFSSL_AES_256
05747         case AES256_WRAP:
05748     #endif
05749             direction = AES_ENCRYPTION;
05750             break;
05751 #endif
05752         default:
05753             WOLFSSL_MSG("Unsupported key wrap algorithm");
05754 #ifdef WOLFSSL_SMALL_STACK
05755             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05756 #endif
05757             XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05758             return BAD_KEYWRAP_ALG_E;
05759     }
05760 
05761     kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_ENCODE);
05762     if (kari == NULL) {
05763 #ifdef WOLFSSL_SMALL_STACK
05764         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05765 #endif
05766         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05767         return MEMORY_E;
05768     }
05769 
05770     /* set user keying material if available */
05771     if (ukmSz > 0 && ukm != NULL) {
05772         kari->ukm = ukm;
05773         kari->ukmSz = ukmSz;
05774         kari->ukmOwner = 0;
05775     }
05776 
05777     /* parse recipient cert, get public key */
05778     ret = wc_PKCS7_KariParseRecipCert(kari, cert, certSz, NULL, 0);
05779     if (ret != 0) {
05780         wc_PKCS7_KariFree(kari);
05781 #ifdef WOLFSSL_SMALL_STACK
05782         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05783 #endif
05784         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05785         return ret;
05786     }
05787 
05788     /* generate sender ephemeral ECC key */
05789     ret = wc_PKCS7_KariGenerateEphemeralKey(kari);
05790     if (ret != 0) {
05791         wc_PKCS7_KariFree(kari);
05792 #ifdef WOLFSSL_SMALL_STACK
05793         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05794 #endif
05795         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05796         return ret;
05797     }
05798 
05799     /* generate KEK (key encryption key) */
05800     ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, keyAgreeOID);
05801     if (ret != 0) {
05802         wc_PKCS7_KariFree(kari);
05803 #ifdef WOLFSSL_SMALL_STACK
05804         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05805 #endif
05806         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05807         return ret;
05808     }
05809 
05810     /* encrypt CEK with KEK */
05811     keySz = wc_PKCS7_KeyWrap(pkcs7->cek, pkcs7->cekSz, kari->kek,
05812                              kari->kekSz, encryptedKey, encryptedKeySz,
05813                              keyWrapOID, direction);
05814     if (keySz <= 0) {
05815         wc_PKCS7_KariFree(kari);
05816 #ifdef WOLFSSL_SMALL_STACK
05817         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05818 #endif
05819         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05820         return keySz;
05821     }
05822     encryptedKeySz = (word32)keySz;
05823 
05824     /* Start of RecipientEncryptedKeys */
05825 
05826     /* EncryptedKey */
05827     encryptedKeyOctetSz = SetOctetString(encryptedKeySz, encryptedKeyOctet);
05828     totalSz += (encryptedKeyOctetSz + encryptedKeySz);
05829 
05830     /* SubjectKeyIdentifier */
05831     subjKeyIdOctetSz = SetOctetString(KEYID_SIZE, subjKeyIdOctet);
05832     totalSz += (subjKeyIdOctetSz + KEYID_SIZE);
05833 
05834     /* RecipientKeyIdentifier IMPLICIT [0] */
05835     recipKeyIdSeqSz = SetImplicit(ASN_SEQUENCE, 0, subjKeyIdOctetSz +
05836                                   KEYID_SIZE, recipKeyIdSeq);
05837     totalSz += recipKeyIdSeqSz;
05838 
05839     /* RecipientEncryptedKey */
05840     recipEncKeySeqSz = SetSequence(totalSz, recipEncKeySeq);
05841     totalSz += recipEncKeySeqSz;
05842 
05843     /* RecipientEncryptedKeys */
05844     recipEncKeysSeqSz = SetSequence(totalSz, recipEncKeysSeq);
05845     totalSz += recipEncKeysSeqSz;
05846 
05847     /* Start of optional UserKeyingMaterial */
05848 
05849     if (kari->ukmSz > 0) {
05850         ukmOctetSz = SetOctetString(kari->ukmSz, ukmOctetStr);
05851         totalSz += (ukmOctetSz + kari->ukmSz);
05852 
05853         ukmExplicitSz = SetExplicit(1, ukmOctetSz + kari->ukmSz,
05854                                     ukmExplicitSeq);
05855         totalSz += ukmExplicitSz;
05856     }
05857 
05858     /* Start of KeyEncryptionAlgorithmIdentifier */
05859 
05860     /* KeyWrapAlgorithm */
05861     keyWrapAlgSz = SetAlgoID(keyWrapOID, keyWrapAlg, oidKeyWrapType, 0);
05862     totalSz += keyWrapAlgSz;
05863 
05864     /* KeyEncryptionAlgorithmIdentifier */
05865     keyEncryptAlgoIdSz = SetAlgoID(keyAgreeOID, keyEncryptAlgoId,
05866                                    oidCmsKeyAgreeType, keyWrapAlgSz);
05867     totalSz += keyEncryptAlgoIdSz;
05868 
05869     /* Start of OriginatorIdentifierOrKey */
05870 
05871     /* recipient ECPoint, public key */
05872     XMEMSET(origPubKeyStr, 0, sizeof(origPubKeyStr)); /* no unused bits */
05873     origPubKeyStr[0] = ASN_BIT_STRING;
05874     origPubKeyStrSz = SetLength(kari->senderKeyExportSz + 1,
05875                                 origPubKeyStr + 1) + 2;
05876     totalSz += (origPubKeyStrSz + kari->senderKeyExportSz);
05877 
05878     /* Originator AlgorithmIdentifier, params set to NULL for interop
05879        compatibility */
05880     origAlgIdSz = SetAlgoID(ECDSAk, origAlgId, oidKeyType, 2);
05881     origAlgId[origAlgIdSz++] = ASN_TAG_NULL;
05882     origAlgId[origAlgIdSz++] = 0;
05883     totalSz += origAlgIdSz;
05884 
05885     /* outer OriginatorPublicKey IMPLICIT [1] */
05886     origPubKeySeqSz = SetImplicit(ASN_SEQUENCE, 1,
05887                                   origAlgIdSz + origPubKeyStrSz +
05888                                   kari->senderKeyExportSz, origPubKeySeq);
05889     totalSz += origPubKeySeqSz;
05890 
05891     /* outer OriginatorIdentiferOrKey IMPLICIT [0] */
05892     origIdOrKeySeqSz = SetImplicit(ASN_SEQUENCE, 0,
05893                                    origPubKeySeqSz + origAlgIdSz +
05894                                    origPubKeyStrSz + kari->senderKeyExportSz,
05895                                    origIdOrKeySeq);
05896     totalSz += origIdOrKeySeqSz;
05897 
05898     /* version, always 3 */
05899     verSz = SetMyVersion(3, ver, 0);
05900     totalSz += verSz;
05901     recip->recipVersion = 3;
05902 
05903     /* outer IMPLICIT [1] kari */
05904     kariSeqSz = SetImplicit(ASN_SEQUENCE, 1, totalSz, kariSeq);
05905     totalSz += kariSeqSz;
05906 
05907     if (totalSz > MAX_RECIP_SZ) {
05908         WOLFSSL_MSG("KeyAgreeRecipientInfo output buffer too small");
05909         wc_PKCS7_KariFree(kari);
05910 #ifdef WOLFSSL_SMALL_STACK
05911         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05912 #endif
05913         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
05914         return BUFFER_E;
05915     }
05916 
05917     XMEMCPY(recip->recip + idx, kariSeq, kariSeqSz);
05918     idx += kariSeqSz;
05919     XMEMCPY(recip->recip + idx, ver, verSz);
05920     idx += verSz;
05921 
05922     XMEMCPY(recip->recip + idx, origIdOrKeySeq, origIdOrKeySeqSz);
05923     idx += origIdOrKeySeqSz;
05924     XMEMCPY(recip->recip + idx, origPubKeySeq, origPubKeySeqSz);
05925     idx += origPubKeySeqSz;
05926 
05927     /* AlgorithmIdentifier with NULL parameter */
05928     XMEMCPY(recip->recip + idx, origAlgId, origAlgIdSz);
05929     idx += origAlgIdSz;
05930 
05931     XMEMCPY(recip->recip + idx, origPubKeyStr, origPubKeyStrSz);
05932     idx += origPubKeyStrSz;
05933     /* ephemeral public key */
05934     XMEMCPY(recip->recip + idx, kari->senderKeyExport, kari->senderKeyExportSz);
05935     idx += kari->senderKeyExportSz;
05936 
05937     if (kari->ukmSz > 0) {
05938         XMEMCPY(recip->recip + idx, ukmExplicitSeq, ukmExplicitSz);
05939         idx += ukmExplicitSz;
05940         XMEMCPY(recip->recip + idx, ukmOctetStr, ukmOctetSz);
05941         idx += ukmOctetSz;
05942         XMEMCPY(recip->recip + idx, kari->ukm, kari->ukmSz);
05943         idx += kari->ukmSz;
05944     }
05945 
05946     XMEMCPY(recip->recip + idx, keyEncryptAlgoId, keyEncryptAlgoIdSz);
05947     idx += keyEncryptAlgoIdSz;
05948     XMEMCPY(recip->recip + idx, keyWrapAlg, keyWrapAlgSz);
05949     idx += keyWrapAlgSz;
05950 
05951     XMEMCPY(recip->recip + idx, recipEncKeysSeq, recipEncKeysSeqSz);
05952     idx += recipEncKeysSeqSz;
05953     XMEMCPY(recip->recip + idx, recipEncKeySeq, recipEncKeySeqSz);
05954     idx += recipEncKeySeqSz;
05955     XMEMCPY(recip->recip + idx, recipKeyIdSeq, recipKeyIdSeqSz);
05956     idx += recipKeyIdSeqSz;
05957     XMEMCPY(recip->recip + idx, subjKeyIdOctet, subjKeyIdOctetSz);
05958     idx += subjKeyIdOctetSz;
05959     /* subject key id */
05960     XMEMCPY(recip->recip + idx, kari->decoded->extSubjKeyId, KEYID_SIZE);
05961     idx += KEYID_SIZE;
05962     XMEMCPY(recip->recip + idx, encryptedKeyOctet, encryptedKeyOctetSz);
05963     idx += encryptedKeyOctetSz;
05964     /* encrypted CEK */
05965     XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
05966     idx += encryptedKeySz;
05967 
05968     wc_PKCS7_KariFree(kari);
05969 #ifdef WOLFSSL_SMALL_STACK
05970     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
05971 #endif
05972 
05973     /* store recipient size */
05974     recip->recipSz = idx;
05975     recip->recipType = PKCS7_KARI;
05976 
05977     /* add recipient to recip list */
05978     if (pkcs7->recipList == NULL) {
05979         pkcs7->recipList = recip;
05980     } else {
05981         lastRecip = pkcs7->recipList;
05982         while (lastRecip->next != NULL) {
05983             lastRecip = lastRecip->next;
05984         }
05985         lastRecip->next = recip;
05986     }
05987 
05988     (void)options;
05989 
05990     return idx;
05991 }
05992 
05993 #endif /* HAVE_ECC */
05994 
05995 #ifndef NO_RSA
05996 
05997 /* Encode and add CMS EnvelopedData KTRI (KeyTransRecipientInfo) RecipientInfo
05998  * to CMS/PKCS#7 EnvelopedData structure.
05999  *
06000  * Returns 0 on success, negative upon error */
06001 int wc_PKCS7_AddRecipient_KTRI(PKCS7* pkcs7, const byte* cert, word32 certSz,
06002                                int options)
06003 {
06004     Pkcs7EncodedRecip* recip = NULL;
06005     Pkcs7EncodedRecip* lastRecip = NULL;
06006 
06007     WC_RNG rng;
06008     word32 idx = 0;
06009     word32 encryptedKeySz = 0;
06010 
06011     int ret = 0, blockKeySz;
06012     int verSz = 0, issuerSz = 0, snSz = 0, keyEncAlgSz = 0;
06013     int issuerSeqSz = 0, recipSeqSz = 0, issuerSerialSeqSz = 0;
06014     int encKeyOctetStrSz;
06015     int sidType;
06016 
06017     byte ver[MAX_VERSION_SZ];
06018     byte issuerSerialSeq[MAX_SEQ_SZ];
06019     byte recipSeq[MAX_SEQ_SZ];
06020     byte issuerSeq[MAX_SEQ_SZ];
06021     byte encKeyOctetStr[MAX_OCTET_STR_SZ];
06022 
06023     byte issuerSKIDSeq[MAX_SEQ_SZ];
06024     byte issuerSKID[MAX_OCTET_STR_SZ];
06025     word32 issuerSKIDSeqSz = 0, issuerSKIDSz = 0;
06026 
06027 #ifdef WOLFSSL_SMALL_STACK
06028     byte*   serial;
06029     byte*   keyAlgArray;
06030     byte*   encryptedKey;
06031     RsaKey* pubKey;
06032     DecodedCert* decoded;
06033 
06034     serial = (byte*)XMALLOC(MAX_SN_SZ, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06035     keyAlgArray = (byte*)XMALLOC(MAX_SN_SZ, pkcs7->heap,
06036                                  DYNAMIC_TYPE_TMP_BUFFER);
06037     encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
06038                                   DYNAMIC_TYPE_TMP_BUFFER);
06039     decoded = (DecodedCert*)XMALLOC(sizeof(DecodedCert), pkcs7->heap,
06040                                     DYNAMIC_TYPE_TMP_BUFFER);
06041 
06042     if (decoded == NULL || serial == NULL ||
06043         encryptedKey == NULL || keyAlgArray == NULL) {
06044         if (serial)
06045             XFREE(serial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06046         if (keyAlgArray)
06047             XFREE(keyAlgArray, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06048         if (encryptedKey)
06049             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06050         if (decoded)
06051             XFREE(decoded, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06052         return MEMORY_E;
06053     }
06054 #else
06055     byte serial[MAX_SN_SZ];
06056     byte keyAlgArray[MAX_ALGO_SZ];
06057     byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
06058 
06059     RsaKey pubKey[1];
06060     DecodedCert decoded[1];
06061 #endif
06062 
06063     encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
06064     XMEMSET(encryptedKey, 0, encryptedKeySz);
06065 
06066     /* default to IssuerAndSerialNumber if not set */
06067     if (pkcs7->sidType != 0) {
06068         sidType = pkcs7->sidType;
06069     } else {
06070         sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
06071     }
06072 
06073     /* allow options to override SubjectIdentifier type if set */
06074     if (options & CMS_SKID) {
06075         sidType = CMS_SKID;
06076     } else if (options & CMS_ISSUER_AND_SERIAL_NUMBER) {
06077         sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
06078     }
06079 
06080     /* allocate recipient struct */
06081     recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap,
06082                                  DYNAMIC_TYPE_PKCS7);
06083     if (recip == NULL) {
06084 #ifdef WOLFSSL_SMALL_STACK
06085         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06086         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06087         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06088         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06089 #endif
06090         return MEMORY_E;
06091     }
06092     XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
06093 
06094     /* get key size for content-encryption key based on algorithm */
06095     blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
06096     if (blockKeySz < 0) {
06097 #ifdef WOLFSSL_SMALL_STACK
06098         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06099         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06100         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06101         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06102 #endif
06103         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06104         return blockKeySz;
06105     }
06106 
06107     /* generate random content encryption key, if needed */
06108     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz);
06109     if (ret < 0) {
06110 #ifdef WOLFSSL_SMALL_STACK
06111         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06112         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06113         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06114         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06115 #endif
06116         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06117         return ret;
06118     }
06119 
06120     InitDecodedCert(decoded, (byte*)cert, certSz, pkcs7->heap);
06121     ret = ParseCert(decoded, CA_TYPE, NO_VERIFY, 0);
06122     if (ret < 0) {
06123         FreeDecodedCert(decoded);
06124 #ifdef WOLFSSL_SMALL_STACK
06125         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06126         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06127         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06128         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06129 #endif
06130         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06131         return ret;
06132     }
06133 
06134     if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
06135 
06136         /* version, must be 0 for IssuerAndSerialNumber */
06137         verSz = SetMyVersion(0, ver, 0);
06138         recip->recipVersion = 0;
06139 
06140         /* IssuerAndSerialNumber */
06141         if (decoded->issuerRaw == NULL || decoded->issuerRawLen == 0) {
06142             WOLFSSL_MSG("DecodedCert lacks raw issuer pointer and length");
06143             FreeDecodedCert(decoded);
06144 #ifdef WOLFSSL_SMALL_STACK
06145             XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06146             XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06147             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06148             XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06149 #endif
06150             XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06151             return -1;
06152         }
06153         issuerSz    = decoded->issuerRawLen;
06154         issuerSeqSz = SetSequence(issuerSz, issuerSeq);
06155 
06156         if (decoded->serialSz == 0) {
06157             WOLFSSL_MSG("DecodedCert missing serial number");
06158             FreeDecodedCert(decoded);
06159 #ifdef WOLFSSL_SMALL_STACK
06160             XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06161             XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06162             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06163             XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06164 #endif
06165             XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06166             return -1;
06167         }
06168         snSz = SetSerialNumber(decoded->serial, decoded->serialSz, serial,
06169                                MAX_SN_SZ, MAX_SN_SZ);
06170 
06171         issuerSerialSeqSz = SetSequence(issuerSeqSz + issuerSz + snSz,
06172                                         issuerSerialSeq);
06173 
06174     } else if (sidType == CMS_SKID) {
06175 
06176         /* version, must be 2 for SubjectKeyIdentifier */
06177         verSz = SetMyVersion(2, ver, 0);
06178         recip->recipVersion = 2;
06179 
06180         issuerSKIDSz = SetOctetString(KEYID_SIZE, issuerSKID);
06181         issuerSKIDSeqSz = SetExplicit(0, issuerSKIDSz + KEYID_SIZE,
06182                                       issuerSKIDSeq);
06183     } else {
06184         FreeDecodedCert(decoded);
06185 #ifdef WOLFSSL_SMALL_STACK
06186         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06187         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06188         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06189         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06190 #endif
06191         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06192         return PKCS7_RECIP_E;
06193     }
06194 
06195     pkcs7->publicKeyOID = decoded->keyOID;
06196 
06197     /* KeyEncryptionAlgorithmIdentifier, only support RSA now */
06198     if (pkcs7->publicKeyOID != RSAk) {
06199         FreeDecodedCert(decoded);
06200 #ifdef WOLFSSL_SMALL_STACK
06201         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06202         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06203         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06204         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06205 #endif
06206         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06207         return ALGO_ID_E;
06208     }
06209 
06210     keyEncAlgSz = SetAlgoID(pkcs7->publicKeyOID, keyAlgArray, oidKeyType, 0);
06211     if (keyEncAlgSz == 0) {
06212         FreeDecodedCert(decoded);
06213 #ifdef WOLFSSL_SMALL_STACK
06214         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06215         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06216         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06217         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06218 #endif
06219         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06220         return BAD_FUNC_ARG;
06221     }
06222 
06223 #ifdef WOLFSSL_SMALL_STACK
06224     pubKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
06225             DYNAMIC_TYPE_TMP_BUFFER);
06226     if (pubKey == NULL) {
06227         FreeDecodedCert(decoded);
06228         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06229         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06230         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06231         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06232         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06233         return MEMORY_E;
06234     }
06235 #endif
06236 
06237     /* EncryptedKey */
06238     ret = wc_InitRsaKey_ex(pubKey, pkcs7->heap, INVALID_DEVID);
06239     if (ret != 0) {
06240         FreeDecodedCert(decoded);
06241 #ifdef WOLFSSL_SMALL_STACK
06242         XFREE(pubKey,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06243         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06244         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06245         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06246         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06247 #endif
06248         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06249         return ret;
06250     }
06251 
06252     if (wc_RsaPublicKeyDecode(decoded->publicKey, &idx, pubKey,
06253                               decoded->pubKeySize) < 0) {
06254         WOLFSSL_MSG("ASN RSA key decode error");
06255         wc_FreeRsaKey(pubKey);
06256         FreeDecodedCert(decoded);
06257 #ifdef WOLFSSL_SMALL_STACK
06258         XFREE(pubKey,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06259         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06260         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06261         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06262         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06263 #endif
06264         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06265         return PUBLIC_KEY_E;
06266     }
06267 
06268     ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
06269     if (ret != 0) {
06270         wc_FreeRsaKey(pubKey);
06271         FreeDecodedCert(decoded);
06272 #ifdef WOLFSSL_SMALL_STACK
06273         XFREE(pubKey,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06274         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06275         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06276         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06277         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06278 #endif
06279         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06280         return MEMORY_E;
06281     }
06282 
06283 
06284     ret = wc_RsaPublicEncrypt(pkcs7->cek, pkcs7->cekSz, encryptedKey,
06285                               encryptedKeySz, pubKey, &rng);
06286     wc_FreeRsaKey(pubKey);
06287     wc_FreeRng(&rng);
06288 
06289 #ifdef WOLFSSL_SMALL_STACK
06290     XFREE(pubKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06291 #endif
06292 
06293     if (ret < 0) {
06294         WOLFSSL_MSG("RSA Public Encrypt failed");
06295         FreeDecodedCert(decoded);
06296 #ifdef WOLFSSL_SMALL_STACK
06297         XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06298         XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06299         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06300         XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06301 #endif
06302         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06303         return ret;
06304     }
06305     encryptedKeySz = ret;
06306 
06307     encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr);
06308 
06309     /* RecipientInfo */
06310     if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
06311         recipSeqSz = SetSequence(verSz + issuerSerialSeqSz + issuerSeqSz +
06312                                  issuerSz + snSz + keyEncAlgSz +
06313                                  encKeyOctetStrSz + encryptedKeySz, recipSeq);
06314 
06315         if (recipSeqSz + verSz + issuerSerialSeqSz + issuerSeqSz + snSz +
06316             keyEncAlgSz + encKeyOctetStrSz + encryptedKeySz > MAX_RECIP_SZ) {
06317             WOLFSSL_MSG("RecipientInfo output buffer too small");
06318             FreeDecodedCert(decoded);
06319 #ifdef WOLFSSL_SMALL_STACK
06320             XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06321             XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06322             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06323             XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06324 #endif
06325             XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06326             return BUFFER_E;
06327         }
06328 
06329     } else {
06330         recipSeqSz = SetSequence(verSz + issuerSKIDSeqSz + issuerSKIDSz +
06331                                  KEYID_SIZE + keyEncAlgSz + encKeyOctetStrSz +
06332                                  encryptedKeySz, recipSeq);
06333 
06334         if (recipSeqSz + verSz + issuerSKIDSeqSz + issuerSKIDSz + KEYID_SIZE +
06335             keyEncAlgSz + encKeyOctetStrSz + encryptedKeySz > MAX_RECIP_SZ) {
06336             WOLFSSL_MSG("RecipientInfo output buffer too small");
06337             FreeDecodedCert(decoded);
06338 #ifdef WOLFSSL_SMALL_STACK
06339             XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06340             XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06341             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06342             XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06343 #endif
06344             XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06345             return BUFFER_E;
06346         }
06347     }
06348 
06349     idx = 0;
06350     XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
06351     idx += recipSeqSz;
06352     XMEMCPY(recip->recip + idx, ver, verSz);
06353     idx += verSz;
06354     if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
06355         XMEMCPY(recip->recip + idx, issuerSerialSeq, issuerSerialSeqSz);
06356         idx += issuerSerialSeqSz;
06357         XMEMCPY(recip->recip + idx, issuerSeq, issuerSeqSz);
06358         idx += issuerSeqSz;
06359         XMEMCPY(recip->recip + idx, decoded->issuerRaw, issuerSz);
06360         idx += issuerSz;
06361         XMEMCPY(recip->recip + idx, serial, snSz);
06362         idx += snSz;
06363     } else {
06364         XMEMCPY(recip->recip + idx, issuerSKIDSeq, issuerSKIDSeqSz);
06365         idx += issuerSKIDSeqSz;
06366         XMEMCPY(recip->recip + idx, issuerSKID, issuerSKIDSz);
06367         idx += issuerSKIDSz;
06368         XMEMCPY(recip->recip + idx, pkcs7->issuerSubjKeyId, KEYID_SIZE);
06369         idx += KEYID_SIZE;
06370     }
06371     XMEMCPY(recip->recip + idx, keyAlgArray, keyEncAlgSz);
06372     idx += keyEncAlgSz;
06373     XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz);
06374     idx += encKeyOctetStrSz;
06375     XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
06376     idx += encryptedKeySz;
06377 
06378     FreeDecodedCert(decoded);
06379 
06380 #ifdef WOLFSSL_SMALL_STACK
06381     XFREE(serial,       pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06382     XFREE(keyAlgArray,  pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06383     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06384     XFREE(decoded,      pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
06385 #endif
06386 
06387     /* store recipient size */
06388     recip->recipSz = idx;
06389     recip->recipType = PKCS7_KTRI;
06390 
06391     /* add recipient to recip list */
06392     if (pkcs7->recipList == NULL) {
06393         pkcs7->recipList = recip;
06394     } else {
06395         lastRecip = pkcs7->recipList;
06396         while (lastRecip->next != NULL) {
06397             lastRecip = lastRecip->next;
06398         }
06399         lastRecip->next = recip;
06400     }
06401 
06402     return idx;
06403 }
06404 
06405 #endif /* !NO_RSA */
06406 
06407 
06408 /* encrypt content using encryptOID algo */
06409 static int wc_PKCS7_EncryptContent(int encryptOID, byte* key, int keySz,
06410                                    byte* iv, int ivSz, byte* aad, word32 aadSz,
06411                                    byte* authTag, word32 authTagSz, byte* in,
06412                                    int inSz, byte* out)
06413 {
06414     int ret;
06415 #ifndef NO_AES
06416     Aes  aes;
06417 #endif
06418 #ifndef NO_DES3
06419     Des  des;
06420     Des3 des3;
06421 #endif
06422 
06423     if (key == NULL || iv == NULL || in == NULL || out == NULL)
06424         return BAD_FUNC_ARG;
06425 
06426     switch (encryptOID) {
06427 #ifndef NO_AES
06428     #ifdef WOLFSSL_AES_128
06429         case AES128CBCb:
06430     #endif
06431     #ifdef WOLFSSL_AES_192
06432         case AES192CBCb:
06433     #endif
06434     #ifdef WOLFSSL_AES_256
06435         case AES256CBCb:
06436     #endif
06437             if (
06438                 #ifdef WOLFSSL_AES_128
06439                     (encryptOID == AES128CBCb && keySz != 16 ) ||
06440                 #endif
06441                 #ifdef WOLFSSL_AES_192
06442                     (encryptOID == AES192CBCb && keySz != 24 ) ||
06443                 #endif
06444                 #ifdef WOLFSSL_AES_256
06445                     (encryptOID == AES256CBCb && keySz != 32 ) ||
06446                 #endif
06447                     (ivSz  != AES_BLOCK_SIZE) )
06448                 return BAD_FUNC_ARG;
06449 
06450             ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
06451             if (ret == 0) {
06452                 ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION);
06453                 if (ret == 0)
06454                     ret = wc_AesCbcEncrypt(&aes, out, in, inSz);
06455                 wc_AesFree(&aes);
06456             }
06457             break;
06458     #ifdef HAVE_AESGCM
06459         #ifdef WOLFSSL_AES_128
06460         case AES128GCMb:
06461         #endif
06462         #ifdef WOLFSSL_AES_192
06463         case AES192GCMb:
06464         #endif
06465         #ifdef WOLFSSL_AES_256
06466         case AES256GCMb:
06467         #endif
06468         #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
06469             defined(WOLFSSL_AES_256)
06470             if (authTag == NULL)
06471                 return BAD_FUNC_ARG;
06472 
06473             ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
06474             if (ret == 0) {
06475                 ret = wc_AesGcmSetKey(&aes, key, keySz);
06476                 if (ret == 0)
06477                     ret = wc_AesGcmEncrypt(&aes, out, in, inSz, iv, ivSz,
06478                                            authTag, authTagSz, aad, aadSz);
06479                 wc_AesFree(&aes);
06480             }
06481             break;
06482         #endif
06483     #endif /* HAVE_AESGCM */
06484     #ifdef HAVE_AESCCM
06485         #ifdef WOLFSSL_AES_128
06486         case AES128CCMb:
06487         #endif
06488         #ifdef WOLFSSL_AES_192
06489         case AES192CCMb:
06490         #endif
06491         #ifdef WOLFSSL_AES_256
06492         case AES256CCMb:
06493         #endif
06494         #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
06495             defined(WOLFSSL_AES_256)
06496             if (authTag == NULL)
06497                 return BAD_FUNC_ARG;
06498 
06499             ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
06500             if (ret == 0) {
06501                 ret = wc_AesCcmSetKey(&aes, key, keySz);
06502                 if (ret == 0)
06503                     ret = wc_AesCcmEncrypt(&aes, out, in, inSz, iv, ivSz,
06504                                            authTag, authTagSz, aad, aadSz);
06505                 wc_AesFree(&aes);
06506             }
06507             break;
06508         #endif
06509     #endif /* HAVE_AESCCM */
06510 #endif /* NO_AES */
06511 #ifndef NO_DES3
06512         case DESb:
06513             if (keySz != DES_KEYLEN || ivSz != DES_BLOCK_SIZE)
06514                 return BAD_FUNC_ARG;
06515 
06516             ret = wc_Des_SetKey(&des, key, iv, DES_ENCRYPTION);
06517             if (ret == 0)
06518                 ret = wc_Des_CbcEncrypt(&des, out, in, inSz);
06519 
06520             break;
06521 
06522         case DES3b:
06523             if (keySz != DES3_KEYLEN || ivSz != DES_BLOCK_SIZE)
06524                 return BAD_FUNC_ARG;
06525 
06526             ret = wc_Des3Init(&des3, NULL, INVALID_DEVID);
06527             if (ret == 0) {
06528                 ret = wc_Des3_SetKey(&des3, key, iv, DES_ENCRYPTION);
06529                 if (ret == 0)
06530                     ret = wc_Des3_CbcEncrypt(&des3, out, in, inSz);
06531                 wc_Des3Free(&des3);
06532             }
06533             break;
06534 #endif
06535         default:
06536             WOLFSSL_MSG("Unsupported content cipher type");
06537             return ALGO_ID_E;
06538     };
06539 
06540 #if defined(NO_AES) || (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM))
06541     (void)authTag;
06542     (void)authTagSz;
06543     (void)aad;
06544     (void)aadSz;
06545 #endif
06546     return ret;
06547 }
06548 
06549 
06550 /* decrypt content using encryptOID algo
06551  * returns 0 on success */
06552 static int wc_PKCS7_DecryptContent(PKCS7* pkcs7, int encryptOID, byte* key,
06553         int keySz, byte* iv, int ivSz, byte* aad, word32 aadSz, byte* authTag,
06554         word32 authTagSz, byte* in, int inSz, byte* out)
06555 {
06556     int ret;
06557 #ifndef NO_AES
06558     Aes  aes;
06559 #endif
06560 #ifndef NO_DES3
06561     Des  des;
06562     Des3 des3;
06563 #endif
06564 
06565     if (iv == NULL || in == NULL || out == NULL)
06566         return BAD_FUNC_ARG;
06567 
06568     if (pkcs7->decryptionCb != NULL) {
06569         return pkcs7->decryptionCb(pkcs7, encryptOID, iv, ivSz,
06570                                       aad, aadSz, authTag, authTagSz, in,
06571                                       inSz, out, pkcs7->decryptionCtx);
06572     }
06573 
06574     if (key == NULL)
06575         return BAD_FUNC_ARG;
06576 
06577     switch (encryptOID) {
06578 #ifndef NO_AES
06579     #ifdef WOLFSSL_AES_128
06580         case AES128CBCb:
06581     #endif
06582     #ifdef WOLFSSL_AES_192
06583         case AES192CBCb:
06584     #endif
06585     #ifdef WOLFSSL_AES_256
06586         case AES256CBCb:
06587     #endif
06588             if (
06589                 #ifdef WOLFSSL_AES_128
06590                     (encryptOID == AES128CBCb && keySz != 16 ) ||
06591                 #endif
06592                 #ifdef WOLFSSL_AES_192
06593                     (encryptOID == AES192CBCb && keySz != 24 ) ||
06594                 #endif
06595                 #ifdef WOLFSSL_AES_256
06596                     (encryptOID == AES256CBCb && keySz != 32 ) ||
06597                 #endif
06598                     (ivSz  != AES_BLOCK_SIZE) )
06599                 return BAD_FUNC_ARG;
06600             ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
06601             if (ret == 0) {
06602                 ret = wc_AesSetKey(&aes, key, keySz, iv, AES_DECRYPTION);
06603                 if (ret == 0)
06604                     ret = wc_AesCbcDecrypt(&aes, out, in, inSz);
06605                 wc_AesFree(&aes);
06606             }
06607             break;
06608     #ifdef HAVE_AESGCM
06609         #ifdef WOLFSSL_AES_128
06610         case AES128GCMb:
06611         #endif
06612         #ifdef WOLFSSL_AES_192
06613         case AES192GCMb:
06614         #endif
06615         #ifdef WOLFSSL_AES_256
06616         case AES256GCMb:
06617         #endif
06618         #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
06619             defined(WOLFSSL_AES_256)
06620             if (authTag == NULL)
06621                 return BAD_FUNC_ARG;
06622 
06623             ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
06624             if (ret == 0) {
06625                 ret = wc_AesGcmSetKey(&aes, key, keySz);
06626                 if (ret == 0)
06627                     ret = wc_AesGcmDecrypt(&aes, out, in, inSz, iv, ivSz,
06628                                            authTag, authTagSz, aad, aadSz);
06629                 wc_AesFree(&aes);
06630             }
06631             break;
06632         #endif
06633     #endif /* HAVE_AESGCM */
06634     #ifdef HAVE_AESCCM
06635         #ifdef WOLFSSL_AES_128
06636         case AES128CCMb:
06637         #endif
06638         #ifdef WOLFSSL_AES_192
06639         case AES192CCMb:
06640         #endif
06641         #ifdef WOLFSSL_AES_256
06642         case AES256CCMb:
06643         #endif
06644         #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
06645             defined(WOLFSSL_AES_256)
06646             if (authTag == NULL)
06647                 return BAD_FUNC_ARG;
06648 
06649             ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
06650             if (ret == 0) {
06651                 ret = wc_AesCcmSetKey(&aes, key, keySz);
06652                 if (ret == 0)
06653                     ret = wc_AesCcmDecrypt(&aes, out, in, inSz, iv, ivSz,
06654                                            authTag, authTagSz, aad, aadSz);
06655                 wc_AesFree(&aes);
06656             }
06657             break;
06658         #endif
06659     #endif /* HAVE_AESCCM */
06660 #endif /* NO_AES */
06661 #ifndef NO_DES3
06662         case DESb:
06663             if (keySz != DES_KEYLEN || ivSz != DES_BLOCK_SIZE)
06664                 return BAD_FUNC_ARG;
06665 
06666             ret = wc_Des_SetKey(&des, key, iv, DES_DECRYPTION);
06667             if (ret == 0)
06668                 ret = wc_Des_CbcDecrypt(&des, out, in, inSz);
06669 
06670             break;
06671         case DES3b:
06672             if (keySz != DES3_KEYLEN || ivSz != DES_BLOCK_SIZE)
06673                 return BAD_FUNC_ARG;
06674 
06675             ret = wc_Des3Init(&des3, NULL, INVALID_DEVID);
06676             if (ret == 0) {
06677                 ret = wc_Des3_SetKey(&des3, key, iv, DES_DECRYPTION);
06678                 if (ret == 0)
06679                     ret = wc_Des3_CbcDecrypt(&des3, out, in, inSz);
06680                 wc_Des3Free(&des3);
06681             }
06682 
06683             break;
06684 #endif
06685         default:
06686             WOLFSSL_MSG("Unsupported content cipher type");
06687             return ALGO_ID_E;
06688     };
06689 
06690 #if defined(NO_AES) || (!defined(HAVE_AESGCM) && !defined(HAVE_AESCCM))
06691     (void)authTag;
06692     (void)authTagSz;
06693     (void)aad;
06694     (void)aadSz;
06695 #endif
06696 
06697     return ret;
06698 }
06699 
06700 
06701 /* Generate random block, place in out, return 0 on success negative on error.
06702  * Used for generation of IV, nonce, etc */
06703 static int wc_PKCS7_GenerateBlock(PKCS7* pkcs7, WC_RNG* rng, byte* out,
06704                                   word32 outSz)
06705 {
06706     int ret;
06707     WC_RNG* rnd = NULL;
06708 
06709     if (out == NULL || outSz == 0)
06710         return BAD_FUNC_ARG;
06711 
06712     /* input RNG is optional, init local one if input rng is NULL */
06713     if (rng == NULL) {
06714         rnd = (WC_RNG*)XMALLOC(sizeof(WC_RNG), pkcs7->heap, DYNAMIC_TYPE_RNG);
06715         if (rnd == NULL)
06716             return MEMORY_E;
06717 
06718         ret = wc_InitRng_ex(rnd, pkcs7->heap, pkcs7->devId);
06719         if (ret != 0) {
06720             XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG);
06721             return ret;
06722         }
06723 
06724     } else {
06725         rnd = rng;
06726     }
06727 
06728     ret = wc_RNG_GenerateBlock(rnd, out, outSz);
06729 
06730     if (rng == NULL) {
06731         wc_FreeRng(rnd);
06732         XFREE(rnd, pkcs7->heap, DYNAMIC_TYPE_RNG);
06733     }
06734 
06735     return ret;
06736 }
06737 
06738 
06739 /* Set default SignerIdentifier type to be used. Is either
06740  * IssuerAndSerialNumber or SubjectKeyIdentifier. Encoding defaults to using
06741  * IssuerAndSerialNumber unless set with this function or explicitly
06742  * overridden via options when adding RecipientInfo type.
06743  *
06744  * Using the type DEGENERATE_SID skips over signer information. In degenerate
06745  * cases there are no signers.
06746  *
06747  * pkcs7 - pointer to initialized PKCS7 structure
06748  * type  - either CMS_ISSUER_AND_SERIAL_NUMBER, CMS_SKID or DEGENERATE_SID
06749  *
06750  * return 0 on success, negative upon error */
06751 int wc_PKCS7_SetSignerIdentifierType(PKCS7* pkcs7, int type)
06752 {
06753     if (pkcs7 == NULL)
06754         return BAD_FUNC_ARG;
06755 
06756     if (type != CMS_ISSUER_AND_SERIAL_NUMBER &&
06757         type != CMS_SKID &&
06758         type != DEGENERATE_SID) {
06759         return BAD_FUNC_ARG;
06760     }
06761 
06762     pkcs7->sidType = type;
06763 
06764     return 0;
06765 }
06766 
06767 
06768 /* Set custom contentType, currently supported with SignedData type
06769  *
06770  * pkcs7       - pointer to initialized PKCS7 structure
06771  * contentType - pointer to array with ASN.1 encoded OID value
06772  * sz          - length of contentType array, octets
06773  *
06774  * return 0 on success, negative upon error */
06775 int wc_PKCS7_SetContentType(PKCS7* pkcs7, byte* contentType, word32 sz)
06776 {
06777     if (pkcs7 == NULL || contentType == NULL || sz == 0)
06778         return BAD_FUNC_ARG;
06779 
06780     if (sz > MAX_OID_SZ) {
06781         WOLFSSL_MSG("input array too large, bounded by MAX_OID_SZ");
06782         return BAD_FUNC_ARG;
06783     }
06784 
06785     XMEMCPY(pkcs7->contentType, contentType, sz);
06786     pkcs7->contentTypeSz = sz;
06787 
06788     return 0;
06789 }
06790 
06791 
06792 /* return size of padded data, padded to blockSz chunks, or negative on error */
06793 int wc_PKCS7_GetPadSize(word32 inputSz, word32 blockSz)
06794 {
06795     int padSz;
06796 
06797     if (blockSz == 0)
06798         return BAD_FUNC_ARG;
06799 
06800     padSz = blockSz - (inputSz % blockSz);
06801 
06802     return padSz;
06803 }
06804 
06805 
06806 /* pad input data to blockSz chunk, place in outSz. out must be big enough
06807  * for input + pad bytes. See wc_PKCS7_GetPadSize() helper. */
06808 int wc_PKCS7_PadData(byte* in, word32 inSz, byte* out, word32 outSz,
06809                      word32 blockSz)
06810 {
06811     int i, padSz;
06812 
06813     if (in == NULL  || inSz == 0 ||
06814         out == NULL || outSz == 0)
06815         return BAD_FUNC_ARG;
06816 
06817     padSz = wc_PKCS7_GetPadSize(inSz, blockSz);
06818 
06819     if (outSz < (inSz + padSz))
06820         return BAD_FUNC_ARG;
06821 
06822     XMEMCPY(out, in, inSz);
06823 
06824     for (i = 0; i < padSz; i++) {
06825         out[inSz + i] = (byte)padSz;
06826     }
06827 
06828     return inSz + padSz;
06829 }
06830 
06831 
06832 /* Encode and add CMS EnvelopedData ORI (OtherRecipientInfo) RecipientInfo
06833  * to CMS/PKCS#7 EnvelopedData structure.
06834  *
06835  * Return 0 on success, negative upon error */
06836 int wc_PKCS7_AddRecipient_ORI(PKCS7* pkcs7, CallbackOriEncrypt oriEncryptCb,
06837                               int options)
06838 {
06839     int oriTypeLenSz, blockKeySz, ret;
06840     word32 idx, recipSeqSz;
06841 
06842     Pkcs7EncodedRecip* recip = NULL;
06843     Pkcs7EncodedRecip* lastRecip = NULL;
06844 
06845     byte recipSeq[MAX_SEQ_SZ];
06846     byte oriTypeLen[MAX_LENGTH_SZ];
06847 
06848     byte oriType[MAX_ORI_TYPE_SZ];
06849     byte oriValue[MAX_ORI_VALUE_SZ];
06850     word32 oriTypeSz = MAX_ORI_TYPE_SZ;
06851     word32 oriValueSz = MAX_ORI_VALUE_SZ;
06852 
06853     if (pkcs7 == NULL || oriEncryptCb == NULL) {
06854         return BAD_FUNC_ARG;
06855     }
06856 
06857     /* allocate memory for RecipientInfo, KEK, encrypted key */
06858     recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip),
06859                                         pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06860     if (recip == NULL)
06861         return MEMORY_E;
06862     XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
06863 
06864     /* get key size for content-encryption key based on algorithm */
06865     blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
06866     if (blockKeySz < 0) {
06867         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06868         return blockKeySz;
06869     }
06870 
06871     /* generate random content encryption key, if needed */
06872     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz);
06873     if (ret < 0) {
06874         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06875         return ret;
06876     }
06877 
06878     /* call user callback to encrypt CEK and get oriType and oriValue
06879        values back */
06880     ret = oriEncryptCb(pkcs7, pkcs7->cek, pkcs7->cekSz, oriType, &oriTypeSz,
06881                        oriValue, &oriValueSz, pkcs7->oriEncryptCtx);
06882     if (ret != 0) {
06883         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
06884         return ret;
06885     }
06886 
06887     oriTypeLenSz = SetLength(oriTypeSz, oriTypeLen);
06888 
06889     recipSeqSz = SetImplicit(ASN_SEQUENCE, 4, 1 + oriTypeLenSz + oriTypeSz +
06890                              oriValueSz, recipSeq);
06891 
06892     idx = 0;
06893     XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
06894     idx += recipSeqSz;
06895     /* oriType */
06896     recip->recip[idx] = ASN_OBJECT_ID;
06897     idx += 1;
06898     XMEMCPY(recip->recip + idx, oriTypeLen, oriTypeLenSz);
06899     idx += oriTypeLenSz;
06900     XMEMCPY(recip->recip + idx, oriType, oriTypeSz);
06901     idx += oriTypeSz;
06902     /* oriValue, input MUST already be ASN.1 encoded */
06903     XMEMCPY(recip->recip + idx, oriValue, oriValueSz);
06904     idx += oriValueSz;
06905 
06906     /* store recipient size */
06907     recip->recipSz = idx;
06908     recip->recipType = PKCS7_ORI;
06909     recip->recipVersion = 4;
06910 
06911     /* add recipient to recip list */
06912     if (pkcs7->recipList == NULL) {
06913         pkcs7->recipList = recip;
06914     } else {
06915         lastRecip = pkcs7->recipList;
06916         while (lastRecip->next != NULL) {
06917             lastRecip = lastRecip->next;
06918         }
06919         lastRecip->next = recip;
06920     }
06921 
06922     (void)options;
06923 
06924     return idx;
06925 }
06926 
06927 #if !defined(NO_PWDBASED) && !defined(NO_SHA)
06928 
06929 
06930 static int wc_PKCS7_GenerateKEK_PWRI(PKCS7* pkcs7, byte* passwd, word32 pLen,
06931                                      byte* salt, word32 saltSz, int kdfOID,
06932                                      int prfOID, int iterations, byte* out,
06933                                      word32 outSz)
06934 {
06935     int ret;
06936 
06937     if (pkcs7 == NULL || passwd == NULL || salt == NULL || out == NULL)
06938         return BAD_FUNC_ARG;
06939 
06940     switch (kdfOID) {
06941 
06942         case PBKDF2_OID:
06943 
06944             ret = wc_PBKDF2(out, passwd, pLen, salt, saltSz, iterations,
06945                             outSz, prfOID);
06946             if (ret != 0) {
06947                 return ret;
06948             }
06949 
06950             break;
06951 
06952         default:
06953             WOLFSSL_MSG("Unsupported KDF OID");
06954             return PKCS7_OID_E;
06955     }
06956 
06957     return 0;
06958 }
06959 
06960 
06961 /* RFC3211 (Section 2.3.1) key wrap algorithm (id-alg-PWRI-KEK).
06962  *
06963  * Returns output size on success, negative upon error */
06964 static int wc_PKCS7_PwriKek_KeyWrap(PKCS7* pkcs7, const byte* kek, word32 kekSz,
06965                                     const byte* cek, word32 cekSz,
06966                                     byte* out, word32 *outSz,
06967                                     const byte* iv, word32 ivSz, int algID)
06968 {
06969     WC_RNG rng;
06970     int blockSz, outLen, ret;
06971     word32 padSz;
06972     byte* lastBlock;
06973 
06974     if (kek == NULL || cek == NULL || iv == NULL || outSz == NULL)
06975         return BAD_FUNC_ARG;
06976 
06977     /* get encryption algorithm block size */
06978     blockSz = wc_PKCS7_GetOIDBlockSize(algID);
06979     if (blockSz < 0)
06980         return blockSz;
06981 
06982     /* get pad bytes needed to block boundary */
06983     padSz = blockSz - ((4 + cekSz) % blockSz);
06984     outLen = 4 + cekSz + padSz;
06985 
06986     /* must be at least two blocks long */
06987     if (outLen < 2 * blockSz)
06988         padSz += blockSz;
06989 
06990     /* if user set out to NULL, give back required length */
06991     if (out == NULL) {
06992         *outSz = outLen;
06993         return LENGTH_ONLY_E;
06994     }
06995 
06996     /* verify output buffer is large enough */
06997     if (*outSz < (word32)outLen)
06998         return BUFFER_E;
06999 
07000     out[0] = cekSz;
07001     out[1] = ~cek[0];
07002     out[2] = ~cek[1];
07003     out[3] = ~cek[2];
07004     XMEMCPY(out + 4, cek, cekSz);
07005 
07006     /* random padding of size padSz */
07007     ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
07008     if (ret != 0)
07009         return ret;
07010 
07011     ret = wc_RNG_GenerateBlock(&rng, out + 4 + cekSz, padSz);
07012 
07013     if (ret == 0) {
07014         /* encrypt, normal */
07015         ret = wc_PKCS7_EncryptContent(algID, (byte*)kek, kekSz, (byte*)iv,
07016                                       ivSz, NULL, 0, NULL, 0, out, outLen, out);
07017     }
07018 
07019     if (ret == 0) {
07020         /* encrypt again, using last ciphertext block as IV */
07021         lastBlock = out + (((outLen / blockSz) - 1) * blockSz);
07022         ret = wc_PKCS7_EncryptContent(algID, (byte*)kek, kekSz, lastBlock,
07023                                       blockSz, NULL, 0, NULL, 0, out,
07024                                       outLen, out);
07025     }
07026 
07027     if (ret == 0) {
07028         *outSz = outLen;
07029     } else {
07030         outLen = ret;
07031     }
07032 
07033     wc_FreeRng(&rng);
07034 
07035     return outLen;
07036 }
07037 
07038 
07039 /* RFC3211 (Section 2.3.2) key unwrap algorithm (id-alg-PWRI-KEK).
07040  *
07041  * Returns cek size on success, negative upon error */
07042 static int wc_PKCS7_PwriKek_KeyUnWrap(PKCS7* pkcs7, const byte* kek,
07043                                       word32 kekSz, const byte* in, word32 inSz,
07044                                       byte* out, word32 outSz, const byte* iv,
07045                                       word32 ivSz, int algID)
07046 {
07047     int blockSz, cekLen, ret;
07048     byte* tmpIv     = NULL;
07049     byte* lastBlock = NULL;
07050     byte* outTmp    = NULL;
07051 
07052     if (pkcs7 == NULL || kek == NULL || in == NULL ||
07053         out == NULL || iv == NULL) {
07054         return BAD_FUNC_ARG;
07055     }
07056 
07057     outTmp = (byte*)XMALLOC(inSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07058     if (outTmp == NULL)
07059         return MEMORY_E;
07060 
07061     /* get encryption algorithm block size */
07062     blockSz = wc_PKCS7_GetOIDBlockSize(algID);
07063     if (blockSz < 0) {
07064         XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07065         return blockSz;
07066     }
07067 
07068     /* input needs to be blockSz multiple and at least 2 * blockSz */
07069     if (((inSz % blockSz) != 0) || (inSz < (2 * (word32)blockSz))) {
07070         WOLFSSL_MSG("PWRI-KEK unwrap input must of block size and >= 2 "
07071                     "times block size");
07072         XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07073         return BAD_FUNC_ARG;
07074     }
07075 
07076     /* use block out[n-1] as IV to decrypt block out[n] */
07077     lastBlock = (byte*)in + inSz - blockSz;
07078     tmpIv = lastBlock - blockSz;
07079 
07080     /* decrypt last block */
07081     ret = wc_PKCS7_DecryptContent(pkcs7, algID, (byte*)kek, kekSz, tmpIv,
07082             blockSz, NULL, 0, NULL, 0, lastBlock, blockSz,
07083             outTmp + inSz - blockSz);
07084 
07085     if (ret == 0) {
07086         /* using last decrypted block as IV, decrypt [0 ... n-1] blocks */
07087         lastBlock = outTmp + inSz - blockSz;
07088         ret = wc_PKCS7_DecryptContent(pkcs7, algID, (byte*)kek, kekSz,
07089                 lastBlock, blockSz, NULL, 0, NULL, 0, (byte*)in, inSz - blockSz,
07090                 outTmp);
07091     }
07092 
07093     if (ret == 0) {
07094         /* decrypt using original kek and iv */
07095         ret = wc_PKCS7_DecryptContent(pkcs7, algID, (byte*)kek, kekSz,
07096                 (byte*)iv, ivSz, NULL, 0, NULL, 0, outTmp, inSz, outTmp);
07097     }
07098 
07099     if (ret != 0) {
07100         ForceZero(outTmp, inSz);
07101         XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07102         return ret;
07103     }
07104 
07105     cekLen = outTmp[0];
07106 
07107     /* verify length */
07108     if ((word32)cekLen > inSz) {
07109         ForceZero(outTmp, inSz);
07110         XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07111         return BAD_FUNC_ARG;
07112     }
07113 
07114     /* verify check bytes */
07115     if ((outTmp[1] ^ outTmp[4]) != 0xFF ||
07116         (outTmp[2] ^ outTmp[5]) != 0xFF ||
07117         (outTmp[3] ^ outTmp[6]) != 0xFF) {
07118         ForceZero(outTmp, inSz);
07119         XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07120         return BAD_FUNC_ARG;
07121     }
07122 
07123     if (outSz < (word32)cekLen) {
07124         ForceZero(outTmp, inSz);
07125         XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07126         return BUFFER_E;
07127     }
07128 
07129     XMEMCPY(out, outTmp + 4, outTmp[0]);
07130     ForceZero(outTmp, inSz);
07131     XFREE(outTmp, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07132 
07133     return cekLen;
07134 }
07135 
07136 
07137 /* Encode and add CMS EnvelopedData PWRI (PasswordRecipientInfo) RecipientInfo
07138  * to CMS/PKCS#7 EnvelopedData structure.
07139  *
07140  * Return 0 on success, negative upon error */
07141 int wc_PKCS7_AddRecipient_PWRI(PKCS7* pkcs7, byte* passwd, word32 pLen,
07142                                byte* salt, word32 saltSz, int kdfOID,
07143                                int hashOID, int iterations, int kekEncryptOID,
07144                                int options)
07145 {
07146     Pkcs7EncodedRecip* recip = NULL;
07147     Pkcs7EncodedRecip* lastRecip = NULL;
07148 
07149     /* PasswordRecipientInfo */
07150     byte recipSeq[MAX_SEQ_SZ];
07151     byte ver[MAX_VERSION_SZ];
07152     word32 recipSeqSz, verSz;
07153 
07154     /* KeyDerivationAlgorithmIdentifier */
07155     byte kdfAlgoIdSeq[MAX_SEQ_SZ];
07156     byte kdfAlgoId[MAX_OID_SZ];
07157     byte kdfParamsSeq[MAX_SEQ_SZ];              /* PBKDF2-params */
07158     byte kdfSaltOctetStr[MAX_OCTET_STR_SZ];     /* salt OCTET STRING */
07159     byte kdfIterations[MAX_VERSION_SZ];
07160     word32 kdfAlgoIdSeqSz, kdfAlgoIdSz;
07161     word32 kdfParamsSeqSz, kdfSaltOctetStrSz, kdfIterationsSz;
07162     /* OPTIONAL: keyLength, not supported yet */
07163     /* OPTIONAL: prf AlgorithIdentifier, not supported yet */
07164 
07165     /* KeyEncryptionAlgorithmIdentifier */
07166     byte keyEncAlgoIdSeq[MAX_SEQ_SZ];
07167     byte keyEncAlgoId[MAX_OID_SZ];              /* id-alg-PWRI-KEK */
07168     byte pwriEncAlgoId[MAX_ALGO_SZ];
07169     byte ivOctetString[MAX_OCTET_STR_SZ];
07170     word32 keyEncAlgoIdSeqSz, keyEncAlgoIdSz;
07171     word32 pwriEncAlgoIdSz, ivOctetStringSz;
07172 
07173     /* EncryptedKey */
07174     byte encKeyOctetStr[MAX_OCTET_STR_SZ];
07175     word32 encKeyOctetStrSz;
07176 
07177     byte tmpIv[MAX_CONTENT_IV_SIZE];
07178     byte* encryptedKey = NULL;
07179     byte* kek = NULL;
07180 
07181     int cekKeySz = 0, kekKeySz = 0, kekBlockSz = 0, ret = 0;
07182     int encryptOID;
07183     word32 idx, totalSz = 0, encryptedKeySz;
07184 
07185     if (pkcs7 == NULL || passwd == NULL || pLen == 0 ||
07186         salt == NULL || saltSz == 0) {
07187         return BAD_FUNC_ARG;
07188     }
07189 
07190     /* allow user to use different KEK encryption algorithm than used for
07191      * main content encryption algorithm, if passed in */
07192     if (kekEncryptOID != 0) {
07193         encryptOID = kekEncryptOID;
07194     } else {
07195         encryptOID = pkcs7->encryptOID;
07196     }
07197 
07198     /* get content-encryption key size, based on algorithm */
07199     cekKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
07200     if (cekKeySz < 0)
07201         return cekKeySz;
07202 
07203     /* get KEK encryption key size, based on algorithm */
07204     if (encryptOID != pkcs7->encryptOID) {
07205         kekKeySz = wc_PKCS7_GetOIDKeySize(encryptOID);
07206     } else {
07207         kekKeySz = cekKeySz;
07208     }
07209 
07210     /* get KEK encryption block size */
07211     kekBlockSz = wc_PKCS7_GetOIDBlockSize(encryptOID);
07212     if (kekBlockSz < 0)
07213         return kekBlockSz;
07214 
07215     /* generate random CEK */
07216     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, cekKeySz);
07217     if (ret < 0)
07218         return ret;
07219 
07220     /* generate random IV */
07221     ret = wc_PKCS7_GenerateBlock(pkcs7, NULL, tmpIv, kekBlockSz);
07222     if (ret != 0)
07223         return ret;
07224 
07225     /* allocate memory for RecipientInfo, KEK, encrypted key */
07226     recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip),
07227                                         pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07228     if (recip == NULL)
07229         return MEMORY_E;
07230 
07231     kek = (byte*)XMALLOC(kekKeySz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07232     if (kek == NULL) {
07233         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07234         return MEMORY_E;
07235     }
07236 
07237     encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ,
07238                                   pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07239     if (encryptedKey == NULL) {
07240         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07241         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07242         return MEMORY_E;
07243     }
07244 
07245     encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
07246     XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
07247     XMEMSET(kek, 0, kekKeySz);
07248     XMEMSET(encryptedKey, 0, encryptedKeySz);
07249 
07250     /* generate KEK: expand password into KEK */
07251     ret = wc_PKCS7_GenerateKEK_PWRI(pkcs7, passwd, pLen, salt, saltSz,
07252                                     kdfOID, hashOID, iterations, kek,
07253                                     kekKeySz);
07254     if (ret < 0) {
07255         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07256         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07257         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07258         return ret;
07259     }
07260 
07261     /* generate encrypted key: encrypt CEK with KEK */
07262     ret = wc_PKCS7_PwriKek_KeyWrap(pkcs7, kek, kekKeySz, pkcs7->cek,
07263                                    pkcs7->cekSz, encryptedKey, &encryptedKeySz,
07264                                    tmpIv, kekBlockSz, encryptOID);
07265     if (ret < 0) {
07266         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07267         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07268         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07269         return ret;
07270     }
07271     encryptedKeySz = ret;
07272 
07273     /* put together encrypted key OCTET STRING */
07274     encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr);
07275     totalSz += (encKeyOctetStrSz + encryptedKeySz);
07276 
07277     /* put together IV OCTET STRING */
07278     ivOctetStringSz = SetOctetString(kekBlockSz, ivOctetString);
07279     totalSz += (ivOctetStringSz + kekBlockSz);
07280 
07281     /* set PWRIAlgorithms AlgorithmIdentifier, adding (ivOctetStringSz +
07282        blockKeySz) for IV OCTET STRING */
07283     pwriEncAlgoIdSz = SetAlgoID(encryptOID, pwriEncAlgoId,
07284                                 oidBlkType, ivOctetStringSz + kekBlockSz);
07285     totalSz += pwriEncAlgoIdSz;
07286 
07287     /* set KeyEncryptionAlgorithms OID */
07288     ret = wc_SetContentType(PWRI_KEK_WRAP, keyEncAlgoId, sizeof(keyEncAlgoId));
07289     if (ret <= 0) {
07290         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07291         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07292         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07293         return ret;
07294     }
07295     keyEncAlgoIdSz = ret;
07296     totalSz += keyEncAlgoIdSz;
07297 
07298     /* KeyEncryptionAlgorithm SEQ */
07299     keyEncAlgoIdSeqSz = SetSequence(keyEncAlgoIdSz + pwriEncAlgoIdSz +
07300                                     ivOctetStringSz + kekBlockSz,
07301                                     keyEncAlgoIdSeq);
07302     totalSz += keyEncAlgoIdSeqSz;
07303 
07304     /* set KDF salt */
07305     kdfSaltOctetStrSz = SetOctetString(saltSz, kdfSaltOctetStr);
07306     totalSz += (kdfSaltOctetStrSz + saltSz);
07307 
07308     /* set KDF iteration count */
07309     kdfIterationsSz = SetMyVersion(iterations, kdfIterations, 0);
07310     totalSz += kdfIterationsSz;
07311 
07312     /* set KDF params SEQ */
07313     kdfParamsSeqSz = SetSequence(kdfSaltOctetStrSz + saltSz + kdfIterationsSz,
07314                                  kdfParamsSeq);
07315     totalSz += kdfParamsSeqSz;
07316 
07317     /* set KDF algo OID */
07318     ret = wc_SetContentType(kdfOID, kdfAlgoId, sizeof(kdfAlgoId));
07319     if (ret <= 0) {
07320         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07321         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07322         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07323         return ret;
07324     }
07325     kdfAlgoIdSz = ret;
07326     totalSz += kdfAlgoIdSz;
07327 
07328     /* set KeyDerivationAlgorithmIdentifier EXPLICIT [0] SEQ */
07329     kdfAlgoIdSeqSz = SetExplicit(0, kdfAlgoIdSz + kdfParamsSeqSz +
07330                                  kdfSaltOctetStrSz + saltSz + kdfIterationsSz,
07331                                  kdfAlgoIdSeq);
07332     totalSz += kdfAlgoIdSeqSz;
07333 
07334     /* set PasswordRecipientInfo CMSVersion, MUST be 0 */
07335     verSz = SetMyVersion(0, ver, 0);
07336     totalSz += verSz;
07337     recip->recipVersion = 0;
07338 
07339     /* set PasswordRecipientInfo SEQ */
07340     recipSeqSz = SetImplicit(ASN_SEQUENCE, 3, totalSz, recipSeq);
07341     totalSz += recipSeqSz;
07342 
07343     if (totalSz > MAX_RECIP_SZ) {
07344         WOLFSSL_MSG("CMS Recipient output buffer too small");
07345         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07346         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07347         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07348         return BUFFER_E;
07349     }
07350 
07351     idx = 0;
07352     XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
07353     idx += recipSeqSz;
07354     XMEMCPY(recip->recip + idx, ver, verSz);
07355     idx += verSz;
07356     XMEMCPY(recip->recip + idx, kdfAlgoIdSeq, kdfAlgoIdSeqSz);
07357     idx += kdfAlgoIdSeqSz;
07358     XMEMCPY(recip->recip + idx, kdfAlgoId, kdfAlgoIdSz);
07359     idx += kdfAlgoIdSz;
07360     XMEMCPY(recip->recip + idx, kdfParamsSeq, kdfParamsSeqSz);
07361     idx += kdfParamsSeqSz;
07362     XMEMCPY(recip->recip + idx, kdfSaltOctetStr, kdfSaltOctetStrSz);
07363     idx += kdfSaltOctetStrSz;
07364     XMEMCPY(recip->recip + idx, salt, saltSz);
07365     idx += saltSz;
07366     XMEMCPY(recip->recip + idx, kdfIterations, kdfIterationsSz);
07367     idx += kdfIterationsSz;
07368     XMEMCPY(recip->recip + idx, keyEncAlgoIdSeq, keyEncAlgoIdSeqSz);
07369     idx += keyEncAlgoIdSeqSz;
07370     XMEMCPY(recip->recip + idx, keyEncAlgoId, keyEncAlgoIdSz);
07371     idx += keyEncAlgoIdSz;
07372     XMEMCPY(recip->recip + idx, pwriEncAlgoId, pwriEncAlgoIdSz);
07373     idx += pwriEncAlgoIdSz;
07374     XMEMCPY(recip->recip + idx, ivOctetString, ivOctetStringSz);
07375     idx += ivOctetStringSz;
07376     XMEMCPY(recip->recip + idx, tmpIv, kekBlockSz);
07377     idx += kekBlockSz;
07378     XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz);
07379     idx += encKeyOctetStrSz;
07380     XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
07381     idx += encryptedKeySz;
07382 
07383     ForceZero(kek, kekBlockSz);
07384     ForceZero(encryptedKey, encryptedKeySz);
07385     XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07386     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07387 
07388     /* store recipient size */
07389     recip->recipSz = idx;
07390     recip->recipType = PKCS7_PWRI;
07391 
07392     /* add recipient to recip list */
07393     if (pkcs7->recipList == NULL) {
07394         pkcs7->recipList = recip;
07395     } else {
07396         lastRecip = pkcs7->recipList;
07397         while (lastRecip->next != NULL) {
07398             lastRecip = lastRecip->next;
07399         }
07400         lastRecip->next = recip;
07401     }
07402 
07403     (void)options;
07404 
07405     return idx;
07406 }
07407 
07408 /* Import password and KDF settings into a PKCS7 structure. Used for setting
07409  * the password info for decryption a EnvelopedData PWRI RecipientInfo.
07410  *
07411  * Returns 0 on success, negative upon error */
07412 int wc_PKCS7_SetPassword(PKCS7* pkcs7, byte* passwd, word32 pLen)
07413 {
07414     if (pkcs7 == NULL || passwd == NULL || pLen == 0)
07415         return BAD_FUNC_ARG;
07416 
07417     pkcs7->pass = passwd;
07418     pkcs7->passSz = pLen;
07419 
07420     return 0;
07421 }
07422 
07423 #endif /* NO_PWDBASED */
07424 
07425 
07426 /* Encode and add CMS EnvelopedData KEKRI (KEKRecipientInfo) RecipientInfo
07427  * to CMS/PKCS#7 EnvelopedData structure.
07428  *
07429  * pkcs7 - pointer to initialized PKCS7 structure
07430  * keyWrapOID - OID sum of key wrap algorithm identifier
07431  * kek        - key encryption key
07432  * kekSz      - size of kek, bytes
07433  * keyID      - key-encryption key identifier, pre-distributed to endpoints
07434  * keyIDSz    - size of keyID, bytes
07435  * timePtr    - pointer to "time_t", which is typically "long" (OPTIONAL)
07436  * otherOID   - ASN.1 encoded OID of other attribute (OPTIONAL)
07437  * otherOIDSz - size of otherOID, bytes (OPTIONAL)
07438  * other      - other attribute (OPTIONAL)
07439  * otherSz    - size of other (OPTIONAL)
07440  *
07441  * Returns 0 on success, negative upon error */
07442 int wc_PKCS7_AddRecipient_KEKRI(PKCS7* pkcs7, int keyWrapOID, byte* kek,
07443                                 word32 kekSz, byte* keyId, word32 keyIdSz,
07444                                 void* timePtr, byte* otherOID,
07445                                 word32 otherOIDSz, byte* other, word32 otherSz,
07446                                 int options)
07447 {
07448     Pkcs7EncodedRecip* recip = NULL;
07449     Pkcs7EncodedRecip* lastRecip = NULL;
07450 
07451     byte recipSeq[MAX_SEQ_SZ];
07452     byte ver[MAX_VERSION_SZ];
07453     byte kekIdSeq[MAX_SEQ_SZ];
07454     byte kekIdOctetStr[MAX_OCTET_STR_SZ];
07455     byte genTime[ASN_GENERALIZED_TIME_SIZE];
07456     byte otherAttSeq[MAX_SEQ_SZ];
07457     byte encAlgoId[MAX_ALGO_SZ];
07458     byte encKeyOctetStr[MAX_OCTET_STR_SZ];
07459 #ifdef WOLFSSL_SMALL_STACK
07460     byte* encryptedKey;
07461 #else
07462     byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
07463 #endif
07464 
07465     int blockKeySz = 0, ret = 0, direction;
07466     word32 idx = 0;
07467     word32 totalSz = 0;
07468     word32 recipSeqSz = 0, verSz = 0;
07469     word32 kekIdSeqSz = 0, kekIdOctetStrSz = 0;
07470     word32 otherAttSeqSz = 0, encAlgoIdSz = 0, encKeyOctetStrSz = 0;
07471     int encryptedKeySz;
07472 
07473     int timeSz = 0;
07474 #ifndef NO_ASN_TIME
07475     time_t* tm = NULL;
07476 #endif
07477 
07478     if (pkcs7 == NULL || kek == NULL || keyId == NULL)
07479         return BAD_FUNC_ARG;
07480 
07481     recip = (Pkcs7EncodedRecip*)XMALLOC(sizeof(Pkcs7EncodedRecip), pkcs7->heap,
07482                                  DYNAMIC_TYPE_PKCS7);
07483     if (recip == NULL)
07484         return MEMORY_E;
07485 
07486     XMEMSET(recip, 0, sizeof(Pkcs7EncodedRecip));
07487 
07488     /* get key size for content-encryption key based on algorithm */
07489     blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
07490     if (blockKeySz < 0) {
07491         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07492         return blockKeySz;
07493     }
07494 
07495     /* generate random content encryption key, if needed */
07496     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz);
07497     if (ret < 0) {
07498         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07499         return ret;
07500     }
07501 
07502     /* EncryptedKey */
07503 #ifdef WOLFSSL_SMALL_STACK
07504     encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
07505                                   DYNAMIC_TYPE_PKCS7);
07506     if (encryptedKey == NULL) {
07507         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07508         return MEMORY_E;
07509     }
07510 #endif
07511     encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
07512     XMEMSET(encryptedKey, 0, encryptedKeySz);
07513 
07514     #ifndef NO_AES
07515         direction = AES_ENCRYPTION;
07516     #else
07517         direction = DES_ENCRYPTION;
07518     #endif
07519 
07520     encryptedKeySz = wc_PKCS7_KeyWrap(pkcs7->cek, pkcs7->cekSz, kek, kekSz,
07521                                       encryptedKey, encryptedKeySz, keyWrapOID,
07522                                       direction);
07523     if (encryptedKeySz < 0) {
07524     #ifdef WOLFSSL_SMALL_STACK
07525         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07526     #endif
07527         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07528         return encryptedKeySz;
07529     }
07530     /* handle a zero size encKey case as WC_KEY_SIZE_E */
07531     if (encryptedKeySz == 0 || encryptedKeySz > MAX_ENCRYPTED_KEY_SZ) {
07532     #ifdef WOLFSSL_SMALL_STACK
07533         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07534     #endif
07535         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07536         return WC_KEY_SIZE_E;
07537     }
07538 
07539     encKeyOctetStrSz = SetOctetString(encryptedKeySz, encKeyOctetStr);
07540     totalSz += (encKeyOctetStrSz + encryptedKeySz);
07541 
07542     /* KeyEncryptionAlgorithmIdentifier */
07543     encAlgoIdSz = SetAlgoID(keyWrapOID, encAlgoId, oidKeyWrapType, 0);
07544     totalSz += encAlgoIdSz;
07545 
07546     /* KEKIdentifier: keyIdentifier */
07547     kekIdOctetStrSz = SetOctetString(keyIdSz, kekIdOctetStr);
07548     totalSz += (kekIdOctetStrSz + keyIdSz);
07549 
07550     /* KEKIdentifier: GeneralizedTime (OPTIONAL) */
07551 #ifndef NO_ASN_TIME
07552     if (timePtr != NULL) {
07553         tm = (time_t*)timePtr;
07554         timeSz = GetAsnTimeString(tm, genTime, sizeof(genTime));
07555         if (timeSz < 0) {
07556             XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07557         #ifdef WOLFSSL_SMALL_STACK
07558             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07559         #endif
07560             return timeSz;
07561         }
07562         totalSz += timeSz;
07563     }
07564 #endif
07565 
07566     /* KEKIdentifier: OtherKeyAttribute SEQ (OPTIONAL) */
07567     if (other != NULL && otherSz > 0) {
07568         otherAttSeqSz = SetSequence(otherOIDSz + otherSz, otherAttSeq);
07569         totalSz += otherAttSeqSz + otherOIDSz + otherSz;
07570     }
07571 
07572     /* KEKIdentifier SEQ */
07573     kekIdSeqSz = SetSequence(kekIdOctetStrSz + keyIdSz + timeSz +
07574                              otherAttSeqSz + otherOIDSz + otherSz, kekIdSeq);
07575     totalSz += kekIdSeqSz;
07576 
07577     /* version */
07578     verSz = SetMyVersion(4, ver, 0);
07579     totalSz += verSz;
07580     recip->recipVersion = 4;
07581 
07582     /* KEKRecipientInfo SEQ */
07583     recipSeqSz = SetImplicit(ASN_SEQUENCE, 2, totalSz, recipSeq);
07584     totalSz += recipSeqSz;
07585 
07586     if (totalSz > MAX_RECIP_SZ) {
07587         WOLFSSL_MSG("CMS Recipient output buffer too small");
07588         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07589     #ifdef WOLFSSL_SMALL_STACK
07590         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07591     #endif
07592         return BUFFER_E;
07593     }
07594 
07595     XMEMCPY(recip->recip + idx, recipSeq, recipSeqSz);
07596     idx += recipSeqSz;
07597     XMEMCPY(recip->recip + idx, ver, verSz);
07598     idx += verSz;
07599     XMEMCPY(recip->recip + idx, kekIdSeq, kekIdSeqSz);
07600     idx += kekIdSeqSz;
07601     XMEMCPY(recip->recip + idx, kekIdOctetStr, kekIdOctetStrSz);
07602     idx += kekIdOctetStrSz;
07603     XMEMCPY(recip->recip + idx, keyId, keyIdSz);
07604     idx += keyIdSz;
07605     if (timePtr != NULL) {
07606         XMEMCPY(recip->recip + idx, genTime, timeSz);
07607         idx += timeSz;
07608     }
07609     if (other != NULL && otherSz > 0) {
07610         XMEMCPY(recip->recip + idx, otherAttSeq, otherAttSeqSz);
07611         idx += otherAttSeqSz;
07612         XMEMCPY(recip->recip + idx, otherOID, otherOIDSz);
07613         idx += otherOIDSz;
07614         XMEMCPY(recip->recip + idx, other, otherSz);
07615         idx += otherSz;
07616     }
07617     XMEMCPY(recip->recip + idx, encAlgoId, encAlgoIdSz);
07618     idx += encAlgoIdSz;
07619     XMEMCPY(recip->recip + idx, encKeyOctetStr, encKeyOctetStrSz);
07620     idx += encKeyOctetStrSz;
07621     XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
07622     idx += encryptedKeySz;
07623 
07624 #ifdef WOLFSSL_SMALL_STACK
07625     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07626 #endif
07627 
07628     /* store recipient size */
07629     recip->recipSz = idx;
07630     recip->recipType = PKCS7_KEKRI;
07631 
07632     /* add recipient to recip list */
07633     if (pkcs7->recipList == NULL) {
07634         pkcs7->recipList = recip;
07635     } else {
07636         lastRecip = pkcs7->recipList;
07637         while(lastRecip->next != NULL) {
07638             lastRecip = lastRecip->next;
07639         }
07640         lastRecip->next = recip;
07641     }
07642 
07643     (void)options;
07644 
07645     return idx;
07646 }
07647 
07648 
07649 static int wc_PKCS7_GetCMSVersion(PKCS7* pkcs7, int cmsContentType)
07650 {
07651     int version = -1;
07652 
07653     if (pkcs7 == NULL)
07654         return BAD_FUNC_ARG;
07655 
07656     switch (cmsContentType) {
07657         case ENVELOPED_DATA:
07658 
07659             /* NOTE: EnvelopedData does not currently support
07660                originatorInfo or unprotectedAttributes. When either of these
07661                are added, version checking below needs to be updated to match
07662                Section 6.1 of RFC 5652 */
07663 
07664             /* if RecipientInfos include pwri or ori, version is 3 */
07665             if (wc_PKCS7_RecipientListIncludesType(pkcs7, PKCS7_PWRI) ||
07666                 wc_PKCS7_RecipientListIncludesType(pkcs7, PKCS7_ORI)) {
07667                 version = 3;
07668                 break;
07669             }
07670 
07671             /* if unprotectedAttrs is absent AND all RecipientInfo structs
07672                are version 0, version is 0 */
07673             if (wc_PKCS7_RecipientListVersionsAllZero(pkcs7)) {
07674                 version = 0;
07675                 break;
07676             }
07677 
07678             /* otherwise, version is 2 */
07679             version = 2;
07680             break;
07681 
07682         default:
07683             break;
07684     }
07685 
07686     return version;
07687 }
07688 
07689 
07690 /* build PKCS#7 envelopedData content type, return enveloped size */
07691 int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz)
07692 {
07693     int ret, idx = 0;
07694     int totalSz, padSz, encryptedOutSz;
07695 
07696     int contentInfoSeqSz = 0, outerContentTypeSz = 0, outerContentSz;
07697     byte contentInfoSeq[MAX_SEQ_SZ];
07698     byte outerContentType[MAX_ALGO_SZ];
07699     byte outerContent[MAX_SEQ_SZ];
07700 
07701     int kariVersion;
07702     int envDataSeqSz, verSz;
07703     byte envDataSeq[MAX_SEQ_SZ];
07704     byte ver[MAX_VERSION_SZ];
07705 
07706     WC_RNG rng;
07707     int blockSz, blockKeySz;
07708     byte* plain;
07709     byte* encryptedContent;
07710 
07711     Pkcs7EncodedRecip* tmpRecip = NULL;
07712     int recipSz, recipSetSz;
07713     byte recipSet[MAX_SET_SZ];
07714 
07715     int encContentOctetSz, encContentSeqSz, contentTypeSz;
07716     int contentEncAlgoSz, ivOctetStringSz;
07717     byte encContentSeq[MAX_SEQ_SZ];
07718     byte contentType[MAX_ALGO_SZ];
07719     byte contentEncAlgo[MAX_ALGO_SZ];
07720     byte tmpIv[MAX_CONTENT_IV_SIZE];
07721     byte ivOctetString[MAX_OCTET_STR_SZ];
07722     byte encContentOctet[MAX_OCTET_STR_SZ];
07723 
07724     if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0)
07725         return BAD_FUNC_ARG;
07726 
07727     if (output == NULL || outputSz == 0)
07728         return BAD_FUNC_ARG;
07729 
07730     blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
07731     if (blockKeySz < 0)
07732         return blockKeySz;
07733 
07734     blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID);
07735     if (blockSz < 0)
07736         return blockSz;
07737 
07738     if (pkcs7->contentOID != FIRMWARE_PKG_DATA) {
07739         /* outer content type */
07740         ret = wc_SetContentType(ENVELOPED_DATA, outerContentType,
07741                                 sizeof(outerContentType));
07742         if (ret < 0)
07743             return ret;
07744 
07745         outerContentTypeSz = ret;
07746     }
07747 
07748     /* generate random content encryption key */
07749     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz);
07750     if (ret != 0) {
07751         return ret;
07752     }
07753 
07754     /* build RecipientInfo, only if user manually set singleCert and size */
07755     if (pkcs7->singleCert != NULL && pkcs7->singleCertSz > 0) {
07756         switch (pkcs7->publicKeyOID) {
07757         #ifndef NO_RSA
07758             case RSAk:
07759                 ret = wc_PKCS7_AddRecipient_KTRI(pkcs7, pkcs7->singleCert,
07760                                                  pkcs7->singleCertSz, 0);
07761                 break;
07762         #endif
07763         #ifdef HAVE_ECC
07764             case ECDSAk:
07765                 ret = wc_PKCS7_AddRecipient_KARI(pkcs7, pkcs7->singleCert,
07766                                                  pkcs7->singleCertSz,
07767                                                  pkcs7->keyWrapOID,
07768                                                  pkcs7->keyAgreeOID, pkcs7->ukm,
07769                                                  pkcs7->ukmSz, 0);
07770                 break;
07771         #endif
07772 
07773             default:
07774                 WOLFSSL_MSG("Unsupported RecipientInfo public key type");
07775                 return BAD_FUNC_ARG;
07776         };
07777 
07778         if (ret < 0) {
07779             WOLFSSL_MSG("Failed to create RecipientInfo");
07780             return ret;
07781         }
07782     }
07783 
07784     recipSz = wc_PKCS7_GetRecipientListSize(pkcs7);
07785     if (recipSz < 0) {
07786         return ret;
07787 
07788     } else if (recipSz == 0) {
07789         WOLFSSL_MSG("You must add at least one CMS recipient");
07790         return PKCS7_RECIP_E;
07791     }
07792     recipSetSz = SetSet(recipSz, recipSet);
07793 
07794     /* version, defined in Section 6.1 of RFC 5652 */
07795     kariVersion = wc_PKCS7_GetCMSVersion(pkcs7, ENVELOPED_DATA);
07796     if (kariVersion < 0) {
07797         WOLFSSL_MSG("Failed to set CMS EnvelopedData version");
07798         return PKCS7_RECIP_E;
07799     }
07800 
07801     verSz = SetMyVersion(kariVersion, ver, 0);
07802 
07803     ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
07804     if (ret != 0)
07805         return ret;
07806 
07807     /* generate IV for block cipher */
07808     ret = wc_PKCS7_GenerateBlock(pkcs7, &rng, tmpIv, blockSz);
07809     wc_FreeRng(&rng);
07810     if (ret != 0)
07811         return ret;
07812 
07813     /* EncryptedContentInfo */
07814     ret = wc_SetContentType(pkcs7->contentOID, contentType,
07815                             sizeof(contentType));
07816     if (ret < 0)
07817         return ret;
07818 
07819     contentTypeSz = ret;
07820 
07821     /* allocate encrypted content buffer and PKCS#7 padding */
07822     padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz);
07823     if (padSz < 0)
07824         return padSz;
07825 
07826     encryptedOutSz = pkcs7->contentSz + padSz;
07827 
07828     plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07829     if (plain == NULL)
07830         return MEMORY_E;
07831 
07832     ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain,
07833                            encryptedOutSz, blockSz);
07834     if (ret < 0) {
07835         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07836         return ret;
07837     }
07838 
07839     encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap,
07840                                       DYNAMIC_TYPE_PKCS7);
07841     if (encryptedContent == NULL) {
07842         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07843         return MEMORY_E;
07844     }
07845 
07846     /* put together IV OCTET STRING */
07847     ivOctetStringSz = SetOctetString(blockSz, ivOctetString);
07848 
07849     /* build up our ContentEncryptionAlgorithmIdentifier sequence,
07850      * adding (ivOctetStringSz + blockSz) for IV OCTET STRING */
07851     contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
07852                                  oidBlkType, ivOctetStringSz + blockSz);
07853 
07854     if (contentEncAlgoSz == 0) {
07855         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07856         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07857         return BAD_FUNC_ARG;
07858     }
07859 
07860     /* encrypt content */
07861     ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->cek,
07862             pkcs7->cekSz, tmpIv, blockSz, NULL, 0, NULL, 0, plain,
07863             encryptedOutSz, encryptedContent);
07864 
07865     if (ret != 0) {
07866         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07867         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07868         return ret;
07869     }
07870 
07871     encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz,
07872                                     encContentOctet);
07873 
07874     encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz +
07875                                   ivOctetStringSz + blockSz +
07876                                   encContentOctetSz + encryptedOutSz,
07877                                   encContentSeq);
07878 
07879     /* keep track of sizes for outer wrapper layering */
07880     totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz +
07881               contentEncAlgoSz + ivOctetStringSz + blockSz +
07882               encContentOctetSz + encryptedOutSz;
07883 
07884     /* EnvelopedData */
07885     envDataSeqSz = SetSequence(totalSz, envDataSeq);
07886     totalSz += envDataSeqSz;
07887 
07888     /* outer content */
07889     outerContentSz = SetExplicit(0, totalSz, outerContent);
07890     totalSz += outerContentTypeSz;
07891     totalSz += outerContentSz;
07892 
07893     if (pkcs7->contentOID != FIRMWARE_PKG_DATA) {
07894         /* ContentInfo */
07895         contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
07896         totalSz += contentInfoSeqSz;
07897     }
07898 
07899     if (totalSz > (int)outputSz) {
07900         WOLFSSL_MSG("Pkcs7_encrypt output buffer too small");
07901         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07902         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
07903         return BUFFER_E;
07904     }
07905 
07906     if (pkcs7->contentOID != FIRMWARE_PKG_DATA) {
07907         XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
07908         idx += contentInfoSeqSz;
07909         XMEMCPY(output + idx, outerContentType, outerContentTypeSz);
07910         idx += outerContentTypeSz;
07911         XMEMCPY(output + idx, outerContent, outerContentSz);
07912         idx += outerContentSz;
07913     }
07914     XMEMCPY(output + idx, envDataSeq, envDataSeqSz);
07915     idx += envDataSeqSz;
07916     XMEMCPY(output + idx, ver, verSz);
07917     idx += verSz;
07918     XMEMCPY(output + idx, recipSet, recipSetSz);
07919     idx += recipSetSz;
07920     /* copy in recipients from list */
07921     tmpRecip = pkcs7->recipList;
07922     while (tmpRecip != NULL) {
07923         XMEMCPY(output + idx, tmpRecip->recip, tmpRecip->recipSz);
07924         idx += tmpRecip->recipSz;
07925         tmpRecip = tmpRecip->next;
07926     }
07927     wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
07928     XMEMCPY(output + idx, encContentSeq, encContentSeqSz);
07929     idx += encContentSeqSz;
07930     XMEMCPY(output + idx, contentType, contentTypeSz);
07931     idx += contentTypeSz;
07932     XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz);
07933     idx += contentEncAlgoSz;
07934     XMEMCPY(output + idx, ivOctetString, ivOctetStringSz);
07935     idx += ivOctetStringSz;
07936     XMEMCPY(output + idx, tmpIv, blockSz);
07937     idx += blockSz;
07938     XMEMCPY(output + idx, encContentOctet, encContentOctetSz);
07939     idx += encContentOctetSz;
07940     XMEMCPY(output + idx, encryptedContent, encryptedOutSz);
07941     idx += encryptedOutSz;
07942 
07943     XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07944     XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
07945 
07946     return idx;
07947 }
07948 
07949 #ifndef NO_RSA
07950 /* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */
07951 static int wc_PKCS7_DecryptKtri(PKCS7* pkcs7, byte* in, word32 inSz,
07952                                word32* idx, byte* decryptedKey,
07953                                word32* decryptedKeySz, int* recipFound)
07954 {
07955     int length, encryptedKeySz = 0, ret = 0;
07956     int keySz, version, sidType = 0;
07957     word32 encOID;
07958     word32 keyIdx;
07959     byte   issuerHash[KEYID_SIZE];
07960     byte*  outKey   = NULL;
07961     byte* pkiMsg    = in;
07962     word32 pkiMsgSz = inSz;
07963     byte   tag;
07964 
07965 
07966 #ifndef NO_PKCS7_STREAM
07967     word32 tmpIdx = *idx;
07968     long rc;
07969 #endif
07970 #ifdef WC_RSA_BLINDING
07971     WC_RNG rng;
07972 #endif
07973 
07974 #ifdef WOLFSSL_SMALL_STACK
07975     mp_int* serialNum  = NULL;
07976     byte* encryptedKey = NULL;
07977     RsaKey* privKey    = NULL;
07978 #else
07979     mp_int serialNum[1];
07980     byte encryptedKey[MAX_ENCRYPTED_KEY_SZ];
07981     RsaKey privKey[1];
07982 #endif
07983 
07984     switch (pkcs7->state) {
07985         case WC_PKCS7_DECRYPT_KTRI:
07986         #ifndef NO_PKCS7_STREAM
07987             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_VERSION_SZ,
07988                             &pkiMsg, idx)) != 0) {
07989                 return ret;
07990             }
07991 
07992             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
07993                     in, inSz);
07994             if (rc < 0) {
07995                 ret = (int)rc;
07996                 break;
07997             }
07998             pkiMsgSz = (word32)rc;
07999 
08000         #endif
08001             if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0)
08002                 return ASN_PARSE_E;
08003 
08004             if (version == 0) {
08005                 sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
08006             } else if (version == 2) {
08007                 sidType = CMS_SKID;
08008             } else {
08009                 return ASN_VERSION_E;
08010             }
08011 
08012         #ifndef NO_PKCS7_STREAM
08013             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
08014                     break;
08015             }
08016             wc_PKCS7_StreamStoreVar(pkcs7, 0, sidType, version);
08017 
08018             /* @TODO getting total amount left because of GetInt call later on
08019              * this could be optimized to stream better */
08020             pkcs7->stream->expected = (pkcs7->stream->maxLen -
08021                                 pkcs7->stream->totalRd) + pkcs7->stream->length;
08022         #endif
08023             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI_2);
08024             FALL_THROUGH;
08025 
08026         case WC_PKCS7_DECRYPT_KTRI_2:
08027         #ifndef NO_PKCS7_STREAM
08028 
08029             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, pkcs7->stream->expected,
08030                             &pkiMsg, idx)) != 0) {
08031                 return ret;
08032             }
08033 
08034             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
08035                     in, inSz);
08036             if (rc < 0) {
08037                 ret = (int)rc;
08038                 break;
08039             }
08040             pkiMsgSz = (word32)rc;
08041 
08042             wc_PKCS7_StreamGetVar(pkcs7, NULL, &sidType, &version);
08043 
08044             /* @TODO get expected size for next part, does not account for
08045              * GetInt call well */
08046             if (pkcs7->stream->expected == MAX_SEQ_SZ) {
08047                 int sz;
08048                 word32 lidx;
08049 
08050                 if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
08051                     lidx = *idx;
08052                     ret = GetSequence(pkiMsg, &lidx, &sz, pkiMsgSz);
08053                     if (ret < 0)
08054                         return ret;
08055                 }
08056                 else {
08057                     lidx = *idx + ASN_TAG_SZ;
08058                     ret = GetLength(pkiMsg, &lidx, &sz, pkiMsgSz);
08059                     if (ret < 0)
08060                         return ret;
08061                 }
08062 
08063                 pkcs7->stream->expected = sz + MAX_ALGO_SZ + ASN_TAG_SZ +
08064                                           MAX_LENGTH_SZ;
08065                 if (pkcs7->stream->length > 0 &&
08066                         pkcs7->stream->length < pkcs7->stream->expected) {
08067                     return WC_PKCS7_WANT_READ_E;
08068                 }
08069             }
08070         #endif /* !NO_PKCS7_STREAM */
08071 
08072             if (sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
08073 
08074                 /* remove IssuerAndSerialNumber */
08075                 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
08076                     return ASN_PARSE_E;
08077 
08078                 if (GetNameHash(pkiMsg, idx, issuerHash, pkiMsgSz) < 0)
08079                     return ASN_PARSE_E;
08080 
08081                 /* if we found correct recipient, issuer hashes will match */
08082                 if (XMEMCMP(issuerHash, pkcs7->issuerHash, KEYID_SIZE) == 0) {
08083                     *recipFound = 1;
08084                 }
08085 
08086         #ifdef WOLFSSL_SMALL_STACK
08087                 serialNum = (mp_int*)XMALLOC(sizeof(mp_int), pkcs7->heap,
08088                                              DYNAMIC_TYPE_TMP_BUFFER);
08089                 if (serialNum == NULL)
08090                     return MEMORY_E;
08091         #endif
08092 
08093                 if (GetInt(serialNum, pkiMsg, idx, pkiMsgSz) < 0) {
08094         #ifdef WOLFSSL_SMALL_STACK
08095                     XFREE(serialNum, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08096         #endif
08097                     return ASN_PARSE_E;
08098                 }
08099 
08100                 mp_clear(serialNum);
08101 
08102         #ifdef WOLFSSL_SMALL_STACK
08103                 XFREE(serialNum, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08104         #endif
08105 
08106             } else {
08107                 /* remove SubjectKeyIdentifier */
08108                 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08109                     return ASN_PARSE_E;
08110 
08111                 if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC))
08112                     return ASN_PARSE_E;
08113 
08114                 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08115                     return ASN_PARSE_E;
08116 
08117                 if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08118                     return ASN_PARSE_E;
08119 
08120                 if (tag != ASN_OCTET_STRING)
08121                     return ASN_PARSE_E;
08122 
08123                 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08124                     return ASN_PARSE_E;
08125 
08126                 /* if we found correct recipient, SKID will match */
08127                 if (XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId,
08128                             KEYID_SIZE) == 0) {
08129                     *recipFound = 1;
08130                 }
08131                 (*idx) += KEYID_SIZE;
08132             }
08133 
08134             if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0)
08135                 return ASN_PARSE_E;
08136 
08137             /* key encryption algorithm must be RSA for now */
08138             if (encOID != RSAk)
08139                 return ALGO_ID_E;
08140 
08141             /* read encryptedKey */
08142             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08143                 return ASN_PARSE_E;
08144 
08145             if (tag != ASN_OCTET_STRING)
08146                 return ASN_PARSE_E;
08147 
08148             if (GetLength(pkiMsg, idx, &encryptedKeySz, pkiMsgSz) < 0) {
08149                 return ASN_PARSE_E;
08150             }
08151             if (encryptedKeySz > MAX_ENCRYPTED_KEY_SZ) {
08152                return BUFFER_E;
08153             }
08154 
08155         #ifndef NO_PKCS7_STREAM
08156             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
08157                     break;
08158             }
08159             wc_PKCS7_StreamStoreVar(pkcs7, encryptedKeySz, sidType, version);
08160             pkcs7->stream->expected = encryptedKeySz;
08161         #endif
08162             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI_3);
08163             FALL_THROUGH;
08164 
08165         case WC_PKCS7_DECRYPT_KTRI_3:
08166         #ifndef NO_PKCS7_STREAM
08167             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
08168                             pkcs7->stream->expected, &pkiMsg, idx)) != 0) {
08169                 return ret;
08170             }
08171             encryptedKeySz = pkcs7->stream->expected;
08172         #endif
08173 
08174         #ifdef WOLFSSL_SMALL_STACK
08175             encryptedKey = (byte*)XMALLOC(encryptedKeySz, pkcs7->heap,
08176                                           DYNAMIC_TYPE_TMP_BUFFER);
08177             if (encryptedKey == NULL)
08178                 return MEMORY_E;
08179         #endif
08180 
08181             if (*recipFound == 1)
08182                 XMEMCPY(encryptedKey, &pkiMsg[*idx], encryptedKeySz);
08183             *idx += encryptedKeySz;
08184 
08185             /* load private key */
08186         #ifdef WOLFSSL_SMALL_STACK
08187             privKey = (RsaKey*)XMALLOC(sizeof(RsaKey), pkcs7->heap,
08188                 DYNAMIC_TYPE_TMP_BUFFER);
08189             if (privKey == NULL) {
08190                 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08191                 return MEMORY_E;
08192             }
08193         #endif
08194 
08195             ret = wc_InitRsaKey_ex(privKey, pkcs7->heap, INVALID_DEVID);
08196             if (ret != 0) {
08197         #ifdef WOLFSSL_SMALL_STACK
08198                 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08199                 XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08200         #endif
08201                 return ret;
08202             }
08203 
08204             if (pkcs7->privateKey != NULL && pkcs7->privateKeySz > 0) {
08205                 keyIdx = 0;
08206                 ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &keyIdx,
08207                         privKey, pkcs7->privateKeySz);
08208             }
08209             else if (pkcs7->devId == INVALID_DEVID) {
08210                 ret = BAD_FUNC_ARG;
08211             }
08212             if (ret != 0) {
08213                 WOLFSSL_MSG("Failed to decode RSA private key");
08214                 wc_FreeRsaKey(privKey);
08215         #ifdef WOLFSSL_SMALL_STACK
08216                 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08217                 XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08218         #endif
08219                 return ret;
08220             }
08221 
08222             /* decrypt encryptedKey */
08223             #ifdef WC_RSA_BLINDING
08224             ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
08225             if (ret == 0) {
08226                 ret = wc_RsaSetRNG(privKey, &rng);
08227             }
08228             #endif
08229             if (ret == 0) {
08230                 keySz = wc_RsaPrivateDecryptInline(encryptedKey, encryptedKeySz,
08231                                                    &outKey, privKey);
08232                 #ifdef WC_RSA_BLINDING
08233                     wc_FreeRng(&rng);
08234                 #endif
08235             } else {
08236                 keySz = ret;
08237             }
08238             wc_FreeRsaKey(privKey);
08239 
08240             if (keySz <= 0 || outKey == NULL) {
08241                 ForceZero(encryptedKey, encryptedKeySz);
08242         #ifdef WOLFSSL_SMALL_STACK
08243                 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08244                 XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08245         #endif
08246                 return keySz;
08247             } else {
08248                 *decryptedKeySz = keySz;
08249                 XMEMCPY(decryptedKey, outKey, keySz);
08250                 ForceZero(encryptedKey, encryptedKeySz);
08251             }
08252 
08253         #ifdef WOLFSSL_SMALL_STACK
08254             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08255             XFREE(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08256         #endif
08257 
08258         #ifndef NO_PKCS7_STREAM
08259             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
08260                 break;
08261             }
08262         #endif
08263             ret = 0; /* success */
08264             break;
08265 
08266         default:
08267             WOLFSSL_MSG("PKCS7 Unknown KTRI decrypt state");
08268             ret = BAD_FUNC_ARG;
08269     }
08270 
08271     return ret;
08272 }
08273 #endif /* !NO_RSA */
08274 
08275 #ifdef HAVE_ECC
08276 
08277 /* remove ASN.1 OriginatorIdentifierOrKey, return 0 on success, <0 on error */
08278 static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari,
08279                         byte* pkiMsg, word32 pkiMsgSz, word32* idx)
08280 {
08281     int ret, length;
08282     word32 keyOID, oidSum = 0;
08283     int curve_id = ECC_CURVE_DEF;
08284     byte tag;
08285 
08286     if (kari == NULL || pkiMsg == NULL || idx == NULL)
08287         return BAD_FUNC_ARG;
08288 
08289     /* remove OriginatorIdentifierOrKey */
08290     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) == 0 &&
08291             tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
08292         if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08293             return ASN_PARSE_E;
08294 
08295     } else {
08296         return ASN_PARSE_E;
08297     }
08298 
08299     /* remove OriginatorPublicKey */
08300     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) == 0 &&
08301             tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
08302         if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08303             return ASN_PARSE_E;
08304 
08305     } else {
08306         return ASN_PARSE_E;
08307     }
08308 
08309     /* remove AlgorithmIdentifier */
08310     if (GetAlgoId(pkiMsg, idx, &keyOID, oidKeyType, pkiMsgSz) < 0)
08311         return ASN_PARSE_E;
08312 
08313     if (keyOID != ECDSAk)
08314         return ASN_PARSE_E;
08315 
08316     /* optional algorithm parameters */
08317     ret = GetObjectId(pkiMsg, idx, &oidSum, oidIgnoreType, pkiMsgSz);
08318     if (ret == 0) {
08319         /* get curve id */
08320         curve_id = wc_ecc_get_oid(oidSum, NULL, 0);
08321         if (curve_id < 0)
08322             return ECC_CURVE_OID_E;
08323     }
08324 
08325     /* remove ECPoint BIT STRING */
08326     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08327         return ASN_PARSE_E;
08328 
08329     if (tag != ASN_BIT_STRING)
08330         return ASN_PARSE_E;
08331 
08332     if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08333         return ASN_PARSE_E;
08334 
08335     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08336         return ASN_EXPECT_0_E;
08337 
08338     if (tag != ASN_OTHER_TYPE)
08339         return ASN_EXPECT_0_E;
08340 
08341     /* get sender ephemeral public ECDSA key */
08342     ret = wc_ecc_init_ex(kari->senderKey, kari->heap, kari->devId);
08343     if (ret != 0)
08344         return ret;
08345 
08346     kari->senderKeyInit = 1;
08347 
08348     /* length-1 for unused bits counter */
08349     ret = wc_ecc_import_x963_ex(pkiMsg + (*idx), length - 1, kari->senderKey,
08350             curve_id);
08351     if (ret != 0) {
08352         ret = wc_EccPublicKeyDecode(pkiMsg, idx, kari->senderKey, *idx + length - 1);
08353         if (ret != 0)
08354             return ret;
08355     }
08356     else {
08357         (*idx) += length - 1;
08358     }
08359 
08360     return 0;
08361 }
08362 
08363 
08364 /* remove optional UserKeyingMaterial if available, return 0 on success,
08365  * < 0 on error */
08366 static int wc_PKCS7_KariGetUserKeyingMaterial(WC_PKCS7_KARI* kari,
08367                         byte* pkiMsg, word32 pkiMsgSz, word32* idx)
08368 {
08369     int length;
08370     word32 savedIdx;
08371     byte tag;
08372 
08373     if (kari == NULL || pkiMsg == NULL || idx == NULL)
08374         return BAD_FUNC_ARG;
08375 
08376     savedIdx = *idx;
08377 
08378     /* starts with EXPLICIT [1] */
08379     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
08380         *idx = savedIdx;
08381         return 0;
08382     }
08383     if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
08384         *idx = savedIdx;
08385         return 0;
08386     }
08387 
08388     if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
08389         *idx = savedIdx;
08390         return 0;
08391     }
08392 
08393     /* get OCTET STRING */
08394     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
08395         *idx = savedIdx;
08396         return 0;
08397     }
08398     if (tag != ASN_OCTET_STRING) {
08399         *idx = savedIdx;
08400         return 0;
08401     }
08402 
08403     if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
08404         *idx = savedIdx;
08405         return 0;
08406     }
08407 
08408     kari->ukm = NULL;
08409     if (length > 0) {
08410         kari->ukm = (byte*)XMALLOC(length, kari->heap, DYNAMIC_TYPE_PKCS7);
08411         if (kari->ukm == NULL)
08412             return MEMORY_E;
08413 
08414         XMEMCPY(kari->ukm, pkiMsg + (*idx), length);
08415         kari->ukmOwner = 1;
08416     }
08417 
08418     (*idx) += length;
08419     kari->ukmSz = length;
08420 
08421     return 0;
08422 }
08423 
08424 
08425 /* remove ASN.1 KeyEncryptionAlgorithmIdentifier, return 0 on success,
08426  * < 0 on error */
08427 static int wc_PKCS7_KariGetKeyEncryptionAlgorithmId(WC_PKCS7_KARI* kari,
08428         byte* pkiMsg, word32 pkiMsgSz, word32* idx,
08429         word32* keyAgreeOID, word32* keyWrapOID)
08430 {
08431     int length = 0;
08432     word32 localIdx;
08433 
08434     if (kari == NULL || pkiMsg == NULL || idx == NULL ||
08435         keyAgreeOID == NULL || keyWrapOID == NULL)
08436         return BAD_FUNC_ARG;
08437 
08438     localIdx = *idx;
08439 
08440     /* remove KeyEncryptionAlgorithmIdentifier */
08441     if (GetSequence(pkiMsg, &localIdx, &length, pkiMsgSz) < 0)
08442         return ASN_PARSE_E;
08443 
08444     localIdx = *idx;
08445     if (GetAlgoId(pkiMsg, &localIdx, keyAgreeOID, oidCmsKeyAgreeType,
08446               pkiMsgSz) < 0) {
08447         return ASN_PARSE_E;
08448     }
08449 
08450     if (localIdx < *idx + length) {
08451         *idx = localIdx;
08452     }
08453     /* remove KeyWrapAlgorithm, stored in parameter of KeyEncAlgoId */
08454     if (GetAlgoId(pkiMsg, idx, keyWrapOID, oidKeyWrapType, pkiMsgSz) < 0)
08455         return ASN_PARSE_E;
08456 
08457     return 0;
08458 }
08459 
08460 
08461 /* remove ASN.1 SubjectKeyIdentifier, return 0 on success, < 0 on error
08462  * if subject key ID matches, recipFound is set to 1 */
08463 static int wc_PKCS7_KariGetSubjectKeyIdentifier(WC_PKCS7_KARI* kari,
08464                         byte* pkiMsg, word32 pkiMsgSz, word32* idx,
08465                         int* recipFound, byte* rid)
08466 {
08467     int length;
08468     byte tag;
08469 
08470     if (kari == NULL || pkiMsg == NULL || idx == NULL || recipFound == NULL ||
08471             rid == NULL)
08472         return BAD_FUNC_ARG;
08473 
08474     /* remove RecipientKeyIdentifier IMPLICIT [0] */
08475     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
08476         return ASN_PARSE_E;
08477     }
08478 
08479     if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
08480         if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08481             return ASN_PARSE_E;
08482 
08483     } else {
08484         return ASN_PARSE_E;
08485     }
08486 
08487     /* remove SubjectKeyIdentifier */
08488     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
08489         return ASN_PARSE_E;
08490     }
08491 
08492     if (tag != ASN_OCTET_STRING)
08493         return ASN_PARSE_E;
08494 
08495     if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08496         return ASN_PARSE_E;
08497 
08498     if (length != KEYID_SIZE)
08499         return ASN_PARSE_E;
08500 
08501     XMEMCPY(rid, pkiMsg + (*idx), KEYID_SIZE);
08502     (*idx) += length;
08503 
08504     /* subject key id should match if recipient found */
08505     if (XMEMCMP(rid, kari->decoded->extSubjKeyId, KEYID_SIZE) == 0) {
08506         *recipFound = 1;
08507     }
08508 
08509     return 0;
08510 }
08511 
08512 
08513 /* remove ASN.1 IssuerAndSerialNumber, return 0 on success, < 0 on error
08514  * if issuer and serial number match, recipFound is set to 1 */
08515 static int wc_PKCS7_KariGetIssuerAndSerialNumber(WC_PKCS7_KARI* kari,
08516                         byte* pkiMsg, word32 pkiMsgSz, word32* idx,
08517                         int* recipFound, byte* rid)
08518 {
08519     int length, ret;
08520 #ifdef WOLFSSL_SMALL_STACK
08521     mp_int* serial;
08522     mp_int* recipSerial;
08523 #else
08524     mp_int  serial[1];
08525     mp_int  recipSerial[1];
08526 #endif
08527 
08528     if (rid == NULL) {
08529         return BAD_FUNC_ARG;
08530     }
08531 
08532     /* remove IssuerAndSerialNumber */
08533     if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
08534         return ASN_PARSE_E;
08535 
08536     if (GetNameHash(pkiMsg, idx, rid, pkiMsgSz) < 0)
08537         return ASN_PARSE_E;
08538 
08539     /* if we found correct recipient, issuer hashes will match */
08540     if (XMEMCMP(rid, kari->decoded->issuerHash, KEYID_SIZE) == 0) {
08541         *recipFound = 1;
08542     }
08543 
08544 #ifdef WOLFSSL_SMALL_STACK
08545     serial = (mp_int*)XMALLOC(sizeof(mp_int), kari->heap,
08546                               DYNAMIC_TYPE_TMP_BUFFER);
08547     if (serial == NULL)
08548         return MEMORY_E;
08549 
08550     recipSerial = (mp_int*)XMALLOC(sizeof(mp_int), kari->heap,
08551                                    DYNAMIC_TYPE_TMP_BUFFER);
08552     if (recipSerial == NULL) {
08553         XFREE(serial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08554         return MEMORY_E;
08555     }
08556 #endif
08557 
08558     if (GetInt(serial, pkiMsg, idx, pkiMsgSz) < 0) {
08559 #ifdef WOLFSSL_SMALL_STACK
08560         XFREE(serial,      kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08561         XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08562 #endif
08563         return ASN_PARSE_E;
08564     }
08565 
08566     ret = mp_read_unsigned_bin(recipSerial, kari->decoded->serial,
08567                              kari->decoded->serialSz);
08568     if (ret != MP_OKAY) {
08569         mp_clear(serial);
08570         WOLFSSL_MSG("Failed to parse CMS recipient serial number");
08571 #ifdef WOLFSSL_SMALL_STACK
08572         XFREE(serial,      kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08573         XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08574 #endif
08575         return ret;
08576     }
08577 
08578     if (mp_cmp(recipSerial, serial) != MP_EQ) {
08579         mp_clear(serial);
08580         mp_clear(recipSerial);
08581         WOLFSSL_MSG("CMS serial number does not match recipient");
08582 #ifdef WOLFSSL_SMALL_STACK
08583         XFREE(serial,      kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08584         XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08585 #endif
08586         return PKCS7_RECIP_E;
08587     }
08588 
08589     mp_clear(serial);
08590     mp_clear(recipSerial);
08591 
08592 #ifdef WOLFSSL_SMALL_STACK
08593     XFREE(serial,      kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08594     XFREE(recipSerial, kari->heap, DYNAMIC_TYPE_TMP_BUFFER);
08595 #endif
08596 
08597     return 0;
08598 }
08599 
08600 
08601 /* remove ASN.1 RecipientEncryptedKeys, return 0 on success, < 0 on error */
08602 static int wc_PKCS7_KariGetRecipientEncryptedKeys(WC_PKCS7_KARI* kari,
08603                         byte* pkiMsg, word32 pkiMsgSz, word32* idx,
08604                         int* recipFound, byte* encryptedKey,
08605                         int* encryptedKeySz, byte* rid)
08606 {
08607     int length;
08608     int ret = 0;
08609     byte tag;
08610     word32 localIdx;
08611 
08612     if (kari == NULL || pkiMsg == NULL || idx == NULL ||
08613         recipFound == NULL || encryptedKey == NULL)
08614         return BAD_FUNC_ARG;
08615 
08616     /* remove RecipientEncryptedKeys */
08617     if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
08618         return ASN_PARSE_E;
08619 
08620     /* remove RecipientEncryptedKeys */
08621     if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
08622         return ASN_PARSE_E;
08623 
08624     /* KeyAgreeRecipientIdentifier is CHOICE of IssuerAndSerialNumber
08625      * or [0] IMMPLICIT RecipientKeyIdentifier */
08626     localIdx = *idx;
08627     if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) < 0)
08628         return ASN_PARSE_E;
08629 
08630     if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) {
08631         /* try to get RecipientKeyIdentifier */
08632         ret = wc_PKCS7_KariGetSubjectKeyIdentifier(kari, pkiMsg, pkiMsgSz,
08633                                                    idx, recipFound, rid);
08634     } else {
08635         /* try to get IssuerAndSerialNumber */
08636         ret = wc_PKCS7_KariGetIssuerAndSerialNumber(kari, pkiMsg, pkiMsgSz,
08637                                                     idx, recipFound, rid);
08638     }
08639 
08640     /* if we don't have either option, malformed CMS */
08641     if (ret != 0)
08642         return ret;
08643 
08644     /* remove EncryptedKey */
08645     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08646         return ASN_PARSE_E;
08647 
08648     if (tag != ASN_OCTET_STRING)
08649         return ASN_PARSE_E;
08650 
08651     if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08652         return ASN_PARSE_E;
08653 
08654     /* put encrypted CEK in decryptedKey buffer for now, decrypt later */
08655     if (length > *encryptedKeySz)
08656         return BUFFER_E;
08657 
08658     XMEMCPY(encryptedKey, pkiMsg + (*idx), length);
08659     *encryptedKeySz = length;
08660     (*idx) += length;
08661 
08662     return 0;
08663 }
08664 
08665 #endif /* HAVE_ECC */
08666 
08667 
08668 int wc_PKCS7_SetOriEncryptCtx(PKCS7* pkcs7, void* ctx)
08669 {
08670     if (pkcs7 == NULL)
08671         return BAD_FUNC_ARG;
08672 
08673     pkcs7->oriEncryptCtx = ctx;
08674 
08675     return 0;
08676 }
08677 
08678 
08679 int wc_PKCS7_SetOriDecryptCtx(PKCS7* pkcs7, void* ctx)
08680 {
08681 
08682     if (pkcs7 == NULL)
08683         return BAD_FUNC_ARG;
08684 
08685     pkcs7->oriDecryptCtx = ctx;
08686 
08687     return 0;
08688 }
08689 
08690 
08691 int wc_PKCS7_SetOriDecryptCb(PKCS7* pkcs7, CallbackOriDecrypt cb)
08692 {
08693     if (pkcs7 == NULL)
08694         return BAD_FUNC_ARG;
08695 
08696     pkcs7->oriDecryptCb = cb;
08697 
08698     return 0;
08699 }
08700 
08701 
08702 /* return 0 on success */
08703 int wc_PKCS7_SetWrapCEKCb(PKCS7* pkcs7, CallbackWrapCEK cb)
08704 {
08705     if (pkcs7 == NULL)
08706         return BAD_FUNC_ARG;
08707 
08708     pkcs7->wrapCEKCb = cb;
08709 
08710     return 0;
08711 }
08712 
08713 /* Decrypt ASN.1 OtherRecipientInfo (ori), as defined by:
08714  *
08715  *   OtherRecipientInfo ::= SEQUENCE {
08716  *     oriType OBJECT IDENTIFIER,
08717  *     oriValue ANY DEFINED BY oriType }
08718  *
08719  * pkcs7          - pointer to initialized PKCS7 structure
08720  * pkiMsg         - pointer to encoded CMS bundle
08721  * pkiMsgSz       - size of pkiMsg, bytes
08722  * idx            - [IN/OUT] pointer to index into pkiMsg
08723  * decryptedKey   - [OUT] output buf for decrypted content encryption key
08724  * decryptedKeySz - [IN/OUT] size of buffer, size of decrypted key
08725  * recipFound     - [OUT] 1 if recipient has been found, 0 if not
08726  *
08727  * Return 0 on success, negative upon error.
08728  */
08729 static int wc_PKCS7_DecryptOri(PKCS7* pkcs7, byte* in, word32 inSz,
08730                                word32* idx, byte* decryptedKey,
08731                                word32* decryptedKeySz, int* recipFound)
08732 {
08733     int ret, seqSz, oriOIDSz;
08734     word32 oriValueSz, tmpIdx;
08735     byte* oriValue;
08736     byte oriOID[MAX_OID_SZ];
08737 
08738     byte* pkiMsg    = in;
08739     word32 pkiMsgSz = inSz;
08740 #ifndef NO_PKCS7_STREAM
08741     word32 stateIdx = *idx;
08742     long rc;
08743 #endif
08744 
08745     if (pkcs7->oriDecryptCb == NULL) {
08746         WOLFSSL_MSG("You must register an ORI Decrypt callback");
08747         return BAD_FUNC_ARG;
08748     }
08749 
08750     switch (pkcs7->state) {
08751 
08752         case WC_PKCS7_DECRYPT_ORI:
08753         #ifndef NO_PKCS7_STREAM
08754             /* @TODO for now just get full buffer, needs divided up */
08755             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
08756                    (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
08757                    pkcs7->stream->length, &pkiMsg, idx)) != 0) {
08758                 return ret;
08759             }
08760 
08761             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
08762                 inSz);
08763             if (rc < 0) {
08764                 ret = (int)rc;
08765                 break;
08766             }
08767             pkiMsgSz = (word32)rc;
08768         #endif
08769             /* get OtherRecipientInfo sequence length */
08770             if (GetLength(pkiMsg, idx, &seqSz, pkiMsgSz) < 0)
08771                 return ASN_PARSE_E;
08772 
08773             tmpIdx = *idx;
08774 
08775             /* remove and store oriType OBJECT IDENTIFIER */
08776             if (GetASNObjectId(pkiMsg, idx, &oriOIDSz, pkiMsgSz) != 0)
08777                 return ASN_PARSE_E;
08778 
08779             XMEMCPY(oriOID, pkiMsg + *idx, oriOIDSz);
08780             *idx += oriOIDSz;
08781 
08782             /* get oriValue, increment idx */
08783             oriValue = pkiMsg + *idx;
08784             oriValueSz = seqSz - (*idx - tmpIdx);
08785             *idx += oriValueSz;
08786 
08787             /* pass oriOID and oriValue to user callback, expect back
08788                decryptedKey and size */
08789             ret = pkcs7->oriDecryptCb(pkcs7, oriOID, (word32)oriOIDSz, oriValue,
08790                                       oriValueSz, decryptedKey, decryptedKeySz,
08791                                       pkcs7->oriDecryptCtx);
08792 
08793             if (ret != 0 || decryptedKey == NULL || *decryptedKeySz == 0) {
08794                 /* decrypt operation failed */
08795                 *recipFound = 0;
08796                 return PKCS7_RECIP_E;
08797             }
08798 
08799             /* mark recipFound, since we only support one RecipientInfo for now */
08800             *recipFound = 1;
08801 
08802         #ifndef NO_PKCS7_STREAM
08803             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &stateIdx, idx)) != 0) {
08804                 break;
08805             }
08806         #endif
08807             ret = 0; /* success */
08808             break;
08809 
08810         default:
08811             WOLFSSL_MSG("PKCS7 ORI unknown state");
08812             ret = BAD_FUNC_ARG;
08813 
08814     }
08815 
08816     return ret;
08817 }
08818 
08819 #if !defined(NO_PWDBASED) && !defined(NO_SHA)
08820 
08821 /* decode ASN.1 PasswordRecipientInfo (pwri), return 0 on success,
08822  * < 0 on error */
08823 static int wc_PKCS7_DecryptPwri(PKCS7* pkcs7, byte* in, word32 inSz,
08824                                word32* idx, byte* decryptedKey,
08825                                word32* decryptedKeySz, int* recipFound)
08826 {
08827     byte* salt;
08828     byte* cek;
08829     byte* kek;
08830 
08831     byte tmpIv[MAX_CONTENT_IV_SIZE];
08832 
08833     int ret = 0, length, saltSz, iterations, blockSz, kekKeySz;
08834     int hashOID = WC_SHA; /* default to SHA1 */
08835     word32 kdfAlgoId, pwriEncAlgoId, keyEncAlgoId, cekSz;
08836     byte* pkiMsg = in;
08837     word32 pkiMsgSz = inSz;
08838     byte  tag;
08839 #ifndef NO_PKCS7_STREAM
08840     word32 tmpIdx = *idx;
08841     long rc;
08842 #endif
08843 
08844     switch (pkcs7->state) {
08845         case WC_PKCS7_DECRYPT_PWRI:
08846         #ifndef NO_PKCS7_STREAM
08847             /*@TODO for now just get full buffer, needs divided up */
08848             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
08849                    (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
08850                    pkcs7->stream->length, &pkiMsg, idx)) != 0) {
08851                 return ret;
08852             }
08853 
08854             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
08855                     inSz);
08856             if (rc < 0) {
08857                 ret = (int)rc;
08858                 break;
08859             }
08860             pkiMsgSz = (word32)rc;
08861         #endif
08862             /* remove KeyDerivationAlgorithmIdentifier */
08863             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08864                 return ASN_PARSE_E;
08865 
08866             if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
08867                 return ASN_PARSE_E;
08868 
08869             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
08870                 return ASN_PARSE_E;
08871 
08872             /* get KeyDerivationAlgorithmIdentifier */
08873             if (wc_GetContentType(pkiMsg, idx, &kdfAlgoId, pkiMsgSz) < 0)
08874                 return ASN_PARSE_E;
08875 
08876             /* get KDF params SEQ */
08877             if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
08878                 return ASN_PARSE_E;
08879 
08880             /* get KDF salt OCTET STRING */
08881             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
08882                 return ASN_PARSE_E;
08883 
08884             if (tag != ASN_OCTET_STRING)
08885                 return ASN_PARSE_E;
08886 
08887             if (GetLength(pkiMsg, idx, &saltSz, pkiMsgSz) < 0)
08888                 return ASN_PARSE_E;
08889 
08890             salt = (byte*)XMALLOC(saltSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08891             if (salt == NULL)
08892                 return MEMORY_E;
08893 
08894             XMEMCPY(salt, pkiMsg + (*idx), saltSz);
08895             *idx += saltSz;
08896 
08897             /* get KDF iterations */
08898             if (GetMyVersion(pkiMsg, idx, &iterations, pkiMsgSz) < 0) {
08899                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08900                 return ASN_PARSE_E;
08901             }
08902 
08903             /* get KeyEncAlgoId SEQ */
08904             if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) {
08905                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08906                 return ASN_PARSE_E;
08907             }
08908 
08909             /* get KeyEncAlgoId */
08910             if (wc_GetContentType(pkiMsg, idx, &keyEncAlgoId, pkiMsgSz) < 0) {
08911                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08912                 return ASN_PARSE_E;
08913             }
08914 
08915             /* get pwriEncAlgoId */
08916             if (GetAlgoId(pkiMsg, idx, &pwriEncAlgoId, oidBlkType, pkiMsgSz) < 0) {
08917                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08918                 return ASN_PARSE_E;
08919             }
08920 
08921             blockSz = wc_PKCS7_GetOIDBlockSize(pwriEncAlgoId);
08922             if (blockSz < 0) {
08923                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08924                 return blockSz;
08925             }
08926 
08927             /* get content-encryption key size, based on algorithm */
08928             kekKeySz = wc_PKCS7_GetOIDKeySize(pwriEncAlgoId);
08929             if (kekKeySz < 0) {
08930                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08931                 return kekKeySz;
08932             }
08933 
08934             /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
08935             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
08936                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08937                 return ASN_PARSE_E;
08938             }
08939 
08940             if (tag != ASN_OCTET_STRING) {
08941                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08942                 return ASN_PARSE_E;
08943             }
08944 
08945             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
08946                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08947                 return ASN_PARSE_E;
08948             }
08949 
08950             if (length != blockSz) {
08951                 WOLFSSL_MSG("Incorrect IV length, must be of content alg block size");
08952                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08953                 return ASN_PARSE_E;
08954             }
08955 
08956             XMEMCPY(tmpIv, pkiMsg + (*idx), length);
08957             *idx += length;
08958 
08959             /* get EncryptedKey */
08960             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0) {
08961                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08962                 return ASN_PARSE_E;
08963             }
08964 
08965             if (tag != ASN_OCTET_STRING) {
08966                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08967                 return ASN_PARSE_E;
08968             }
08969 
08970             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) {
08971                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08972                 return ASN_PARSE_E;
08973             }
08974 
08975             /* allocate temporary space for decrypted key */
08976             cekSz = length;
08977             cek = (byte*)XMALLOC(cekSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
08978             if (cek == NULL) {
08979                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08980                 return MEMORY_E;
08981             }
08982 
08983             /* generate KEK */
08984             kek = (byte*)XMALLOC(kekKeySz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08985             if (kek == NULL) {
08986                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08987                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08988                 return MEMORY_E;
08989             }
08990 
08991             ret = wc_PKCS7_GenerateKEK_PWRI(pkcs7, pkcs7->pass, pkcs7->passSz,
08992                                             salt, saltSz, kdfAlgoId, hashOID,
08993                                             iterations, kek, kekKeySz);
08994             if (ret < 0) {
08995                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08996                 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08997                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
08998                 return ASN_PARSE_E;
08999             }
09000 
09001             /* decrypt CEK with KEK */
09002             ret = wc_PKCS7_PwriKek_KeyUnWrap(pkcs7, kek, kekKeySz,
09003                                              pkiMsg + (*idx), length, cek,
09004                                              cekSz, tmpIv, blockSz,
09005                                              pwriEncAlgoId);
09006             if (ret < 0) {
09007                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09008                 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09009                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09010                 return ret;
09011             }
09012             cekSz = ret;
09013 
09014             if (*decryptedKeySz < cekSz) {
09015                 WOLFSSL_MSG("Decrypted key buffer too small for CEK");
09016                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09017                 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09018                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09019                 return BUFFER_E;
09020             }
09021 
09022             XMEMCPY(decryptedKey, cek, cekSz);
09023             *decryptedKeySz = cekSz;
09024 
09025             XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09026             XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09027             XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09028 
09029             /* mark recipFound, since we only support one RecipientInfo for now */
09030             *recipFound = 1;
09031             *idx += length;
09032         #ifndef NO_PKCS7_STREAM
09033             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09034                 break;
09035             }
09036         #endif
09037             ret = 0; /* success */
09038             break;
09039 
09040         default:
09041             WOLFSSL_MSG("PKCS7 PWRI unknown state");
09042             ret = BAD_FUNC_ARG;
09043     }
09044 
09045     return ret;
09046 }
09047 
09048 #endif /* NO_PWDBASED | NO_SHA */
09049 
09050 /* decode ASN.1 KEKRecipientInfo (kekri), return 0 on success,
09051  * < 0 on error */
09052 static int wc_PKCS7_DecryptKekri(PKCS7* pkcs7, byte* in, word32 inSz,
09053                                word32* idx, byte* decryptedKey,
09054                                word32* decryptedKeySz, int* recipFound)
09055 {
09056     int length, keySz, dateLen, direction;
09057     byte* keyId = NULL;
09058     const byte* datePtr = NULL;
09059     byte  dateFormat, tag;
09060     word32 keyIdSz, kekIdSz, keyWrapOID, localIdx;
09061 
09062     int ret = 0;
09063     byte* pkiMsg    = in;
09064     word32 pkiMsgSz = inSz;
09065 #ifndef NO_PKCS7_STREAM
09066     word32 tmpIdx = *idx;
09067     long rc;
09068 #endif
09069 
09070     WOLFSSL_ENTER("wc_PKCS7_DecryptKekri");
09071     switch (pkcs7->state) {
09072         case WC_PKCS7_DECRYPT_KEKRI:
09073         #ifndef NO_PKCS7_STREAM
09074             /* @TODO for now just get full buffer, needs divided up */
09075             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
09076                    (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
09077                    pkcs7->stream->length, &pkiMsg, idx)) != 0) {
09078                 return ret;
09079             }
09080 
09081             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
09082                     inSz);
09083             if (rc < 0) {
09084                 ret = (int)rc;
09085                 break;
09086             }
09087             pkiMsgSz = (word32)rc;
09088         #endif
09089             /* remove KEKIdentifier */
09090             if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
09091                 return ASN_PARSE_E;
09092 
09093             kekIdSz = length;
09094 
09095             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
09096                 return ASN_PARSE_E;
09097 
09098             if (tag != ASN_OCTET_STRING)
09099                 return ASN_PARSE_E;
09100 
09101             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
09102                 return ASN_PARSE_E;
09103 
09104             /* save keyIdentifier and length */
09105             keyId = pkiMsg + *idx;
09106             keyIdSz = length;
09107             *idx += keyIdSz;
09108 
09109             /* may have OPTIONAL GeneralizedTime */
09110             localIdx = *idx;
09111             if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag,
09112                         pkiMsgSz) == 0 && tag == ASN_GENERALIZED_TIME) {
09113                 if (wc_GetDateInfo(pkiMsg + *idx, pkiMsgSz, &datePtr, &dateFormat,
09114                                    &dateLen) != 0) {
09115                     return ASN_PARSE_E;
09116                 }
09117                 *idx += (dateLen + 1);
09118             }
09119 
09120             /* may have OPTIONAL OtherKeyAttribute */
09121             localIdx = *idx;
09122             if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag,
09123                             pkiMsgSz) == 0 && tag == (ASN_SEQUENCE |
09124                             ASN_CONSTRUCTED)) {
09125                 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
09126                     return ASN_PARSE_E;
09127 
09128                 /* skip it */
09129                 *idx += length;
09130             }
09131 
09132             /* get KeyEncryptionAlgorithmIdentifier */
09133             if (GetAlgoId(pkiMsg, idx, &keyWrapOID, oidKeyWrapType, pkiMsgSz) < 0)
09134                 return ASN_PARSE_E;
09135 
09136             /* get EncryptedKey */
09137             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
09138                 return ASN_PARSE_E;
09139 
09140             if (tag != ASN_OCTET_STRING)
09141                 return ASN_PARSE_E;
09142 
09143             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
09144                 return ASN_PARSE_E;
09145 
09146             #ifndef NO_AES
09147                 direction = AES_DECRYPTION;
09148             #else
09149                 direction = DES_DECRYPTION;
09150             #endif
09151 
09152             /* decrypt CEK with KEK */
09153             if (pkcs7->wrapCEKCb) {
09154                 keySz = pkcs7->wrapCEKCb(pkcs7, pkiMsg + *idx, length, keyId,
09155                                      keyIdSz, NULL, 0, decryptedKey,
09156                                      *decryptedKeySz, keyWrapOID,
09157                                      (int)PKCS7_KEKRI, direction);
09158             }
09159             else {
09160                 keySz = wc_PKCS7_KeyWrap(pkiMsg + *idx, length, pkcs7->privateKey,
09161                                      pkcs7->privateKeySz, decryptedKey, *decryptedKeySz,
09162                                      keyWrapOID, direction);
09163             }
09164             if (keySz <= 0)
09165                 return keySz;
09166 
09167             *decryptedKeySz = (word32)keySz;
09168 
09169             /* mark recipFound, since we only support one RecipientInfo for now */
09170             *recipFound = 1;
09171             *idx += length;
09172 
09173         #ifndef NO_PKCS7_STREAM
09174             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09175                 break;
09176             }
09177         #endif
09178             ret = 0; /* success */
09179             break;
09180 
09181         default:
09182             WOLFSSL_MSG("PKCS7 KEKRI unknown state");
09183             ret = BAD_FUNC_ARG;
09184 
09185     }
09186 
09187     (void)keyId;
09188     return ret;
09189 }
09190 
09191 
09192 /* decode ASN.1 KeyAgreeRecipientInfo (kari), return 0 on success,
09193  * < 0 on error */
09194 static int wc_PKCS7_DecryptKari(PKCS7* pkcs7, byte* in, word32 inSz,
09195                                word32* idx, byte* decryptedKey,
09196                                word32* decryptedKeySz, int* recipFound)
09197 {
09198 #ifdef HAVE_ECC
09199     int ret, keySz;
09200     int encryptedKeySz;
09201     int direction = 0;
09202     word32 keyAgreeOID, keyWrapOID;
09203     byte rid[KEYID_SIZE];
09204 
09205 #ifdef WOLFSSL_SMALL_STACK
09206     byte* encryptedKey;
09207 #else
09208     byte  encryptedKey[MAX_ENCRYPTED_KEY_SZ];
09209 #endif
09210 
09211     byte* pkiMsg    = in;
09212     word32 pkiMsgSz = inSz;
09213 #ifndef NO_PKCS7_STREAM
09214     word32 tmpIdx = (idx) ? *idx : 0;
09215     long rc;
09216 #endif
09217 
09218     WOLFSSL_ENTER("wc_PKCS7_DecryptKari");
09219     if (pkcs7 == NULL || pkiMsg == NULL ||
09220             ((pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0) &&
09221               pkcs7->wrapCEKCb == NULL) ||
09222         idx == NULL || decryptedKey == NULL || decryptedKeySz == NULL) {
09223         return BAD_FUNC_ARG;
09224     }
09225 
09226     switch (pkcs7->state) {
09227         case WC_PKCS7_DECRYPT_KARI: {
09228         #ifndef NO_PKCS7_STREAM
09229             /* @TODO for now just get full buffer, needs divided up */
09230             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
09231                    (pkcs7->stream->maxLen - pkcs7->stream->totalRd) +
09232                    pkcs7->stream->length, &pkiMsg, idx)) != 0) {
09233                 return ret;
09234             }
09235 
09236             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
09237                     inSz);
09238             if (rc < 0) {
09239                 ret = (int)rc;
09240                 break;
09241             }
09242             pkiMsgSz = (word32)rc;
09243         #endif
09244             WC_PKCS7_KARI* kari;
09245 
09246             kari = wc_PKCS7_KariNew(pkcs7, WC_PKCS7_DECODE);
09247             if (kari == NULL)
09248                 return MEMORY_E;
09249 
09250         #ifdef WOLFSSL_SMALL_STACK
09251             encryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
09252                                           DYNAMIC_TYPE_PKCS7);
09253             if (encryptedKey == NULL) {
09254                 wc_PKCS7_KariFree(kari);
09255                 return MEMORY_E;
09256             }
09257         #endif
09258             encryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
09259 
09260             /* parse cert and key */
09261             if (pkcs7->singleCert != NULL) {
09262                 ret = wc_PKCS7_KariParseRecipCert(kari, (byte*)pkcs7->singleCert,
09263                                               pkcs7->singleCertSz, pkcs7->privateKey,
09264                                               pkcs7->privateKeySz);
09265                 if (ret != 0) {
09266                     wc_PKCS7_KariFree(kari);
09267                 #ifdef WOLFSSL_SMALL_STACK
09268                     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09269                 #endif
09270                     return ret;
09271                 }
09272             }
09273 
09274             /* remove OriginatorIdentifierOrKey */
09275             ret = wc_PKCS7_KariGetOriginatorIdentifierOrKey(kari, pkiMsg,
09276                                                             pkiMsgSz, idx);
09277             if (ret != 0) {
09278                 wc_PKCS7_KariFree(kari);
09279                 #ifdef WOLFSSL_SMALL_STACK
09280                     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09281                 #endif
09282                 return ret;
09283             }
09284 
09285             /* try and remove optional UserKeyingMaterial */
09286             ret = wc_PKCS7_KariGetUserKeyingMaterial(kari, pkiMsg, pkiMsgSz, idx);
09287             if (ret != 0) {
09288                 wc_PKCS7_KariFree(kari);
09289                 #ifdef WOLFSSL_SMALL_STACK
09290                     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09291                 #endif
09292                 return ret;
09293             }
09294 
09295             /* remove KeyEncryptionAlgorithmIdentifier */
09296             ret = wc_PKCS7_KariGetKeyEncryptionAlgorithmId(kari, pkiMsg,
09297                     pkiMsgSz, idx, &keyAgreeOID, &keyWrapOID);
09298             if (ret != 0) {
09299                 wc_PKCS7_KariFree(kari);
09300                 #ifdef WOLFSSL_SMALL_STACK
09301                     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09302                 #endif
09303                 return ret;
09304             }
09305 
09306             /* if user has not explicitly set keyAgreeOID, set from one in bundle */
09307             if (pkcs7->keyAgreeOID == 0)
09308                 pkcs7->keyAgreeOID = keyAgreeOID;
09309 
09310             /* set direction based on key wrap algorithm */
09311             switch (keyWrapOID) {
09312         #ifndef NO_AES
09313             #ifdef WOLFSSL_AES_128
09314                 case AES128_WRAP:
09315             #endif
09316             #ifdef WOLFSSL_AES_192
09317                 case AES192_WRAP:
09318             #endif
09319             #ifdef WOLFSSL_AES_256
09320                 case AES256_WRAP:
09321             #endif
09322                     direction = AES_DECRYPTION;
09323                     break;
09324         #endif
09325                 default:
09326                     WOLFSSL_MSG("AES key wrap algorithm unsupported");
09327                     if (pkcs7->wrapCEKCb) {
09328                         WOLFSSL_MSG("Direction not set!");
09329                         break; /* if unwrapping callback is set then do not
09330                                 * force restriction of supported wrap
09331                                 * algorithms */
09332                     }
09333 
09334                     wc_PKCS7_KariFree(kari);
09335                     #ifdef WOLFSSL_SMALL_STACK
09336                         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09337                     #endif
09338                     return BAD_KEYWRAP_ALG_E;
09339             }
09340 
09341             /* remove RecipientEncryptedKeys */
09342             ret = wc_PKCS7_KariGetRecipientEncryptedKeys(kari, pkiMsg, pkiMsgSz,
09343                            idx, recipFound, encryptedKey, &encryptedKeySz, rid);
09344             if (ret != 0) {
09345                 wc_PKCS7_KariFree(kari);
09346                 #ifdef WOLFSSL_SMALL_STACK
09347                     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09348                 #endif
09349                 return ret;
09350             }
09351 
09352             /* decrypt CEK with KEK */
09353             if (pkcs7->wrapCEKCb) {
09354                 word32 tmpKeySz = 0;
09355                 byte* tmpKeyDer = NULL;
09356 
09357                 ret = wc_ecc_export_x963(kari->senderKey, NULL, &tmpKeySz);
09358                 if (ret != LENGTH_ONLY_E) {
09359                     return ret;
09360                 }
09361 
09362                 /* buffer space for algorithm/curve */
09363                 tmpKeySz += MAX_SEQ_SZ;
09364                 tmpKeySz += 2 * MAX_ALGO_SZ;
09365 
09366                 /* buffer space for public key sequence */
09367                 tmpKeySz += MAX_SEQ_SZ;
09368                 tmpKeySz += TRAILING_ZERO;
09369 
09370                 tmpKeyDer = (byte*)XMALLOC(tmpKeySz, pkcs7->heap,
09371                         DYNAMIC_TYPE_TMP_BUFFER);
09372                 if (tmpKeyDer == NULL) {
09373                     return MEMORY_E;
09374                 }
09375 
09376                 ret = wc_EccPublicKeyToDer(kari->senderKey, tmpKeyDer,
09377                                          tmpKeySz, 1);
09378                 if (ret < 0) {
09379                     XFREE(tmpKeyDer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
09380                     return ret;
09381                 }
09382                 tmpKeySz = (word32)ret;
09383 
09384                 keySz = pkcs7->wrapCEKCb(pkcs7, encryptedKey, encryptedKeySz,
09385                         rid, KEYID_SIZE, tmpKeyDer, tmpKeySz,
09386                         decryptedKey, *decryptedKeySz,
09387                         keyWrapOID, (int)PKCS7_KARI, direction);
09388                 XFREE(tmpKeyDer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
09389 
09390                 if (keySz  > 0) {
09391                     /* If unwrapping was successful then consider recipient
09392                      * found. Checking for NULL singleCert to confirm previous
09393                      * SID check was not done */
09394                     if (pkcs7->singleCert == NULL)
09395                         *recipFound = 1;
09396                 }
09397             }
09398             else {
09399                 /* create KEK */
09400                 ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, pkcs7->keyAgreeOID);
09401                 if (ret != 0) {
09402                     wc_PKCS7_KariFree(kari);
09403                     #ifdef WOLFSSL_SMALL_STACK
09404                         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09405                     #endif
09406                     return ret;
09407                 }
09408 
09409                 /* decrypt CEK with KEK */
09410                 keySz = wc_PKCS7_KeyWrap(encryptedKey, encryptedKeySz, kari->kek,
09411                                          kari->kekSz, decryptedKey, *decryptedKeySz,
09412                                          keyWrapOID, direction);
09413             }
09414             if (keySz <= 0) {
09415                 wc_PKCS7_KariFree(kari);
09416                 #ifdef WOLFSSL_SMALL_STACK
09417                     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09418                 #endif
09419                 return keySz;
09420             }
09421             *decryptedKeySz = (word32)keySz;
09422 
09423             wc_PKCS7_KariFree(kari);
09424             #ifdef WOLFSSL_SMALL_STACK
09425                 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09426             #endif
09427             #ifndef NO_PKCS7_STREAM
09428             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09429                 break;
09430             }
09431             #endif
09432             ret = 0; /* success */
09433         }
09434         break;
09435 
09436         default:
09437             WOLFSSL_MSG("PKCS7 kari unknown state");
09438             ret = BAD_FUNC_ARG;
09439 
09440     }
09441 
09442     (void)pkiMsg;
09443     (void)pkiMsgSz;
09444 
09445     return ret;
09446 #else
09447     (void)in;
09448     (void)inSz;
09449     (void)pkcs7;
09450     (void)idx;
09451     (void)decryptedKey;
09452     (void)decryptedKeySz;
09453     (void)recipFound;
09454 
09455     return NOT_COMPILED_IN;
09456 #endif /* HAVE_ECC */
09457 }
09458 
09459 
09460 /* decode ASN.1 RecipientInfos SET, return 0 on success, < 0 on error */
09461 static int wc_PKCS7_DecryptRecipientInfos(PKCS7* pkcs7, byte* in,
09462                             word32  inSz, word32* idx, byte* decryptedKey,
09463                             word32* decryptedKeySz, int* recipFound)
09464 {
09465     word32 savedIdx;
09466     int version, ret = 0, length;
09467     byte* pkiMsg = in;
09468     word32 pkiMsgSz = inSz;
09469     byte  tag;
09470 #ifndef NO_PKCS7_STREAM
09471     word32 tmpIdx;
09472     long rc;
09473 #endif
09474 
09475     if (pkcs7 == NULL || pkiMsg == NULL || idx == NULL ||
09476         decryptedKey == NULL || decryptedKeySz == NULL ||
09477         recipFound == NULL) {
09478         return BAD_FUNC_ARG;
09479     }
09480 
09481     WOLFSSL_ENTER("wc_PKCS7_DecryptRecipientInfos");
09482 #ifndef NO_PKCS7_STREAM
09483     tmpIdx = *idx;
09484 #endif
09485 
09486     /* check if in the process of decrypting */
09487     switch (pkcs7->state) {
09488         case WC_PKCS7_DECRYPT_KTRI:
09489         case WC_PKCS7_DECRYPT_KTRI_2:
09490         case WC_PKCS7_DECRYPT_KTRI_3:
09491         #ifndef NO_RSA
09492             ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx,
09493                                       decryptedKey, decryptedKeySz, recipFound);
09494         #else
09495             return NOT_COMPILED_IN;
09496         #endif
09497             break;
09498 
09499         case WC_PKCS7_DECRYPT_KARI:
09500                 ret = wc_PKCS7_DecryptKari(pkcs7, in, inSz, idx,
09501                                       decryptedKey, decryptedKeySz, recipFound);
09502                 break;
09503 
09504         case WC_PKCS7_DECRYPT_KEKRI:
09505                 ret = wc_PKCS7_DecryptKekri(pkcs7, in, inSz, idx,
09506                                       decryptedKey, decryptedKeySz, recipFound);
09507                 break;
09508 
09509         case WC_PKCS7_DECRYPT_PWRI:
09510         #if !defined(NO_PWDBASED) && !defined(NO_SHA)
09511                 ret = wc_PKCS7_DecryptPwri(pkcs7, in, inSz, idx,
09512                                       decryptedKey, decryptedKeySz, recipFound);
09513         #else
09514                 return NOT_COMPILED_IN;
09515         #endif
09516                 break;
09517 
09518         case WC_PKCS7_DECRYPT_ORI:
09519             ret = wc_PKCS7_DecryptOri(pkcs7, in, inSz, idx,
09520                                       decryptedKey, decryptedKeySz, recipFound);
09521             break;
09522 
09523         default:
09524             /* not in decrypting state */
09525             break;
09526     }
09527 
09528     if (ret < 0) {
09529         return ret;
09530     }
09531 
09532     savedIdx = *idx;
09533 #ifndef NO_PKCS7_STREAM
09534     rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz);
09535     if (rc < 0) {
09536         return (int)rc;
09537     }
09538     pkiMsgSz = (word32)rc;
09539     if (pkcs7->stream->length > 0)
09540         pkiMsg = pkcs7->stream->buffer;
09541 #endif
09542 
09543     /* when looking for next recipient, use first sequence and version to
09544      * indicate there is another, if not, move on */
09545     while(*recipFound == 0) {
09546 
09547         /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to
09548          * last good saved one */
09549         if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) > 0) {
09550 
09551         #ifndef NO_RSA
09552             /* found ktri */
09553             #ifndef NO_PKCS7_STREAM
09554             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09555                 break;
09556             }
09557             #endif
09558             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KTRI);
09559             ret = wc_PKCS7_DecryptKtri(pkcs7, in, inSz, idx,
09560                                       decryptedKey, decryptedKeySz,
09561                                       recipFound);
09562             if (ret != 0)
09563                 return ret;
09564         #else
09565             return NOT_COMPILED_IN;
09566         #endif
09567         }
09568         else {
09569             word32 localIdx;
09570             /* kari is IMPLICIT[1] */
09571             *idx = savedIdx;
09572             localIdx = *idx;
09573 
09574             if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) != 0) {
09575                 /* no room for recipient info */
09576                 break;
09577             }
09578 
09579             if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
09580                 (*idx)++;
09581                 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
09582                     return ASN_PARSE_E;
09583 
09584                 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) {
09585                     *idx = savedIdx;
09586                     break;
09587                 }
09588 
09589                 if (version != 3)
09590                     return ASN_VERSION_E;
09591 
09592                 /* found kari */
09593             #ifndef NO_PKCS7_STREAM
09594                 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09595                     break;
09596                 }
09597             #endif
09598                 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KARI);
09599                 ret = wc_PKCS7_DecryptKari(pkcs7, in, inSz, idx,
09600                                           decryptedKey, decryptedKeySz,
09601                                           recipFound);
09602                 if (ret != 0)
09603                     return ret;
09604 
09605             /* kekri is IMPLICIT[2] */
09606             } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 2)) {
09607                 (*idx)++;
09608 
09609                 if (GetLength(pkiMsg, idx, &version, pkiMsgSz) < 0)
09610                     return ASN_PARSE_E;
09611 
09612                 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) {
09613                     *idx = savedIdx;
09614                     break;
09615                 }
09616 
09617                 if (version != 4)
09618                     return ASN_VERSION_E;
09619 
09620                 /* found kekri */
09621             #ifndef NO_PKCS7_STREAM
09622                 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09623                     break;
09624                 }
09625             #endif
09626                 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_KEKRI);
09627                 ret = wc_PKCS7_DecryptKekri(pkcs7, in, inSz, idx,
09628                                            decryptedKey, decryptedKeySz,
09629                                            recipFound);
09630                 if (ret != 0)
09631                     return ret;
09632 
09633             /* pwri is IMPLICIT[3] */
09634             } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 3)) {
09635         #if !defined(NO_PWDBASED) && !defined(NO_SHA)
09636                 (*idx)++;
09637 
09638                 if (GetLength(pkiMsg, idx, &version, pkiMsgSz) < 0)
09639                     return ASN_PARSE_E;
09640 
09641                 if (GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0) {
09642                     *idx = savedIdx;
09643                     break;
09644                 }
09645 
09646                 if (version != 0)
09647                     return ASN_VERSION_E;
09648 
09649                 /* found pwri */
09650             #ifndef NO_PKCS7_STREAM
09651                 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09652                     break;
09653                 }
09654             #endif
09655                 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_PWRI);
09656                 ret = wc_PKCS7_DecryptPwri(pkcs7, in, inSz, idx,
09657                                            decryptedKey, decryptedKeySz,
09658                                            recipFound);
09659                 if (ret != 0)
09660                     return ret;
09661         #else
09662                 return NOT_COMPILED_IN;
09663         #endif
09664 
09665             /* ori is IMPLICIT[4] */
09666             } else if (tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 4)) {
09667                 (*idx)++;
09668 
09669                 /* found ori */
09670             #ifndef NO_PKCS7_STREAM
09671                 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09672                     break;
09673                 }
09674             #endif
09675                 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_DECRYPT_ORI);
09676                 ret = wc_PKCS7_DecryptOri(pkcs7, in, inSz, idx,
09677                                           decryptedKey, decryptedKeySz,
09678                                           recipFound);
09679                 if (ret != 0)
09680                     return ret;
09681 
09682             } else {
09683                 /* failed to find RecipientInfo, restore idx and continue */
09684                 *idx = savedIdx;
09685                 break;
09686             }
09687         }
09688 
09689         /* update good idx */
09690         savedIdx = *idx;
09691     }
09692 
09693     return ret;
09694 }
09695 
09696 
09697 /* Parse encoded EnvelopedData bundle up to RecipientInfo set.
09698  *
09699  * return size of RecipientInfo SET on success, negative upon error */
09700 static int wc_PKCS7_ParseToRecipientInfoSet(PKCS7* pkcs7, byte* in,
09701                                             word32 inSz, word32* idx,
09702                                             int type)
09703 {
09704     int version = 0, length, ret = 0;
09705     word32 contentType;
09706     byte* pkiMsg = in;
09707     word32 pkiMsgSz = inSz;
09708     byte  tag;
09709 #ifndef NO_PKCS7_STREAM
09710     word32 tmpIdx = 0;
09711     long rc;
09712 #endif
09713 
09714     if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 || idx == NULL)
09715         return BAD_FUNC_ARG;
09716 
09717     if ((type != ENVELOPED_DATA) && (type != AUTH_ENVELOPED_DATA) &&
09718             pkcs7->contentOID != FIRMWARE_PKG_DATA)
09719         return BAD_FUNC_ARG;
09720 
09721 #ifndef NO_PKCS7_STREAM
09722     if (pkcs7->stream == NULL) {
09723         if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
09724             return ret;
09725         }
09726     }
09727 #endif
09728 
09729     switch (pkcs7->state) {
09730         case WC_PKCS7_INFOSET_START:
09731         case WC_PKCS7_INFOSET_BER:
09732         case WC_PKCS7_INFOSET_STAGE1:
09733         case WC_PKCS7_INFOSET_STAGE2:
09734         case WC_PKCS7_INFOSET_END:
09735             break;
09736 
09737         default:
09738             WOLFSSL_MSG("Warning, setting PKCS7 info state to start");
09739             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_START);
09740     }
09741 
09742     switch (pkcs7->state) {
09743         case WC_PKCS7_INFOSET_START:
09744         #ifndef NO_PKCS7_STREAM
09745             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
09746                             ASN_TAG_SZ, &pkiMsg, idx)) != 0) {
09747                 return ret;
09748             }
09749 
09750             rc  = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz);
09751             if (rc < 0) {
09752                 ret = (int)rc;
09753                 break;
09754             }
09755             pkiMsgSz = (word32)rc;
09756         #endif
09757             /* read past ContentInfo, verify type is envelopedData */
09758             if (ret == 0 && GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
09759             {
09760                 ret = ASN_PARSE_E;
09761             }
09762 
09763             if (ret == 0 && length == 0 && pkiMsg[(*idx)-1] == 0x80) {
09764         #ifdef ASN_BER_TO_DER
09765                 word32 len;
09766 
09767                 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_BER);
09768                 FALL_THROUGH;
09769 
09770                 /* full buffer is needed for conversion */
09771                 case WC_PKCS7_INFOSET_BER:
09772                 #ifndef NO_PKCS7_STREAM
09773                 if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
09774                             pkcs7->stream->maxLen - pkcs7->stream->length,
09775                             &pkiMsg, idx)) != 0) {
09776                     return ret;
09777                 }
09778 
09779                 rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
09780                         in, inSz);
09781                 if (rc < 0) {
09782                     ret = (int)rc;
09783                     break;
09784                 }
09785                 pkiMsgSz = (word32)rc;
09786                 #endif
09787 
09788                 len = 0;
09789 
09790                 ret = wc_BerToDer(pkiMsg, pkiMsgSz, NULL, &len);
09791                 if (ret != LENGTH_ONLY_E)
09792                     return ret;
09793                 pkcs7->der = (byte*)XMALLOC(len, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
09794                 if (pkcs7->der == NULL)
09795                     return MEMORY_E;
09796                 ret = wc_BerToDer(pkiMsg, pkiMsgSz, pkcs7->der, &len);
09797                 if (ret < 0)
09798                     return ret;
09799 
09800                 pkiMsg = in = pkcs7->der;
09801                 pkiMsgSz = pkcs7->derSz = len;
09802                 *idx = 0;
09803 
09804                 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
09805                     return ASN_PARSE_E;
09806         #else
09807                 return BER_INDEF_E;
09808         #endif
09809             }
09810         #ifndef NO_PKCS7_STREAM
09811             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09812                 break;
09813             }
09814         #endif
09815             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_STAGE1);
09816             FALL_THROUGH;
09817 
09818         case WC_PKCS7_INFOSET_STAGE1:
09819         #ifndef NO_PKCS7_STREAM
09820             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_OID_SZ +
09821                             MAX_LENGTH_SZ + ASN_TAG_SZ, &pkiMsg, idx)) != 0) {
09822                 return ret;
09823             }
09824 
09825             pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz;
09826         #endif
09827             if (pkcs7->contentOID != FIRMWARE_PKG_DATA ||
09828                     type == AUTH_ENVELOPED_DATA) {
09829                 if (ret == 0 && wc_GetContentType(pkiMsg, idx, &contentType,
09830                             pkiMsgSz) < 0)
09831                     ret = ASN_PARSE_E;
09832 
09833                 if (ret == 0) {
09834                     if (type == ENVELOPED_DATA && contentType != ENVELOPED_DATA) {
09835                         WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData");
09836                         ret = PKCS7_OID_E;
09837                     } else if (type == AUTH_ENVELOPED_DATA &&
09838                            contentType != AUTH_ENVELOPED_DATA) {
09839                         WOLFSSL_MSG("PKCS#7 input not of type AuthEnvelopedData");
09840                         ret = PKCS7_OID_E;
09841                     }
09842                 }
09843 
09844                 if (ret == 0 && GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) != 0)
09845                     ret = ASN_PARSE_E;
09846 
09847                 if (ret == 0 && tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC
09848                             | 0))
09849                     ret = ASN_PARSE_E;
09850 
09851                 if (ret == 0 && GetLength_ex(pkiMsg, idx, &length, pkiMsgSz,
09852                             NO_USER_CHECK) < 0)
09853                     ret = ASN_PARSE_E;
09854             }
09855 
09856             if (ret < 0)
09857                 break;
09858 
09859         #ifndef NO_PKCS7_STREAM
09860             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09861                     break;
09862             }
09863         #endif
09864             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_STAGE2);
09865             FALL_THROUGH;
09866 
09867         case WC_PKCS7_INFOSET_STAGE2:
09868         #ifndef NO_PKCS7_STREAM
09869             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
09870                             MAX_VERSION_SZ, &pkiMsg, idx)) != 0) {
09871                 return ret;
09872             }
09873 
09874             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
09875                     inSz);
09876             if (rc < 0) {
09877                 ret = (int)rc;
09878                 break;
09879             }
09880             pkiMsgSz = (word32)rc;
09881         #endif
09882             /* remove EnvelopedData and version */
09883             if (pkcs7->contentOID != FIRMWARE_PKG_DATA ||
09884                     type == AUTH_ENVELOPED_DATA) {
09885                 if (ret == 0 && GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
09886                     ret = ASN_PARSE_E;
09887             }
09888 
09889             if (ret == 0 && GetMyVersion(pkiMsg, idx, &version, pkiMsgSz) < 0)
09890                 ret = ASN_PARSE_E;
09891 
09892             if (ret < 0)
09893                 break;
09894 
09895         #ifndef NO_PKCS7_STREAM
09896             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09897                 break;
09898             }
09899 
09900             pkcs7->stream->varOne = version;
09901         #endif
09902             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_INFOSET_END);
09903             FALL_THROUGH;
09904 
09905         case WC_PKCS7_INFOSET_END:
09906         #ifndef NO_PKCS7_STREAM
09907             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
09908                             MAX_SET_SZ, &pkiMsg, idx)) != 0) {
09909                 return ret;
09910             }
09911 
09912             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
09913                     inSz);
09914             if (rc < 0) {
09915                 ret = (int)rc;
09916                 break;
09917             }
09918             pkiMsgSz = (word32)rc;
09919             version = pkcs7->stream->varOne;
09920         #endif
09921 
09922             if (type == ENVELOPED_DATA) {
09923                 /* TODO :: make this more accurate */
09924                 if ((pkcs7->publicKeyOID == RSAk &&
09925                      (version != 0 && version != 2))
09926                 #ifdef HAVE_ECC
09927                         || (pkcs7->publicKeyOID == ECDSAk &&
09928                             (version != 0 && version != 2 && version != 3))
09929                 #endif
09930                         ) {
09931                     WOLFSSL_MSG("PKCS#7 envelopedData version incorrect");
09932                     ret = ASN_VERSION_E;
09933                 }
09934             } else {
09935                 /* AuthEnvelopedData version MUST be 0 */
09936                 if (version != 0) {
09937                     WOLFSSL_MSG("PKCS#7 AuthEnvelopedData needs to be of version 0");
09938                     ret = ASN_VERSION_E;
09939                 }
09940             }
09941 
09942             /* remove RecipientInfo set, get length of set */
09943             if (ret == 0 && GetSet(pkiMsg, idx, &length, pkiMsgSz) < 0)
09944                 ret = ASN_PARSE_E;
09945 
09946             if (ret < 0)
09947                 break;
09948 
09949         #ifndef NO_PKCS7_STREAM
09950             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, idx)) != 0) {
09951                 break;
09952             }
09953         #endif
09954 
09955             if (ret == 0)
09956                 ret = length;
09957 
09958             break;
09959 
09960         default:
09961             WOLFSSL_MSG("Bad PKCS7 info set state");
09962             ret = BAD_FUNC_ARG;
09963             break;
09964     }
09965 
09966     return ret;
09967 }
09968 
09969 
09970 /* Import secret/private key into a PKCS7 structure. Used for setting
09971  * the secret key for decryption a EnvelopedData KEKRI RecipientInfo.
09972  *
09973  * Returns 0 on success, negative upon error */
09974 WOLFSSL_API int wc_PKCS7_SetKey(PKCS7* pkcs7, byte* key, word32 keySz)
09975 {
09976     if (pkcs7 == NULL || key == NULL || keySz == 0)
09977         return BAD_FUNC_ARG;
09978 
09979     pkcs7->privateKey = key;
09980     pkcs7->privateKeySz = keySz;
09981 
09982     return 0;
09983 }
09984 
09985 
09986 /* append data to encrypted content cache in PKCS7 structure
09987  * return 0 on success, negative on error */
09988 static int PKCS7_CacheEncryptedContent(PKCS7* pkcs7, byte* in, word32 inSz)
09989 {
09990     byte* oldCache;
09991     word32 oldCacheSz;
09992 
09993     if (pkcs7 == NULL || in == NULL)
09994         return BAD_FUNC_ARG;
09995 
09996     /* save pointer to old cache */
09997     oldCache = pkcs7->cachedEncryptedContent;
09998     oldCacheSz = pkcs7->cachedEncryptedContentSz;
09999 
10000     /* re-allocate new buffer to fit appended data */
10001     pkcs7->cachedEncryptedContent = (byte*)XMALLOC(oldCacheSz + inSz,
10002             pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10003     if (pkcs7->cachedEncryptedContent == NULL) {
10004         pkcs7->cachedEncryptedContentSz = 0;
10005         XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10006         return MEMORY_E;
10007     }
10008 
10009     if (oldCache != NULL) {
10010         XMEMCPY(pkcs7->cachedEncryptedContent, oldCache, oldCacheSz);
10011     }
10012     XMEMCPY(pkcs7->cachedEncryptedContent + oldCacheSz, in, inSz);
10013     pkcs7->cachedEncryptedContentSz += inSz;
10014 
10015     XFREE(oldCache, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10016 
10017     return 0;
10018 }
10019 
10020 
10021 /* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */
10022 WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in,
10023                                          word32 inSz, byte* output,
10024                                          word32 outputSz)
10025 {
10026     int recipFound = 0;
10027     int ret, length = 0;
10028     word32 idx = 0;
10029 #ifndef NO_PKCS7_STREAM
10030     word32 tmpIdx = 0;
10031     long rc;
10032 #endif
10033     word32 contentType, encOID = 0;
10034     word32 decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
10035 
10036     int expBlockSz = 0, blockKeySz = 0;
10037     byte  tmpIvBuf[MAX_CONTENT_IV_SIZE];
10038     byte* tmpIv = tmpIvBuf;
10039 
10040     byte* pkiMsg    = in;
10041     word32 pkiMsgSz = inSz;
10042     byte* decryptedKey = NULL;
10043     int encryptedContentTotalSz = 0;
10044     int encryptedContentSz = 0;
10045     byte padLen;
10046     byte* encryptedContent = NULL;
10047     int explicitOctet = 0;
10048     word32 localIdx;
10049     byte   tag;
10050 
10051     if (pkcs7 == NULL)
10052         return BAD_FUNC_ARG;
10053 
10054     if (pkiMsg == NULL || pkiMsgSz == 0 ||
10055         output == NULL || outputSz == 0)
10056         return BAD_FUNC_ARG;
10057 
10058 #ifndef NO_PKCS7_STREAM
10059     (void)tmpIv; /* help out static analysis */
10060     if (pkcs7->stream == NULL) {
10061         if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
10062             return ret;
10063         }
10064     }
10065 #endif
10066 
10067     switch (pkcs7->state) {
10068         case WC_PKCS7_START:
10069         case WC_PKCS7_INFOSET_START:
10070         case WC_PKCS7_INFOSET_BER:
10071         case WC_PKCS7_INFOSET_STAGE1:
10072         case WC_PKCS7_INFOSET_STAGE2:
10073         case WC_PKCS7_INFOSET_END:
10074             ret = wc_PKCS7_ParseToRecipientInfoSet(pkcs7, pkiMsg, pkiMsgSz,
10075                     &idx, ENVELOPED_DATA);
10076             if (ret < 0) {
10077                 break;
10078             }
10079 
10080         #ifdef ASN_BER_TO_DER
10081             /* check if content was BER and has been converted to DER */
10082             if (pkcs7->derSz > 0)
10083                 pkiMsg = in = pkcs7->der;
10084         #endif
10085 
10086             decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
10087                                                        DYNAMIC_TYPE_PKCS7);
10088             if (decryptedKey == NULL)
10089                 return MEMORY_E;
10090             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2);
10091         #ifndef NO_PKCS7_STREAM
10092             tmpIdx = idx;
10093             pkcs7->stream->aad = decryptedKey;
10094         #endif
10095             FALL_THROUGH;
10096 
10097         case WC_PKCS7_ENV_2:
10098         #ifndef NO_PKCS7_STREAM
10099             /* store up enough buffer for initial info set decode */
10100             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
10101                             MAX_VERSION_SZ + ASN_TAG_SZ, &pkiMsg, &idx)) != 0) {
10102                 return ret;
10103             }
10104         #endif
10105             FALL_THROUGH;
10106 
10107         case WC_PKCS7_DECRYPT_KTRI:
10108         case WC_PKCS7_DECRYPT_KTRI_2:
10109         case WC_PKCS7_DECRYPT_KTRI_3:
10110         case WC_PKCS7_DECRYPT_KARI:
10111         case WC_PKCS7_DECRYPT_KEKRI:
10112         case WC_PKCS7_DECRYPT_PWRI:
10113         case WC_PKCS7_DECRYPT_ORI:
10114         #ifndef NO_PKCS7_STREAM
10115             decryptedKey   = pkcs7->stream->aad;
10116             decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
10117         #endif
10118 
10119             ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx,
10120                                         decryptedKey, &decryptedKeySz,
10121                                         &recipFound);
10122             if (ret == 0 && recipFound == 0) {
10123                 WOLFSSL_MSG("No recipient found in envelopedData that matches input");
10124                 ret = PKCS7_RECIP_E;
10125             }
10126 
10127             if (ret != 0)
10128                 break;
10129         #ifndef NO_PKCS7_STREAM
10130             tmpIdx               = idx;
10131             pkcs7->stream->aadSz = decryptedKeySz;
10132         #endif
10133             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_3);
10134             FALL_THROUGH;
10135 
10136         case WC_PKCS7_ENV_3:
10137 
10138         #ifndef NO_PKCS7_STREAM
10139             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
10140                                                 MAX_VERSION_SZ + ASN_TAG_SZ +
10141                                                 MAX_LENGTH_SZ, &pkiMsg, &idx))
10142                                                 != 0) {
10143                 return ret;
10144             }
10145 
10146             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
10147                     inSz);
10148             if (rc < 0) {
10149                 ret = (int)rc;
10150                 break;
10151             }
10152             pkiMsgSz = (word32)rc;
10153         #else
10154             ret = 0;
10155         #endif
10156 
10157             /* remove EncryptedContentInfo */
10158             if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
10159                 ret = ASN_PARSE_E;
10160             }
10161 
10162             if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
10163                         pkiMsgSz) < 0) {
10164                 ret = ASN_PARSE_E;
10165             }
10166 
10167             if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
10168                         pkiMsgSz) < 0) {
10169                 ret = ASN_PARSE_E;
10170             }
10171 
10172             blockKeySz = wc_PKCS7_GetOIDKeySize(encOID);
10173             if (ret == 0 && blockKeySz < 0) {
10174                 ret = blockKeySz;
10175             }
10176 
10177             expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID);
10178             if (ret == 0 && expBlockSz < 0) {
10179                 ret = expBlockSz;
10180             }
10181 
10182             /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
10183             if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) != 0) {
10184                 ret = ASN_PARSE_E;
10185             }
10186 
10187             if (ret == 0 && tag != ASN_OCTET_STRING) {
10188                 ret = ASN_PARSE_E;
10189             }
10190 
10191             if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
10192                 ret = ASN_PARSE_E;
10193             }
10194 
10195             if (ret == 0 && length != expBlockSz) {
10196                 WOLFSSL_MSG("Incorrect IV length, must be of content alg block size");
10197                 ret = ASN_PARSE_E;
10198             }
10199 
10200             if (ret != 0)
10201                 break;
10202         #ifndef NO_PKCS7_STREAM
10203             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
10204                 break;
10205             }
10206             wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, length);
10207             pkcs7->stream->contentSz = blockKeySz;
10208             pkcs7->stream->expected = length + MAX_LENGTH_SZ + MAX_LENGTH_SZ +
10209                 ASN_TAG_SZ + ASN_TAG_SZ;
10210         #endif
10211             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_4);
10212             FALL_THROUGH;
10213 
10214         case WC_PKCS7_ENV_4:
10215 
10216         #ifndef NO_PKCS7_STREAM
10217             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
10218                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
10219                 return ret;
10220             }
10221 
10222             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
10223                     inSz);
10224             if (rc < 0) {
10225                 ret = (int)rc;
10226                 break;
10227             }
10228             pkiMsgSz = (word32)rc;
10229 
10230             wc_PKCS7_StreamGetVar(pkcs7, 0, 0, &length);
10231             tmpIv = pkcs7->stream->tmpIv;
10232             if (tmpIv == NULL) {
10233                 /* check added to help out static analysis tool */
10234                 ret = MEMORY_E;
10235                 break;
10236             }
10237         #else
10238             ret = 0;
10239         #endif
10240 
10241             XMEMCPY(tmpIv, &pkiMsg[idx], length);
10242             idx += length;
10243 
10244             explicitOctet = 0;
10245             localIdx = idx;
10246             if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 &&
10247                     tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) {
10248                 explicitOctet = 1;
10249             }
10250 
10251             /* read encryptedContent, cont[0] */
10252             if (tag != (ASN_CONTEXT_SPECIFIC | 0) &&
10253                           tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) {
10254                 ret = ASN_PARSE_E;
10255             }
10256             idx++;
10257 
10258             if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentTotalSz,
10259                                                                pkiMsgSz) <= 0) {
10260                 ret = ASN_PARSE_E;
10261             }
10262 
10263             if (ret != 0)
10264                 break;
10265 
10266         #ifndef NO_PKCS7_STREAM
10267             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
10268                 break;
10269             }
10270             pkcs7->stream->expected = encryptedContentTotalSz;
10271             wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, 0);
10272             wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet);
10273         #endif
10274             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_5);
10275             FALL_THROUGH;
10276 
10277         case WC_PKCS7_ENV_5:
10278 
10279         #ifndef NO_PKCS7_STREAM
10280             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
10281                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
10282                 return ret;
10283             }
10284 
10285             wc_PKCS7_StreamGetVar(pkcs7, &encOID, &expBlockSz, &explicitOctet);
10286             tmpIv = pkcs7->stream->tmpIv;
10287             encryptedContentTotalSz = pkcs7->stream->expected;
10288 
10289             /* restore decrypted key */
10290             decryptedKey   = pkcs7->stream->aad;
10291             decryptedKeySz = pkcs7->stream->aadSz;
10292             blockKeySz = pkcs7->stream->contentSz;
10293         #else
10294             ret = 0;
10295         #endif
10296 
10297             if (explicitOctet) {
10298                 /* encrypted content may be fragmented into multiple
10299                  * consecutive OCTET STRINGs, if so loop through
10300                  * collecting and caching encrypted content bytes */
10301                 localIdx = idx;
10302                 while (idx < (localIdx + encryptedContentTotalSz)) {
10303 
10304                     if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
10305                         ret = ASN_PARSE_E;
10306                     }
10307 
10308                     if (ret == 0 && (tag != ASN_OCTET_STRING)) {
10309                         ret = ASN_PARSE_E;
10310                     }
10311 
10312                     if (ret == 0 && GetLength(pkiMsg, &idx,
10313                                 &encryptedContentSz, pkiMsgSz) <= 0) {
10314                         ret = ASN_PARSE_E;
10315                     }
10316 
10317                     if (ret == 0) {
10318                         ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx],
10319                                                           encryptedContentSz);
10320                     }
10321 
10322                     if (ret != 0) {
10323                         break;
10324                     }
10325 
10326                     /* advance idx past encrypted content */
10327                     idx += encryptedContentSz;
10328                 }
10329 
10330                 if (ret != 0) {
10331                     break;
10332                 }
10333 
10334             } else {
10335                 /* cache encrypted content, no OCTET STRING */
10336                 ret = PKCS7_CacheEncryptedContent(pkcs7, &pkiMsg[idx],
10337                                                   encryptedContentTotalSz);
10338                 if (ret != 0) {
10339                     break;
10340                 }
10341                 idx += encryptedContentTotalSz;
10342             }
10343 
10344             /* use cached content */
10345             encryptedContent = pkcs7->cachedEncryptedContent;
10346             encryptedContentSz = pkcs7->cachedEncryptedContentSz;
10347 
10348             /* decrypt encryptedContent */
10349             ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey,
10350                     blockKeySz, tmpIv, expBlockSz, NULL, 0, NULL, 0,
10351                     encryptedContent, encryptedContentSz, encryptedContent);
10352             if (ret != 0) {
10353                 break;
10354             }
10355 
10356             padLen = encryptedContent[encryptedContentSz-1];
10357 
10358             /* copy plaintext to output */
10359             if (padLen > encryptedContentSz ||
10360                     (word32)(encryptedContentSz - padLen) > outputSz) {
10361                 ret = BUFFER_E;
10362                 break;
10363             }
10364             XMEMCPY(output, encryptedContent, encryptedContentSz - padLen);
10365 
10366             /* free memory, zero out keys */
10367             ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
10368             XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10369             if (pkcs7->cachedEncryptedContent != NULL) {
10370                 XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
10371                       DYNAMIC_TYPE_PKCS7);
10372                 pkcs7->cachedEncryptedContent = NULL;
10373                 pkcs7->cachedEncryptedContentSz = 0;
10374             }
10375 
10376             ret = encryptedContentSz - padLen;
10377         #ifndef NO_PKCS7_STREAM
10378             pkcs7->stream->aad = NULL;
10379             pkcs7->stream->aadSz = 0;
10380             wc_PKCS7_ResetStream(pkcs7);
10381         #endif
10382             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
10383             break;
10384 
10385         default:
10386             WOLFSSL_MSG("PKCS#7 unknown decode enveloped state");
10387             ret = BAD_FUNC_ARG;
10388     }
10389 
10390 #ifndef NO_PKCS7_STREAM
10391     if (ret < 0 && ret != WC_PKCS7_WANT_READ_E) {
10392         wc_PKCS7_ResetStream(pkcs7);
10393         wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
10394         if (pkcs7->cachedEncryptedContent != NULL) {
10395             XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap,
10396                   DYNAMIC_TYPE_PKCS7);
10397             pkcs7->cachedEncryptedContent = NULL;
10398             pkcs7->cachedEncryptedContentSz = 0;
10399         }
10400     }
10401 #else
10402     if (decryptedKey != NULL && ret < 0) {
10403         ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
10404         XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10405     }
10406     if (pkcs7->cachedEncryptedContent != NULL && ret < 0) {
10407         XFREE(pkcs7->cachedEncryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10408         pkcs7->cachedEncryptedContent = NULL;
10409         pkcs7->cachedEncryptedContentSz = 0;
10410     }
10411 #endif
10412     return ret;
10413 }
10414 
10415 
10416 /* build PKCS#7 authEnvelopedData content type, return enveloped size */
10417 int wc_PKCS7_EncodeAuthEnvelopedData(PKCS7* pkcs7, byte* output,
10418                                      word32 outputSz)
10419 {
10420 #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
10421     int ret, idx = 0;
10422     int totalSz, encryptedOutSz;
10423 
10424     int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
10425     byte contentInfoSeq[MAX_SEQ_SZ];
10426     byte outerContentType[MAX_ALGO_SZ];
10427     byte outerContent[MAX_SEQ_SZ];
10428 
10429     int envDataSeqSz, verSz;
10430     byte envDataSeq[MAX_SEQ_SZ];
10431     byte ver[MAX_VERSION_SZ];
10432 
10433     WC_RNG rng;
10434     int blockSz, blockKeySz;
10435     byte* encryptedContent;
10436 
10437     Pkcs7EncodedRecip* tmpRecip = NULL;
10438     int recipSz, recipSetSz;
10439     byte recipSet[MAX_SET_SZ];
10440 
10441     int encContentOctetSz, encContentSeqSz, contentTypeSz;
10442     int contentEncAlgoSz, nonceOctetStringSz, macOctetStringSz;
10443     byte encContentSeq[MAX_SEQ_SZ];
10444     byte contentType[MAX_ALGO_SZ];
10445     byte contentEncAlgo[MAX_ALGO_SZ];
10446     byte nonceOctetString[MAX_OCTET_STR_SZ];
10447     byte encContentOctet[MAX_OCTET_STR_SZ];
10448     byte macOctetString[MAX_OCTET_STR_SZ];
10449 
10450     byte authTag[AES_BLOCK_SIZE];
10451     byte nonce[GCM_NONCE_MID_SZ];   /* GCM nonce is larger than CCM */
10452     byte macInt[MAX_VERSION_SZ];
10453     word32 nonceSz = 0, macIntSz = 0;
10454 
10455     /* authAttribs */
10456     byte* flatAuthAttribs = NULL;
10457     byte authAttribSet[MAX_SET_SZ];
10458     EncodedAttrib authAttribs[MAX_AUTH_ATTRIBS_SZ];
10459     word32 authAttribsSz = 0, authAttribsCount = 0;
10460     word32 authAttribsSetSz = 0;
10461 
10462     byte* aadBuffer = NULL;
10463     word32 aadBufferSz = 0;
10464     byte authAttribAadSet[MAX_SET_SZ];
10465     word32 authAttribsAadSetSz = 0;
10466 
10467     /* unauthAttribs */
10468     byte* flatUnauthAttribs = NULL;
10469     byte unauthAttribSet[MAX_SET_SZ];
10470     EncodedAttrib unauthAttribs[MAX_UNAUTH_ATTRIBS_SZ];
10471     word32 unauthAttribsSz = 0, unauthAttribsCount = 0;
10472     word32 unauthAttribsSetSz = 0;
10473 
10474 
10475     PKCS7Attrib contentTypeAttrib;
10476     byte contentTypeValue[MAX_OID_SZ];
10477     /* contentType OID (1.2.840.113549.1.9.3) */
10478     const byte contentTypeOid[] =
10479             { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01,
10480                              0x09, 0x03 };
10481 
10482     if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0)
10483         return BAD_FUNC_ARG;
10484 
10485     if (output == NULL || outputSz == 0)
10486         return BAD_FUNC_ARG;
10487 
10488     switch (pkcs7->encryptOID) {
10489 #ifdef HAVE_AESGCM
10490     #ifdef WOLFSSL_AES_128
10491         case AES128GCMb:
10492             break;
10493     #endif
10494     #ifdef WOLFSSL_AES_192
10495         case AES192GCMb:
10496             break;
10497     #endif
10498     #ifdef WOLFSSL_AES_256
10499         case AES256GCMb:
10500             break;
10501     #endif
10502 #endif
10503 #ifdef HAVE_AESCCM
10504     #ifdef WOLFSSL_AES_128
10505         case AES128CCMb:
10506             break;
10507     #endif
10508     #ifdef WOLFSSL_AES_192
10509         case AES192CCMb:
10510             break;
10511     #endif
10512     #ifdef WOLFSSL_AES_256
10513         case AES256CCMb:
10514             break;
10515     #endif
10516 #endif
10517         default:
10518             WOLFSSL_MSG("CMS AuthEnvelopedData must use AES-GCM or AES-CCM");
10519             return BAD_FUNC_ARG;
10520     }
10521 
10522     blockKeySz = wc_PKCS7_GetOIDKeySize(pkcs7->encryptOID);
10523     if (blockKeySz < 0)
10524         return blockKeySz;
10525 
10526     blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID);
10527     if (blockSz < 0)
10528         return blockSz;
10529 
10530     /* outer content type */
10531     ret = wc_SetContentType(AUTH_ENVELOPED_DATA, outerContentType,
10532                             sizeof(outerContentType));
10533     if (ret < 0)
10534         return ret;
10535 
10536     outerContentTypeSz = ret;
10537 
10538     /* version, defined as 0 in RFC 5083 */
10539     verSz = SetMyVersion(0, ver, 0);
10540 
10541     /* generate random content encryption key */
10542     ret = PKCS7_GenerateContentEncryptionKey(pkcs7, blockKeySz);
10543     if (ret != 0) {
10544         return ret;
10545     }
10546 
10547     /* build RecipientInfo, only if user manually set singleCert and size */
10548     if (pkcs7->singleCert != NULL && pkcs7->singleCertSz > 0) {
10549         switch (pkcs7->publicKeyOID) {
10550         #ifndef NO_RSA
10551             case RSAk:
10552                 ret = wc_PKCS7_AddRecipient_KTRI(pkcs7, pkcs7->singleCert,
10553                                                  pkcs7->singleCertSz, 0);
10554                 break;
10555         #endif
10556         #ifdef HAVE_ECC
10557             case ECDSAk:
10558                 ret = wc_PKCS7_AddRecipient_KARI(pkcs7, pkcs7->singleCert,
10559                                                  pkcs7->singleCertSz,
10560                                                  pkcs7->keyWrapOID,
10561                                                  pkcs7->keyAgreeOID, pkcs7->ukm,
10562                                                  pkcs7->ukmSz, 0);
10563                 break;
10564         #endif
10565 
10566             default:
10567                 WOLFSSL_MSG("Unsupported RecipientInfo public key type");
10568                 return BAD_FUNC_ARG;
10569         };
10570 
10571         if (ret < 0) {
10572             WOLFSSL_MSG("Failed to create RecipientInfo");
10573             return ret;
10574         }
10575     }
10576 
10577     recipSz = wc_PKCS7_GetRecipientListSize(pkcs7);
10578     if (recipSz < 0) {
10579         return ret;
10580 
10581     } else if (recipSz == 0) {
10582         WOLFSSL_MSG("You must add at least one CMS recipient");
10583         return PKCS7_RECIP_E;
10584     }
10585     recipSetSz = SetSet(recipSz, recipSet);
10586 
10587     /* generate random nonce and IV for encryption */
10588     switch (pkcs7->encryptOID) {
10589 #ifdef HAVE_AESGCM
10590     #ifdef WOLFSSL_AES_128
10591         case AES128GCMb:
10592             FALL_THROUGH;
10593     #endif
10594     #ifdef WOLFSSL_AES_192
10595         case AES192GCMb:
10596             FALL_THROUGH;
10597     #endif
10598     #ifdef WOLFSSL_AES_256
10599         case AES256GCMb:
10600     #endif
10601     #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
10602         defined(WOLFSSL_AES_256)
10603             /* GCM nonce is GCM_NONCE_MID_SZ (12) */
10604             nonceSz = GCM_NONCE_MID_SZ;
10605             break;
10606     #endif
10607 #endif /* HAVE_AESGCM */
10608 #ifdef HAVE_AESCCM
10609     #ifdef WOLFSSL_AES_128
10610         case AES128CCMb:
10611             FALL_THROUGH;
10612     #endif
10613     #ifdef WOLFSSL_AES_192
10614         case AES192CCMb:
10615             FALL_THROUGH;
10616     #endif
10617     #ifdef WOLFSSL_AES_256
10618         case AES256CCMb:
10619     #endif
10620     #if defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_192) || \
10621         defined(WOLFSSL_AES_256)
10622             /* CCM nonce is CCM_NONCE_MIN_SZ (7) */
10623             nonceSz = CCM_NONCE_MIN_SZ;
10624             break;
10625     #endif
10626 #endif /* HAVE_AESCCM */
10627     }
10628 
10629     ret = wc_InitRng_ex(&rng, pkcs7->heap, pkcs7->devId);
10630     if (ret != 0)
10631         return ret;
10632 
10633     ret = wc_PKCS7_GenerateBlock(pkcs7, &rng, nonce, nonceSz);
10634     wc_FreeRng(&rng);
10635     if (ret != 0) {
10636         return ret;
10637     }
10638 
10639 
10640     /* authAttribs: add contentType attrib if needed */
10641     if (pkcs7->contentOID != DATA) {
10642 
10643         /* if type is not id-data, contentType attribute MUST be added */
10644         contentTypeAttrib.oid = contentTypeOid;
10645         contentTypeAttrib.oidSz = sizeof(contentTypeOid);
10646 
10647         /* try to set from contentOID first, known types */
10648         ret = wc_SetContentType(pkcs7->contentOID, contentTypeValue,
10649                                 sizeof(contentTypeValue));
10650         if (ret > 0) {
10651             contentTypeAttrib.value = contentTypeValue;
10652             contentTypeAttrib.valueSz = ret;
10653 
10654         /* otherwise, try to set from custom content type */
10655         } else {
10656             if (pkcs7->contentTypeSz == 0) {
10657                 WOLFSSL_MSG("CMS pkcs7->contentType must be set if "
10658                             "contentOID is not");
10659                 return BAD_FUNC_ARG;
10660             }
10661             contentTypeAttrib.value = pkcs7->contentType;
10662             contentTypeAttrib.valueSz = pkcs7->contentTypeSz;
10663         }
10664 
10665         authAttribsSz += EncodeAttributes(authAttribs, 1,
10666                                           &contentTypeAttrib, 1);
10667         authAttribsCount += 1;
10668     }
10669 
10670     /* authAttribs: add in user authenticated attributes */
10671     if (pkcs7->authAttribs != NULL && pkcs7->authAttribsSz > 0) {
10672         authAttribsSz += EncodeAttributes(authAttribs + authAttribsCount,
10673                                  MAX_AUTH_ATTRIBS_SZ - authAttribsCount,
10674                                  pkcs7->authAttribs,
10675                                  pkcs7->authAttribsSz);
10676         authAttribsCount += pkcs7->authAttribsSz;
10677     }
10678 
10679     /* authAttribs: flatten authAttribs */
10680     if (authAttribsSz > 0 && authAttribsCount > 0) {
10681         flatAuthAttribs = (byte*)XMALLOC(authAttribsSz, pkcs7->heap,
10682                                          DYNAMIC_TYPE_PKCS7);
10683         if (flatAuthAttribs == NULL) {
10684             return MEMORY_E;
10685         }
10686 
10687         FlattenAttributes(pkcs7, flatAuthAttribs, authAttribs,
10688                           authAttribsCount);
10689 
10690         authAttribsSetSz = SetImplicit(ASN_SET, 1, authAttribsSz,
10691                                        authAttribSet);
10692 
10693         /* From RFC5083, "For the purpose of constructing the AAD, the
10694          * IMPLICIT [1] tag in the authAttrs field is not used for the
10695          * DER encoding: rather a universal SET OF tag is used. */
10696         authAttribsAadSetSz = SetSet(authAttribsSz, authAttribAadSet);
10697 
10698         /* allocate temp buffer to hold alternate attrib encoding for aad */
10699         aadBuffer = (byte*)XMALLOC(authAttribsSz + authAttribsAadSetSz,
10700                                    pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
10701         if (aadBuffer == NULL) {
10702             XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10703             return MEMORY_E;
10704         }
10705 
10706         /* build up alternate attrib encoding for aad */
10707         aadBufferSz = 0;
10708         XMEMCPY(aadBuffer + aadBufferSz, authAttribAadSet, authAttribsAadSetSz);
10709         aadBufferSz += authAttribsAadSetSz;
10710         XMEMCPY(aadBuffer + aadBufferSz, flatAuthAttribs, authAttribsSz);
10711         aadBufferSz += authAttribsSz;
10712     }
10713 
10714     /* build up unauthenticated attributes (unauthAttrs) */
10715     if (pkcs7->unauthAttribsSz > 0) {
10716         unauthAttribsSz = EncodeAttributes(unauthAttribs + unauthAttribsCount,
10717                                      MAX_UNAUTH_ATTRIBS_SZ - unauthAttribsCount,
10718                                      pkcs7->unauthAttribs,
10719                                      pkcs7->unauthAttribsSz);
10720         unauthAttribsCount = pkcs7->unauthAttribsSz;
10721 
10722         flatUnauthAttribs = (byte*)XMALLOC(unauthAttribsSz, pkcs7->heap,
10723                                             DYNAMIC_TYPE_PKCS7);
10724         if (flatUnauthAttribs == NULL) {
10725             if (aadBuffer)
10726                 XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
10727             if (flatAuthAttribs)
10728                 XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10729             return MEMORY_E;
10730         }
10731 
10732         FlattenAttributes(pkcs7, flatUnauthAttribs, unauthAttribs,
10733                           unauthAttribsCount);
10734         unauthAttribsSetSz = SetImplicit(ASN_SET, 2, unauthAttribsSz,
10735                                          unauthAttribSet);
10736     }
10737 
10738     /* allocate encrypted content buffer */
10739     encryptedOutSz = pkcs7->contentSz;
10740     encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap,
10741                                       DYNAMIC_TYPE_PKCS7);
10742     if (encryptedContent == NULL) {
10743         if (aadBuffer)
10744             XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
10745         if (flatUnauthAttribs)
10746             XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10747         if (flatAuthAttribs)
10748             XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10749         return MEMORY_E;
10750     }
10751 
10752     /* encrypt content */
10753     ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->cek,
10754             pkcs7->cekSz, nonce, nonceSz, aadBuffer, aadBufferSz, authTag,
10755             sizeof(authTag), pkcs7->content, encryptedOutSz, encryptedContent);
10756 
10757     if (aadBuffer) {
10758         XFREE(aadBuffer, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
10759         aadBuffer = NULL;
10760     }
10761 
10762     if (ret != 0) {
10763         if (flatUnauthAttribs)
10764             XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10765         if (flatAuthAttribs)
10766             XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10767         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10768         return ret;
10769     }
10770 
10771     /* EncryptedContentInfo */
10772     ret = wc_SetContentType(pkcs7->contentOID, contentType,
10773                             sizeof(contentType));
10774     if (ret < 0) {
10775         if (flatUnauthAttribs)
10776             XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10777         if (flatAuthAttribs)
10778             XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10779         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10780         return ret;
10781     }
10782 
10783     contentTypeSz = ret;
10784 
10785     /* put together nonce OCTET STRING */
10786     nonceOctetStringSz = SetOctetString(nonceSz, nonceOctetString);
10787 
10788     /* put together aes-ICVlen INTEGER */
10789     macIntSz = SetMyVersion(sizeof(authTag), macInt, 0);
10790 
10791     /* build up our ContentEncryptionAlgorithmIdentifier sequence,
10792      * adding (nonceOctetStringSz + blockSz + macIntSz) for nonce OCTET STRING
10793      * and tag size */
10794     contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
10795                                  oidBlkType, nonceOctetStringSz + nonceSz +
10796                                  macIntSz);
10797 
10798     if (contentEncAlgoSz == 0) {
10799         if (flatUnauthAttribs)
10800             XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10801         if (flatAuthAttribs)
10802             XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10803         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10804         return BAD_FUNC_ARG;
10805     }
10806 
10807     encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0, encryptedOutSz,
10808                                     encContentOctet);
10809 
10810     encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz +
10811                                   nonceOctetStringSz + nonceSz + macIntSz +
10812                                   encContentOctetSz + encryptedOutSz,
10813                                   encContentSeq);
10814 
10815     macOctetStringSz = SetOctetString(sizeof(authTag), macOctetString);
10816 
10817     /* keep track of sizes for outer wrapper layering */
10818     totalSz = verSz + recipSetSz + recipSz + encContentSeqSz + contentTypeSz +
10819               contentEncAlgoSz + nonceOctetStringSz + nonceSz + macIntSz +
10820               encContentOctetSz + encryptedOutSz + authAttribsSz +
10821               authAttribsSetSz + macOctetStringSz + sizeof(authTag) +
10822               unauthAttribsSz + unauthAttribsSetSz;
10823 
10824     /* EnvelopedData */
10825     envDataSeqSz = SetSequence(totalSz, envDataSeq);
10826     totalSz += envDataSeqSz;
10827 
10828     /* outer content */
10829     outerContentSz = SetExplicit(0, totalSz, outerContent);
10830     totalSz += outerContentTypeSz;
10831     totalSz += outerContentSz;
10832 
10833     /* ContentInfo */
10834     contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
10835     totalSz += contentInfoSeqSz;
10836 
10837     if (totalSz > (int)outputSz) {
10838         WOLFSSL_MSG("Pkcs7_encrypt output buffer too small");
10839         if (flatUnauthAttribs)
10840             XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10841         if (flatAuthAttribs)
10842             XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10843         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10844         return BUFFER_E;
10845     }
10846 
10847     XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
10848     idx += contentInfoSeqSz;
10849     XMEMCPY(output + idx, outerContentType, outerContentTypeSz);
10850     idx += outerContentTypeSz;
10851     XMEMCPY(output + idx, outerContent, outerContentSz);
10852     idx += outerContentSz;
10853     XMEMCPY(output + idx, envDataSeq, envDataSeqSz);
10854     idx += envDataSeqSz;
10855     XMEMCPY(output + idx, ver, verSz);
10856     idx += verSz;
10857     XMEMCPY(output + idx, recipSet, recipSetSz);
10858     idx += recipSetSz;
10859     /* copy in recipients from list */
10860     tmpRecip = pkcs7->recipList;
10861     while (tmpRecip != NULL) {
10862         XMEMCPY(output + idx, tmpRecip->recip, tmpRecip->recipSz);
10863         idx += tmpRecip->recipSz;
10864         tmpRecip = tmpRecip->next;
10865     }
10866     wc_PKCS7_FreeEncodedRecipientSet(pkcs7);
10867     XMEMCPY(output + idx, encContentSeq, encContentSeqSz);
10868     idx += encContentSeqSz;
10869     XMEMCPY(output + idx, contentType, contentTypeSz);
10870     idx += contentTypeSz;
10871     XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz);
10872     idx += contentEncAlgoSz;
10873     XMEMCPY(output + idx, nonceOctetString, nonceOctetStringSz);
10874     idx += nonceOctetStringSz;
10875     XMEMCPY(output + idx, nonce, nonceSz);
10876     idx += nonceSz;
10877     XMEMCPY(output + idx, macInt, macIntSz);
10878     idx += macIntSz;
10879     XMEMCPY(output + idx, encContentOctet, encContentOctetSz);
10880     idx += encContentOctetSz;
10881     XMEMCPY(output + idx, encryptedContent, encryptedOutSz);
10882     idx += encryptedOutSz;
10883 
10884     /* authenticated attributes */
10885     if (flatAuthAttribs && authAttribsSz > 0) {
10886         XMEMCPY(output + idx, authAttribSet, authAttribsSetSz);
10887         idx += authAttribsSetSz;
10888         XMEMCPY(output + idx, flatAuthAttribs, authAttribsSz);
10889         idx += authAttribsSz;
10890         XFREE(flatAuthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10891     }
10892 
10893     XMEMCPY(output + idx, macOctetString, macOctetStringSz);
10894     idx += macOctetStringSz;
10895     XMEMCPY(output + idx, authTag, sizeof(authTag));
10896     idx += sizeof(authTag);
10897 
10898     /* unauthenticated attributes */
10899     if (unauthAttribsSz > 0) {
10900         XMEMCPY(output + idx, unauthAttribSet, unauthAttribsSetSz);
10901         idx += unauthAttribsSetSz;
10902         XMEMCPY(output + idx, flatUnauthAttribs, unauthAttribsSz);
10903         idx += unauthAttribsSz;
10904     }
10905 
10906     if (flatUnauthAttribs != NULL) {
10907         XFREE(flatUnauthAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10908     }
10909 
10910     XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
10911 
10912     return idx;
10913 
10914 #else
10915     WOLFSSL_MSG("AuthEnvelopedData requires AES-GCM or AES-CCM to be enabled");
10916     (void)pkcs7;
10917     (void)output;
10918     (void)outputSz;
10919 
10920     return NOT_COMPILED_IN;
10921 #endif /* HAVE_AESGCM | HAVE_AESCCM */
10922 }
10923 
10924 
10925 /* unwrap and decrypt PKCS#7 AuthEnvelopedData object, return decoded size */
10926 WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* in,
10927                                                  word32 inSz, byte* output,
10928                                                  word32 outputSz)
10929 {
10930 #if defined(HAVE_AESGCM) || defined(HAVE_AESCCM)
10931     int recipFound = 0;
10932     int ret = 0, length;
10933     word32 idx = 0;
10934 #ifndef NO_PKCS7_STREAM
10935     word32 tmpIdx = 0;
10936     long rc;
10937 #endif
10938     word32 contentType, encOID = 0;
10939     word32 decryptedKeySz = 0;
10940     byte* pkiMsg = in;
10941     word32 pkiMsgSz = inSz;
10942 
10943     int expBlockSz = 0, blockKeySz = 0;
10944     byte authTag[AES_BLOCK_SIZE];
10945     byte nonce[GCM_NONCE_MID_SZ];       /* GCM nonce is larger than CCM */
10946     int nonceSz = 0, authTagSz = 0, macSz = 0;
10947 
10948 #ifdef WOLFSSL_SMALL_STACK
10949     byte* decryptedKey = NULL;
10950 #else
10951     byte  decryptedKey[MAX_ENCRYPTED_KEY_SZ];
10952 #endif
10953     int encryptedContentSz = 0;
10954     byte* encryptedContent = NULL;
10955     int explicitOctet = 0;
10956 
10957     byte authAttribSetByte = 0;
10958     byte* encodedAttribs = NULL;
10959     word32 encodedAttribIdx = 0, encodedAttribSz = 0;
10960     byte* authAttrib = NULL;
10961     int authAttribSz = 0;
10962     word32 localIdx;
10963     byte tag;
10964 
10965     if (pkcs7 == NULL)
10966         return BAD_FUNC_ARG;
10967 
10968     if (pkiMsg == NULL || pkiMsgSz == 0 ||
10969         output == NULL || outputSz == 0)
10970         return BAD_FUNC_ARG;
10971 #ifndef NO_PKCS7_STREAM
10972     if (pkcs7->stream == NULL) {
10973         if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
10974             return ret;
10975         }
10976     }
10977 #endif
10978 
10979     switch (pkcs7->state) {
10980         case WC_PKCS7_START:
10981         case WC_PKCS7_INFOSET_START:
10982         case WC_PKCS7_INFOSET_STAGE1:
10983         case WC_PKCS7_INFOSET_STAGE2:
10984         case WC_PKCS7_INFOSET_END:
10985             ret = wc_PKCS7_ParseToRecipientInfoSet(pkcs7, pkiMsg, pkiMsgSz,
10986                     &idx, AUTH_ENVELOPED_DATA);
10987             if (ret < 0)
10988                 break;
10989 
10990         #ifndef NO_PKCS7_STREAM
10991             tmpIdx = idx;
10992         #endif
10993             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_2);
10994             FALL_THROUGH;
10995 
10996         case WC_PKCS7_AUTHENV_2:
10997         #ifndef NO_PKCS7_STREAM
10998             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
10999                             MAX_VERSION_SZ + ASN_TAG_SZ, &pkiMsg, &idx)) != 0) {
11000                 break;
11001             }
11002         #endif
11003         #ifdef WOLFSSL_SMALL_STACK
11004             decryptedKey = (byte*)XMALLOC(MAX_ENCRYPTED_KEY_SZ, pkcs7->heap,
11005                                                                DYNAMIC_TYPE_PKCS7);
11006             if (decryptedKey == NULL) {
11007                 ret = MEMORY_E;
11008                 break;
11009             }
11010         #ifndef NO_PKCS7_STREAM
11011             pkcs7->stream->key = decryptedKey;
11012         #endif
11013         #endif
11014             FALL_THROUGH;
11015 
11016         case WC_PKCS7_DECRYPT_KTRI:
11017         case WC_PKCS7_DECRYPT_KTRI_2:
11018         case WC_PKCS7_DECRYPT_KTRI_3:
11019         case WC_PKCS7_DECRYPT_KARI:
11020         case WC_PKCS7_DECRYPT_KEKRI:
11021         case WC_PKCS7_DECRYPT_PWRI:
11022         case WC_PKCS7_DECRYPT_ORI:
11023 
11024             decryptedKeySz = MAX_ENCRYPTED_KEY_SZ;
11025         #ifdef WOLFSSL_SMALL_STACK
11026             #ifndef NO_PKCS7_STREAM
11027             decryptedKey = pkcs7->stream->key;
11028             #endif
11029         #endif
11030 
11031             ret = wc_PKCS7_DecryptRecipientInfos(pkcs7, in, inSz, &idx,
11032                                                 decryptedKey, &decryptedKeySz,
11033                                                 &recipFound);
11034             if (ret != 0) {
11035                 break;
11036             }
11037 
11038             if (recipFound == 0) {
11039                 WOLFSSL_MSG("No recipient found in envelopedData that matches input");
11040                 ret = PKCS7_RECIP_E;
11041                 break;
11042             }
11043 
11044         #ifndef NO_PKCS7_STREAM
11045             tmpIdx = idx;
11046         #endif
11047             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_3);
11048             FALL_THROUGH;
11049 
11050         case WC_PKCS7_AUTHENV_3:
11051         #ifndef NO_PKCS7_STREAM
11052             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
11053                             MAX_ALGO_SZ + MAX_ALGO_SZ + ASN_TAG_SZ,
11054                             &pkiMsg, &idx)) != 0) {
11055                 break;
11056             }
11057 
11058             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
11059                 in, inSz);
11060             if (rc < 0) {
11061                 ret = (int)rc;
11062                 break;
11063             }
11064             pkiMsgSz = (word32)rc;
11065         #endif
11066 
11067             /* remove EncryptedContentInfo */
11068             if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
11069                 ret = ASN_PARSE_E;
11070             }
11071 
11072             if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
11073                         pkiMsgSz) < 0) {
11074                 ret = ASN_PARSE_E;
11075             }
11076 
11077             if (ret == 0 && GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
11078                         pkiMsgSz) < 0) {
11079                 ret = ASN_PARSE_E;
11080             }
11081 
11082             blockKeySz = wc_PKCS7_GetOIDKeySize(encOID);
11083             if (ret == 0 && blockKeySz < 0) {
11084                 ret = blockKeySz;
11085             }
11086 
11087             expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID);
11088             if (ret == 0 && expBlockSz < 0) {
11089                 ret = expBlockSz;
11090             }
11091 
11092             /* get nonce, stored in OPTIONAL parameter of AlgoID */
11093             if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
11094                 ret = ASN_PARSE_E;
11095             }
11096 
11097             if (ret == 0 && tag != ASN_OCTET_STRING) {
11098                 ret = ASN_PARSE_E;
11099             }
11100 
11101             if (ret < 0)
11102                 break;
11103 
11104         #ifndef NO_PKCS7_STREAM
11105             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11106                 break;
11107             }
11108             wc_PKCS7_StreamStoreVar(pkcs7, encOID, blockKeySz, 0);
11109         #endif
11110             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_4);
11111             FALL_THROUGH;
11112 
11113         case WC_PKCS7_AUTHENV_4:
11114 
11115         #ifndef NO_PKCS7_STREAM
11116             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
11117                             MAX_VERSION_SZ + ASN_TAG_SZ + MAX_LENGTH_SZ,
11118                             &pkiMsg, &idx)) != 0) {
11119                 break;
11120             }
11121 
11122             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
11123                     inSz);
11124             if (rc < 0) {
11125                 ret = (int)rc;
11126                 break;
11127             }
11128             pkiMsgSz = (word32)rc;
11129         #endif
11130             if (ret == 0 && GetLength(pkiMsg, &idx, &nonceSz, pkiMsgSz) < 0) {
11131                 ret = ASN_PARSE_E;
11132             }
11133 
11134             if (ret == 0 && nonceSz > (int)sizeof(nonce)) {
11135                 WOLFSSL_MSG("AuthEnvelopedData nonce too large for buffer");
11136                 ret = ASN_PARSE_E;
11137             }
11138 
11139             if (ret == 0) {
11140                 XMEMCPY(nonce, &pkiMsg[idx], nonceSz);
11141                 idx += nonceSz;
11142             }
11143 
11144             /* get mac size, also stored in OPTIONAL parameter of AlgoID */
11145             if (ret == 0 && GetMyVersion(pkiMsg, &idx, &macSz, pkiMsgSz) < 0) {
11146                 ret = ASN_PARSE_E;
11147             }
11148 
11149             if (ret == 0) {
11150                 explicitOctet = 0;
11151                 localIdx = idx;
11152                 if (GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 &&
11153                         tag == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0))
11154                     explicitOctet = 1;
11155 
11156                 /* read encryptedContent, cont[0] */
11157                 ret = GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz);
11158             }
11159 
11160             if (ret == 0 &&
11161                     tag != (ASN_CONTEXT_SPECIFIC | 0) &&
11162                     tag != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) {
11163                 ret = ASN_PARSE_E;
11164             }
11165 
11166             if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz,
11167                         pkiMsgSz) <= 0) {
11168                 ret = ASN_PARSE_E;
11169             }
11170 
11171             if (explicitOctet) {
11172                 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
11173                     ret = ASN_PARSE_E;
11174                 }
11175                 if (ret == 0 && tag != ASN_OCTET_STRING) {
11176                     ret = ASN_PARSE_E;
11177                 }
11178 
11179                 if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz,
11180                             pkiMsgSz) <= 0) {
11181                     ret = ASN_PARSE_E;
11182                 }
11183             }
11184 
11185             if (ret < 0)
11186                 break;
11187 
11188         #ifndef NO_PKCS7_STREAM
11189             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11190                 break;
11191             }
11192 
11193             /* store nonce for later */
11194             if (nonceSz > 0) {
11195                 pkcs7->stream->nonceSz = nonceSz;
11196                 pkcs7->stream->nonce = (byte*)XMALLOC(nonceSz, pkcs7->heap,
11197                         DYNAMIC_TYPE_PKCS7);
11198                 if (pkcs7->stream->nonce == NULL) {
11199                     ret = MEMORY_E;
11200                     break;
11201                 }
11202                 else {
11203                     XMEMCPY(pkcs7->stream->nonce, nonce, nonceSz);
11204                 }
11205             }
11206 
11207             pkcs7->stream->expected = encryptedContentSz;
11208             wc_PKCS7_StreamStoreVar(pkcs7, encOID, blockKeySz,
11209                     encryptedContentSz);
11210         #endif
11211 
11212             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_5);
11213             FALL_THROUGH;
11214 
11215         case WC_PKCS7_AUTHENV_5:
11216         #ifndef NO_PKCS7_STREAM
11217             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
11218                             ASN_TAG_SZ + ASN_TAG_SZ + pkcs7->stream->expected,
11219                             &pkiMsg, &idx)) != 0) {
11220                 break;
11221             }
11222 
11223             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
11224                     inSz);
11225             if (rc < 0) {
11226                 ret = (int)rc;
11227                 break;
11228             }
11229             pkiMsgSz = (word32)rc;
11230 
11231             encryptedContentSz = pkcs7->stream->expected;
11232         #endif
11233 
11234             encryptedContent = (byte*)XMALLOC(encryptedContentSz, pkcs7->heap,
11235                                                                DYNAMIC_TYPE_PKCS7);
11236             if (ret == 0 && encryptedContent == NULL) {
11237                 ret = MEMORY_E;
11238             }
11239 
11240             if (ret == 0) {
11241                 XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz);
11242                 idx += encryptedContentSz;
11243             }
11244         #ifndef NO_PKCS7_STREAM
11245                 pkcs7->stream->bufferPt = encryptedContent;
11246         #endif
11247 
11248             /* may have IMPLICIT [1] authenticatedAttributes */
11249             localIdx = idx;
11250             if (ret == 0 && GetASNTag(pkiMsg, &localIdx, &tag, pkiMsgSz) == 0 &&
11251                     tag == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) {
11252                 encodedAttribIdx = idx;
11253                 encodedAttribs = pkiMsg + idx;
11254                 idx++;
11255 
11256                 if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
11257                     ret = ASN_PARSE_E;
11258             #ifndef NO_PKCS7_STREAM
11259                 pkcs7->stream->expected = length;
11260             #endif
11261                 encodedAttribSz = length + (idx - encodedAttribIdx);
11262 
11263                 if (ret != 0)
11264                     break;
11265 
11266             #ifndef NO_PKCS7_STREAM
11267                 if (encodedAttribSz > 0) {
11268                     pkcs7->stream->aadSz = encodedAttribSz;
11269                     pkcs7->stream->aad = (byte*)XMALLOC(encodedAttribSz,
11270                             pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11271                     if (pkcs7->stream->aad == NULL) {
11272                         ret = MEMORY_E;
11273                         break;
11274                     }
11275                     else {
11276                         XMEMCPY(pkcs7->stream->aad, encodedAttribs,
11277                                 (idx - encodedAttribIdx));
11278                     }
11279                 }
11280 
11281                 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11282                     break;
11283                 }
11284             #endif
11285                 wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRB);
11286             }
11287             else {
11288             #ifndef NO_PKCS7_STREAM
11289                 if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11290                     break;
11291                 }
11292             #endif
11293                 goto authenv_atrbend; /* jump over attribute cases */
11294             }
11295             FALL_THROUGH;
11296 
11297         case WC_PKCS7_AUTHENV_ATRB:
11298     #ifndef NO_PKCS7_STREAM
11299             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
11300                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
11301                 return ret;
11302             }
11303 
11304             length = pkcs7->stream->expected;
11305             encodedAttribs = pkcs7->stream->aad;
11306     #else
11307             length = 0;
11308     #endif
11309 
11310             /* save pointer and length */
11311             authAttrib = &pkiMsg[idx];
11312             authAttribSz = length;
11313 
11314             if (ret == 0 && wc_PKCS7_ParseAttribs(pkcs7, authAttrib, authAttribSz) < 0) {
11315                 WOLFSSL_MSG("Error parsing authenticated attributes");
11316                 ret = ASN_PARSE_E;
11317                 break;
11318             }
11319 
11320             idx += length;
11321 
11322     #ifndef NO_PKCS7_STREAM
11323             if (encodedAttribSz > 0) {
11324                 XMEMCPY(pkcs7->stream->aad + (encodedAttribSz - length),
11325                         authAttrib, authAttribSz);
11326             }
11327             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11328                 break;
11329             }
11330 
11331     #endif
11332             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_ATRBEND);
11333             FALL_THROUGH;
11334 
11335 authenv_atrbend:
11336         case WC_PKCS7_AUTHENV_ATRBEND:
11337         #ifndef NO_PKCS7_STREAM
11338             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_LENGTH_SZ +
11339                             ASN_TAG_SZ, &pkiMsg, &idx)) != 0) {
11340                 return ret;
11341             }
11342 
11343             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK,
11344                 in, inSz);
11345             if (rc < 0) {
11346                 ret = (int)rc;
11347                 break;
11348             }
11349             pkiMsgSz = (word32)rc;
11350 
11351             if (pkcs7->stream->aadSz > 0) {
11352                 encodedAttribSz = pkcs7->stream->aadSz;
11353                 encodedAttribs  = pkcs7->stream->aad;
11354             }
11355         #endif
11356 
11357 
11358             /* get authTag OCTET STRING */
11359             if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0) {
11360                 ret = ASN_PARSE_E;
11361             }
11362             if (ret == 0 && tag != ASN_OCTET_STRING) {
11363                 ret = ASN_PARSE_E;
11364             }
11365 
11366             if (ret == 0 && GetLength(pkiMsg, &idx, &authTagSz, pkiMsgSz) < 0) {
11367                 ret = ASN_PARSE_E;
11368             }
11369 
11370             if (ret == 0 && authTagSz > (int)sizeof(authTag)) {
11371                 WOLFSSL_MSG("AuthEnvelopedData authTag too large for buffer");
11372                 ret = ASN_PARSE_E;
11373             }
11374 
11375             if (ret == 0) {
11376                 XMEMCPY(authTag, &pkiMsg[idx], authTagSz);
11377                 idx += authTagSz;
11378             }
11379 
11380             if (ret == 0 && authAttrib != NULL) {
11381                 /* temporarily swap authAttribs byte[0] to SET OF instead of
11382                  * IMPLICIT [1], for aad calculation */
11383                 authAttribSetByte = encodedAttribs[0];
11384 
11385                 encodedAttribs[0] = ASN_SET | ASN_CONSTRUCTED;
11386             }
11387 
11388             if (ret < 0)
11389                 break;
11390 
11391         #ifndef NO_PKCS7_STREAM
11392             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11393                 break;
11394             }
11395             pkcs7->stream->expected = (pkcs7->stream->maxLen -
11396                 pkcs7->stream->totalRd) + pkcs7->stream->length;
11397 
11398 
11399             /* store tag for later */
11400             if (authTagSz > 0) {
11401                 pkcs7->stream->tagSz = authTagSz;
11402                 pkcs7->stream->tag = (byte*)XMALLOC(authTagSz, pkcs7->heap,
11403                         DYNAMIC_TYPE_PKCS7);
11404                 if (pkcs7->stream->tag == NULL) {
11405                     ret = MEMORY_E;
11406                     break;
11407                 }
11408                 else {
11409                     XMEMCPY(pkcs7->stream->tag, authTag, authTagSz);
11410                 }
11411             }
11412 
11413         #endif
11414             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_AUTHENV_6);
11415             FALL_THROUGH;
11416 
11417         case WC_PKCS7_AUTHENV_6:
11418         #ifndef NO_PKCS7_STREAM
11419             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
11420                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
11421                 break;
11422             }
11423 
11424             /* restore all variables needed */
11425             if (pkcs7->stream->nonceSz > 0) {
11426                 nonceSz = pkcs7->stream->nonceSz;
11427                 if (nonceSz > GCM_NONCE_MID_SZ) {
11428                     WOLFSSL_MSG("PKCS7 saved nonce is too large");
11429                     ret = BUFFER_E;
11430                     break;
11431                 }
11432                 else {
11433                     XMEMCPY(nonce, pkcs7->stream->nonce, nonceSz);
11434                 }
11435             }
11436 
11437             if (pkcs7->stream->tagSz > 0) {
11438                 authTagSz = pkcs7->stream->tagSz;
11439                 if (authTagSz > AES_BLOCK_SIZE) {
11440                     WOLFSSL_MSG("PKCS7 saved tag is too large");
11441                     ret = BUFFER_E;
11442                     break;
11443                 }
11444                 else {
11445                     XMEMCPY(authTag, pkcs7->stream->tag, authTagSz);
11446                 }
11447             }
11448 
11449             if (pkcs7->stream->aadSz > 0) {
11450                 encodedAttribSz = pkcs7->stream->aadSz;
11451                 encodedAttribs  = pkcs7->stream->aad;
11452             }
11453 
11454             wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz,
11455                                   &encryptedContentSz);
11456             encryptedContent   = pkcs7->stream->bufferPt;
11457         #ifdef WOLFSSL_SMALL_STACK
11458             decryptedKey = pkcs7->stream->key;
11459         #endif
11460         #endif
11461 
11462             /* decrypt encryptedContent */
11463             ret = wc_PKCS7_DecryptContent(pkcs7, encOID, decryptedKey,
11464                     blockKeySz, nonce, nonceSz, encodedAttribs, encodedAttribSz,
11465                     authTag, authTagSz, encryptedContent, encryptedContentSz,
11466                     encryptedContent);
11467             if (ret != 0) {
11468                 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11469                 return ret;
11470             }
11471 
11472             if (authAttrib != NULL) {
11473                 /* restore authAttrib IMPLICIT [1] */
11474                 encodedAttribs[0] = authAttribSetByte;
11475             }
11476 
11477             /* copy plaintext to output */
11478             XMEMCPY(output, encryptedContent, encryptedContentSz);
11479 
11480             /* free memory, zero out keys */
11481             ForceZero(encryptedContent, encryptedContentSz);
11482             XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11483             ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
11484         #ifdef WOLFSSL_SMALL_STACK
11485             XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11486             decryptedKey = NULL;
11487         #ifdef WOLFSSL_SMALL_STACK
11488             #ifndef NO_PKCS7_STREAM
11489             pkcs7->stream->key = NULL;
11490             #endif
11491         #endif
11492         #endif
11493             ret = encryptedContentSz;
11494         #ifndef NO_PKCS7_STREAM
11495             wc_PKCS7_ResetStream(pkcs7);
11496         #endif
11497             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
11498             break;
11499         default:
11500             WOLFSSL_MSG("Unknown PKCS7 state");
11501             ret = BAD_FUNC_ARG;
11502     }
11503 
11504 #ifdef WOLFSSL_SMALL_STACK
11505     if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) {
11506         if (decryptedKey != NULL) {
11507             ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
11508         }
11509         XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11510     }
11511 #endif
11512 #ifndef NO_PKCS7_STREAM
11513     if (ret != 0 && ret != WC_PKCS7_WANT_READ_E) {
11514         wc_PKCS7_ResetStream(pkcs7);
11515     }
11516 #endif
11517 
11518     return ret;
11519 
11520 #else
11521     WOLFSSL_MSG("AuthEnvelopedData requires AES-GCM or AES-CCM to be enabled");
11522     (void)pkcs7;
11523     (void)in;
11524     (void)inSz;
11525     (void)output;
11526     (void)outputSz;
11527 
11528     return NOT_COMPILED_IN;
11529 #endif /* HAVE_AESGCM | HAVE_AESCCM */
11530 }
11531 
11532 
11533 #ifndef NO_PKCS7_ENCRYPTED_DATA
11534 
11535 /* build PKCS#7 encryptedData content type, return encrypted size */
11536 int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz)
11537 {
11538     int ret, idx = 0;
11539     int totalSz, padSz, encryptedOutSz;
11540 
11541     int contentInfoSeqSz, outerContentTypeSz, outerContentSz;
11542     byte contentInfoSeq[MAX_SEQ_SZ];
11543     byte outerContentType[MAX_ALGO_SZ];
11544     byte outerContent[MAX_SEQ_SZ];
11545 
11546     int encDataSeqSz, verSz, blockSz;
11547     byte encDataSeq[MAX_SEQ_SZ];
11548     byte ver[MAX_VERSION_SZ];
11549 
11550     byte* plain = NULL;
11551     byte* encryptedContent = NULL;
11552 
11553     int encContentOctetSz, encContentSeqSz, contentTypeSz;
11554     int contentEncAlgoSz, ivOctetStringSz;
11555     byte encContentSeq[MAX_SEQ_SZ];
11556     byte contentType[MAX_OID_SZ];
11557     byte contentEncAlgo[MAX_ALGO_SZ];
11558     byte tmpIv[MAX_CONTENT_IV_SIZE];
11559     byte ivOctetString[MAX_OCTET_STR_SZ];
11560     byte encContentOctet[MAX_OCTET_STR_SZ];
11561 
11562     byte attribSet[MAX_SET_SZ];
11563     EncodedAttrib* attribs = NULL;
11564     word32 attribsSz;
11565     word32 attribsCount;
11566     word32 attribsSetSz;
11567 
11568     byte* flatAttribs = NULL;
11569 
11570     if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
11571         pkcs7->encryptOID == 0 || pkcs7->encryptionKey == NULL ||
11572         pkcs7->encryptionKeySz == 0)
11573         return BAD_FUNC_ARG;
11574 
11575     if (output == NULL || outputSz == 0)
11576         return BAD_FUNC_ARG;
11577 
11578     if (pkcs7->version == 3) {
11579         verSz = SetMyVersion(0, ver, 0);
11580         outerContentTypeSz = 0;
11581     }
11582     else {
11583         /* outer content type */
11584         ret = wc_SetContentType(ENCRYPTED_DATA, outerContentType,
11585                                 sizeof(outerContentType));
11586         if (ret < 0)
11587             return ret;
11588 
11589         outerContentTypeSz = ret;
11590 
11591         /* version, 2 if unprotectedAttrs present, 0 if absent */
11592         if (pkcs7->unprotectedAttribsSz > 0) {
11593             verSz = SetMyVersion(2, ver, 0);
11594         } else {
11595             verSz = SetMyVersion(0, ver, 0);
11596         }
11597     }
11598 
11599     /* EncryptedContentInfo */
11600     ret = wc_SetContentType(pkcs7->contentOID, contentType,
11601                             sizeof(contentType));
11602     if (ret < 0)
11603         return ret;
11604 
11605     contentTypeSz = ret;
11606 
11607     /* allocate encrypted content buffer, do PKCS#7 padding */
11608     blockSz = wc_PKCS7_GetOIDBlockSize(pkcs7->encryptOID);
11609     if (blockSz < 0)
11610         return blockSz;
11611 
11612     padSz = wc_PKCS7_GetPadSize(pkcs7->contentSz, blockSz);
11613     if (padSz < 0)
11614         return padSz;
11615 
11616     encryptedOutSz = pkcs7->contentSz + padSz;
11617 
11618     plain = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap,
11619                            DYNAMIC_TYPE_PKCS7);
11620     if (plain == NULL)
11621         return MEMORY_E;
11622 
11623     ret = wc_PKCS7_PadData(pkcs7->content, pkcs7->contentSz, plain,
11624                            encryptedOutSz, blockSz);
11625     if (ret < 0) {
11626         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11627         return ret;
11628     }
11629 
11630     encryptedContent = (byte*)XMALLOC(encryptedOutSz, pkcs7->heap,
11631                                       DYNAMIC_TYPE_PKCS7);
11632     if (encryptedContent == NULL) {
11633         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11634         return MEMORY_E;
11635     }
11636 
11637     /* put together IV OCTET STRING */
11638     ivOctetStringSz = SetOctetString(blockSz, ivOctetString);
11639 
11640     /* build up ContentEncryptionAlgorithmIdentifier sequence,
11641        adding (ivOctetStringSz + blockSz) for IV OCTET STRING */
11642     contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo,
11643                                  oidBlkType, ivOctetStringSz + blockSz);
11644     if (contentEncAlgoSz == 0) {
11645         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11646         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11647         return BAD_FUNC_ARG;
11648     }
11649 
11650     /* encrypt content */
11651     WOLFSSL_MSG("Encrypting the content");
11652     ret = wc_PKCS7_GenerateBlock(pkcs7, NULL, tmpIv, blockSz);
11653     if (ret != 0) {
11654         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11655         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11656         return ret;
11657     }
11658 
11659     ret = wc_PKCS7_EncryptContent(pkcs7->encryptOID, pkcs7->encryptionKey,
11660             pkcs7->encryptionKeySz, tmpIv, blockSz, NULL, 0, NULL, 0,
11661             plain, encryptedOutSz, encryptedContent);
11662     if (ret != 0) {
11663         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11664         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11665         return ret;
11666     }
11667 
11668     encContentOctetSz = SetImplicit(ASN_OCTET_STRING, 0,
11669                                     encryptedOutSz, encContentOctet);
11670 
11671     encContentSeqSz = SetSequence(contentTypeSz + contentEncAlgoSz +
11672                                   ivOctetStringSz + blockSz +
11673                                   encContentOctetSz + encryptedOutSz,
11674                                   encContentSeq);
11675 
11676     /* optional UnprotectedAttributes */
11677     if (pkcs7->unprotectedAttribsSz != 0) {
11678 
11679         if (pkcs7->unprotectedAttribs == NULL) {
11680             XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11681             XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11682             return BAD_FUNC_ARG;
11683         }
11684 
11685         attribs = (EncodedAttrib*)XMALLOC(
11686                 sizeof(EncodedAttrib) * pkcs7->unprotectedAttribsSz,
11687                 pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11688         if (attribs == NULL) {
11689             XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11690             XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11691             return MEMORY_E;
11692         }
11693 
11694         attribsCount = pkcs7->unprotectedAttribsSz;
11695         attribsSz = EncodeAttributes(attribs, pkcs7->unprotectedAttribsSz,
11696                                      pkcs7->unprotectedAttribs,
11697                                      pkcs7->unprotectedAttribsSz);
11698 
11699         flatAttribs = (byte*)XMALLOC(attribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11700         if (flatAttribs == NULL) {
11701             XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11702             XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11703             XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11704             return MEMORY_E;
11705         }
11706 
11707         FlattenAttributes(pkcs7, flatAttribs, attribs, attribsCount);
11708         attribsSetSz = SetImplicit(ASN_SET, 1, attribsSz, attribSet);
11709 
11710     } else {
11711         attribsSz = 0;
11712         attribsSetSz = 0;
11713     }
11714 
11715     /* keep track of sizes for outer wrapper layering */
11716     totalSz = verSz + encContentSeqSz + contentTypeSz + contentEncAlgoSz +
11717               ivOctetStringSz + blockSz + encContentOctetSz + encryptedOutSz +
11718               attribsSz + attribsSetSz;
11719 
11720     /* EncryptedData */
11721     encDataSeqSz = SetSequence(totalSz, encDataSeq);
11722     totalSz += encDataSeqSz;
11723 
11724     if (pkcs7->version != 3) {
11725         /* outer content */
11726         outerContentSz = SetExplicit(0, totalSz, outerContent);
11727         totalSz += outerContentTypeSz;
11728         totalSz += outerContentSz;
11729         /* ContentInfo */
11730         contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
11731         totalSz += contentInfoSeqSz;
11732     } else {
11733         contentInfoSeqSz = 0;
11734         outerContentSz = 0;
11735     }
11736 
11737     if (totalSz > (int)outputSz) {
11738         WOLFSSL_MSG("PKCS#7 output buffer too small");
11739         if (pkcs7->unprotectedAttribsSz != 0) {
11740             XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11741             XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11742         }
11743         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11744         XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11745         return BUFFER_E;
11746     }
11747 
11748     XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
11749     idx += contentInfoSeqSz;
11750     XMEMCPY(output + idx, outerContentType, outerContentTypeSz);
11751     idx += outerContentTypeSz;
11752     XMEMCPY(output + idx, outerContent, outerContentSz);
11753     idx += outerContentSz;
11754     XMEMCPY(output + idx, encDataSeq, encDataSeqSz);
11755     idx += encDataSeqSz;
11756     XMEMCPY(output + idx, ver, verSz);
11757     idx += verSz;
11758     XMEMCPY(output + idx, encContentSeq, encContentSeqSz);
11759     idx += encContentSeqSz;
11760     XMEMCPY(output + idx, contentType, contentTypeSz);
11761     idx += contentTypeSz;
11762     XMEMCPY(output + idx, contentEncAlgo, contentEncAlgoSz);
11763     idx += contentEncAlgoSz;
11764     XMEMCPY(output + idx, ivOctetString, ivOctetStringSz);
11765     idx += ivOctetStringSz;
11766     XMEMCPY(output + idx, tmpIv, blockSz);
11767     idx += blockSz;
11768     XMEMCPY(output + idx, encContentOctet, encContentOctetSz);
11769     idx += encContentOctetSz;
11770     XMEMCPY(output + idx, encryptedContent, encryptedOutSz);
11771     idx += encryptedOutSz;
11772 
11773     if (pkcs7->unprotectedAttribsSz != 0) {
11774         XMEMCPY(output + idx, attribSet, attribsSetSz);
11775         idx += attribsSetSz;
11776         XMEMCPY(output + idx, flatAttribs, attribsSz);
11777         idx += attribsSz;
11778         XFREE(attribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11779         XFREE(flatAttribs, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11780     }
11781 
11782     XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11783     XFREE(plain, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
11784 
11785     return idx;
11786 }
11787 
11788 
11789 /* decode and store unprotected attributes in PKCS7->decodedAttrib. Return
11790  * 0 on success, negative on error. User must call wc_PKCS7_Free(). */
11791 static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg,
11792                                              word32 pkiMsgSz, word32* inOutIdx)
11793 {
11794     int ret, attribLen;
11795     word32 idx;
11796     byte tag;
11797 
11798     if (pkcs7 == NULL || pkiMsg == NULL ||
11799         pkiMsgSz == 0 || inOutIdx == NULL)
11800         return BAD_FUNC_ARG;
11801 
11802     idx = *inOutIdx;
11803 
11804     if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
11805         return ASN_PARSE_E;
11806 
11807     if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1))
11808         return ASN_PARSE_E;
11809 
11810     if (GetLength(pkiMsg, &idx, &attribLen, pkiMsgSz) < 0)
11811         return ASN_PARSE_E;
11812 
11813     /* loop through attributes */
11814     if ((ret = wc_PKCS7_ParseAttribs(pkcs7, pkiMsg + idx, attribLen)) < 0) {
11815         return ret;
11816     }
11817 
11818     *inOutIdx = idx;
11819 
11820     return 0;
11821 }
11822 
11823 
11824 /* unwrap and decrypt PKCS#7/CMS encrypted-data object, returned decoded size */
11825 int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* in, word32 inSz,
11826                                  byte* output, word32 outputSz)
11827 {
11828     int ret = 0, version, length = 0, haveAttribs = 0;
11829     word32 idx = 0;
11830 
11831 #ifndef NO_PKCS7_STREAM
11832     word32 tmpIdx = 0;
11833     long rc;
11834 #endif
11835     word32 contentType, encOID;
11836 
11837     int expBlockSz = 0;
11838     byte tmpIvBuf[MAX_CONTENT_IV_SIZE];
11839     byte *tmpIv = tmpIvBuf;
11840 
11841     int encryptedContentSz = 0;
11842     byte padLen;
11843     byte* encryptedContent = NULL;
11844 
11845     byte* pkiMsg = in;
11846     word32 pkiMsgSz = inSz;
11847     byte  tag;
11848 
11849     if (pkcs7 == NULL ||
11850             ((pkcs7->encryptionKey == NULL || pkcs7->encryptionKeySz == 0) &&
11851               pkcs7->decryptionCb == NULL))
11852         return BAD_FUNC_ARG;
11853 
11854     if (pkiMsg == NULL || pkiMsgSz == 0 ||
11855         output == NULL || outputSz == 0)
11856         return BAD_FUNC_ARG;
11857 
11858 #ifndef NO_PKCS7_STREAM
11859     (void)tmpIv; /* help out static analysis */
11860     if (pkcs7->stream == NULL) {
11861         if ((ret = wc_PKCS7_CreateStream(pkcs7)) != 0) {
11862             return ret;
11863         }
11864     }
11865 #endif
11866 
11867     switch (pkcs7->state) {
11868         case WC_PKCS7_START:
11869 #ifndef NO_PKCS7_STREAM
11870             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ +
11871                             MAX_ALGO_SZ, &pkiMsg, &idx)) != 0) {
11872                 return ret;
11873             }
11874 
11875             rc  = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz);
11876             if (rc < 0) {
11877                 ret = (int)rc;
11878                 break;
11879             }
11880             pkiMsgSz = (word32)rc;
11881 #endif
11882 
11883             if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
11884                 ret = ASN_PARSE_E;
11885 
11886             if (pkcs7->version != 3) { /* ContentInfo not in firmware bundles */
11887                 /* read past ContentInfo, verify type is encrypted-data */
11888                 if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
11889                             pkiMsgSz) < 0)
11890                     ret = ASN_PARSE_E;
11891 
11892                 if (ret == 0 && contentType != ENCRYPTED_DATA) {
11893                     WOLFSSL_MSG("PKCS#7 input not of type EncryptedData");
11894                     ret = PKCS7_OID_E;
11895                 }
11896             }
11897             if (ret != 0) break;
11898 #ifndef NO_PKCS7_STREAM
11899             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11900                 break;
11901             }
11902 #endif
11903             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE2);
11904             FALL_THROUGH;
11905             /* end of stage 1 */
11906 
11907         case WC_PKCS7_STAGE2:
11908 #ifndef NO_PKCS7_STREAM
11909             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
11910                             MAX_LENGTH_SZ + MAX_SEQ_SZ + ASN_TAG_SZ, &pkiMsg,
11911                             &idx)) != 0) {
11912                 return ret;
11913             }
11914 
11915             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
11916                     inSz);
11917             if (rc < 0) {
11918                 ret = (int)rc;
11919                 break;
11920             }
11921             pkiMsgSz = (word32)rc;
11922 #endif
11923             if (pkcs7->version != 3) {
11924                 if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
11925                     ret = ASN_PARSE_E;
11926                 if (ret == 0 && tag !=
11927                         (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
11928                     ret = ASN_PARSE_E;
11929 
11930                 if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
11931                     ret = ASN_PARSE_E;
11932 
11933                 /* remove EncryptedData and version */
11934                 if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
11935                     ret = ASN_PARSE_E;
11936             }
11937 
11938             if (ret != 0) break;
11939 #ifndef NO_PKCS7_STREAM
11940             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11941                 break;
11942             }
11943 #endif
11944             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE3);
11945             FALL_THROUGH;
11946             /* end of stage 2 */
11947 
11948        case WC_PKCS7_STAGE3:
11949 #ifndef NO_PKCS7_STREAM
11950             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
11951                             MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_ALGO_SZ * 2,
11952                             &pkiMsg, &idx)) != 0) {
11953                 return ret;
11954             }
11955 
11956             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
11957                     inSz);
11958             if (rc < 0) {
11959                 ret = (int)rc;
11960                 break;
11961             }
11962             pkiMsgSz = (word32)rc;
11963 #endif
11964             /* get version, check later */
11965             haveAttribs = 0;
11966             if (ret == 0 && GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
11967                 ret = ASN_PARSE_E;
11968 
11969             /* remove EncryptedContentInfo */
11970             if (ret == 0 && GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
11971                 ret = ASN_PARSE_E;
11972 
11973             if (ret == 0 && wc_GetContentType(pkiMsg, &idx, &contentType,
11974                         pkiMsgSz) < 0)
11975                 ret = ASN_PARSE_E;
11976 
11977             if (ret == 0 && (ret = GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType,
11978                         pkiMsgSz)) < 0)
11979                 ret = ASN_PARSE_E;
11980             if (ret == 0 && (expBlockSz = wc_PKCS7_GetOIDBlockSize(encOID)) < 0)
11981                 ret = expBlockSz;
11982 
11983             if (ret != 0) break;
11984 #ifndef NO_PKCS7_STREAM
11985             /* store expBlockSz for later */
11986             pkcs7->stream->varOne = expBlockSz;
11987             pkcs7->stream->varTwo = encOID;
11988 
11989             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
11990                 break;
11991             }
11992 
11993             /* store version for later */
11994             pkcs7->stream->vers = version;
11995 #endif
11996             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE4);
11997             FALL_THROUGH;
11998             /* end of stage 3 */
11999 
12000         /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */
12001        case WC_PKCS7_STAGE4:
12002 #ifndef NO_PKCS7_STREAM
12003             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
12004                             ASN_TAG_SZ + MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) {
12005                 return ret;
12006             }
12007 
12008             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
12009                     inSz);
12010             if (rc < 0) {
12011                 ret = (int)rc;
12012                 break;
12013             }
12014             pkiMsgSz = (word32)rc;
12015 
12016             /* restore saved variables */
12017             expBlockSz = pkcs7->stream->varOne;
12018 #endif
12019             if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
12020                 ret = ASN_PARSE_E;
12021             if (ret == 0 && tag != ASN_OCTET_STRING)
12022                 ret = ASN_PARSE_E;
12023 
12024             if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12025                 ret = ASN_PARSE_E;
12026 
12027             if (ret == 0 && length != expBlockSz) {
12028                 WOLFSSL_MSG("Incorrect IV length, must be of content alg block size");
12029                 ret = ASN_PARSE_E;
12030             }
12031 
12032             if (ret != 0) break;
12033 #ifndef NO_PKCS7_STREAM
12034             /* next chunk of data expected should have the IV */
12035             pkcs7->stream->expected = length;
12036 
12037             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
12038                 break;
12039             }
12040 #endif
12041             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE5);
12042             FALL_THROUGH;
12043             /* end of stage 4 */
12044 
12045        case WC_PKCS7_STAGE5:
12046 #ifndef NO_PKCS7_STREAM
12047             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
12048                             pkcs7->stream->expected + ASN_TAG_SZ +
12049                             MAX_LENGTH_SZ, &pkiMsg, &idx)) != 0) {
12050                 return ret;
12051             }
12052 
12053             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
12054                     inSz);
12055             if (rc < 0) {
12056                 ret = (int)rc;
12057                 break;
12058             }
12059             pkiMsgSz = (word32)rc;
12060 
12061             /* use IV buffer from stream structure */
12062             tmpIv  = pkcs7->stream->tmpIv;
12063             length = pkcs7->stream->expected;
12064 #endif
12065             XMEMCPY(tmpIv, &pkiMsg[idx], length);
12066             idx += length;
12067             /* read encryptedContent, cont[0] */
12068             if (ret == 0 && GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
12069                 ret = ASN_PARSE_E;
12070             if (ret == 0 && tag != (ASN_CONTEXT_SPECIFIC | 0))
12071                 ret = ASN_PARSE_E;
12072 
12073             if (ret == 0 && GetLength(pkiMsg, &idx, &encryptedContentSz,
12074                         pkiMsgSz) <= 0)
12075                 ret = ASN_PARSE_E;
12076 
12077             if (ret < 0)
12078                 break;
12079 #ifndef NO_PKCS7_STREAM
12080             /* next chunk of data should contain encrypted content */
12081             pkcs7->stream->varThree = encryptedContentSz;
12082             if ((ret = wc_PKCS7_StreamEndCase(pkcs7, &tmpIdx, &idx)) != 0) {
12083                 break;
12084             }
12085 
12086             if (pkcs7->stream->totalRd +  encryptedContentSz < pkiMsgSz) {
12087                 pkcs7->stream->flagOne = 1;
12088             }
12089 
12090             pkcs7->stream->expected = (pkcs7->stream->maxLen -
12091                 pkcs7->stream->totalRd) + pkcs7->stream->length;
12092 
12093 #endif
12094             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_STAGE6);
12095             FALL_THROUGH;
12096             /* end of stage 5 */
12097 
12098         case WC_PKCS7_STAGE6:
12099 #ifndef NO_PKCS7_STREAM
12100             if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz,
12101                             pkcs7->stream->expected, &pkiMsg, &idx)) != 0) {
12102                 return ret;
12103             }
12104 
12105             rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in,
12106                     inSz);
12107             if (rc < 0) {
12108                 ret = (int)rc;
12109                 break;
12110             }
12111             pkiMsgSz = (word32)rc;
12112 
12113             /* restore saved variables */
12114             expBlockSz = pkcs7->stream->varOne;
12115             encOID     = pkcs7->stream->varTwo;
12116             encryptedContentSz = pkcs7->stream->varThree;
12117             version    = pkcs7->stream->vers;
12118             tmpIv      = pkcs7->stream->tmpIv;
12119 #else
12120             encOID = 0;
12121 #endif
12122             if (ret == 0 && (encryptedContent = (byte*)XMALLOC(
12123                 encryptedContentSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7)) == NULL) {
12124                 ret = MEMORY_E;
12125                 break;
12126             }
12127 
12128             if (ret == 0) {
12129                 XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz);
12130                 idx += encryptedContentSz;
12131 
12132                 /* decrypt encryptedContent */
12133                 ret = wc_PKCS7_DecryptContent(pkcs7, encOID,
12134                             pkcs7->encryptionKey, pkcs7->encryptionKeySz, tmpIv,
12135                             expBlockSz, NULL, 0, NULL, 0, encryptedContent,
12136                             encryptedContentSz, encryptedContent);
12137                 if (ret != 0) {
12138                     XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12139                 }
12140             }
12141 
12142             if (ret == 0) {
12143                 padLen = encryptedContent[encryptedContentSz-1];
12144 
12145                 if (padLen > encryptedContentSz) {
12146                     WOLFSSL_MSG("Bad padding size found");
12147                     ret = BUFFER_E;
12148                     XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12149                     break;
12150                 }
12151 
12152                 /* copy plaintext to output */
12153                 XMEMCPY(output, encryptedContent, encryptedContentSz - padLen);
12154 
12155                 /* get implicit[1] unprotected attributes, optional */
12156                 wc_PKCS7_FreeDecodedAttrib(pkcs7->decodedAttrib, pkcs7->heap);
12157                 pkcs7->decodedAttrib = NULL;
12158             #ifndef NO_PKCS7_STREAM
12159                 if (pkcs7->stream->flagOne)
12160             #else
12161                 if (idx < pkiMsgSz)
12162             #endif
12163                 {
12164                     haveAttribs = 1;
12165 
12166                     ret = wc_PKCS7_DecodeUnprotectedAttributes(pkcs7, pkiMsg,
12167                                                        pkiMsgSz, &idx);
12168                     if (ret != 0) {
12169                         ForceZero(encryptedContent, encryptedContentSz);
12170                         XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12171                         ret = ASN_PARSE_E;
12172                     }
12173                 }
12174             }
12175 
12176             if (ret == 0) {
12177                 ForceZero(encryptedContent, encryptedContentSz);
12178                 XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12179 
12180                 /* go back and check the version now that attribs have been processed */
12181                 if (pkcs7->version == 3 && version != 0) {
12182                     WOLFSSL_MSG("Wrong PKCS#7 FirmwareEncryptedData version");
12183                     return ASN_VERSION_E;
12184                 }
12185 
12186                 if (pkcs7->version != 3 &&
12187                    ((haveAttribs == 0 && version != 0) ||
12188                     (haveAttribs == 1 && version != 2))) {
12189                     WOLFSSL_MSG("Wrong PKCS#7 EncryptedData version");
12190                     return ASN_VERSION_E;
12191                 }
12192                 ret = encryptedContentSz - padLen;
12193             }
12194 
12195             if (ret != 0) break;
12196         #ifndef NO_PKCS7_STREAM
12197             wc_PKCS7_ResetStream(pkcs7);
12198         #endif
12199             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
12200             break;
12201 
12202         default:
12203             WOLFSSL_MSG("Error in unknown PKCS#7 Decode Encrypted Data state");
12204             return BAD_STATE_E;
12205     }
12206 
12207     if (ret != 0) {
12208     #ifndef NO_PKCS7_STREAM
12209         /* restart in error case */
12210         wc_PKCS7_ResetStream(pkcs7);
12211     #endif
12212         wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
12213     }
12214     return ret;
12215 }
12216 
12217 
12218 /* Function to set callback during decryption, this overrides the default
12219  * decryption function and can be used for choosing a key at run time based
12220  * on the parsed bundle so far.
12221  * returns 0 on success
12222  */
12223 int wc_PKCS7_SetDecodeEncryptedCb(PKCS7* pkcs7,
12224         CallbackDecryptContent decryptionCb)
12225 {
12226     if (pkcs7 != NULL) {
12227         pkcs7->decryptionCb = decryptionCb;
12228     }
12229     return 0;
12230 }
12231 
12232 
12233 /* Set an optional user context that gets passed to callback
12234  * returns 0 on success
12235  */
12236 int wc_PKCS7_SetDecodeEncryptedCtx(PKCS7* pkcs7, void* ctx)
12237 {
12238     if (pkcs7 != NULL) {
12239         pkcs7->decryptionCtx = ctx;
12240     }
12241     return 0;
12242 }
12243 #endif /* NO_PKCS7_ENCRYPTED_DATA */
12244 
12245 #if defined(HAVE_LIBZ) && !defined(NO_PKCS7_COMPRESSED_DATA)
12246 
12247 /* build PKCS#7 compressedData content type, return encrypted size */
12248 int wc_PKCS7_EncodeCompressedData(PKCS7* pkcs7, byte* output, word32 outputSz)
12249 {
12250     byte contentInfoSeq[MAX_SEQ_SZ];
12251     byte contentInfoTypeOid[MAX_OID_SZ];
12252     byte contentInfoContentSeq[MAX_SEQ_SZ]; /* EXPLICIT [0] */
12253     byte compressedDataSeq[MAX_SEQ_SZ];
12254     byte cmsVersion[MAX_VERSION_SZ];
12255     byte compressAlgId[MAX_ALGO_SZ];
12256     byte encapContentInfoSeq[MAX_SEQ_SZ];
12257     byte contentTypeOid[MAX_OID_SZ];
12258     byte contentSeq[MAX_SEQ_SZ];            /* EXPLICIT [0] */
12259     byte contentOctetStr[MAX_OCTET_STR_SZ];
12260 
12261     int ret;
12262     word32 totalSz, idx;
12263     word32 contentInfoSeqSz, contentInfoContentSeqSz, contentInfoTypeOidSz;
12264     word32 compressedDataSeqSz, cmsVersionSz, compressAlgIdSz;
12265     word32 encapContentInfoSeqSz, contentTypeOidSz, contentSeqSz;
12266     word32 contentOctetStrSz;
12267 
12268     byte* compressed;
12269     word32 compressedSz;
12270 
12271     if (pkcs7 == NULL || pkcs7->content == NULL || pkcs7->contentSz == 0 ||
12272         output == NULL || outputSz == 0) {
12273         return BAD_FUNC_ARG;
12274     }
12275 
12276     /* allocate space for compressed content. The libz code says the compressed
12277      * buffer should be srcSz + 0.1% + 12. */
12278     compressedSz = (pkcs7->contentSz + (word32)(pkcs7->contentSz * 0.001) + 12);
12279     compressed = (byte*)XMALLOC(compressedSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12280     if (compressed == NULL) {
12281         WOLFSSL_MSG("Error allocating memory for CMS compressed content");
12282         return MEMORY_E;
12283     }
12284 
12285     /* compress content */
12286     ret = wc_Compress(compressed, compressedSz, pkcs7->content,
12287                       pkcs7->contentSz, 0);
12288     if (ret < 0) {
12289         XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12290         return ret;
12291     }
12292     compressedSz = (word32)ret;
12293 
12294     /* eContent OCTET STRING, working backwards */
12295     contentOctetStrSz = SetOctetString(compressedSz, contentOctetStr);
12296     totalSz = contentOctetStrSz + compressedSz;
12297 
12298     /* EXPLICIT [0] eContentType */
12299     contentSeqSz = SetExplicit(0, totalSz, contentSeq);
12300     totalSz += contentSeqSz;
12301 
12302     /* eContentType OBJECT IDENTIFIER */
12303     ret = wc_SetContentType(pkcs7->contentOID, contentTypeOid,
12304                             sizeof(contentTypeOid));
12305     if (ret < 0) {
12306         XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12307         return ret;
12308     }
12309 
12310     contentTypeOidSz = ret;
12311     totalSz += contentTypeOidSz;
12312 
12313     /* EncapsulatedContentInfo SEQUENCE */
12314     encapContentInfoSeqSz = SetSequence(totalSz, encapContentInfoSeq);
12315     totalSz += encapContentInfoSeqSz;
12316 
12317     /* compressionAlgorithm AlgorithmIdentifier */
12318     /* Only supports zlib for compression currently:
12319      * id-alg-zlibCompress (1.2.840.113549.1.9.16.3.8) */
12320     compressAlgIdSz = SetAlgoID(ZLIBc, compressAlgId, oidCompressType, 0);
12321     totalSz += compressAlgIdSz;
12322 
12323     /* version */
12324     cmsVersionSz = SetMyVersion(0, cmsVersion, 0);
12325     totalSz += cmsVersionSz;
12326 
12327     /* CompressedData SEQUENCE */
12328     compressedDataSeqSz = SetSequence(totalSz, compressedDataSeq);
12329     totalSz += compressedDataSeqSz;
12330 
12331     /* ContentInfo content EXPLICIT SEQUENCE */
12332     contentInfoContentSeqSz = SetExplicit(0, totalSz, contentInfoContentSeq);
12333     totalSz += contentInfoContentSeqSz;
12334 
12335     /* ContentInfo ContentType (compressedData) */
12336     if (pkcs7->version == 3) {
12337         contentInfoTypeOidSz = 0;
12338     }
12339     else {
12340         ret = wc_SetContentType(COMPRESSED_DATA, contentInfoTypeOid,
12341                                 sizeof(contentInfoTypeOid));
12342         if (ret < 0) {
12343             XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12344             return ret;
12345         }
12346 
12347         contentInfoTypeOidSz = ret;
12348         totalSz += contentInfoTypeOidSz;
12349     }
12350 
12351     /* ContentInfo SEQUENCE */
12352     contentInfoSeqSz = SetSequence(totalSz, contentInfoSeq);
12353     totalSz += contentInfoSeqSz;
12354 
12355     if (outputSz < totalSz) {
12356         XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12357         return BUFFER_E;
12358     }
12359 
12360     idx = 0;
12361     XMEMCPY(output + idx, contentInfoSeq, contentInfoSeqSz);
12362     idx += contentInfoSeqSz;
12363     XMEMCPY(output + idx, contentInfoTypeOid, contentInfoTypeOidSz);
12364     idx += contentInfoTypeOidSz;
12365     XMEMCPY(output + idx, contentInfoContentSeq, contentInfoContentSeqSz);
12366     idx += contentInfoContentSeqSz;
12367     XMEMCPY(output + idx, compressedDataSeq, compressedDataSeqSz);
12368     idx += compressedDataSeqSz;
12369     XMEMCPY(output + idx, cmsVersion, cmsVersionSz);
12370     idx += cmsVersionSz;
12371     XMEMCPY(output + idx, compressAlgId, compressAlgIdSz);
12372     idx += compressAlgIdSz;
12373     XMEMCPY(output + idx, encapContentInfoSeq, encapContentInfoSeqSz);
12374     idx += encapContentInfoSeqSz;
12375     XMEMCPY(output + idx, contentTypeOid, contentTypeOidSz);
12376     idx += contentTypeOidSz;
12377     XMEMCPY(output + idx, contentSeq, contentSeqSz);
12378     idx += contentSeqSz;
12379     XMEMCPY(output + idx, contentOctetStr, contentOctetStrSz);
12380     idx += contentOctetStrSz;
12381     XMEMCPY(output + idx, compressed, compressedSz);
12382     idx += compressedSz;
12383 
12384     XFREE(compressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12385 
12386     return idx;
12387 }
12388 
12389 /* unwrap and decompress PKCS#7/CMS compressedData object,
12390  * returned decoded size */
12391 int wc_PKCS7_DecodeCompressedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz,
12392                                   byte* output, word32 outputSz)
12393 {
12394     int length, version, ret;
12395     word32 idx = 0, algOID, contentType;
12396     byte tag;
12397 
12398     byte* decompressed;
12399     word32 decompressedSz;
12400 
12401     if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 ||
12402         output == NULL || outputSz == 0) {
12403         return BAD_FUNC_ARG;
12404     }
12405 
12406     /* get ContentInfo SEQUENCE */
12407     if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12408         return ASN_PARSE_E;
12409 
12410     if (pkcs7->version != 3) {
12411         /* get ContentInfo contentType */
12412         if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
12413             return ASN_PARSE_E;
12414 
12415         if (contentType != COMPRESSED_DATA)
12416             return ASN_PARSE_E;
12417     }
12418 
12419     /* get ContentInfo content EXPLICIT SEQUENCE */
12420     if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
12421         return ASN_PARSE_E;
12422 
12423     if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
12424         return ASN_PARSE_E;
12425 
12426     if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12427         return ASN_PARSE_E;
12428 
12429     /* get CompressedData SEQUENCE */
12430     if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12431         return ASN_PARSE_E;
12432 
12433     /* get version */
12434     if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
12435         return ASN_PARSE_E;
12436 
12437     if (version != 0) {
12438         WOLFSSL_MSG("CMS CompressedData version MUST be 0, but is not");
12439         return ASN_PARSE_E;
12440     }
12441 
12442     /* get CompressionAlgorithmIdentifier */
12443     if (GetAlgoId(pkiMsg, &idx, &algOID, oidIgnoreType, pkiMsgSz) < 0)
12444         return ASN_PARSE_E;
12445 
12446     /* Only supports zlib for compression currently:
12447      * id-alg-zlibCompress (1.2.840.113549.1.9.16.3.8) */
12448     if (algOID != ZLIBc) {
12449         WOLFSSL_MSG("CMS CompressedData only supports zlib algorithm");
12450         return ASN_PARSE_E;
12451     }
12452 
12453     /* get EncapsulatedContentInfo SEQUENCE */
12454     if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12455         return ASN_PARSE_E;
12456 
12457     /* get ContentType OID */
12458     if (wc_GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0)
12459         return ASN_PARSE_E;
12460 
12461     pkcs7->contentOID = contentType;
12462 
12463     /* get eContent EXPLICIT SEQUENCE */
12464     if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
12465         return ASN_PARSE_E;
12466 
12467     if (tag != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0))
12468         return ASN_PARSE_E;
12469 
12470     if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12471         return ASN_PARSE_E;
12472 
12473     /* get content OCTET STRING */
12474     if (GetASNTag(pkiMsg, &idx, &tag, pkiMsgSz) < 0)
12475         return ASN_PARSE_E;
12476 
12477     if (tag != ASN_OCTET_STRING)
12478         return ASN_PARSE_E;
12479 
12480     if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0)
12481         return ASN_PARSE_E;
12482 
12483     /* allocate space for decompressed data */
12484     decompressed = (byte*)XMALLOC(length, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12485     if (decompressed == NULL) {
12486         WOLFSSL_MSG("Error allocating memory for CMS decompression buffer");
12487         return MEMORY_E;
12488     }
12489 
12490     /* decompress content */
12491     ret = wc_DeCompress(decompressed, length, &pkiMsg[idx], length);
12492     if (ret < 0) {
12493         XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12494         return ret;
12495     }
12496     decompressedSz = (word32)ret;
12497 
12498     /* get content */
12499     if (outputSz < decompressedSz) {
12500         WOLFSSL_MSG("CMS output buffer too small to hold decompressed data");
12501         XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12502         return BUFFER_E;
12503     }
12504 
12505     XMEMCPY(output, decompressed, decompressedSz);
12506     XFREE(decompressed, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
12507 
12508     return decompressedSz;
12509 }
12510 
12511 #endif /* HAVE_LIBZ && !NO_PKCS7_COMPRESSED_DATA */
12512 
12513 #else  /* HAVE_PKCS7 */
12514 
12515 
12516 #ifdef _MSC_VER
12517     /* 4206 warning for blank file */
12518     #pragma warning(disable: 4206)
12519 #endif
12520 
12521 
12522 #endif /* HAVE_PKCS7 */
12523 
12524