Xuyi Wang / wolfcrypt

Dependents:   OS

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pkcs12.c Source File

pkcs12.c

00001 /* pkcs12.c
00002  *
00003  * Copyright (C) 2006-2017 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 <wolfcrypt/settings.h>
00028 
00029 #if !defined(NO_ASN) && !defined(NO_PWDBASED)
00030 
00031 #include <wolfcrypt/asn.h>
00032 #include <wolfcrypt/asn_public.h>
00033 #include <wolfcrypt/error-crypt.h>
00034 #include <wolfcrypt/hmac.h>
00035 #include <wolfcrypt/logging.h>
00036 #ifdef NO_INLINE
00037     #include <wolfcrypt/misc.h>
00038 #else
00039     #define WOLFSSL_MISC_INCLUDED
00040     #include <wolfcrypt/src/misc.c>
00041 #endif
00042 #include <wolfcrypt/pkcs12.h>
00043 #include <wolfcrypt/pwdbased.h>
00044 #include <wolfcrypt/hash.h>
00045 
00046 
00047 #define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; }
00048 
00049 enum {
00050     WC_PKCS12_KeyBag = 667,
00051     WC_PKCS12_ShroudedKeyBag = 668,
00052     WC_PKCS12_CertBag = 669,
00053     WC_PKCS12_CertBag_Type1 = 675,
00054     WC_PKCS12_CrlBag = 670,
00055     WC_PKCS12_SecretBag = 671,
00056     WC_PKCS12_SafeContentsBag = 672,
00057     WC_PKCS12_DATA = 651,
00058     WC_PKCS12_ENCRYPTED_DATA = 656,
00059 
00060     WC_PKCS12_DATA_OBJ_SZ = 11,
00061 };
00062 
00063 /* static const byte WC_PKCS12_ENCRYPTED_OID[] =
00064                          {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06}; */
00065 static const byte WC_PKCS12_DATA_OID[] =
00066                          {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01};
00067 static const byte WC_PKCS12_CertBag_Type1_OID[] =
00068                    {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x16, 0x01};
00069 static const byte WC_PKCS12_CertBag_OID[] =
00070              {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0c, 0x0a, 0x01, 0x03};
00071 static const byte WC_PKCS12_KeyBag_OID[] =
00072              {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0c, 0x0a, 0x01, 0x01};
00073 static const byte WC_PKCS12_ShroudedKeyBag_OID[] =
00074              {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0c, 0x0a, 0x01, 0x02};
00075 
00076 
00077 typedef struct ContentInfo {
00078     byte* data;
00079     struct ContentInfo* next;
00080     word32 encC;  /* encryptedContent */
00081     word32 dataSz;
00082     int type; /* DATA / encrypted / envelpoed */
00083 } ContentInfo;
00084 
00085 
00086 typedef struct AuthenticatedSafe {
00087     ContentInfo* CI;
00088     byte* data; /* T contents.... */
00089     word32 oid; /* encrypted or not */
00090     word32 numCI; /* number of Content Info structs */
00091     word32 dataSz;
00092 } AuthenticatedSafe;
00093 
00094 
00095 typedef struct MacData {
00096     byte* digest;
00097     byte* salt;
00098     word32 oid;
00099     word32 digestSz;
00100     word32 saltSz;
00101     int itt; /* number of itterations when creating HMAC key */
00102 } MacData;
00103 
00104 
00105 struct WC_PKCS12 {
00106     void* heap;
00107     AuthenticatedSafe* safe;
00108     MacData* signData;
00109     word32 oid; /* DATA / Enveloped DATA ... */
00110 };
00111 
00112 
00113 /* for friendlyName, localKeyId .... */
00114 typedef struct WC_PKCS12_ATTRIBUTE {
00115     byte* data;
00116     word32 oid;
00117     word32 dataSz;
00118 } WC_PKCS12_ATTRIBUTE;
00119 
00120 
00121 WC_PKCS12* wc_PKCS12_new(void)
00122 {
00123     WC_PKCS12* pkcs12 = (WC_PKCS12*)XMALLOC(sizeof(WC_PKCS12),
00124                                                       NULL, DYNAMIC_TYPE_PKCS);
00125     if (pkcs12 == NULL) {
00126         WOLFSSL_MSG("Memory issue when creating WC_PKCS12 struct");
00127         return NULL;
00128     }
00129 
00130     XMEMSET(pkcs12, 0, sizeof(WC_PKCS12));
00131 
00132     return pkcs12;
00133 }
00134 
00135 
00136 static void freeSafe(AuthenticatedSafe* safe, void* heap)
00137 {
00138     int i;
00139 
00140     if (safe == NULL) {
00141         return;
00142     }
00143 
00144     /* free content info structs */
00145     for (i = safe->numCI; i > 0; i--) {
00146         ContentInfo* ci = safe->CI;
00147         safe->CI = ci->next;
00148         XFREE(ci, heap, DYNAMIC_TYPE_PKCS);
00149     }
00150     if (safe->data != NULL) {
00151         XFREE(safe->data, heap, DYNAMIC_TYPE_PKCS);
00152     }
00153     XFREE(safe, heap, DYNAMIC_TYPE_PKCS);
00154 
00155     (void)heap;
00156 }
00157 
00158 
00159 void wc_PKCS12_free(WC_PKCS12* pkcs12)
00160 {
00161     void* heap;
00162 
00163     /* if null pointer is passed in do nothing */
00164     if (pkcs12 == NULL) {
00165         WOLFSSL_MSG("Trying to free null WC_PKCS12 object");
00166         return;
00167     }
00168 
00169     heap = pkcs12->heap;
00170     if (pkcs12->safe != NULL) {
00171         freeSafe(pkcs12->safe, heap);
00172     }
00173 
00174     /* free mac data */
00175     if (pkcs12->signData != NULL) {
00176         if (pkcs12->signData->digest != NULL) {
00177             XFREE(pkcs12->signData->digest, heap, DYNAMIC_TYPE_DIGEST);
00178             pkcs12->signData->digest = NULL;
00179         }
00180         if (pkcs12->signData->salt != NULL) {
00181             XFREE(pkcs12->signData->salt, heap, DYNAMIC_TYPE_SALT);
00182             pkcs12->signData->salt = NULL;
00183         }
00184         XFREE(pkcs12->signData, heap, DYNAMIC_TYPE_PKCS);
00185         pkcs12->signData = NULL;
00186     }
00187 
00188     XFREE(pkcs12, NULL, DYNAMIC_TYPE_PKCS);
00189     pkcs12 = NULL;
00190 }
00191 
00192 
00193 static int GetSafeContent(WC_PKCS12* pkcs12, const byte* input,
00194                           word32* idx, int maxIdx)
00195 {
00196     AuthenticatedSafe* safe;
00197     word32 oid;
00198     word32 localIdx = *idx;
00199     int ret;
00200     int size = 0;
00201 
00202     safe = (AuthenticatedSafe*)XMALLOC(sizeof(AuthenticatedSafe), pkcs12->heap,
00203                                        DYNAMIC_TYPE_PKCS);
00204     if (safe == NULL) {
00205         return MEMORY_E;
00206     }
00207     XMEMSET(safe, 0, sizeof(AuthenticatedSafe));
00208 
00209     ret = GetObjectId(input, &localIdx, &oid, oidIgnoreType, maxIdx);
00210     if (ret < 0) {
00211         WOLFSSL_LEAVE("Get object id failed", ret);
00212         freeSafe(safe, pkcs12->heap);
00213         return ASN_PARSE_E;
00214     }
00215 
00216     safe->oid = oid;
00217     /* check tag, length */
00218     if (input[localIdx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
00219         WOLFSSL_MSG("Unexpected tag in PKCS12 DER");
00220         freeSafe(safe, pkcs12->heap);
00221         return ASN_PARSE_E;
00222     }
00223     if ((ret = GetLength(input, &localIdx, &size, maxIdx)) <= 0) {
00224         freeSafe(safe, pkcs12->heap);
00225         return ret;
00226     }
00227 
00228     switch (oid) {
00229         case WC_PKCS12_ENCRYPTED_DATA:
00230             WOLFSSL_MSG("Found PKCS12 OBJECT: ENCRYPTED DATA\n");
00231             break;
00232 
00233         case WC_PKCS12_DATA:
00234             WOLFSSL_MSG("Found PKCS12 OBJECT: DATA");
00235             /* get octets holding contents */
00236             if (input[localIdx++] != ASN_OCTET_STRING) {
00237                 WOLFSSL_MSG("Wrong tag with content PKCS12 type DATA");
00238                 freeSafe(safe, pkcs12->heap);
00239                 return ASN_PARSE_E;
00240             }
00241             if ((ret = GetLength(input, &localIdx, &size, maxIdx)) <= 0) {
00242                 freeSafe(safe, pkcs12->heap);
00243                 return ret;
00244             }
00245 
00246             break;
00247     }
00248 
00249     safe->dataSz = size;
00250     safe->data = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
00251     if (safe->data == NULL) {
00252         freeSafe(safe, pkcs12->heap);
00253         return MEMORY_E;
00254     }
00255     XMEMCPY(safe->data, input + localIdx, size);
00256     *idx = localIdx;
00257 
00258     /* an instance of AuthenticatedSafe is created from
00259      * ContentInfo's strung together in a SEQUENCE. Here we itterate
00260      * through the ContentInfo's and add them to our
00261      * AuthenticatedSafe struct */
00262     localIdx = 0;
00263     input = safe->data;
00264     {
00265         int CISz;
00266         ret = GetSequence(input, &localIdx, &CISz, safe->dataSz);
00267         if (ret < 0) {
00268             freeSafe(safe, pkcs12->heap);
00269             return ASN_PARSE_E;
00270         }
00271         CISz += localIdx;
00272         while ((int)localIdx < CISz) {
00273             int curSz = 0;
00274             word32 curIdx;
00275             ContentInfo* ci = NULL;
00276 
00277         #ifdef WOLFSSL_DEBUG_PKCS12
00278             printf("\t\tlooking for Content Info.... ");
00279         #endif
00280 
00281             if ((ret = GetSequence(input, &localIdx, &curSz, safe->dataSz))
00282                                                                           < 0) {
00283                 freeSafe(safe, pkcs12->heap);
00284                 return ret;
00285             }
00286 
00287             if (curSz > CISz) {
00288                 /* subset should not be larger than universe */
00289                 freeSafe(safe, pkcs12->heap);
00290                 return ASN_PARSE_E;
00291             }
00292 
00293             curIdx = localIdx;
00294             if ((ret = GetObjectId(input, &localIdx, &oid, oidIgnoreType,
00295                                                            safe->dataSz)) < 0) {
00296                 WOLFSSL_LEAVE("Get object id failed", ret);
00297                 freeSafe(safe, pkcs12->heap);
00298                 return ret;
00299             }
00300 
00301             /* create new content info struct ... possible OID sanity check? */
00302             ci = (ContentInfo*)XMALLOC(sizeof(ContentInfo), pkcs12->heap,
00303                                        DYNAMIC_TYPE_PKCS);
00304             if (ci == NULL) {
00305                 freeSafe(safe, pkcs12->heap);
00306                 return MEMORY_E;
00307             }
00308 
00309             ci->type   = oid;
00310             ci->dataSz = curSz - (localIdx-curIdx);
00311             ci->data   = (byte*)input + localIdx;
00312             localIdx  += ci->dataSz;
00313 
00314         #ifdef WOLFSSL_DEBUG_PKCS12
00315             switch (oid) {
00316                 case WC_PKCS12_ENCRYPTED_DATA:
00317                     printf("CONTENT INFO: ENCRYPTED DATA, size = %d\n", ci->dataSz);
00318                     break;
00319 
00320                 case WC_PKCS12_DATA:
00321                     printf("CONTENT INFO: DATA, size = %d\n", ci->dataSz);
00322                     break;
00323                 default:
00324                     printf("CONTENT INFO: UNKNOWN, size = %d\n", ci->dataSz);
00325             }
00326         #endif
00327 
00328             /* insert to head of list */
00329             ci->next = safe->CI;
00330             safe->CI = ci;
00331             safe->numCI += 1;
00332         }
00333     }
00334 
00335     pkcs12->safe = safe;
00336     *idx += localIdx;
00337 
00338     return ret;
00339 }
00340 
00341 
00342 /* optional mac data */
00343 static int GetSignData(WC_PKCS12* pkcs12, const byte* mem, word32* idx,
00344                        word32 totalSz)
00345 {
00346     MacData* mac;
00347     word32 curIdx = *idx;
00348     word32 oid = 0;
00349     int size, ret;
00350 
00351     /* Digest Info : Sequence
00352      *      DigestAlgorithmIdentifier
00353      *      Digest
00354      */
00355     if ((ret = GetSequence(mem, &curIdx, &size, totalSz)) <= 0) {
00356         WOLFSSL_MSG("Failed to get PKCS12 sequence");
00357         return ret;
00358     }
00359 
00360 #ifdef WOLFSSL_DEBUG_PKCS12
00361     printf("\t\tSEQUENCE: DigestInfo size = %d\n", size);
00362 #endif
00363 
00364     mac = (MacData*)XMALLOC(sizeof(MacData), pkcs12->heap, DYNAMIC_TYPE_PKCS);
00365     if (mac == NULL) {
00366         return MEMORY_E;
00367     }
00368     XMEMSET(mac, 0, sizeof(MacData));
00369 
00370     /* DigestAlgorithmIdentifier */
00371     if ((ret = GetAlgoId(mem, &curIdx, &oid, oidIgnoreType, totalSz)) < 0) {
00372         WOLFSSL_MSG("Failed to get PKCS12 sequence");
00373         XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
00374         return ret;
00375     }
00376     mac->oid = oid;
00377 
00378 #ifdef WOLFSSL_DEBUG_PKCS12
00379     printf("\t\tALGO ID = %d\n", oid);
00380 #endif
00381 
00382     /* Digest: should be octet type holding digest */
00383     if (mem[curIdx++] != ASN_OCTET_STRING) {
00384         WOLFSSL_MSG("Failed to get digest");
00385         XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
00386         return ASN_PARSE_E;
00387     }
00388 
00389     if ((ret = GetLength(mem, &curIdx, &size, totalSz)) <= 0) {
00390         XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
00391         return ret;
00392     }
00393     mac->digestSz = size;
00394     mac->digest = (byte*)XMALLOC(mac->digestSz, pkcs12->heap,
00395                                  DYNAMIC_TYPE_DIGEST);
00396     if (mac->digest == NULL || mac->digestSz + curIdx > totalSz) {
00397         ERROR_OUT(MEMORY_E, exit_gsd);
00398     }
00399     XMEMCPY(mac->digest, mem + curIdx, mac->digestSz);
00400 
00401 #ifdef WOLFSSL_DEBUG_PKCS12
00402     {
00403         byte* p;
00404         for (printf("\t\tDigest = "), p = (byte*)mem+curIdx;
00405              p < (byte*)mem + curIdx + mac->digestSz;
00406              printf("%02X", *p), p++);
00407         printf(" : size = %d\n", mac->digestSz);
00408     }
00409 #endif
00410 
00411     curIdx += mac->digestSz;
00412 
00413     /* get salt, should be octet string */
00414     if (mem[curIdx++] != ASN_OCTET_STRING) {
00415         WOLFSSL_MSG("Failed to get salt");
00416         ERROR_OUT(ASN_PARSE_E, exit_gsd);
00417     }
00418 
00419     if ((ret = GetLength(mem, &curIdx, &size, totalSz)) <= 0) {
00420         goto exit_gsd;
00421     }
00422     mac->saltSz = size;
00423     mac->salt = (byte*)XMALLOC(mac->saltSz, pkcs12->heap, DYNAMIC_TYPE_SALT);
00424     if (mac->salt == NULL || mac->saltSz + curIdx > totalSz) {
00425         ERROR_OUT(MEMORY_E, exit_gsd);
00426     }
00427     XMEMCPY(mac->salt, mem + curIdx, mac->saltSz);
00428 
00429 #ifdef WOLFSSL_DEBUG_PKCS12
00430     {
00431         byte* p;
00432         for (printf("\t\tSalt = "), p = (byte*)mem + curIdx;
00433              p < (byte*)mem + curIdx + mac->saltSz;
00434              printf("%02X", *p), p++);
00435         printf(" : size = %d\n", mac->saltSz);
00436     }
00437 #endif
00438 
00439     curIdx += mac->saltSz;
00440 
00441     /* check for MAC iterations, default to 1 */
00442     mac->itt = WC_PKCS12_MAC_DEFAULT;
00443     if (curIdx < totalSz) {
00444         int number = 0;
00445         if ((ret = GetShortInt(mem, &curIdx, &number, totalSz)) >= 0) {
00446             /* found a iteration value */
00447             mac->itt = number;
00448         }
00449     }
00450 
00451 #ifdef WOLFSSL_DEBUG_PKCS12
00452     printf("\t\tITTERATIONS : %d\n", mac->itt);
00453 #endif
00454 
00455     *idx = curIdx;
00456     pkcs12->signData = mac;
00457     ret = 0; /* success */
00458 
00459 exit_gsd:
00460 
00461     /* failure cleanup */
00462     if (ret != 0) {
00463         if (mac) {
00464             if (mac->digest)
00465                 XFREE(mac->digest, pkcs12->heap, DYNAMIC_TYPE_DIGEST);
00466             XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
00467         }
00468     }
00469 
00470     return ret;
00471 }
00472 
00473 
00474 /* expects PKCS12 signData to be set up with OID
00475  *
00476  * returns the size of mac created on success. A negative value will be returned
00477  *         in the case that an error happened.
00478  */
00479 static int wc_PKCS12_create_mac(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
00480                          const byte* psw, word32 pswSz, byte* out, word32 outSz)
00481 {
00482     Hmac     hmac;
00483     MacData* mac;
00484     int ret, kLen;
00485     enum wc_HashType hashT;
00486     int idx = 0;
00487     int id  = 3; /* value from RFC 7292 indicating key is used for MAC */
00488     word32 i;
00489     byte unicodePasswd[MAX_UNICODE_SZ];
00490     byte key[MAX_KEY_SIZE];
00491 
00492     if (pkcs12 == NULL || pkcs12->signData == NULL || data == NULL ||
00493             out == NULL) {
00494         return BAD_FUNC_ARG;
00495     }
00496 
00497     mac = pkcs12->signData;
00498 
00499     /* unicode set up from asn.c */
00500     if ((pswSz * 2 + 2) > (int)sizeof(unicodePasswd)) {
00501         WOLFSSL_MSG("PKCS12 max unicode size too small");
00502         return UNICODE_SIZE_E;
00503     }
00504 
00505     for (i = 0; i < pswSz; i++) {
00506         unicodePasswd[idx++] = 0x00;
00507         unicodePasswd[idx++] = (byte)psw[i];
00508     }
00509     /* add trailing NULL */
00510     unicodePasswd[idx++] = 0x00;
00511     unicodePasswd[idx++] = 0x00;
00512 
00513     /* get hash type used and resulting size of HMAC key */
00514     hashT = wc_OidGetHash(mac->oid);
00515     if (hashT == WC_HASH_TYPE_NONE) {
00516         WOLFSSL_MSG("Unsupported hash used");
00517         return BAD_FUNC_ARG;
00518     }
00519     kLen = wc_HashGetDigestSize(hashT);
00520 
00521     /* check out buffer is large enough */
00522     if (kLen < 0 || outSz < (word32)kLen) {
00523         return BAD_FUNC_ARG;
00524     }
00525 
00526     /* idx contains size of unicodePasswd */
00527     if ((ret = wc_PKCS12_PBKDF_ex(key, unicodePasswd, idx, mac->salt,
00528               mac->saltSz, mac->itt, kLen, (int)hashT, id, pkcs12->heap)) < 0) {
00529         return ret;
00530     }
00531 
00532     /* now that key has been created use it to get HMAC hash on data */
00533     if ((ret = wc_HmacInit(&hmac, pkcs12->heap, INVALID_DEVID)) != 0) {
00534         return ret;
00535     }
00536     ret = wc_HmacSetKey(&hmac, (int)hashT, key, kLen);
00537     if (ret == 0)
00538         ret = wc_HmacUpdate(&hmac, data, dataSz);
00539     if (ret == 0)
00540         ret = wc_HmacFinal(&hmac, out);
00541     wc_HmacFree(&hmac);
00542 
00543     if (ret != 0)
00544         return ret;
00545 
00546     return kLen; /* same as digest size */
00547 }
00548 
00549 
00550 /* check mac on pkcs12, pkcs12->mac has been sanity checked before entering *
00551  * returns the result of comparison, success is 0 */
00552 static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
00553                             const byte* psw, word32 pswSz)
00554 {
00555     MacData* mac;
00556     int ret;
00557     byte digest[WC_MAX_DIGEST_SIZE];
00558 
00559     if (pkcs12 == NULL || pkcs12->signData == NULL || data == NULL) {
00560         return BAD_FUNC_ARG;
00561     }
00562 
00563     mac = pkcs12->signData;
00564 
00565 #ifdef WOLFSSL_DEBUG_PKCS12
00566     printf("Verifying MAC with OID = %d\n", mac->oid);
00567 #endif
00568 
00569     /* check if this builds digest size is too small */
00570     if (mac->digestSz > WC_MAX_DIGEST_SIZE) {
00571         WOLFSSL_MSG("PKCS12 max digest size too small");
00572         return BAD_FUNC_ARG;
00573     }
00574 
00575     if ((ret = wc_PKCS12_create_mac(pkcs12, data, dataSz, psw, pswSz,
00576             digest, WC_MAX_DIGEST_SIZE)) < 0) {
00577         return ret;
00578     }
00579 
00580 #ifdef WOLFSSL_DEBUG_PKCS12
00581     {
00582         byte* p;
00583         for (printf("\t\tHash = "), p = (byte*)digest;
00584              p < (byte*)digest + mac->digestSz;
00585              printf("%02X", *p), p++);
00586         printf(" : size = %d\n", mac->digestSz);
00587     }
00588 #endif
00589 
00590     return XMEMCMP(digest, mac->digest, mac->digestSz);
00591 }
00592 
00593 
00594 /* Convert DER format stored in der buffer to WC_PKCS12 struct
00595  * Puts the raw contents of Content Info into structure without completly
00596  * parsing or decoding.
00597  * der    : pointer to der buffer holding PKCS12
00598  * derSz  : size of der buffer
00599  * pkcs12 : non-null pkcs12 pointer
00600  * return 0 on success and negative on failure.
00601  */
00602 int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12)
00603 {
00604     word32 idx  = 0;
00605     word32 totalSz = 0;
00606     int ret;
00607     int size    = 0;
00608     int version = 0;
00609 
00610     WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio");
00611 
00612     if (der == NULL || pkcs12 == NULL) {
00613         return BAD_FUNC_ARG;
00614     }
00615 
00616     totalSz = derSz;
00617     if ((ret = GetSequence(der, &idx, &size, totalSz)) <= 0) {
00618         WOLFSSL_MSG("Failed to get PKCS12 sequence");
00619         return ret;
00620     }
00621 
00622     /* get version */
00623     if ((ret = GetMyVersion(der, &idx, &version, totalSz)) < 0) {
00624         return ret;
00625     }
00626 
00627 #ifdef WOLFSSL_DEBUG_PKCS12
00628     printf("\nBEGIN: PKCS12 size = %d\n", totalSz);
00629     printf("version = %d\n", version);
00630 #endif
00631 
00632     if (version != 3) {
00633         WOLFSSL_MSG("PKCS12 unsupported version!");
00634         return ASN_VERSION_E;
00635     }
00636 
00637     if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
00638         return ret;
00639     }
00640 
00641 #ifdef WOLFSSL_DEBUG_PKCS12
00642     printf("\tSEQUENCE: AuthenticatedSafe size = %d\n", size);
00643 #endif
00644 
00645     if ((ret = GetSafeContent(pkcs12, der, &idx, size + idx)) < 0) {
00646         WOLFSSL_MSG("GetSafeContent error");
00647         return ret;
00648     }
00649 
00650     /* if more buffer left check for MAC data */
00651     if (idx < totalSz) {
00652         if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
00653             WOLFSSL_MSG("Ignoring unknown data at end of PKCS12 DER buffer");
00654         }
00655         else {
00656         #ifdef WOLFSSL_DEBUG_PKCS12
00657             printf("\tSEQUENCE: Signature size = %d\n", size);
00658         #endif
00659 
00660             if ((ret = GetSignData(pkcs12, der, &idx, totalSz)) < 0) {
00661                 return ASN_PARSE_E;
00662             }
00663         }
00664     }
00665 
00666 #ifdef WOLFSSL_DEBUG_PKCS12
00667     printf("END: PKCS12\n");
00668 #endif
00669 
00670     return ret;
00671 }
00672 
00673 
00674 /* helper function to free WC_DerCertList */
00675 void wc_FreeCertList(WC_DerCertList* list, void* heap)
00676 {
00677     WC_DerCertList* current = list;
00678     WC_DerCertList* next;
00679 
00680     if (list == NULL) {
00681         return;
00682     }
00683 
00684     while (current != NULL) {
00685         next = current->next;
00686         if (current->buffer != NULL) {
00687             XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS);
00688         }
00689         XFREE(current, heap, DYNAMIC_TYPE_PKCS);
00690         current = next;
00691     }
00692 
00693     (void)heap;
00694 }
00695 
00696 static void freeDecCertList(WC_DerCertList** list, byte** pkey, word32* pkeySz,
00697     byte** cert, word32* certSz, void* heap)
00698 {
00699     WC_DerCertList* current  = *list;
00700     WC_DerCertList* previous = NULL;
00701     DecodedCert DeCert;
00702 
00703     while (current != NULL) {
00704 
00705         InitDecodedCert(&DeCert, current->buffer, current->bufferSz, heap);
00706         if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) == 0) {
00707             if (wc_CheckPrivateKey(*pkey, *pkeySz, &DeCert) == 1) {
00708                 WOLFSSL_MSG("Key Pair found");
00709                 *cert = current->buffer;
00710                 *certSz = current->bufferSz;
00711 
00712                 if (previous == NULL) {
00713                     *list = current->next;
00714                 }
00715                 else {
00716                     previous->next = current->next;
00717                 }
00718                 FreeDecodedCert(&DeCert);
00719                 XFREE(current, heap, DYNAMIC_TYPE_PKCS);
00720                 break;
00721             }
00722         }
00723         FreeDecodedCert(&DeCert);
00724 
00725         previous = current;
00726         current  = current->next;
00727     }
00728 }
00729 
00730 
00731 /* return 0 on success and negative on failure.
00732  * By side effect returns private key, cert, and optionally ca.
00733  * Parses and decodes the parts of PKCS12
00734  *
00735  * NOTE: can parse with USER RSA enabled but may return cert that is not the
00736  *       pair for the key when using RSA key pairs.
00737  *
00738  * pkcs12 : non-null WC_PKCS12 struct
00739  * psw    : password to use for PKCS12 decode
00740  * pkey   : Private key returned
00741  * cert   : x509 cert returned
00742  * ca     : optional ca returned
00743  */
00744 int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
00745         byte** pkey, word32* pkeySz, byte** cert, word32* certSz,
00746         WC_DerCertList** ca)
00747 {
00748     ContentInfo* ci       = NULL;
00749     WC_DerCertList* certList = NULL;
00750     WC_DerCertList* tailList = NULL;
00751     byte* buf             = NULL;
00752     word32 i, oid;
00753     int ret, pswSz;
00754 
00755     WOLFSSL_ENTER("wc_PKCS12_parse");
00756 
00757     if (pkcs12 == NULL || psw == NULL || cert == NULL || certSz == NULL ||
00758         pkey == NULL   || pkeySz == NULL) {
00759         return BAD_FUNC_ARG;
00760     }
00761 
00762     pswSz = (int)XSTRLEN(psw);
00763     *cert = NULL;
00764     *pkey = NULL;
00765     if (ca != NULL)
00766         *ca = NULL;
00767 
00768     /* if there is sign data then verify the MAC */
00769     if (pkcs12->signData != NULL ) {
00770         if ((ret = wc_PKCS12_verify(pkcs12, pkcs12->safe->data,
00771                                pkcs12->safe->dataSz, (byte*)psw, pswSz)) != 0) {
00772             WOLFSSL_MSG("PKCS12 Bad MAC on verify");
00773             WOLFSSL_LEAVE("wc_PKCS12_parse verify ", ret);
00774             return MAC_CMP_FAILED_E;
00775         }
00776     }
00777 
00778     if (pkcs12->safe == NULL) {
00779         WOLFSSL_MSG("No PKCS12 safes to parse");
00780         return BAD_FUNC_ARG;
00781     }
00782 
00783     /* Decode content infos */
00784     ci = pkcs12->safe->CI;
00785     for (i = 0; i < pkcs12->safe->numCI; i++) {
00786         byte*  data;
00787         word32 idx = 0;
00788         int    size, totalSz;
00789 
00790         if (ci->type == WC_PKCS12_ENCRYPTED_DATA) {
00791             int number;
00792 
00793             WOLFSSL_MSG("Decrypting PKCS12 Content Info Container");
00794             data = ci->data;
00795             if (data[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
00796                 ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00797             }
00798             if ((ret = GetLength(data, &idx, &size, ci->dataSz)) < 0) {
00799                 goto exit_pk12par;
00800             }
00801 
00802             if ((ret = GetSequence(data, &idx, &size, ci->dataSz)) < 0) {
00803                 goto exit_pk12par;
00804             }
00805 
00806             if ((ret = GetShortInt(data, &idx, &number, ci->dataSz)) < 0) {
00807                 goto exit_pk12par;
00808             }
00809 
00810             if (number != 0) {
00811                 WOLFSSL_MSG("Expecting 0 for Integer with Encrypted PKCS12");
00812             }
00813 
00814             if ((ret = GetSequence(data, &idx, &size, ci->dataSz)) < 0) {
00815                 goto exit_pk12par;
00816             }
00817 
00818             ret = GetObjectId(data, &idx, &oid, oidIgnoreType, ci->dataSz);
00819             if (ret < 0 || oid != WC_PKCS12_DATA) {
00820                 WOLFSSL_MSG("Not PKCS12 DATA object or get object parse error");
00821                 ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00822             }
00823 
00824             /* decrypted content overwrites input buffer */
00825             size = ci->dataSz - idx;
00826             buf = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
00827             if (buf == NULL) {
00828                 ERROR_OUT(MEMORY_E, exit_pk12par);
00829             }
00830             XMEMCPY(buf, data + idx, size);
00831 
00832             if ((ret = DecryptContent(buf, size, psw, pswSz)) < 0) {
00833                 WOLFSSL_MSG("Decryption failed, algorithm not compiled in?");
00834                 goto exit_pk12par;
00835             }
00836 
00837             data = buf;
00838             idx = 0;
00839 
00840         #ifdef WOLFSSL_DEBUG_PKCS12
00841             {
00842                 byte* p;
00843                 for (printf("\tData = "), p = (byte*)buf;
00844                     p < (byte*)buf + size;
00845                     printf("%02X", *p), p++);
00846                 printf("\n");
00847             }
00848         #endif
00849         }
00850         else { /* type DATA */
00851             WOLFSSL_MSG("Parsing PKCS12 DATA Content Info Container");
00852             data = ci->data;
00853             if (data[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
00854                 ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00855             }
00856             if ((ret = GetLength(data, &idx, &size, ci->dataSz)) <= 0) {
00857                 goto exit_pk12par;
00858             }
00859             if (data[idx++] != ASN_OCTET_STRING) {
00860                 ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00861             }
00862             if ((ret = GetLength(data, &idx, &size, ci->dataSz)) < 0) {
00863                 goto exit_pk12par;
00864             }
00865 
00866         }
00867 
00868         /* parse through bags in ContentInfo */
00869         if ((ret = GetSequence(data, &idx, &totalSz, ci->dataSz)) < 0) {
00870             goto exit_pk12par;
00871         }
00872         totalSz += idx;
00873 
00874         while ((int)idx < totalSz) {
00875             int bagSz;
00876             if ((ret = GetSequence(data, &idx, &bagSz, ci->dataSz)) < 0) {
00877                 goto exit_pk12par;
00878             }
00879             bagSz += idx;
00880 
00881             if ((ret = GetObjectId(data, &idx, &oid, oidIgnoreType,
00882                                                              ci->dataSz)) < 0) {
00883                 goto exit_pk12par;
00884             }
00885 
00886             switch (oid) {
00887                 case WC_PKCS12_KeyBag: /* 667 */
00888                     WOLFSSL_MSG("PKCS12 Key Bag found");
00889                     if (data[idx++] !=
00890                                      (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
00891                         ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00892                     }
00893                     if ((ret = GetLength(data, &idx, &size, ci->dataSz)) <= 0) {
00894                         goto exit_pk12par;
00895                     }
00896                     if (*pkey == NULL) {
00897                         *pkey = (byte*)XMALLOC(size, pkcs12->heap,
00898                                                        DYNAMIC_TYPE_PUBLIC_KEY);
00899                         if (*pkey == NULL) {
00900                             ERROR_OUT(MEMORY_E, exit_pk12par);
00901                         }
00902                         XMEMCPY(*pkey, data + idx, size);
00903                         *pkeySz =  ToTraditional(*pkey, size);
00904                     }
00905 
00906                 #ifdef WOLFSSL_DEBUG_PKCS12
00907                     {
00908                         byte* p;
00909                         for (printf("\tKey = "), p = (byte*)*pkey;
00910                             p < (byte*)*pkey + size;
00911                             printf("%02X", *p), p++);
00912                         printf("\n");
00913                     }
00914                 #endif
00915                     idx += size;
00916                     break;
00917 
00918                 case WC_PKCS12_ShroudedKeyBag: /* 668 */
00919                     {
00920                         byte* k;
00921 
00922                         WOLFSSL_MSG("PKCS12 Shrouded Key Bag found");
00923                         if (data[idx++] !=
00924                                      (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
00925                             ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00926                         }
00927                         if ((ret = GetLength(data, &idx, &size,
00928                                                              ci->dataSz)) < 0) {
00929                             goto exit_pk12par;
00930                         }
00931 
00932                         k = (byte*)XMALLOC(size, pkcs12->heap,
00933                                                        DYNAMIC_TYPE_PUBLIC_KEY);
00934                         if (k == NULL) {
00935                             ERROR_OUT(MEMORY_E, exit_pk12par);
00936                         }
00937                         XMEMCPY(k, data + idx, size);
00938 
00939                         /* overwrites input, be warned */
00940                         if ((ret = ToTraditionalEnc(k, size, psw, pswSz)) < 0) {
00941                             XFREE(k, pkcs12->heap, DYNAMIC_TYPE_PUBLIC_KEY);
00942                             goto exit_pk12par;
00943                         }
00944 
00945                         if (ret < size) {
00946                             /* shrink key buffer */
00947                             byte* tmp = (byte*)XMALLOC(ret, pkcs12->heap,
00948                                                  DYNAMIC_TYPE_PUBLIC_KEY);
00949                             if (tmp == NULL) {
00950                                 XFREE(k, pkcs12->heap, DYNAMIC_TYPE_PUBLIC_KEY);
00951                                 ERROR_OUT(MEMORY_E, exit_pk12par);
00952                             }
00953                             XMEMCPY(tmp, k, ret);
00954                             XFREE(k, pkcs12->heap, DYNAMIC_TYPE_PUBLIC_KEY);
00955                             k = tmp;
00956                         }
00957                         size = ret;
00958 
00959                         if (*pkey == NULL) {
00960                             *pkey = k;
00961                             *pkeySz = size;
00962                         }
00963                         else { /* only expecting one key */
00964                             XFREE(k, pkcs12->heap, DYNAMIC_TYPE_PUBLIC_KEY);
00965                         }
00966                         idx += size;
00967 
00968                     #ifdef WOLFSSL_DEBUG_PKCS12
00969                         {
00970                             byte* p;
00971                             for (printf("\tKey = "), p = (byte*)k;
00972                                 p < (byte*)k + ret;
00973                                 printf("%02X", *p), p++);
00974                             printf("\n");
00975                         }
00976                     #endif
00977                     }
00978                     break;
00979 
00980                 case WC_PKCS12_CertBag: /* 669 */
00981                 {
00982                     WC_DerCertList* node;
00983                     WOLFSSL_MSG("PKCS12 Cert Bag found");
00984                     if (data[idx++] !=
00985                                      (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
00986                         ERROR_OUT(ASN_PARSE_E, exit_pk12par);
00987                     }
00988                     if ((ret = GetLength(data, &idx, &size, ci->dataSz)) < 0) {
00989                         goto exit_pk12par;
00990                     }
00991 
00992                     /* get cert bag type */
00993                     if ((ret = GetSequence(data, &idx, &size, ci->dataSz)) <0) {
00994                         goto exit_pk12par;
00995                     }
00996 
00997                     if ((ret = GetObjectId(data, &idx, &oid, oidIgnoreType,
00998                                                              ci->dataSz)) < 0) {
00999                         goto exit_pk12par;
01000                     }
01001 
01002                     switch (oid) {
01003                         case WC_PKCS12_CertBag_Type1:  /* 675 */
01004                             /* type 1 */
01005                             WOLFSSL_MSG("PKCS12 cert bag type 1");
01006                             if (data[idx++] !=
01007                                      (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
01008                                 ERROR_OUT(ASN_PARSE_E, exit_pk12par);
01009                             }
01010                             if ((ret = GetLength(data, &idx, &size, ci->dataSz))
01011                                                                          <= 0) {
01012                                 goto exit_pk12par;
01013                             }
01014                             if (data[idx++] != ASN_OCTET_STRING) {
01015                                 ERROR_OUT(ASN_PARSE_E, exit_pk12par);
01016 
01017                             }
01018                             if ((ret = GetLength(data, &idx, &size, ci->dataSz))
01019                                                                           < 0) {
01020                                 goto exit_pk12par;
01021                             }
01022                             break;
01023                        default:
01024                             WOLFSSL_MSG("Unknown PKCS12 cert bag type");
01025                     }
01026 
01027                     if (size + idx > (word32)bagSz) {
01028                         ERROR_OUT(ASN_PARSE_E, exit_pk12par);
01029                     }
01030 
01031                     /* list to hold all certs found */
01032                     node = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList),
01033                                                pkcs12->heap, DYNAMIC_TYPE_PKCS);
01034                     if (node == NULL) {
01035                         ERROR_OUT(MEMORY_E, exit_pk12par);
01036                     }
01037                     XMEMSET(node, 0, sizeof(WC_DerCertList));
01038 
01039                     node->buffer = (byte*)XMALLOC(size, pkcs12->heap,
01040                                                              DYNAMIC_TYPE_PKCS);
01041                     if (node->buffer == NULL) {
01042                         XFREE(node, pkcs12->heap, DYNAMIC_TYPE_PKCS);
01043                         ERROR_OUT(MEMORY_E, exit_pk12par);
01044                     }
01045                     XMEMCPY(node->buffer, data + idx, size);
01046                     node->bufferSz = size;
01047 
01048                     /* put the new node into the list */
01049                     if (certList != NULL) {
01050                         WOLFSSL_MSG("Pushing new cert onto queue");
01051                         tailList->next = node;
01052                         tailList = node;
01053                     }
01054                     else {
01055                         certList = node;
01056                         tailList = node;
01057                     }
01058 
01059                     /* on to next */
01060                     idx += size;
01061                 }
01062                     break;
01063 
01064                 case WC_PKCS12_CrlBag: /* 670 */
01065                     WOLFSSL_MSG("PKCS12 CRL BAG not yet supported");
01066                     break;
01067 
01068                 case WC_PKCS12_SecretBag: /* 671 */
01069                     WOLFSSL_MSG("PKCS12 Secret BAG not yet supported");
01070                     break;
01071 
01072                 case WC_PKCS12_SafeContentsBag: /* 672 */
01073                     WOLFSSL_MSG("PKCS12 Safe Contents BAG not yet supported");
01074                     break;
01075 
01076                 default:
01077                     WOLFSSL_MSG("Unknown PKCS12 BAG type found");
01078             }
01079 
01080             /* Attribute, unknown bag or unsupported */
01081             if ((int)idx < bagSz) {
01082                 idx = bagSz; /* skip for now */
01083             }
01084         }
01085 
01086         /* free temporary buffer */
01087         if (buf != NULL) {
01088             XFREE(buf, pkcs12->heap, DYNAMIC_TYPE_PKCS);
01089             buf = NULL;
01090         }
01091 
01092         ci = ci->next;
01093         WOLFSSL_MSG("Done Parsing PKCS12 Content Info Container");
01094     }
01095 
01096     /* check if key pair, remove from list */
01097     if (*pkey != NULL) {
01098         freeDecCertList(&certList, pkey, pkeySz, cert, certSz, pkcs12->heap);
01099     }
01100 
01101     /* if ca arg provided return certList, otherwise free it */
01102     if (ca != NULL) {
01103         *ca = certList;
01104     }
01105     else {
01106         /* free list, not wanted */
01107         wc_FreeCertList(certList, pkcs12->heap);
01108     }
01109 
01110     ret = 0; /* success */
01111 
01112 exit_pk12par:
01113 
01114     if (ret != 0) {
01115         /* failure cleanup */
01116         if (*pkey) {
01117             XFREE(*pkey, pkcs12->heap, DYNAMIC_TYPE_PUBLIC_KEY);
01118             *pkey = NULL;
01119         }
01120         if (buf) {
01121             XFREE(buf, pkcs12->heap, DYNAMIC_TYPE_PKCS);
01122             buf = NULL;
01123         }
01124 
01125         wc_FreeCertList(certList, pkcs12->heap);
01126     }
01127 
01128     return ret;
01129 }
01130 
01131 
01132 /* Helper function to shroud keys.
01133  *
01134  * pkcs12 structure to use with shrouding key
01135  * rng    random number generator used
01136  * out    buffer to hold results
01137  * outSz  size of out buffer
01138  * key    key that is going to be shrouded
01139  * keySz  size of key buffer
01140  * vAlgo  algorithm version
01141  * pass   password to use
01142  * passSz size of pass buffer
01143  * itt    number of iterations
01144  *
01145  * returns the size of the shrouded key on success
01146  */
01147 static int wc_PKCS12_shroud_key(WC_PKCS12* pkcs12, WC_RNG* rng,
01148         byte* out, word32* outSz, byte* key, word32 keySz, int vAlgo,
01149         const char* pass, int passSz, int itt)
01150 {
01151     void* heap;
01152     word32 tmpIdx = 0;
01153     int vPKCS     = 1; /* PKCS#12 default set to 1 */
01154     word32 sz;
01155     word32 totalSz = 0;
01156     int ret;
01157 
01158 
01159     if (outSz == NULL || pkcs12 == NULL || rng == NULL || key == NULL ||
01160             pass == NULL) {
01161         return BAD_FUNC_ARG;
01162     }
01163 
01164     heap = wc_PKCS12_GetHeap(pkcs12);
01165 
01166     /* check if trying to get size */
01167     if (out != NULL) {
01168         tmpIdx += MAX_LENGTH_SZ + 1; /* save room for length and tag (+1) */
01169         sz = *outSz - tmpIdx;
01170     }
01171 
01172     /* case of no encryption */
01173     if (vAlgo < 0) {
01174         const byte* curveOID = NULL;
01175         word32 oidSz = 0;
01176         int algoID;
01177 
01178         WOLFSSL_MSG("creating PKCS12 Key Bag");
01179 
01180         /* check key type and get OID if ECC */
01181         if ((ret = wc_GetKeyOID(key, keySz, &curveOID, &oidSz, &algoID, heap))
01182                 < 0) {
01183             return ret;
01184         }
01185 
01186         /* PKCS#8 wrapping around key */
01187         ret = wc_CreatePKCS8Key(out + tmpIdx, &sz, key, keySz, algoID,
01188                 curveOID, oidSz);
01189     }
01190     else {
01191         WOLFSSL_MSG("creating PKCS12 Shrouded Key Bag");
01192 
01193         if (vAlgo == PBE_SHA1_DES) {
01194             vPKCS = PKCS5;
01195             vAlgo = 10;
01196         }
01197 
01198         ret = UnTraditionalEnc(key, keySz, out + tmpIdx, &sz, pass, passSz,
01199                 vPKCS, vAlgo, NULL, 0, itt, rng, heap);
01200     }
01201     if (ret == LENGTH_ONLY_E) {
01202         *outSz =  sz + MAX_LENGTH_SZ + 1;
01203         return LENGTH_ONLY_E;
01204     }
01205     if (ret < 0) {
01206         return ret;
01207     }
01208 
01209     totalSz += ret;
01210 
01211     /* out should not be null at this point but check before writing */
01212     if (out == NULL) {
01213         return BAD_FUNC_ARG;
01214     }
01215 
01216     /* rewind index and set tag and length */
01217     tmpIdx -= MAX_LENGTH_SZ + 1;
01218     sz = SetExplicit(0, ret, out + tmpIdx);
01219     tmpIdx += sz; totalSz += sz;
01220     XMEMMOVE(out + tmpIdx, out + MAX_LENGTH_SZ + 1, ret);
01221 
01222     return totalSz;
01223 }
01224 
01225 
01226 /* Helper function to create key bag.
01227  *
01228  * pkcs12 structure to use with key bag
01229  * rng    random number generator used
01230  * out    buffer to hold results
01231  * outSz  size of out buffer
01232  * key    key that is going into key bag
01233  * keySz  size of key buffer
01234  * algo   algorithm version
01235  * iter   number of iterations
01236  * pass   password to use
01237  * passSz size of pass buffer
01238  *
01239  * returns the size of the key bag on success
01240  */
01241 static int wc_PKCS12_create_key_bag(WC_PKCS12* pkcs12, WC_RNG* rng,
01242         byte* out, word32* outSz, byte* key, word32 keySz, int algo, int iter,
01243         char* pass, int passSz)
01244 {
01245     void* heap;
01246     byte* tmp;
01247     word32 length  = 0;
01248     word32 idx     = 0;
01249     word32 totalSz = 0;
01250     word32 sz;
01251     word32 i;
01252     word32 tmpSz;
01253     int ret;
01254 
01255     /* get max size for shrouded key */
01256     ret =  wc_PKCS12_shroud_key(pkcs12, rng, NULL, &length, key, keySz,
01257             algo, pass, passSz, iter);
01258     if (ret != LENGTH_ONLY_E && ret < 0) {
01259         return ret;
01260     }
01261 
01262     if (out == NULL) {
01263         *outSz = MAX_SEQ_SZ + WC_PKCS12_DATA_OBJ_SZ + 1 + MAX_LENGTH_SZ +
01264             length;
01265         return LENGTH_ONLY_E;
01266     }
01267 
01268     heap = wc_PKCS12_GetHeap(pkcs12);
01269 
01270     /* leave room for sequence */
01271     idx += MAX_SEQ_SZ;
01272 
01273     if (algo < 0) { /* not encrypted */
01274         out[idx++] = ASN_OBJECT_ID; totalSz++;
01275         sz = SetLength(sizeof(WC_PKCS12_KeyBag_OID), out + idx);
01276         idx += sz; totalSz += sz;
01277         for (i = 0; i < sizeof(WC_PKCS12_KeyBag_OID); i++) {
01278             out[idx++] = WC_PKCS12_KeyBag_OID[i]; totalSz++;
01279         }
01280     }
01281     else { /* encrypted */
01282         out[idx++] = ASN_OBJECT_ID; totalSz++;
01283         sz = SetLength(sizeof(WC_PKCS12_ShroudedKeyBag_OID), out + idx);
01284         idx += sz; totalSz += sz;
01285         for (i = 0; i < sizeof(WC_PKCS12_ShroudedKeyBag_OID); i++) {
01286             out[idx++] = WC_PKCS12_ShroudedKeyBag_OID[i]; totalSz++;
01287         }
01288     }
01289 
01290     /* shroud key */
01291     tmp = (byte*)XMALLOC(length, heap, DYNAMIC_TYPE_TMP_BUFFER);
01292     if (tmp == NULL) {
01293         return MEMORY_E;
01294     }
01295 
01296     ret =  wc_PKCS12_shroud_key(pkcs12, rng, tmp, &length, key, keySz,
01297             algo, pass, passSz, iter);
01298     if (ret < 0) {
01299         XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
01300         return ret;
01301     }
01302     length = ret;
01303     XMEMCPY(out + idx, tmp, length);
01304     XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
01305     totalSz += length;
01306 
01307     /* set begining sequence */
01308     tmpSz = SetSequence(totalSz, out);
01309     XMEMMOVE(out + tmpSz, out + MAX_SEQ_SZ, totalSz);
01310 
01311     (void)heap;
01312     return totalSz + tmpSz;
01313 }
01314 
01315 
01316 /* Helper function to create cert bag.
01317  *
01318  * pkcs12 structure to use with cert bag
01319  * out    buffer to hold results
01320  * outSz  size of out buffer
01321  * cert   cert that is going into cert bag
01322  * certSz size of cert buffer
01323  *
01324  * returns the size of the cert bag on success
01325  */
01326 static int wc_PKCS12_create_cert_bag(WC_PKCS12* pkcs12,
01327         byte* out, word32* outSz, byte* cert, word32 certSz)
01328 {
01329     word32 length = 0;
01330     word32 idx = 0;
01331     word32 totalSz = 0;
01332     word32 sz;
01333     int WC_CERTBAG_OBJECT_ID  = 13;
01334     int WC_CERTBAG1_OBJECT_ID = 12;
01335     word32 i;
01336     word32 tmpSz;
01337 
01338     if (out == NULL) {
01339         *outSz = MAX_SEQ_SZ + WC_CERTBAG_OBJECT_ID + 1 + MAX_LENGTH_SZ +
01340             MAX_SEQ_SZ + WC_CERTBAG1_OBJECT_ID + 1 + MAX_LENGTH_SZ + 1 +
01341             MAX_LENGTH_SZ + certSz;
01342         return LENGTH_ONLY_E;
01343     }
01344 
01345     /* check buffer size able to handle max size */
01346     if (*outSz < (MAX_SEQ_SZ + WC_CERTBAG_OBJECT_ID + 1 + MAX_LENGTH_SZ +
01347             MAX_SEQ_SZ + WC_CERTBAG1_OBJECT_ID + 1 + MAX_LENGTH_SZ + 1 +
01348             MAX_LENGTH_SZ + certSz)) {
01349         return BUFFER_E;
01350     }
01351 
01352     /* save room for sequence */
01353     idx += MAX_SEQ_SZ;
01354 
01355     /* objectId WC_PKCS12_CertBag */
01356     out[idx++] = ASN_OBJECT_ID; totalSz++;
01357     sz = SetLength(sizeof(WC_PKCS12_CertBag_OID), out + idx);
01358     idx += sz; totalSz += sz;
01359     for (i = 0; i < sizeof(WC_PKCS12_CertBag_OID); i++) {
01360         out[idx++] = WC_PKCS12_CertBag_OID[i]; totalSz++;
01361     }
01362 
01363     /**** Cert Bag type 1 ****/
01364     out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC); totalSz++;
01365 
01366     /* save room for length and sequence */
01367     idx += MAX_LENGTH_SZ;
01368     idx += MAX_SEQ_SZ;
01369 
01370     /* object id WC_PKCS12_CertBag_Type1 */
01371     out[idx++] = ASN_OBJECT_ID; length++;
01372     sz = SetLength(sizeof(WC_PKCS12_CertBag_Type1_OID), out + idx);
01373     idx += sz; length += sz;
01374     for (i = 0; i < sizeof(WC_PKCS12_CertBag_Type1_OID); i++) {
01375         out[idx++] = WC_PKCS12_CertBag_Type1_OID[i]; length++;
01376     }
01377 
01378     out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC); length++;
01379     sz = 0;
01380     idx += MAX_LENGTH_SZ; /* save room for length */
01381 
01382     /* place the cert in the buffer */
01383     out[idx++] = ASN_OCTET_STRING; sz++;
01384     tmpSz = SetLength(certSz, out + idx);
01385     idx += tmpSz; sz += tmpSz;
01386     XMEMCPY(out + idx, cert, certSz);
01387     idx += certSz; sz += certSz;
01388 
01389     /* rewind idx and place length */
01390     idx -= (sz + MAX_LENGTH_SZ);
01391     tmpSz = SetLength(sz, out + idx);
01392     XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, sz);
01393     idx += tmpSz + sz; length += tmpSz + sz;
01394 
01395     /* rewind idx and set sequence */
01396     idx -= (length + MAX_SEQ_SZ);
01397     tmpSz = SetSequence(length, out + idx);
01398     XMEMMOVE(out + idx + tmpSz, out + idx + MAX_SEQ_SZ, length);
01399     length += tmpSz;
01400 
01401     /* place final length */
01402     idx -= MAX_LENGTH_SZ;
01403     tmpSz = SetLength(length, out + idx);
01404     XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, length);
01405     length += tmpSz;
01406 
01407     /* place final sequence */
01408     totalSz += length;
01409     tmpSz = SetSequence(totalSz, out);
01410     XMEMMOVE(out + tmpSz, out + MAX_SEQ_SZ, totalSz);
01411 
01412     (void)pkcs12;
01413 
01414     return totalSz + tmpSz;
01415 }
01416 
01417 
01418 /* Helper function to encrypt content.
01419  *
01420  * pkcs12    structure to use with key bag
01421  * rng       random number generator used
01422  * out       buffer to hold results
01423  * outSz     size of out buffer
01424  * content   content to encrypt
01425  * contentSz size of content buffer
01426  * vAlgo     algorithm version
01427  * pass      password to use
01428  * passSz    size of pass buffer
01429  * iter      number of iterations
01430  * type      content type i.e WC_PKCS12_ENCRYPTED_DATA or WC_PKCS12_DATA
01431  *
01432  * returns the size of result on success
01433  */
01434 static int wc_PKCS12_encrypt_content(WC_PKCS12* pkcs12, WC_RNG* rng,
01435         byte* out, word32* outSz, byte* content, word32 contentSz, int vAlgo,
01436         const char* pass, int passSz, int iter, int type)
01437 {
01438     void* heap;
01439     int vPKCS     = 1; /* PKCS#12 is always set to 1 */
01440     int ret;
01441     byte*  tmp;
01442     word32 idx = 0;
01443     word32 totalSz = 0;
01444     word32 length = 0;
01445     word32 tmpSz;
01446     word32 encSz;
01447     word32 i;
01448 
01449     WOLFSSL_MSG("encrypting PKCS12 content");
01450 
01451     heap = wc_PKCS12_GetHeap(pkcs12);
01452 
01453     /* ENCRYPTED DATA
01454      * ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC
01455      * length
01456      * sequence
01457      * short int
01458      * sequence
01459      * get object id */
01460     if (type == WC_PKCS12_ENCRYPTED_DATA) {
01461         if (out == NULL) {
01462             *outSz = 1 + MAX_LENGTH_SZ + MAX_SEQ_SZ + MAX_VERSION_SZ +
01463                 MAX_SEQ_SZ + WC_PKCS12_DATA_OBJ_SZ;
01464             ret = EncryptContent(NULL, contentSz + MAX_SEQ_SZ, NULL, &encSz,
01465                     pass, passSz, vPKCS, vAlgo, NULL, 0, iter, rng, heap);
01466             if (ret != LENGTH_ONLY_E) {
01467                 return ret;
01468             }
01469 
01470             *outSz += encSz;
01471             return LENGTH_ONLY_E;
01472         }
01473 
01474         if (*outSz < (1 + MAX_LENGTH_SZ + MAX_SEQ_SZ + MAX_VERSION_SZ)) {
01475             return BUFFER_E;
01476         }
01477         out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC); totalSz++;
01478 
01479         /* save room for length and sequence */
01480         idx += MAX_LENGTH_SZ;
01481         idx += MAX_SEQ_SZ;
01482 
01483         tmpSz = SetMyVersion(0, out + idx, 0);
01484         idx += tmpSz; length += tmpSz;
01485 
01486         encSz = contentSz;
01487         if ((ret = EncryptContent(NULL, contentSz, NULL, &encSz,
01488                    pass, passSz, vPKCS, vAlgo, NULL, 0, iter, rng, heap)) < 0) {
01489             if (ret != LENGTH_ONLY_E) {
01490                 return ret;
01491             }
01492         }
01493 
01494         if (*outSz < (idx + MAX_SEQ_SZ + WC_PKCS12_DATA_OBJ_SZ + encSz)) {
01495             return BUFFER_E;
01496         }
01497         tmp = (byte*)XMALLOC(encSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
01498         if (tmp == NULL) {
01499             return MEMORY_E;
01500         }
01501 
01502         if ((ret = EncryptContent(content, contentSz, tmp, &encSz,
01503                    pass, passSz, vPKCS, vAlgo, NULL, 0, iter, rng, heap)) < 0) {
01504             XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
01505             return ret;
01506         }
01507         encSz = ret;
01508 
01509         #ifdef WOLFSSL_DEBUG_PKCS12
01510         {
01511             byte* p;
01512             for (printf("(size %u) Encrypted Content = ", encSz),
01513                     p = (byte*)tmp;
01514                 p < (byte*)tmp + encSz;
01515                 printf("%02X", *p), p++);
01516             printf("\n");
01517         }
01518         #endif
01519 
01520         tmpSz = SetSequence(WC_PKCS12_DATA_OBJ_SZ + encSz, out + idx);
01521         idx += tmpSz; length += tmpSz;
01522 
01523         out[idx++] = ASN_OBJECT_ID; length++;
01524         tmpSz = SetLength(sizeof(WC_PKCS12_DATA_OID), out + idx);
01525         idx += tmpSz; length += tmpSz;
01526         for (i = 0; i < sizeof(WC_PKCS12_DATA_OID); i++) {
01527             out[idx++] = WC_PKCS12_DATA_OID[i]; length++;
01528         }
01529 
01530         /* copy over encrypted data */
01531         XMEMCPY(out + idx, tmp, encSz);
01532         XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER);
01533         idx += encSz; length += encSz;
01534 
01535         /* rewind and place sequence */
01536         idx -= (length + MAX_SEQ_SZ);
01537         tmpSz = SetSequence(length, out + idx);
01538         XMEMMOVE(out + idx + tmpSz, out + idx + MAX_SEQ_SZ, length);
01539         length += tmpSz;
01540 
01541         /* now place length */
01542         idx -= MAX_LENGTH_SZ;
01543         tmpSz = SetLength(length, out + idx);
01544         XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, length);
01545         totalSz += length + tmpSz;
01546 
01547         return totalSz;
01548     }
01549 
01550     /* DATA
01551      * ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC
01552      * length
01553      * ASN_OCTET_STRING
01554      * length
01555      * sequence containing all bags */
01556     if (type == WC_PKCS12_DATA) {
01557         if (out == NULL) {
01558             *outSz = 1 + MAX_LENGTH_SZ + 1 + MAX_LENGTH_SZ + contentSz;
01559             return LENGTH_ONLY_E;
01560         }
01561 
01562         if (*outSz < (1 + MAX_LENGTH_SZ + 1 + MAX_LENGTH_SZ + contentSz)) {
01563             return BUFFER_E;
01564         }
01565 
01566         out[idx++] = (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC);
01567         totalSz++;
01568 
01569         /* save room for length */
01570         idx += MAX_LENGTH_SZ;
01571 
01572         out[idx++] = ASN_OCTET_STRING; length++;
01573         tmpSz = SetLength(contentSz, out + idx);
01574         idx += tmpSz; length += tmpSz;
01575 
01576         /* sequence containing all bags */
01577         XMEMCPY(out + idx, content, contentSz);
01578         idx += contentSz; length += contentSz;
01579 
01580         idx -= (MAX_LENGTH_SZ + length);
01581         tmpSz = SetLength(length, out + idx);
01582         XMEMMOVE(out + idx + tmpSz, out + idx + MAX_LENGTH_SZ, length);
01583         totalSz += length + tmpSz;
01584 
01585         return totalSz;
01586     }
01587 
01588     WOLFSSL_MSG("Unknown/Unsupported content type");
01589     return BAD_FUNC_ARG;
01590 }
01591 
01592 
01593 /*
01594  * pass : password to use with encryption
01595  * passSz : size of the password buffer
01596  * name : friendlyName to use
01597  * key  : DER format of key
01598  * keySz : size of key buffer
01599  * cert : DER format of certificate
01600  * certSz : size of the certificate buffer
01601  * ca   : a list of extra certificates
01602  * nidKey  : type of encryption to use on the key (-1 means no encryption)
01603  * nidCert : type of encryption to use on the certificate
01604  *           (-1 means no encryption)
01605  * iter    : number of iterations with encryption
01606  * macIter : number of iterations when creating MAC
01607  * keyType : flag for signature and/or encryption key
01608  * heap : pointer to allocate from memory
01609  *
01610  * returns a pointer to a new WC_PKCS12 structure on success and NULL if failed
01611  */
01612 WC_PKCS12* wc_PKCS12_create(char* pass, word32 passSz, char* name,
01613         byte* key, word32 keySz, byte* cert, word32 certSz, WC_DerCertList* ca,
01614         int nidKey, int nidCert, int iter, int macIter, int keyType, void* heap)
01615 {
01616     WC_PKCS12*         pkcs12;
01617     AuthenticatedSafe* safe;
01618     ContentInfo*       ci;
01619     WC_RNG rng;
01620     int algo;
01621     int ret;
01622     int type;
01623     word32 idx;
01624     word32 sz;
01625     word32 tmpSz;
01626 
01627     byte*  certCi = NULL;
01628     word32 certCiSz;
01629     byte*  keyCi;
01630     word32 keyCiSz;
01631 
01632     byte*  certBuf = NULL;
01633     word32 certBufSz;
01634     byte*  keyBuf;
01635     word32 keyBufSz = 0;
01636 
01637     WOLFSSL_ENTER("wc_PKCS12_create()");
01638 
01639     if ((ret = wc_InitRng_ex(&rng, heap, INVALID_DEVID)) != 0) {
01640         return NULL;
01641     }
01642 
01643     if ((pkcs12 = wc_PKCS12_new()) == NULL) {
01644         wc_FreeRng(&rng);
01645         WOLFSSL_LEAVE("wc_PKCS12_create", MEMORY_E);
01646         return NULL;
01647     }
01648 
01649     if ((ret = wc_PKCS12_SetHeap(pkcs12, heap)) != 0) {
01650         wc_PKCS12_free(pkcs12);
01651         wc_FreeRng(&rng);
01652         WOLFSSL_LEAVE("wc_PKCS12_create", ret);
01653         return NULL;
01654     }
01655 
01656     if (iter <= 0) {
01657         iter = WC_PKCS12_ITT_DEFAULT;
01658     }
01659 
01660     /**** add private key bag ****/
01661     switch (nidKey) {
01662         case PBE_SHA1_RC4_128:
01663             algo = 1;
01664             break;
01665 
01666         case PBE_SHA1_DES:
01667             algo = 2;
01668             break;
01669 
01670         case PBE_SHA1_DES3:
01671             algo = 3;
01672             break;
01673 
01674         /* no encryption */
01675         case -1:
01676             algo = -1;
01677             break;
01678 
01679         default:
01680             WOLFSSL_MSG("Unknown/Unsupported key encryption");
01681             wc_PKCS12_free(pkcs12);
01682             wc_FreeRng(&rng);
01683             return NULL;
01684     }
01685 
01686     /* get max size for key bag */
01687     ret = wc_PKCS12_create_key_bag(pkcs12, &rng, NULL, &keyBufSz, key, keySz,
01688             algo, iter, pass, passSz);
01689     if (ret != LENGTH_ONLY_E && ret < 0) {
01690         wc_PKCS12_free(pkcs12);
01691         wc_FreeRng(&rng);
01692         WOLFSSL_LEAVE("wc_PKCS12_create", ret);
01693         return NULL;
01694     }
01695 
01696     /* account for sequence around bag */
01697     keyBufSz += MAX_SEQ_SZ;
01698 
01699     keyBuf = (byte*)XMALLOC(keyBufSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
01700     if (keyBuf == NULL) {
01701         wc_PKCS12_free(pkcs12);
01702         wc_FreeRng(&rng);
01703         WOLFSSL_LEAVE("wc_PKCS12_create", MEMORY_E);
01704         return NULL;
01705     }
01706 
01707     ret = wc_PKCS12_create_key_bag(pkcs12, &rng, keyBuf + MAX_SEQ_SZ, &keyBufSz,
01708             key, keySz, algo, iter, pass, passSz);
01709     if (ret < 0) {
01710         wc_PKCS12_free(pkcs12);
01711         wc_FreeRng(&rng);
01712         XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01713         WOLFSSL_LEAVE("wc_PKCS12_create", ret);
01714         return NULL;
01715     }
01716     keyBufSz = ret;
01717 
01718     tmpSz = SetSequence(keyBufSz, keyBuf);
01719     XMEMMOVE(keyBuf + tmpSz, keyBuf + MAX_SEQ_SZ, keyBufSz);
01720     keyBufSz += tmpSz;
01721 
01722     ret = wc_PKCS12_encrypt_content(pkcs12, &rng, NULL, &keyCiSz,
01723             NULL, keyBufSz, algo, pass, passSz, iter, WC_PKCS12_DATA);
01724     if (ret != LENGTH_ONLY_E) {
01725         wc_PKCS12_free(pkcs12);
01726         wc_FreeRng(&rng);
01727         XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01728         WOLFSSL_LEAVE("wc_PKCS12_create", ret);
01729         return NULL;
01730     }
01731     keyCi = (byte*)XMALLOC(keyCiSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
01732     if (keyCi == NULL) {
01733         wc_PKCS12_free(pkcs12);
01734         wc_FreeRng(&rng);
01735         XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01736         return NULL;
01737     }
01738 
01739     ret = wc_PKCS12_encrypt_content(pkcs12, &rng, keyCi, &keyCiSz,
01740             keyBuf, keyBufSz, algo, pass, passSz, iter, WC_PKCS12_DATA);
01741     if (ret < 0 ) {
01742         wc_PKCS12_free(pkcs12);
01743         wc_FreeRng(&rng);
01744         XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01745         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01746         WOLFSSL_LEAVE("wc_PKCS12_create", ret);
01747         return NULL;
01748     }
01749     keyCiSz = ret;
01750     XFREE(keyBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01751 
01752     #ifdef WOLFSSL_DEBUG_PKCS12
01753     {
01754         byte* p;
01755         for (printf("(size %u) Key Content Info = ", keyCiSz), p = (byte*)keyCi;
01756             p < (byte*)keyCi + keyCiSz;
01757             printf("%02X", *p), p++);
01758         printf("\n");
01759     }
01760     #endif
01761 
01762 
01763     /**** add main certificate bag and extras ****/
01764     switch (nidCert) {
01765         case PBE_SHA1_RC4_128:
01766             type = WC_PKCS12_ENCRYPTED_DATA;
01767             algo = 1;
01768             break;
01769 
01770         case PBE_SHA1_DES:
01771             type = WC_PKCS12_ENCRYPTED_DATA;
01772             algo = 2;
01773             break;
01774 
01775         case PBE_SHA1_DES3:
01776             type = WC_PKCS12_ENCRYPTED_DATA;
01777             algo = 3;
01778             break;
01779 
01780         case -1:
01781             type = WC_PKCS12_DATA;
01782             algo = -1;
01783             break;
01784 
01785         default:
01786             WOLFSSL_MSG("Unknown/Unsupported certificate encryption");
01787             XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01788             wc_PKCS12_free(pkcs12);
01789             wc_FreeRng(&rng);
01790             return NULL;
01791     }
01792 
01793     /* get max size of buffer needed */
01794     ret = wc_PKCS12_create_cert_bag(pkcs12, NULL, &certBufSz, cert, certSz);
01795     if (ret != LENGTH_ONLY_E) {
01796         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01797         wc_PKCS12_free(pkcs12);
01798         wc_FreeRng(&rng);
01799         return NULL;
01800     }
01801 
01802     if (ca != NULL) {
01803         WC_DerCertList* current = ca;
01804         word32 curBufSz = 0;
01805 
01806         /* get max buffer size */
01807         while (current != NULL) {
01808             ret = wc_PKCS12_create_cert_bag(pkcs12, NULL, &curBufSz,
01809                     current->buffer, current->bufferSz);
01810             if (ret != LENGTH_ONLY_E) {
01811                 XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01812                 wc_PKCS12_free(pkcs12);
01813                 wc_FreeRng(&rng);
01814                 return NULL;
01815             }
01816             certBufSz += curBufSz;
01817             current    = current->next;
01818         }
01819     }
01820 
01821     /* account for Sequence that holds all certificate bags */
01822     certBufSz += MAX_SEQ_SZ;
01823 
01824     /* completed getting max size, now create buffer and start adding bags */
01825     certBuf = (byte*)XMALLOC(certBufSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
01826     if (certBuf == NULL) {
01827         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01828         wc_PKCS12_free(pkcs12);
01829         wc_FreeRng(&rng);
01830         WOLFSSL_MSG("Memory error creating certificate bags");
01831         return NULL;
01832     }
01833 
01834     idx = 0;
01835     idx += MAX_SEQ_SZ;
01836 
01837     sz = certBufSz - idx;
01838     if ((ret = wc_PKCS12_create_cert_bag(pkcs12, certBuf + idx, &sz,
01839             cert, certSz)) < 0) {
01840         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01841         XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01842         wc_PKCS12_free(pkcs12);
01843         wc_FreeRng(&rng);
01844         return NULL;
01845     }
01846     idx += ret;
01847 
01848     if (ca != NULL) {
01849         WC_DerCertList* current = ca;
01850 
01851         while (current != NULL) {
01852             sz = certBufSz - idx;
01853             if ((ret = wc_PKCS12_create_cert_bag(pkcs12, certBuf + idx, &sz,
01854                current->buffer, current->bufferSz)) < 0) {
01855                 XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01856                 XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01857                 wc_PKCS12_free(pkcs12);
01858                 wc_FreeRng(&rng);
01859                 return NULL;
01860             }
01861             idx    += ret;
01862             current = current->next;
01863         }
01864     }
01865 
01866     /* set sequence and create encrypted content with all certificate bags */
01867     tmpSz = SetSequence(idx - MAX_SEQ_SZ, certBuf);
01868     XMEMMOVE(certBuf + tmpSz, certBuf + MAX_SEQ_SZ, idx - MAX_SEQ_SZ);
01869     certBufSz = tmpSz + (idx - MAX_SEQ_SZ);
01870 
01871     /* get buffer size needed for content info */
01872     ret = wc_PKCS12_encrypt_content(pkcs12, &rng, NULL, &certCiSz,
01873             NULL, certBufSz, algo, pass, passSz, iter, type);
01874     if (ret != LENGTH_ONLY_E) {
01875         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01876         XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01877         wc_PKCS12_free(pkcs12);
01878         wc_FreeRng(&rng);
01879         WOLFSSL_LEAVE("wc_PKCS12_create()", ret);
01880         return NULL;
01881     }
01882     certCi = (byte*)XMALLOC(certCiSz, heap, DYNAMIC_TYPE_TMP_BUFFER);
01883     if (certCi == NULL) {
01884         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01885         XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01886         wc_PKCS12_free(pkcs12);
01887         wc_FreeRng(&rng);
01888         return NULL;
01889     }
01890 
01891     ret = wc_PKCS12_encrypt_content(pkcs12, &rng, certCi, &certCiSz,
01892             certBuf, certBufSz, algo, pass, passSz, iter, type);
01893     if (ret < 0) {
01894         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01895         XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01896         XFREE(certCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01897         wc_PKCS12_free(pkcs12);
01898         wc_FreeRng(&rng);
01899         WOLFSSL_LEAVE("wc_PKCS12_create()", ret);
01900         return NULL;
01901     }
01902     certCiSz = ret;
01903     XFREE(certBuf, heap, DYNAMIC_TYPE_TMP_BUFFER);
01904 
01905     #ifdef WOLFSSL_DEBUG_PKCS12
01906     {
01907         byte* p;
01908         for (printf("(size %u) Encrypted Certificate Content Info = ",certCiSz),
01909                 p = (byte*)certCi;
01910             p < (byte*)certCi + certCiSz;
01911             printf("%02X", *p), p++);
01912         printf("\n");
01913     }
01914     #endif
01915 
01916     /**** create safe and and Content Info ****/
01917     safe = (AuthenticatedSafe*)XMALLOC(sizeof(AuthenticatedSafe), heap,
01918             DYNAMIC_TYPE_PKCS);
01919     if (safe == NULL) {
01920         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01921         XFREE(certCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01922         wc_PKCS12_free(pkcs12);
01923         wc_FreeRng(&rng);
01924         return NULL;
01925     }
01926     pkcs12->safe = safe; /* set so all of safe is free'd with wc_PKCS12_free */
01927     XMEMSET(safe, 0, sizeof(AuthenticatedSafe));
01928 
01929     safe->dataSz = certCiSz + keyCiSz;
01930     safe->data   = (byte*)XMALLOC(safe->dataSz, heap, DYNAMIC_TYPE_PKCS);
01931     if (safe->data == NULL) {
01932         XFREE(keyCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01933         XFREE(certCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01934         wc_PKCS12_free(pkcs12);
01935         wc_FreeRng(&rng);
01936         return NULL;
01937     }
01938     XMEMCPY(safe->data, certCi, certCiSz);
01939     XMEMCPY(safe->data + certCiSz, keyCi, keyCiSz);
01940     XFREE(certCi, heap, DYNAMIC_TYPE_TMP_BUFFER);
01941     XFREE(keyCi,  heap, DYNAMIC_TYPE_TMP_BUFFER);
01942 
01943     safe->numCI = 2;
01944 
01945     /* add Content Info structs to safe, key first then cert */
01946     ci = (ContentInfo*)XMALLOC(sizeof(ContentInfo), heap, DYNAMIC_TYPE_PKCS);
01947     if (ci == NULL) {
01948         wc_PKCS12_free(pkcs12);
01949         wc_FreeRng(&rng);
01950         return NULL;
01951     }
01952     XMEMSET(ci, 0, sizeof(ContentInfo));
01953     safe->CI = ci;
01954     ci->data = safe->data + certCiSz;
01955     ci->dataSz = keyCiSz;
01956     ci->type = WC_PKCS12_DATA;
01957 
01958     ci = (ContentInfo*)XMALLOC(sizeof(ContentInfo), heap, DYNAMIC_TYPE_PKCS);
01959     if (ci == NULL) {
01960         wc_PKCS12_free(pkcs12);
01961         wc_FreeRng(&rng);
01962         return NULL;
01963     }
01964     XMEMSET(ci, 0, sizeof(ContentInfo));
01965     ci->next = safe->CI;
01966     safe->CI = ci;
01967     ci->data = safe->data;
01968     ci->dataSz = certCiSz;
01969     if (nidCert < 0) {
01970         ci->type = WC_PKCS12_DATA;
01971     }
01972     else {
01973         ci->type = WC_PKCS12_ENCRYPTED_DATA;
01974     }
01975 
01976     /* create MAC */
01977     if (macIter > 0) {
01978         MacData* mac;
01979         byte digest[WC_MAX_DIGEST_SIZE]; /* for MAC */
01980 
01981         mac = (MacData*)XMALLOC(sizeof(MacData), heap, DYNAMIC_TYPE_PKCS);
01982         if (mac == NULL) {
01983             wc_PKCS12_free(pkcs12);
01984             wc_FreeRng(&rng);
01985             return NULL;
01986         }
01987         XMEMSET(mac, 0, sizeof(MacData));
01988         pkcs12->signData = mac; /* now wc_PKCS12_free will free all mac too */
01989 
01990         #ifndef NO_SHA256
01991             mac->oid = SHA256h;
01992         #elif !defined(NO_SHA)
01993             mac->oid = SHA;
01994         #elif defined(WOLFSSL_SHA384)
01995             mac->oid = SHA384;
01996         #elif defined(WOLFSSL_SHA512)
01997             mac->oid = SHA512;
01998         #else
01999             WOLFSSL_MSG("No supported hash algorithm compiled in!");
02000             wc_PKCS12_free(pkcs12);
02001             wc_FreeRng(&rng);
02002             return NULL;
02003         #endif
02004 
02005         /* store number of iterations */
02006         mac->itt = macIter;
02007 
02008         /* set mac salt */
02009         mac->saltSz = 8;
02010         mac->salt = (byte*)XMALLOC(mac->saltSz, heap, DYNAMIC_TYPE_PKCS);
02011         if (mac->salt == NULL) {
02012             wc_PKCS12_free(pkcs12);
02013             wc_FreeRng(&rng);
02014             return NULL;
02015         }
02016 
02017         if ((ret = wc_RNG_GenerateBlock(&rng, mac->salt, mac->saltSz)) != 0) {
02018             WOLFSSL_MSG("Error generating random salt");
02019             wc_PKCS12_free(pkcs12);
02020             wc_FreeRng(&rng);
02021             return NULL;
02022         }
02023         ret = wc_PKCS12_create_mac(pkcs12, safe->data, safe->dataSz,
02024                          (const byte*)pass, passSz, digest, WC_MAX_DIGEST_SIZE);
02025         if (ret < 0) {
02026             wc_PKCS12_free(pkcs12);
02027             wc_FreeRng(&rng);
02028             return NULL;
02029         }
02030 
02031         mac->digestSz = ret;
02032         mac->digest = (byte*)XMALLOC(ret, heap, DYNAMIC_TYPE_PKCS);
02033         if (mac->digest == NULL) {
02034             wc_PKCS12_free(pkcs12);
02035             wc_FreeRng(&rng);
02036             return NULL;
02037         }
02038         XMEMCPY(mac->digest, digest, mac->digestSz);
02039     }
02040     else {
02041         pkcs12->signData = NULL;
02042     }
02043 
02044     wc_FreeRng(&rng);
02045     (void)name;
02046     (void)keyType;
02047 
02048     return pkcs12;
02049 }
02050 
02051 
02052 /* if using a specific memory heap */
02053 int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap)
02054 {
02055     if (pkcs12 == NULL) {
02056         return BAD_FUNC_ARG;
02057     }
02058     pkcs12->heap = heap;
02059 
02060     return 0;
02061 }
02062 
02063 
02064 /* getter for heap */
02065 void* wc_PKCS12_GetHeap(WC_PKCS12* pkcs12)
02066 {
02067     if (pkcs12 == NULL) {
02068         return NULL;
02069     }
02070 
02071     return pkcs12->heap;
02072 }
02073 
02074 #undef ERROR_OUT
02075 
02076 #endif /* !NO_ASN && !NO_PWDBASED */
02077