Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: CyaSSL-Twitter-OAuth4Tw Example-client-tls-cert TwitterReader TweetTest ... more
Diff: wolfcrypt/src/pkcs12.c
- Revision:
- 11:cee25a834751
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wolfcrypt/src/pkcs12.c Tue May 30 01:44:10 2017 +0000
@@ -0,0 +1,1165 @@
+/* pkcs12.c
+ *
+ * Copyright (C) 2006-2016 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
+
+#include <wolfssl/wolfcrypt/settings.h>
+
+#if !defined(NO_ASN) && !defined(NO_PWDBASED)
+
+#include <wolfssl/wolfcrypt/asn.h>
+#include <wolfssl/wolfcrypt/asn_public.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/hmac.h>
+#include <wolfssl/wolfcrypt/logging.h>
+#ifdef NO_INLINE
+ #include <wolfssl/wolfcrypt/misc.h>
+#else
+ #define WOLFSSL_MISC_INCLUDED
+ #include <wolfcrypt/src/misc.c>
+#endif
+#include <wolfssl/wolfcrypt/pkcs12.h>
+#include <wolfssl/wolfcrypt/pwdbased.h>
+
+
+enum {
+ WC_PKCS12_KeyBag = 667,
+ WC_PKCS12_ShroudedKeyBag = 668,
+ WC_PKCS12_CertBag = 669,
+ WC_PKCS12_CertBag_Type1 = 675,
+ WC_PKCS12_CrlBag = 670,
+ WC_PKCS12_SecretBag = 671,
+ WC_PKCS12_SafeContentsBag = 672,
+ WC_PKCS12_DATA = 651,
+ WC_PKCS12_ENCRYPTED_DATA = 656,
+};
+
+typedef struct ContentInfo {
+ byte* data;
+ struct ContentInfo* next;
+ word32 encC; /* encryptedContent */
+ word32 dataSz;
+ int type; /* DATA / encrypted / envelpoed */
+} ContentInfo;
+
+
+typedef struct AuthenticatedSafe {
+ ContentInfo* CI;
+ byte* data; /* T contents.... */
+ word32 oid; /* encrypted or not */
+ word32 numCI; /* number of Content Info structs */
+ word32 dataSz;
+} AuthenticatedSafe;
+
+
+typedef struct MacData {
+ byte* digest;
+ byte* salt;
+ word32 oid;
+ word32 digestSz;
+ word32 saltSz;
+ int itt; /* number of itterations when creating HMAC key */
+} MacData;
+
+
+struct WC_PKCS12 {
+ void* heap;
+ AuthenticatedSafe* safe;
+ MacData* signData;
+ word32 oid; /* DATA / Enveloped DATA ... */
+};
+
+
+/* for friendlyName, localKeyId .... */
+typedef struct WC_PKCS12_ATTRIBUTE {
+ byte* data;
+ word32 oid;
+ word32 dataSz;
+} WC_PKCS12_ATTRIBUTE;
+
+
+WC_PKCS12* wc_PKCS12_new(void)
+{
+ WC_PKCS12* pkcs12 = (WC_PKCS12*)XMALLOC(sizeof(WC_PKCS12),
+ NULL, DYNAMIC_TYPE_PKCS);
+ if (pkcs12 == NULL) {
+ WOLFSSL_MSG("Memory issue when creating WC_PKCS12 struct");
+ return NULL;
+ }
+
+ XMEMSET(pkcs12, 0, sizeof(WC_PKCS12));
+
+ return pkcs12;
+}
+
+
+static void freeSafe(AuthenticatedSafe* safe, void* heap)
+{
+ int i;
+
+ if (safe == NULL) {
+ return;
+ }
+
+ /* free content info structs */
+ for (i = safe->numCI; i > 0; i--) {
+ ContentInfo* ci = safe->CI;
+ safe->CI = ci->next;
+ XFREE(ci, heap, DYNAMIC_TYPE_PKCS);
+ }
+ if (safe->data != NULL) {
+ XFREE(safe->data, heap, DYNAMIC_TYPE_PKCS);
+ }
+ XFREE(safe, heap, DYNAMIC_TYPE_PKCS);
+
+ (void)heap;
+}
+
+
+void wc_PKCS12_free(WC_PKCS12* pkcs12)
+{
+ void* heap;
+
+ /* if null pointer is passed in do nothing */
+ if (pkcs12 == NULL) {
+ WOLFSSL_MSG("Trying to free null WC_PKCS12 object");
+ return;
+ }
+
+ heap = pkcs12->heap;
+ if (pkcs12->safe != NULL) {
+ freeSafe(pkcs12->safe, heap);
+ }
+
+ /* free mac data */
+ if (pkcs12->signData != NULL) {
+ if (pkcs12->signData->digest != NULL) {
+ XFREE(pkcs12->signData->digest, heap, DYNAMIC_TYPE_PKCS);
+ }
+ if (pkcs12->signData->salt != NULL) {
+ XFREE(pkcs12->signData->salt, heap, DYNAMIC_TYPE_PKCS);
+ }
+ XFREE(pkcs12->signData, heap, DYNAMIC_TYPE_PKCS);
+ }
+
+ XFREE(pkcs12, NULL, DYNAMIC_TYPE_PKCS);
+ pkcs12 = NULL;
+
+ (void)heap;
+}
+
+
+static int GetSafeContent(WC_PKCS12* pkcs12, const byte* input,
+ word32* idx, int maxIdx)
+{
+ AuthenticatedSafe* safe;
+ word32 oid;
+ word32 localIdx = *idx;
+ int ret;
+ int size = 0;
+
+ safe = (AuthenticatedSafe*)XMALLOC(sizeof(AuthenticatedSafe), pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (safe == NULL) {
+ return MEMORY_E;
+ }
+ XMEMSET(safe, 0, sizeof(AuthenticatedSafe));
+
+ ret = GetObjectId(input, &localIdx, &oid, oidIgnoreType, maxIdx);
+ if (ret < 0) {
+ WOLFSSL_LEAVE("Get object id failed", ret);
+ freeSafe(safe, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+
+ safe->oid = oid;
+ /* check tag, length */
+ if (input[localIdx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ WOLFSSL_MSG("Unexpected tag in PKCS12 DER");
+ freeSafe(safe, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(input, &localIdx, &size, maxIdx)) <= 0) {
+ freeSafe(safe, pkcs12->heap);
+ return ret;
+ }
+
+ switch (oid) {
+ case WC_PKCS12_ENCRYPTED_DATA:
+ WOLFSSL_MSG("Found PKCS12 OBJECT: ENCRYPTED DATA\n");
+ break;
+
+ case WC_PKCS12_DATA:
+ WOLFSSL_MSG("Found PKCS12 OBJECT: DATA");
+ /* get octets holding contents */
+ if (input[localIdx++] != ASN_OCTET_STRING) {
+ WOLFSSL_MSG("Wrong tag with content PKCS12 type DATA");
+ freeSafe(safe, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(input, &localIdx, &size, maxIdx)) <= 0) {
+ freeSafe(safe, pkcs12->heap);
+ return ret;
+ }
+
+ break;
+ }
+
+ safe->dataSz = size;
+ safe->data = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ if (safe->data == NULL) {
+ freeSafe(safe, pkcs12->heap);
+ return MEMORY_E;
+ }
+ XMEMCPY(safe->data, input + localIdx, size);
+ *idx = localIdx;
+
+ /* an instance of AuthenticatedSafe is created from
+ * ContentInfo's strung together in a SEQUENCE. Here we itterate
+ * through the ContentInfo's and add them to our
+ * AuthenticatedSafe struct */
+ localIdx = 0;
+ input = safe->data;
+ {
+ int CISz;
+ ret = GetSequence(input, &localIdx, &CISz, safe->dataSz);
+ if (ret < 0) {
+ freeSafe(safe, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ CISz += localIdx;
+ while ((int)localIdx < CISz) {
+ int curSz = 0;
+ word32 curIdx;
+ ContentInfo* ci = NULL;
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\t\tlooking for Content Info.... ");
+ #endif
+
+ if ((ret = GetSequence(input, &localIdx, &curSz, safe->dataSz))
+ < 0) {
+ freeSafe(safe, pkcs12->heap);
+ return ret;
+ }
+
+ if (curSz > CISz) {
+ /* subset should not be larger than universe */
+ freeSafe(safe, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+
+ curIdx = localIdx;
+ if ((ret = GetObjectId(input, &localIdx, &oid, oidIgnoreType,
+ safe->dataSz)) < 0) {
+ WOLFSSL_LEAVE("Get object id failed", ret);
+ freeSafe(safe, pkcs12->heap);
+ return ret;
+ }
+
+ /* create new content info struct ... possible OID sanity check? */
+ ci = (ContentInfo*)XMALLOC(sizeof(ContentInfo), pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (ci == NULL) {
+ freeSafe(safe, pkcs12->heap);
+ return MEMORY_E;
+ }
+
+ ci->type = oid;
+ ci->dataSz = curSz - (localIdx-curIdx);
+ ci->data = (byte*)input + localIdx;
+ localIdx += ci->dataSz;
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ switch (oid) {
+ case WC_PKCS12_ENCRYPTED_DATA:
+ printf("CONTENT INFO: ENCRYPTED DATA, size = %d\n", ci->dataSz);
+ break;
+
+ case WC_PKCS12_DATA:
+ printf("CONTENT INFO: DATA, size = %d\n", ci->dataSz);
+ break;
+ default:
+ printf("CONTENT INFO: UNKNOWN, size = %d\n", ci->dataSz);
+ }
+ #endif
+
+ /* insert to head of list */
+ ci->next = safe->CI;
+ safe->CI = ci;
+ safe->numCI += 1;
+ }
+ }
+
+ pkcs12->safe = safe;
+ *idx += localIdx;
+
+ return 1;
+}
+
+
+/* optional mac data */
+static int GetSignData(WC_PKCS12* pkcs12, const byte* mem, word32* idx,
+ word32 totalSz)
+{
+ MacData* mac;
+ word32 curIdx = *idx;
+ word32 oid = 0;
+ int size, ret;
+
+
+ /* Digest Info : Sequence
+ * DigestAlgorithmIdentifier
+ * Digest
+ */
+ if ((ret = GetSequence(mem, &curIdx, &size, totalSz)) <= 0) {
+ WOLFSSL_MSG("Failed to get PKCS12 sequence");
+ return ret;
+ }
+
+#ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\t\tSEQUENCE: DigestInfo size = %d\n", size);
+#endif
+
+ mac = (MacData*)XMALLOC(sizeof(MacData), pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ if (mac == NULL) {
+ return MEMORY_E;
+ }
+ XMEMSET(mac, 0, sizeof(MacData));
+
+ /* DigestAlgorithmIdentifier */
+ if ((ret = GetAlgoId(mem, &curIdx, &oid, oidIgnoreType, totalSz)) < 0) {
+ WOLFSSL_MSG("Failed to get PKCS12 sequence");
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return ret;
+ }
+ mac->oid = oid;
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\t\tALGO ID = %d\n", oid);
+ #endif
+
+ /* Digest: should be octet type holding digest */
+ if (mem[curIdx++] != ASN_OCTET_STRING) {
+ WOLFSSL_MSG("Failed to get digest");
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return ASN_PARSE_E;
+ }
+
+ if ((ret = GetLength(mem, &curIdx, &size, totalSz)) <= 0) {
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return ret;
+ }
+ mac->digestSz = size;
+ mac->digest = (byte*)XMALLOC(mac->digestSz, pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (mac->digest == NULL || mac->digestSz + curIdx > totalSz) {
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return MEMORY_E;
+ }
+ XMEMCPY(mac->digest, mem + curIdx, mac->digestSz);
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ {
+ byte* p;
+ for (printf("\t\tDigest = "), p = (byte*)mem+curIdx;
+ p < (byte*)mem + curIdx + mac->digestSz;
+ printf("%02X", *p), p++);
+ printf(" : size = %d\n", mac->digestSz);
+ }
+ #endif
+ curIdx += mac->digestSz;
+
+ /* get salt, should be octet string */
+ if (mem[curIdx++] != ASN_OCTET_STRING) {
+ WOLFSSL_MSG("Failed to get salt");
+ XFREE(mac->digest, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return ASN_PARSE_E;
+ }
+
+ if ((ret = GetLength(mem, &curIdx, &size, totalSz)) <= 0) {
+ XFREE(mac->digest, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return ret;
+ }
+ mac->saltSz = size;
+ mac->salt = (byte*)XMALLOC(mac->saltSz, pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (mac->salt == NULL || mac->saltSz + curIdx > totalSz) {
+ XFREE(mac->digest, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ XFREE(mac, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ return MEMORY_E;
+ }
+ XMEMCPY(mac->salt, mem + curIdx, mac->saltSz);
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ {
+ byte* p;
+ for (printf("\t\tSalt = "), p = (byte*)mem + curIdx;
+ p < (byte*)mem + curIdx + mac->saltSz;
+ printf("%02X", *p), p++);
+ printf(" : size = %d\n", mac->saltSz);
+ }
+ #endif
+ curIdx += mac->saltSz;
+
+ /* check for MAC itterations, default to 1 */
+ mac->itt = 1;
+ if (curIdx < totalSz) {
+ int number = 0;
+ if ((ret = GetShortInt(mem, &curIdx, &number, totalSz)) >= 0) {
+ /* found a itteration value */
+ mac->itt = number;
+ }
+ }
+
+#ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\t\tITTERATIONS : %d\n", mac->itt);
+#endif
+
+ *idx = curIdx;
+ pkcs12->signData = mac;
+
+ return 0;
+}
+
+
+/* check mac on pkcs12, pkcs12->mac has been sanity checked before entering *
+ * returns the result of comparison, success is 0 */
+static int wc_PKCS12_verify(WC_PKCS12* pkcs12, byte* data, word32 dataSz,
+ const byte* psw, word32 pswSz)
+{
+ Hmac hmac;
+ MacData* mac;
+ int ret, typeH, kLen;
+ int idx = 0;
+ int id = 3; /* value from RFC 7292 indicating key is used for MAC */
+ word32 i;
+ byte digest[MAX_DIGEST_SIZE];
+ byte unicodePasswd[MAX_UNICODE_SZ];
+ byte key[MAX_KEY_SIZE];
+
+ mac = pkcs12->signData;
+
+#ifdef WOLFSSL_DEBUG_PKCS12
+ printf("Verifying MAC with OID = %d\n", mac->oid);
+#endif
+
+ /* check if this builds digest size is too small */
+ if (mac->digestSz > MAX_DIGEST_SIZE) {
+ WOLFSSL_MSG("PKCS12 max digest size too small");
+ return BAD_FUNC_ARG;
+ }
+
+ /* unicode set up from asn.c */
+ if ( (pswSz * 2 + 2) > (int)sizeof(unicodePasswd)) {
+ WOLFSSL_MSG("PKCS12 max unicode size too small");
+ return UNICODE_SIZE_E;
+ }
+
+ for (i = 0; i < pswSz; i++) {
+ unicodePasswd[idx++] = 0x00;
+ unicodePasswd[idx++] = (byte)psw[i];
+ }
+ /* add trailing NULL */
+ unicodePasswd[idx++] = 0x00;
+ unicodePasswd[idx++] = 0x00;
+
+ /* get hash type used and resulting size of HMAC key */
+ switch (mac->oid) {
+ #ifndef NO_SHA
+ case SHAh: /* 88 */
+ typeH = SHA;
+ kLen = SHA_DIGEST_SIZE;
+ break;
+ #endif
+
+ #ifndef NO_SHA256
+ case SHA256h: /* 414 */
+ typeH = SHA256;
+ kLen = SHA256_DIGEST_SIZE;
+ break;
+ #endif
+
+ #ifdef WOLFSSL_SHA384
+ case SHA384h: /* 415 */
+ typeH = SHA384;
+ kLen = SHA384_DIGEST_SIZE;
+ break;
+ #endif
+
+ #ifdef WOLFSSL_SHA512
+ case SHA512h: /* 416 */
+ typeH = SHA512;
+ kLen = SHA512_DIGEST_SIZE;
+ break;
+ #endif
+
+ default: /* May be SHA224 or was just not built in */
+ WOLFSSL_MSG("Unsupported hash used");
+ return BAD_FUNC_ARG;
+ }
+
+ /* idx contains size of unicodePasswd */
+ if ((ret = wc_PKCS12_PBKDF_ex(key, unicodePasswd, idx, mac->salt,
+ mac->saltSz, mac->itt, kLen, typeH, id, pkcs12->heap)) < 0) {
+ return ret;
+ }
+
+ /* now that key has been created use it to get HMAC hash on data */
+ if ((ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID)) != 0) {
+ return ret;
+ }
+ ret = wc_HmacSetKey(&hmac, typeH, key, kLen);
+ if (ret == 0)
+ ret = wc_HmacUpdate(&hmac, data, dataSz);
+ if (ret == 0)
+ ret = wc_HmacFinal(&hmac, digest);
+ wc_HmacFree(&hmac);
+
+ if (ret != 0)
+ return ret;
+
+#ifdef WOLFSSL_DEBUG_PKCS12
+ {
+ byte* p;
+ for (printf("\t\tHash = "), p = (byte*)digest;
+ p < (byte*)digest + mac->digestSz;
+ printf("%02X", *p), p++);
+ printf(" : size = %d\n", mac->digestSz);
+ }
+#endif
+
+ return XMEMCMP(digest, mac->digest, mac->digestSz);
+}
+
+
+/* Convert DER format stored in der buffer to WC_PKCS12 struct
+ * Puts the raw contents of Content Info into structure without completly
+ * parsing or decoding.
+ * der : pointer to der buffer holding PKCS12
+ * derSz : size of der buffer
+ * pkcs12 : non-null pkcs12 pointer
+ */
+int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12)
+{
+ word32 idx = 0;
+ word32 totalSz = 0;
+ int ret;
+ int size = 0;
+ int version = 0;
+
+ WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio");
+
+ if (der == NULL || pkcs12 == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ totalSz = derSz;
+ if ((ret = GetSequence(der, &idx, &size, totalSz)) <= 0) {
+ WOLFSSL_MSG("Failed to get PKCS12 sequence");
+ return ret;
+ }
+
+ /* get version */
+ if ((ret = GetMyVersion(der, &idx, &version, totalSz)) < 0) {
+ return ret;
+ }
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\nBEGIN: PKCS12 size = %d\n", totalSz);
+ printf("version = %d\n", version);
+ #endif
+
+ if (version != 3) {
+ WOLFSSL_MSG("PKCS12 unsupported version!");
+ return ASN_VERSION_E;
+ }
+
+ if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
+ return ret;
+ }
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\tSEQUENCE: AuthenticatedSafe size = %d\n", size);
+ #endif
+
+ if ((ret = GetSafeContent(pkcs12, der, &idx, size + idx)) < 0) {
+ WOLFSSL_MSG("GetSafeContent error");
+ return ret;
+ }
+
+ /* if more buffer left check for MAC data */
+ if (idx < totalSz) {
+ if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
+ WOLFSSL_MSG("Ignoring unknown data at end of PKCS12 DER buffer");
+ }
+ else {
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ printf("\tSEQUENCE: Signature size = %d\n", size);
+ #endif
+
+ if ((ret = GetSignData(pkcs12, der, &idx, totalSz)) < 0) {
+ return ASN_PARSE_E;
+ }
+ }
+ }
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ printf("END: PKCS12\n");
+ #endif
+
+ return 1;
+}
+
+
+/* helper function to free WC_DerCertList */
+static void freeCertList(WC_DerCertList* list, void* heap) {
+ WC_DerCertList* current;
+
+ if (list == NULL) {
+ return;
+ }
+
+ current = list;
+ while(current != NULL) {
+ WC_DerCertList* next = current->next;
+ if (current->buffer != NULL) {
+ XFREE(current->buffer, heap, DYNAMIC_TYPE_PKCS);
+ }
+ XFREE(current, heap, DYNAMIC_TYPE_PKCS);
+ current = next;
+ }
+
+ (void)heap;
+}
+
+
+static void freeBuffers(byte* a, byte* b, void* heap)
+{
+ if (a != NULL) {
+ XFREE(a, heap, DYNAMIC_TYPE_PKCS);
+ }
+ if (b != NULL) {
+ XFREE(b, heap, DYNAMIC_TYPE_PKCS);
+ }
+ (void)heap;
+}
+
+
+/* return 1 on success and 0 on failure.
+ * By side effect returns private key, cert, and optionally ca.
+ * Parses and decodes the parts of PKCS12
+ *
+ * NOTE: can parse with USER RSA enabled but may return cert that is not the
+ * pair for the key when using RSA key pairs.
+ *
+ * pkcs12 : non-null WC_PKCS12 struct
+ * psw : password to use for PKCS12 decode
+ * pkey : Private key returned
+ * cert : x509 cert returned
+ * ca : optional ca returned
+ */
+int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
+ byte** pkey, word32* pkeySz, byte** cert, word32* certSz,
+ WC_DerCertList** ca)
+{
+ ContentInfo* ci = NULL;
+ WC_DerCertList* certList = NULL;
+ byte* buf = NULL;
+ word32 i, oid;
+ int ret, pswSz;
+
+ WOLFSSL_ENTER("wc_PKCS12_parse");
+
+ if (pkcs12 == NULL || psw == NULL || cert == NULL || certSz == NULL ||
+ pkey == NULL || pkeySz == NULL) {
+ return BAD_FUNC_ARG;
+ }
+ pswSz = (int)XSTRLEN(psw);
+ *cert = NULL;
+ *pkey = NULL;
+ if (ca != NULL) {
+ *ca = NULL;
+ }
+
+ /* if there is sign data then verify the MAC */
+ if (pkcs12->signData != NULL ) {
+ if ((ret = wc_PKCS12_verify(pkcs12, pkcs12->safe->data,
+ pkcs12->safe->dataSz, (byte*)psw, pswSz)) != 0) {
+ WOLFSSL_MSG("PKCS12 Bad MAC on verify");
+ WOLFSSL_LEAVE("wc_PKCS12_parse verify ", ret);
+ return MAC_CMP_FAILED_E;
+ }
+ }
+
+ if (pkcs12->safe == NULL) {
+ WOLFSSL_MSG("No PKCS12 safes to parse");
+ return BAD_FUNC_ARG;
+ }
+
+ /* Decode content infos */
+ ci = pkcs12->safe->CI;
+ for (i = 0; i < pkcs12->safe->numCI; i++) {
+ byte* data;
+ word32 idx = 0;
+ int size, totalSz;
+
+ if (ci->type == WC_PKCS12_ENCRYPTED_DATA) {
+ int number;
+
+ WOLFSSL_MSG("Decrypting PKCS12 Content Info Container");
+ data = ci->data;
+ if (data[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ if ((ret = GetSequence(data, &idx, &size, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ if ((ret = GetShortInt(data, &idx, &number, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ if (number != 0) {
+ WOLFSSL_MSG("Expecting 0 for Integer with Encrypted PKCS12");
+ }
+
+ if ((ret = GetSequence(data, &idx, &size, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ ret = GetObjectId(data, &idx, &oid, oidIgnoreType, ci->dataSz);
+ if (ret < 0 || oid != WC_PKCS12_DATA) {
+ WOLFSSL_MSG("Not PKCS12 DATA object or get object parse error");
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+
+ /* decrypted content overwrites input buffer */
+ size = ci->dataSz - idx;
+ buf = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ if (buf == NULL) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return MEMORY_E;
+ }
+ XMEMCPY(buf, data + idx, size);
+
+ if ((ret = DecryptContent(buf, size, psw, pswSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ WOLFSSL_MSG("Decryption failed, algorithm not compiled in?");
+ return ret;
+ }
+
+ data = buf;
+ idx = 0;
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ {
+ byte* p;
+ for (printf("\tData = "), p = (byte*)buf;
+ p < (byte*)buf + size;
+ printf("%02X", *p), p++);
+ printf("\n");
+ }
+ #endif
+ }
+ else { /* type DATA */
+ WOLFSSL_MSG("Parsing PKCS12 DATA Content Info Container");
+ data = ci->data;
+ if (data[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz)) <= 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+ if (data[idx++] != ASN_OCTET_STRING) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ }
+
+ /* parse through bags in ContentInfo */
+ if ((ret = GetSequence(data, &idx, &totalSz, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+ totalSz += idx;
+
+ while ((int)idx < totalSz) {
+ int bagSz;
+ if ((ret = GetSequence(data, &idx, &bagSz, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+ bagSz += idx;
+
+ if ((ret = GetObjectId(data, &idx, &oid, oidIgnoreType,
+ ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ switch (oid) {
+ case WC_PKCS12_KeyBag: /* 667 */
+ WOLFSSL_MSG("PKCS12 Key Bag found");
+ if (data[idx++] !=
+ (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz)) <= 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if (*pkey == NULL) {
+ *pkey = (byte*)XMALLOC(size, pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (*pkey == NULL) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return MEMORY_E;
+ }
+ XMEMCPY(*pkey, data + idx, size);
+ *pkeySz = ToTraditional(*pkey, size);
+ }
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ {
+ byte* p;
+ for (printf("\tKey = "), p = (byte*)*pkey;
+ p < (byte*)*pkey + size;
+ printf("%02X", *p), p++);
+ printf("\n");
+ }
+ #endif
+ idx += size;
+ break;
+
+ case WC_PKCS12_ShroudedKeyBag: /* 668 */
+ {
+ byte* k;
+ WOLFSSL_MSG("PKCS12 Shrouded Key Bag found");
+ if (data[idx++] !=
+ (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size,
+ ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+
+ k = (byte*)XMALLOC(size, pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (k == NULL) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return MEMORY_E;
+ }
+ XMEMCPY(k, data + idx, size);
+
+ /* overwrites input, be warned */
+ if ((ret = ToTraditionalEnc(k, size, psw, pswSz)) < 0) {
+ freeBuffers(k, NULL, pkcs12->heap);
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ if (ret < size) {
+ /* shrink key buffer */
+ k = (byte*)XREALLOC(k, ret, pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (k == NULL) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return MEMORY_E;
+ }
+ }
+ size = ret;
+
+ if (*pkey == NULL) {
+ *pkey = k;
+ *pkeySz = size;
+ }
+ else { /* only expecting one key */
+ freeBuffers(k, NULL, pkcs12->heap);
+ }
+ idx += size;
+
+ #ifdef WOLFSSL_DEBUG_PKCS12
+ {
+ byte* p;
+ for (printf("\tKey = "), p = (byte*)k;
+ p < (byte*)k + ret;
+ printf("%02X", *p), p++);
+ printf("\n");
+ }
+ #endif
+ }
+ break;
+
+ case WC_PKCS12_CertBag: /* 669 */
+ {
+ WC_DerCertList* node;
+ WOLFSSL_MSG("PKCS12 Cert Bag found");
+ if (data[idx++] !=
+ (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ /* get cert bag type */
+ if ((ret = GetSequence(data, &idx, &size, ci->dataSz)) <0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ if ((ret = GetObjectId(data, &idx, &oid, oidIgnoreType,
+ ci->dataSz)) < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+
+ switch (oid) {
+ case WC_PKCS12_CertBag_Type1: /* 675 */
+ /* type 1 */
+ WOLFSSL_MSG("PKCS12 cert bag type 1");
+ if (data[idx++] !=
+ (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC)) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz))
+ <= 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+ if (data[idx++] != ASN_OCTET_STRING) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+ if ((ret = GetLength(data, &idx, &size, ci->dataSz))
+ < 0) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ret;
+ }
+ break;
+ default:
+ WOLFSSL_MSG("Unknown PKCS12 cert bag type");
+ }
+
+ if (size + idx > (word32)bagSz) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return ASN_PARSE_E;
+ }
+
+ /* list to hold all certs found */
+ node = (WC_DerCertList*)XMALLOC(sizeof(WC_DerCertList),
+ pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ if (node == NULL) {
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return MEMORY_E;
+ }
+ XMEMSET(node, 0, sizeof(WC_DerCertList));
+
+ node->buffer = (byte*)XMALLOC(size, pkcs12->heap,
+ DYNAMIC_TYPE_PKCS);
+ if (node->buffer == NULL) {
+ XFREE(node, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ freeBuffers(*pkey, buf, pkcs12->heap);
+ freeCertList(certList, pkcs12->heap);
+ return MEMORY_E;
+ }
+ XMEMCPY(node->buffer, data + idx, size);
+ node->bufferSz = size;
+
+ /* put the new node into the list */
+ if (certList != NULL) {
+ WOLFSSL_MSG("Pushing new cert onto stack");
+ node->next = certList;
+ certList = node;
+ }
+ else {
+ certList = node;
+ }
+
+ /* on to next */
+ idx += size;
+ }
+ break;
+
+ case WC_PKCS12_CrlBag: /* 670 */
+ WOLFSSL_MSG("PKCS12 CRL BAG not yet supported");
+ break;
+
+ case WC_PKCS12_SecretBag: /* 671 */
+ WOLFSSL_MSG("PKCS12 Secret BAG not yet supported");
+ break;
+
+ case WC_PKCS12_SafeContentsBag: /* 672 */
+ WOLFSSL_MSG("PKCS12 Safe Contents BAG not yet supported");
+ break;
+
+ default:
+ WOLFSSL_MSG("Unknown PKCS12 BAG type found");
+ }
+
+ /* Attribute, unknown bag or unsupported */
+ if ((int)idx < bagSz) {
+ idx = bagSz; /* skip for now */
+ }
+ }
+
+ /* free temporary buffer */
+ if (buf != NULL) {
+ XFREE(buf, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ buf = NULL;
+ }
+ ci = ci->next;
+ WOLFSSL_MSG("Done Parsing PKCS12 Content Info Container");
+ }
+
+ /* check if key pair, remove from list */
+ {
+ WC_DerCertList* current = certList;
+ WC_DerCertList* previous = NULL;
+
+ if (*pkey != NULL) {
+
+ while (current != NULL) {
+ DecodedCert DeCert;
+ InitDecodedCert(&DeCert, current->buffer, current->bufferSz,
+ pkcs12->heap);
+ if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) == 0) {
+ if (wc_CheckPrivateKey(*pkey, *pkeySz, &DeCert) == 1) {
+ WOLFSSL_MSG("Key Pair found");
+ *cert = current->buffer;
+ *certSz = current->bufferSz;
+
+ if (previous == NULL) {
+ certList = current->next;
+ }
+ else {
+ previous->next = current->next;
+ }
+ FreeDecodedCert(&DeCert);
+ XFREE(current, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+ break;
+ }
+ }
+
+ FreeDecodedCert(&DeCert);
+ previous = current;
+ current = current->next;
+ }
+
+ }
+ }
+
+ if (ca != NULL) {
+ *ca = certList;
+ }
+ else {
+ /* free list, not wanted */
+ freeCertList(certList, pkcs12->heap);
+ }
+
+ return 1;
+}
+
+
+/* if using a specific memory heap */
+int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap)
+{
+ if (pkcs12 == NULL) {
+ return BAD_FUNC_ARG;
+ }
+ pkcs12->heap = heap;
+
+ return 0;
+}
+
+
+/* getter for heap */
+void* wc_PKCS12_GetHeap(WC_PKCS12* pkcs12)
+{
+ if (pkcs12 == NULL) {
+ return NULL;
+ }
+
+ return pkcs12->heap;
+}
+
+#endif /* !defined(NO_ASN) && !defined(NO_PWDBASED) */
+
+