Ver Fonte

PKCS12 : Add PKCS12 parsing

Jacob Barthelmeh há 7 anos atrás
pai
commit
b686deecbe

+ 1 - 0
.gitignore

@@ -146,6 +146,7 @@ mplabx/wolfcrypt_test.X/nbproject/Makefile-*
 mplabx/wolfcrypt_test.X/nbproject/Package-default.bash
 mplabx/wolfssl.X/nbproject/Makefile-*
 mplabx/wolfssl.X/nbproject/Package-default.bash
+*.dSYM
 
 # Vagrant folder
 .vagrant/

+ 2 - 1
certs/include.am

@@ -28,7 +28,8 @@ EXTRA_DIST += \
 	     certs/server-keyPkcs8.pem \
 	     certs/server-revoked-cert.pem \
 	     certs/server-revoked-key.pem \
-         certs/wolfssl-website-ca.pem
+	     certs/wolfssl-website-ca.pem \
+	     certs/test-servercert.p12
 EXTRA_DIST += \
 	     certs/ca-key.der \
 	     certs/ca-cert.der \

BIN
certs/test-servercert.p12


+ 3 - 0
rpm/spec.in

@@ -210,6 +210,7 @@ mkdir -p $RPM_BUILD_ROOT/
 %{_includedir}/wolfssl/wolfcrypt/mpi_class.h
 %{_includedir}/wolfssl/wolfcrypt/mpi_superclass.h
 %{_includedir}/wolfssl/wolfcrypt/pkcs7.h
+%{_includedir}/wolfssl/wolfcrypt/pkcs12.h
 %{_includedir}/wolfssl/wolfcrypt/wc_port.h
 %{_includedir}/wolfssl/wolfcrypt/poly1305.h
 %{_includedir}/wolfssl/wolfcrypt/pwdbased.h
@@ -274,6 +275,8 @@ mkdir -p $RPM_BUILD_ROOT/
 %{_libdir}/pkgconfig/wolfssl.pc
 
 %changelog
+* Fri Oct 28 2016 Jacob Barthelmeh <jacob@wolfssl.com>
+- Added header for pkcs12
 * Fri Sep 23 2016 John Safranek <john@wolfssl.com>
 - Add the dtls-sctp example sources
 * Mon Jun 14 2016 Jacob Barthelmeh <jacob@wolfssl.com>

+ 1 - 0
src/include.am

@@ -153,6 +153,7 @@ endif
 
 if BUILD_PWDBASED
 src_libwolfssl_la_SOURCES += wolfcrypt/src/pwdbased.c
+src_libwolfssl_la_SOURCES += wolfcrypt/src/pkcs12.c
 endif
 
 if BUILD_DSA

+ 407 - 0
src/ssl.c

@@ -11371,6 +11371,99 @@ byte* wolfSSL_X509_get_hw_serial_number(WOLFSSL_X509* x509,byte* in,
 
 #endif /* WOLFSSL_SEP */
 
+/* require OPENSSL_EXTRA since wolfSSL_X509_free is wrapped by OPENSSL_EXTRA */
+#if !defined(NO_CERTS) && defined(OPENSSL_EXTRA)
+/* return 1 on success 0 on fail */
+int wolfSSL_sk_X509_push(STACK_OF(WOLFSSL_X509_NAME)* sk, WOLFSSL_X509* x509)
+{
+    WOLFSSL_STACK* node;
+
+    if (sk == NULL || x509 == NULL) {
+        return 0;
+    }
+
+    /* no previous values in stack */
+    if (sk->data.x509 == NULL) {
+        sk->data.x509 = x509;
+        sk->num += 1;
+        return 1;
+    }
+
+    /* stack already has value(s) create a new node and add more */
+    node = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
+                                                             DYNAMIC_TYPE_X509);
+    if (node == NULL) {
+        WOLFSSL_MSG("Memory error");
+        return 0;
+    }
+    XMEMSET(node, 0, sizeof(WOLFSSL_STACK));
+
+    /* push new x509 onto head of stack */
+    node->data.x509 = sk->data.x509;
+    node->next      = sk->next;
+    sk->next        = node;
+    sk->data.x509   = x509;
+    sk->num        += 1;
+
+    return 1;
+}
+
+
+WOLFSSL_X509* wolfSSL_sk_X509_pop(STACK_OF(WOLFSSL_X509_NAME)* sk) {
+    WOLFSSL_STACK* node;
+    WOLFSSL_X509*  x509;
+
+    if (sk == NULL) {
+        return NULL;
+    }
+
+    node = sk->next;
+    x509 = sk->data.x509;
+
+    if (node != NULL) { /* update sk and remove node from stack */
+        sk->data.x509 = node->data.x509;
+        sk->next = node->next;
+        XFREE(node, NULL, DYNAMIC_TYPE_X509);
+    }
+    else { /* last x509 in stack */
+        sk->data.x509 = NULL;
+    }
+
+    if (sk->num > 0) {
+        sk->num -= 1;
+    }
+
+    return x509;
+}
+
+
+/* free structure for x509 stack */
+void wolfSSL_sk_X509_free(STACK_OF(WOLFSSL_X509_NAME)* sk) {
+    WOLFSSL_STACK* node;
+
+    if (sk == NULL) {
+        return;
+    }
+
+    /* parse through stack freeing each node */
+    node = sk->next;
+    while (sk->num > 1) {
+        WOLFSSL_STACK* tmp = node;
+        node = node->next;
+
+        wolfSSL_X509_free(tmp->data.x509);
+        XFREE(tmp, NULL, DYNAMIC_TYPE_X509);
+        sk->num -= 1;
+    }
+
+    /* free head of stack */
+    if (sk->num == 1) {
+	wolfSSL_X509_free(sk->data.x509);
+    }
+    XFREE(sk, NULL, DYNAMIC_TYPE_X509);
+}
+#endif /* NO_CERTS && OPENSSL_EXTRA */
+
 
 WOLFSSL_X509* wolfSSL_X509_d2i(WOLFSSL_X509** x509, const byte* in, int len)
 {
@@ -12411,6 +12504,320 @@ WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE* store,
 
 
 #ifndef NO_CERTS
+
+#if !defined(NO_ASN) && !defined(NO_PWDBASED)
+WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio, WC_PKCS12** pkcs12)
+{
+    WC_PKCS12* localPkcs12    = NULL;
+    const unsigned char* mem  = NULL;
+    int ret;
+    word32 size;
+
+    WOLFSSL_ENTER("wolfSSL_d2i_PKCS12_bio");
+
+    if (bio == NULL) {
+        WOLFSSL_MSG("Bad Function Argument bio is NULL");
+        return NULL;
+    }
+
+    localPkcs12 = wc_PKCS12_new();
+    if (localPkcs12 == NULL) {
+        WOLFSSL_MSG("Memory error");
+        return NULL;
+    }
+
+    if (pkcs12 != NULL) {
+        *pkcs12 = localPkcs12;
+    }
+
+    ret = wolfSSL_BIO_get_mem_data(bio, &mem);
+    if (mem == NULL || ret <= 0) {
+        WOLFSSL_MSG("Failed to get data from bio struct");
+        wc_PKCS12_free(localPkcs12);
+        if (pkcs12 != NULL) {
+            *pkcs12 = NULL;
+        }
+        return NULL;
+    }
+    size = ret;
+
+    ret = wc_d2i_PKCS12(mem, size, localPkcs12);
+    if (ret <= 0) {
+        WOLFSSL_MSG("Failed to get PKCS12 sequence");
+        wc_PKCS12_free(localPkcs12);
+        if (pkcs12 != NULL) {
+            *pkcs12 = NULL;
+        }
+        return NULL;
+    }
+
+    return localPkcs12;
+}
+
+
+/* return 1 on success, 0 on failure */
+int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
+      WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, STACK_OF(WOLFSSL_X509)** ca)
+{
+    DecodedCert DeCert;
+    int ret;
+    byte* certData = NULL;
+    word32 certDataSz;
+    byte* pk = NULL;
+    word32 pkSz;
+    DerCertList* certList = NULL;
+
+    WOLFSSL_ENTER("wolfSSL_PKCS12_parse");
+
+    if (pkcs12 == NULL || psw == NULL || pkey == NULL || cert == NULL) {
+        WOLFSSL_MSG("Bad argument value");
+        return 0;
+    }
+
+    *pkey = NULL;
+    *cert = NULL;
+
+    if (ca == NULL) {
+        ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz,
+            NULL);
+    }
+    else {
+        *ca = NULL;
+        ret = wc_PKCS12_parse(pkcs12, psw, &pk, &pkSz, &certData, &certDataSz,
+            &certList);
+    }
+    if (ret < 0) {
+        WOLFSSL_LEAVE("wolfSSL_PKCS12_parse", ret);
+        return 0;
+    }
+
+    /* Decode cert and place in X509 stack struct */
+    if (certList != NULL) {
+        DerCertList* current = certList;
+
+        *ca = (STACK_OF(WOLFSSL_X509)*)XMALLOC(sizeof(STACK_OF(WOLFSSL_X509)),
+                                               pkcs12->heap, DYNAMIC_TYPE_PKCS);
+        if (*ca == NULL) {
+            if (pk != NULL) {
+                XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            }
+            if (certData != NULL) {
+                XFREE(*cert, pkcs12->heap, DYNAMIC_TYPE_PKCS); *cert = NULL;
+            }
+            /* Free up DerCertList and move on */
+            while (current != NULL) {
+                DerCertList* next = current->next;
+
+                XFREE(current->buffer, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                XFREE(current, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                current = next;
+            }
+            return 0;
+        }
+        XMEMSET(*ca, 0, sizeof(STACK_OF(WOLFSSL_X509)));
+
+        /* add list of DER certs as X509's to stack */
+        while (current != NULL) {
+            DerCertList*  toFree = current;
+            WOLFSSL_X509* x509;
+
+            x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), pkcs12->heap,
+                                                             DYNAMIC_TYPE_PKCS);
+            InitX509(x509, 1, pkcs12->heap);
+            InitDecodedCert(&DeCert, current->buffer, current->bufferSz,
+                                                                  pkcs12->heap);
+            if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) {
+                WOLFSSL_MSG("Issue with parsing certificate");
+                FreeDecodedCert(&DeCert);
+                wolfSSL_X509_free(x509);
+            }
+            else {
+                if ((ret = CopyDecodedToX509(x509, &DeCert)) != 0) {
+                    WOLFSSL_MSG("Failed to copy decoded cert");
+                    FreeDecodedCert(&DeCert);
+                    wolfSSL_X509_free(x509);
+                    wolfSSL_sk_X509_free(*ca); *ca = NULL;
+                    if (pk != NULL) {
+                        XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                    }
+                    if (certData != NULL) {
+                        XFREE(certData, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                    }
+                    /* Free up DerCertList */
+                    while (current != NULL) {
+                        DerCertList* next = current->next;
+
+                        XFREE(current->buffer, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                        XFREE(current, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                        current = next;
+                    }
+                    return 0;
+                }
+                FreeDecodedCert(&DeCert);
+
+                if (wolfSSL_sk_X509_push(*ca, x509) != 1) {
+                    WOLFSSL_MSG("Failed to push x509 onto stack");
+                    wolfSSL_X509_free(x509);
+                    wolfSSL_sk_X509_free(*ca); *ca = NULL;
+                    if (pk != NULL) {
+                        XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                    }
+                    if (certData != NULL) {
+                        XFREE(certData, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                    }
+
+                    /* Free up DerCertList */
+                    while (current != NULL) {
+                        DerCertList* next = current->next;
+
+                        XFREE(current->buffer, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                        XFREE(current, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                        current = next;
+                    }
+                    return 0;
+                }
+            }
+            current = current->next;
+            XFREE(toFree->buffer, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            XFREE(toFree, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+        }
+    }
+
+
+    /* Decode cert and place in X509 struct */
+    if (certData != NULL) {
+        *cert = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), pkcs12->heap,
+                                                             DYNAMIC_TYPE_PKCS);
+        if (*cert == NULL) {
+            if (pk != NULL) {
+                XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            }
+            if (ca != NULL) {
+                wolfSSL_sk_X509_free(*ca); *ca = NULL;
+            }
+            XFREE(certData, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            return 0;
+        }
+        InitX509(*cert, 1, pkcs12->heap);
+        InitDecodedCert(&DeCert, certData, certDataSz, pkcs12->heap);
+        if (ParseCertRelative(&DeCert, CERT_TYPE, NO_VERIFY, NULL) != 0) {
+            WOLFSSL_MSG("Issue with parsing certificate");
+        }
+        if ((ret = CopyDecodedToX509(*cert, &DeCert)) != 0) {
+            WOLFSSL_MSG("Failed to copy decoded cert");
+            FreeDecodedCert(&DeCert);
+            if (pk != NULL) {
+                XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            }
+            if (ca != NULL) {
+                wolfSSL_sk_X509_free(*ca); *ca = NULL;
+            }
+            wolfSSL_X509_free(*cert); *cert = NULL;
+            return 0;
+        }
+        FreeDecodedCert(&DeCert);
+        XFREE(certData, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+    }
+
+
+    /* get key type */
+    ret = BAD_STATE_E;
+    if (pk != NULL) { /* decode key if present */
+        *pkey = (WOLFSSL_EVP_PKEY*)XMALLOC(sizeof(WOLFSSL_EVP_PKEY),
+                                               pkcs12->heap, DYNAMIC_TYPE_PKCS);
+        if (*pkey == NULL) {
+            wolfSSL_X509_free(*cert); *cert = NULL;
+            if (ca != NULL) {
+                wolfSSL_sk_X509_free(*ca); *ca = NULL;
+            }
+            XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            return 0;
+        }
+        #ifndef NO_RSA
+        {
+            word32 keyIdx = 0;
+            RsaKey key;
+
+            if (wc_InitRsaKey(&key, pkcs12->heap) != 0) {
+                ret = BAD_STATE_E;
+            }
+            else {
+                if ((ret = wc_RsaPrivateKeyDecode(pk, &keyIdx, &key, pkSz))
+                                                                         == 0) {
+                    (*pkey)->type = RSAk;
+                    WOLFSSL_MSG("Found PKCS12 RSA key");
+                }
+                wc_FreeRsaKey(&key);
+            }
+        }
+        #endif /* NO_RSA */
+
+        #ifdef HAVE_ECC
+        {
+            word32  keyIdx = 0;
+            ecc_key key;
+
+            if (ret != 0) { /* if is in fail state check if ECC key */
+                if (wc_ecc_init(&key) != 0) {
+                    wolfSSL_X509_free(*cert); *cert = NULL;
+                    if (ca != NULL) {
+                        wolfSSL_sk_X509_free(*ca); *ca = NULL;
+                    }
+                    XFREE(*pkey, pkcs12->heap, DYNAMIC_TYPE_PKCS); *pkey = NULL;
+                    XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                    return 0;
+                }
+
+                if ((ret = wc_EccPrivateKeyDecode(pk, &keyIdx, &key, pkSz))
+                                                                         != 0) {
+                    wolfSSL_X509_free(*cert); *cert = NULL;
+                    if (ca != NULL) {
+                        wolfSSL_sk_X509_free(*ca); *ca = NULL;
+                    }
+                    XFREE(*pkey, pkcs12->heap, DYNAMIC_TYPE_PKCS); *pkey = NULL;
+                    XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+                    WOLFSSL_MSG("Bad PKCS12 key format");
+                    return 0;
+                }
+                (*pkey)->type = ECDSAk;
+                (*pkey)->pkey_curve = key.dp->oidSum;
+                wc_ecc_free(&key);
+                WOLFSSL_MSG("Found PKCS12 ECC key");
+            }
+        }
+        #else
+        if (ret != 0) { /* if is in fail state and no ECC then fail */
+            wolfSSL_X509_free(*cert); *cert = NULL;
+            if (ca != NULL) {
+                wolfSSL_sk_X509_free(*ca); *ca = NULL;
+            }
+            XFREE(*pkey, pkcs12->heap, DYNAMIC_TYPE_PKCS); *pkey = NULL;
+            XFREE(pk, pkcs12->heap, DYNAMIC_TYPE_PKCS);
+            WOLFSSL_MSG("Bad PKCS12 key format");
+            return 0;
+        }
+        #endif /* HAVE_ECC */
+
+        (*pkey)->save_type = 0;
+        (*pkey)->pkey_sz   = pkSz;
+        (*pkey)->pkey.ptr  = (char*)pk;
+    }
+
+    (void)ret;
+    (void)ca;
+
+    return 1;
+}
+#endif /* !defined(NO_ASN) && !defined(NO_PWDBASED) */
+
+
+/* no-op function. Was initially used for adding encryption algorithms available
+ * for PKCS12 */
+void wolfSSL_PKCS12_PBE_add(void)
+{
+    WOLFSSL_ENTER("wolfSSL_PKCS12_PBE_add");
+}
+
 int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509)
 {
     int result = SSL_FATAL_ERROR;

+ 79 - 0
tests/api.c

@@ -45,6 +45,7 @@
 
 #ifdef OPENSSL_EXTRA
     #include <wolfssl/openssl/ssl.h>
+    #include <wolfssl/openssl/pkcs12.h>
 #endif
 
 /* enable testing buffer load functions */
@@ -1996,6 +1997,83 @@ static void test_wolfSSL_X509_NAME_get_entry(void)
 #endif /* !NO_CERTS */
 }
 
+
+/* Testing functions dealing with PKCS12 parsing out X509 certs */
+static void test_wolfSSL_PKCS12(void)
+{
+    /* .p12 file is encrypted with DES3 */
+#if defined(OPENSSL_EXTRA) && !defined(NO_DES3) && !defined(NO_FILESYSTEM) && \
+    !defined(NO_ASN) && !defined(NO_PWDBASED)
+    byte buffer[5300];
+    char file[] = "./certs/test-servercert.p12";
+    FILE *f;
+    int  bytes, ret;
+    WOLFSSL_BIO      *bio;
+    WOLFSSL_EVP_PKEY *pkey;
+    WC_PKCS12        *pkcs12;
+    WOLFSSL_X509     *cert;
+    WOLFSSL_X509     *tmp;
+    STACK_OF(WOLFSSL_X509) *ca;
+
+    printf(testingFmt, "wolfSSL_PKCS12()");
+
+    f = fopen(file, "rb");
+    AssertNotNull(f);
+    bytes = (int)fread(buffer, 1, sizeof(buffer), f);
+    fclose(f);
+
+    bio = BIO_new_mem_buf((void*)buffer, bytes);
+    AssertNotNull(bio);
+
+    pkcs12 = d2i_PKCS12_bio(bio, NULL);
+    AssertNotNull(pkcs12);
+    PKCS12_free(pkcs12);
+
+    d2i_PKCS12_bio(bio, &pkcs12);
+    AssertNotNull(pkcs12);
+
+    /* check verify MAC fail case */
+    ret = PKCS12_parse(pkcs12, "bad", &pkey, &cert, NULL);
+    AssertIntEQ(ret, 0);
+    AssertNull(pkey);
+    AssertNull(cert);
+
+    /* check parse with no extra certs kept */
+    ret = PKCS12_parse(pkcs12, "wolfSSL test", &pkey, &cert, NULL);
+    AssertIntEQ(ret, 1);
+    AssertNotNull(pkey);
+    AssertNotNull(cert);
+
+    wolfSSL_EVP_PKEY_free(pkey);
+    wolfSSL_X509_free(cert);
+
+    /* check parse with extra certs kept */
+    ret = PKCS12_parse(pkcs12, "wolfSSL test", &pkey, &cert, &ca);
+    AssertIntEQ(ret, 1);
+    AssertNotNull(pkey);
+    AssertNotNull(cert);
+    AssertNotNull(ca);
+
+    /* should be 2 other certs on stack */
+    tmp = sk_X509_pop(ca);
+    AssertNotNull(tmp);
+    X509_free(tmp);
+    tmp = sk_X509_pop(ca);
+    AssertNotNull(tmp);
+    X509_free(tmp);
+    AssertNull(sk_X509_pop(ca));
+
+    EVP_PKEY_free(pkey);
+    X509_free(cert);
+    BIO_free(bio);
+    PKCS12_free(pkcs12);
+    sk_X509_free(ca);
+
+    printf(resultFmt, passed);
+#endif /* OPENSSL_EXTRA */
+}
+
+
 /* Testing function  wolfSSL_CTX_SetMinVersion; sets the minimum downgrade
  * version allowed.
  * POST: 1 on success.
@@ -2155,6 +2233,7 @@ void ApiTest(void)
 
     /* X509 tests */
     test_wolfSSL_X509_NAME_get_entry();
+    test_wolfSSL_PKCS12();
 
     /*OCSP Stapling. */
     AssertIntEQ(test_wolfSSL_UseOCSPStapling(), SSL_SUCCESS);

+ 274 - 12
wolfcrypt/src/asn.c

@@ -582,12 +582,15 @@ WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
 
 /* Windows header clash for WinCE using GetVersion */
 WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx,
-                               int* version)
+                               int* version, word32 maxIdx)
 {
     word32 idx = *inOutIdx;
 
     WOLFSSL_ENTER("GetMyVersion");
 
+    if (idx + MIN_VERSION_SZ > maxIdx)
+        return  ASN_PARSE_E;
+
     if (input[idx++] != ASN_INTEGER)
         return ASN_PARSE_E;
 
@@ -603,13 +606,16 @@ WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx,
 
 #ifndef NO_PWDBASED
 /* Get small count integer, 32 bits or less */
-static int GetShortInt(const byte* input, word32* inOutIdx, int* number)
+int GetShortInt(const byte* input, word32* inOutIdx, int* number, word32 maxIdx)
 {
     word32 idx = *inOutIdx;
     word32 len;
 
     *number = 0;
 
+    if (idx + 2 > maxIdx) /*one for type and one for length */
+        return ASN_PARSE_E;
+
     if (input[idx++] != ASN_INTEGER)
         return ASN_PARSE_E;
 
@@ -617,6 +623,9 @@ static int GetShortInt(const byte* input, word32* inOutIdx, int* number)
     if (len > 4)
         return ASN_PARSE_E;
 
+    if (len + idx > maxIdx)
+        return ASN_PARSE_E;
+
     while (len--) {
         *number  = *number << 8 | input[idx++];
     }
@@ -629,14 +638,15 @@ static int GetShortInt(const byte* input, word32* inOutIdx, int* number)
 
 #ifndef NO_ASN_TIME
 /* May not have one, not an error */
-static int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version)
+static int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version,
+                              word32 maxIdx)
 {
     word32 idx = *inOutIdx;
 
     WOLFSSL_ENTER("GetExplicitVersion");
     if (input[idx++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) {
         *inOutIdx = ++idx;  /* eat header */
-        return GetMyVersion(input, inOutIdx, version);
+        return GetMyVersion(input, inOutIdx, version, maxIdx);
     }
 
     /* go back as is */
@@ -1365,7 +1375,7 @@ int wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
 
-    if (GetMyVersion(input, inOutIdx, &version) < 0)
+    if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
         return ASN_PARSE_E;
 
     key->type = RSA_PRIVATE;
@@ -1393,7 +1403,7 @@ int ToTraditional(byte* input, word32 sz)
     if (GetSequence(input, &inOutIdx, &length, sz) < 0)
         return ASN_PARSE_E;
 
-    if (GetMyVersion(input, &inOutIdx, &version) < 0)
+    if (GetMyVersion(input, &inOutIdx, &version, sz) < 0)
         return ASN_PARSE_E;
 
     if (GetAlgoId(input, &inOutIdx, &oid, oidKeyType, sz) < 0)
@@ -1419,6 +1429,108 @@ int ToTraditional(byte* input, word32 sz)
 }
 
 
+/* check that the private key is a pair for the public key in certificate
+ * return 1 (true) on match
+ * return 0 or negative value on failure/error
+ *
+ * key   : buffer holding DER fromat key
+ * keySz : size of key buffer
+ * der   : a initialized and parsed DecodedCert holding a certificate */
+int wc_CheckPrivateKey(byte* key, word32 keySz, DecodedCert* der)
+{
+    if (key == NULL || der == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
+    #if !defined(NO_RSA)
+    {
+        RsaKey a, b;
+        word32 keyIdx = 0;
+        int    ret    = 0;
+
+        /* test if RSA key */
+        if (wc_InitRsaKey(&a, NULL) == 0) {
+            if (wc_RsaPrivateKeyDecode(key, &keyIdx, &a, keySz) == 0 &&
+                der->keyOID == RSAk) {
+                WOLFSSL_MSG("Checking RSA key pair");
+                keyIdx = 0; /* reset to 0 for parsing public key */
+
+                if (wc_InitRsaKey(&b, NULL) == 0) {
+                    if ((ret = wc_RsaPublicKeyDecode(der->publicKey, &keyIdx,
+                                                   &b, der->pubKeySize)) == 0) {
+                        /* limit for user RSA crypto because of RsaKey
+                         * dereference. */
+                        #if defined(HAVE_USER_RSA)
+                            WOLFSSL_MSG("Cannot verify RSA pair with user RSA");
+                            wc_FreeRsaKey(&b);
+                            wc_FreeRsaKey(&a);
+                            return 1; /* return first RSA cert as match */
+                        #else
+                        /* both keys extracted successfully now check n and e
+                         * values are the same. This is dereferencing RsaKey */
+                        if (mp_cmp(&(a.n), &(b.n)) != MP_EQ ||
+                            mp_cmp(&(a.e), &(b.e)) != MP_EQ) {
+                            ret = MP_CMP_E;
+                        }
+                        else {
+                            /* match found, free keys and return success */
+                            wc_FreeRsaKey(&b);
+                            wc_FreeRsaKey(&a);
+                            return 1;
+                        }
+                        #endif
+                    }
+                    wc_FreeRsaKey(&b);
+                }
+            }
+            wc_FreeRsaKey(&a);
+        }
+
+        /* if ret is not 0 then there was a failed comparision attempt */
+        if (ret != 0) {
+            return ret;
+        }
+    }
+    #endif /* NO_RSA */
+
+    #ifdef HAVE_ECC
+    {
+        int ret = 0;
+        word32  keyIdx = 0;
+        ecc_key key_pair;
+
+        if ((ret = wc_ecc_init(&key_pair)) == 0) {
+            if (wc_EccPrivateKeyDecode(key, &keyIdx, &key_pair, keySz) == 0 &&
+                    der->keyOID == ECDSAk) {
+                WOLFSSL_MSG("Checking ECC key pair");
+                keyIdx = 0;
+                if ((ret = wc_ecc_import_x963(der->publicKey, der->pubKeySize,
+                                                             &key_pair)) == 0) {
+                    /* public and private extracted successfuly no check if is
+                     * a pair and also do sanity checks on key. wc_ecc_check_key
+                     * checks that private * base generator equals pubkey */
+                    if ((ret = wc_ecc_check_key(&key_pair)) == 0) {
+                        /* found a match */
+                        wc_ecc_free(&key_pair);
+                        return 1;
+                    }
+
+                }
+            }
+            wc_ecc_free(&key_pair);
+        }
+
+        /* error on attempt to match */
+        if (ret != 0) {
+            return ret;
+        }
+    }
+    #endif /* HAVE_ECC */
+
+    /* no match found */
+    return 0;
+}
+
 #ifndef NO_PWDBASED
 
 /* Check To see if PKCS version algo is supported, set id if it is return 0
@@ -1715,7 +1827,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
     XMEMCPY(salt, &input[inOutIdx], saltSz);
     inOutIdx += saltSz;
 
-    if (GetShortInt(input, &inOutIdx, &iterations) < 0) {
+    if (GetShortInt(input, &inOutIdx, &iterations, sz) < 0) {
 #ifdef WOLFSSL_SMALL_STACK
         XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
 #endif
@@ -1803,6 +1915,150 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
     return ToTraditional(input, length);
 }
 
+/* decrypt PKCS */
+int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz)
+{
+    word32 inOutIdx = 0, oid;
+    int    ret;
+    int    first, second, length, version, saltSz, id;
+    int    iterations = 0;
+#ifdef WOLFSSL_SMALL_STACK
+    byte*  salt = NULL;
+    byte*  cbcIv = NULL;
+#else
+    byte   salt[MAX_SALT_SIZE];
+    byte   cbcIv[MAX_IV_SIZE];
+#endif
+
+    if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0)
+        return ASN_PARSE_E;
+
+    first  = input[inOutIdx - 2];   /* PKCS version always 2nd to last byte */
+    second = input[inOutIdx - 1];   /* version.algo, algo id last byte */
+
+    if (CheckAlgo(first, second, &id, &version) < 0)
+        return ASN_INPUT_E;  /* Algo ID error */
+
+    if (version == PKCS5v2) {
+
+        if (GetSequence(input, &inOutIdx, &length, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (GetAlgoId(input, &inOutIdx, &oid, oidKdfType, sz) < 0)
+            return ASN_PARSE_E;
+
+        if (oid != PBKDF2_OID)
+            return ASN_PARSE_E;
+    }
+
+    if (GetSequence(input, &inOutIdx, &length, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (input[inOutIdx++] != ASN_OCTET_STRING)
+        return ASN_PARSE_E;
+
+    if (GetLength(input, &inOutIdx, &saltSz, sz) < 0)
+        return ASN_PARSE_E;
+
+    if (saltSz > MAX_SALT_SIZE)
+        return ASN_PARSE_E;
+
+#ifdef WOLFSSL_SMALL_STACK
+    salt = (byte*)XMALLOC(MAX_SALT_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (salt == NULL)
+        return MEMORY_E;
+#endif
+
+    XMEMCPY(salt, &input[inOutIdx], saltSz);
+    inOutIdx += saltSz;
+
+    if (GetShortInt(input, &inOutIdx, &iterations, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    if (cbcIv == NULL) {
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        return MEMORY_E;
+    }
+#endif
+
+    if (version == PKCS5v2) {
+        /* get encryption algo */
+        /* JOHN: New type. Need a little more research. */
+        if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+
+        if (CheckAlgoV2(oid, &id) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;  /* PKCS v2 algo id error */
+        }
+
+        if (input[inOutIdx++] != ASN_OCTET_STRING) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+
+        if (GetLength(input, &inOutIdx, &length, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+            XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+            XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+            return ASN_PARSE_E;
+        }
+
+        XMEMCPY(cbcIv, &input[inOutIdx], length);
+        inOutIdx += length;
+    }
+
+    if (input[inOutIdx++] != ASN_LONG_LENGTH) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    if (GetLength(input, &inOutIdx, &length, sz) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ASN_PARSE_E;
+    }
+
+    if ((ret = DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
+                   input + inOutIdx, length, version, cbcIv)) < 0) {
+#ifdef WOLFSSL_SMALL_STACK
+        XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+        XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+        return ret;  /* decrypt failure */
+    }
+
+#ifdef WOLFSSL_SMALL_STACK
+    XFREE(salt,  NULL, DYNAMIC_TYPE_TMP_BUFFER);
+    XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+
+    XMEMMOVE(input, input + inOutIdx, length);
+    return length;
+}
 #endif /* NO_PWDBASED */
 
 #ifndef NO_RSA
@@ -1813,6 +2069,10 @@ int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
 {
     int    length;
 
+    if (input == NULL || inOutIdx == NULL || key == NULL) {
+        return BAD_FUNC_ARG;
+    }
+
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
 
@@ -1995,7 +2255,7 @@ int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key,
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
 
-    if (GetMyVersion(input, inOutIdx, &version) < 0)
+    if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
         return ASN_PARSE_E;
 
     if (GetInt(&key->p,  input, inOutIdx, inSz) < 0 ||
@@ -2320,7 +2580,8 @@ static int GetCertHeader(DecodedCert* cert)
         return ASN_PARSE_E;
     cert->sigIndex = len + cert->srcIdx;
 
-    if (GetExplicitVersion(cert->source, &cert->srcIdx, &cert->version) < 0)
+    if (GetExplicitVersion(cert->source, &cert->srcIdx, &cert->version,
+                                                              cert->maxIdx) < 0)
         return ASN_PARSE_E;
 
     if (GetSerialNumber(cert->source, &cert->srcIdx, cert->serial,
@@ -3188,6 +3449,7 @@ static int GetDate(DecodedCert* cert, int dateType)
     byte   b;
     word32 startIdx = 0;
 
+    XMEMSET(date, 0, MAX_DATE_SIZE);
     if (dateType == BEFORE)
         cert->beforeDate = &cert->source[cert->srcIdx];
     else
@@ -8605,7 +8867,7 @@ int wc_EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key,
     if (GetSequence(input, inOutIdx, &length, inSz) < 0)
         return ASN_PARSE_E;
 
-    if (GetMyVersion(input, inOutIdx, &version) < 0)
+    if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
         return ASN_PARSE_E;
 
     b = input[*inOutIdx];
@@ -9161,7 +9423,7 @@ static int DecodeResponseData(byte* source,
     if (source[idx] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED))
     {
         idx += 2; /* Eat the value and length */
-        if (GetMyVersion(source, &idx, &version) < 0)
+        if (GetMyVersion(source, &idx, &version, size) < 0)
             return ASN_PARSE_E;
     } else
         version = 0;
@@ -9821,7 +10083,7 @@ int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm)
 
     /* may have version */
     if (buff[idx] == ASN_INTEGER) {
-        if (GetMyVersion(buff, &idx, &version) < 0)
+        if (GetMyVersion(buff, &idx, &version, sz) < 0)
             return ASN_PARSE_E;
     }
 

+ 1082 - 0
wolfcrypt/src/pkcs12.c

@@ -0,0 +1,1082 @@
+/* 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>
+
+WC_PKCS12* wc_PKCS12_new(void)
+{
+    WC_PKCS12* pkcs12 = (WC_PKCS12*)XMALLOC(sizeof(WC_PKCS12),
+                                                      NULL, DYNAMIC_TYPE_PKCS);
+    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_HmacSetKey(&hmac, typeH, key, kLen)) != 0) {
+        return ret;
+    }
+    if ((ret = wc_HmacUpdate(&hmac, data, dataSz)) != 0) {
+        return ret;
+    }
+    if ((ret = wc_HmacFinal(&hmac, digest)) != 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 DerCertList */
+static void freeCertList(DerCertList* list, void* heap) {
+    DerCertList* current;
+
+    if (list == NULL) {
+        return;
+    }
+
+    current = list;
+    while(current != NULL) {
+        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,
+        DerCertList** ca)
+{
+    ContentInfo* ci       = NULL;
+    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;
+        }
+    }
+
+
+    /* 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);
+                            }
+                        }
+                        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 */
+                {
+                    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 = (DerCertList*)XMALLOC(sizeof(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(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 */
+    {
+        DerCertList* current  = certList;
+        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;
+}
+
+#endif /* !defined(NO_ASN) && !defined(NO_PWDBASED) */
+

+ 4 - 4
wolfcrypt/src/pkcs7.c

@@ -735,7 +735,7 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
         return ASN_PARSE_E;
 
     /* Get the version */
-    if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+    if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
         return ASN_PARSE_E;
 
     if (version != 1) {
@@ -830,7 +830,7 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz)
             return ASN_PARSE_E;
 
         /* Get the version */
-        if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+        if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
             return ASN_PARSE_E;
 
         if (version != 1) {
@@ -1530,7 +1530,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
     if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0)
         return ASN_PARSE_E;
 
-    if (GetMyVersion(pkiMsg, &idx, &version) < 0)
+    if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0)
         return ASN_PARSE_E;
 
     if (version != 0) {
@@ -1563,7 +1563,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
             break;
         }
 
-        if (GetMyVersion(pkiMsg, &idx, &version) < 0) {
+        if (GetMyVersion(pkiMsg, &idx, &version, pkiMsgSz) < 0) {
             idx = savedIdx;
             break;
         }

+ 4 - 0
wolfssl.vcproj

@@ -259,6 +259,10 @@
 				RelativePath=".\wolfcrypt\src\pkcs7.c"
 				>
 			</File>
+			<File
+				RelativePath=".\wolfcrypt\src\pkcs12.c"
+				>
+			</File>
 			<File
 				RelativePath=".\wolfcrypt\src\poly1305.c"
 				>

+ 1 - 0
wolfssl.vcxproj

@@ -305,6 +305,7 @@
     <ClCompile Include="wolfcrypt\src\md5.c" />
     <ClCompile Include="wolfcrypt\src\memory.c" />
     <ClCompile Include="wolfcrypt\src\pkcs7.c" />
+    <ClCompile Include="wolfcrypt\src\pkcs12.c" />
     <ClCompile Include="wolfcrypt\src\poly1305.c" />
     <ClCompile Include="wolfcrypt\src\pwdbased.c" />
     <ClCompile Include="wolfcrypt\src\rabbit.c" />

+ 12 - 0
wolfssl/internal.h

@@ -45,6 +45,7 @@
 #endif
 #ifndef NO_ASN
     #include <wolfssl/wolfcrypt/asn.h>
+    #include <wolfssl/wolfcrypt/pkcs12.h>
 #endif
 #ifndef NO_MD5
     #include <wolfssl/wolfcrypt/md5.h>
@@ -2485,6 +2486,17 @@ typedef struct Arrays {
 #define MAX_DATE_SZ 32
 #endif
 
+typedef struct WOLFSSL_STACK {
+    unsigned long num; /* number of nodes in stack
+                        * (saftey measure for freeing and shortcut for count) */
+    union {
+        WOLFSSL_X509* x509;
+        WOLFSSL_BIO*  bio;
+    } data;
+    WOLFSSL_STACK* next;
+} WOLFSSL_STACK;
+
+
 struct WOLFSSL_X509_NAME {
     char  *name;
     char  staticName[ASN_NAME_MAX];

+ 12 - 0
wolfssl/openssl/pkcs12.h

@@ -1,2 +1,14 @@
 /* pkcs12.h for openssl */
 
+#include <wolfssl/wolfcrypt/pkcs12.h>
+
+/* wolfCrypt level does not make use of ssl.h */
+#define PKCS12         WC_PKCS12
+#define PKCS12_new     wc_PKCS12_new
+#define PKCS12_free    wc_PKCS12_free
+
+/* wolfSSL level using structs from ssl.h and calls down to wolfCrypt */
+#define d2i_PKCS12_bio wolfSSL_d2i_PKCS12_bio
+#define PKCS12_parse   wolfSSL_PKCS12_parse
+#define PKCS12_PBE_add wolfSSL_PKCS12_PBE_add
+

+ 2 - 0
wolfssl/openssl/ssl.h

@@ -398,6 +398,8 @@ typedef WOLFSSL_X509_STORE_CTX X509_STORE_CTX;
 
 #define sk_num wolfSSL_sk_num
 #define sk_value wolfSSL_sk_value
+#define sk_X509_pop  wolfSSL_sk_X509_pop
+#define sk_X509_free wolfSSL_sk_X509_free
 
 #define SSL_CTX_get_ex_data wolfSSL_CTX_get_ex_data
 #define SSL_CTX_set_ex_data wolfSSL_CTX_set_ex_data

+ 20 - 2
wolfssl/ssl.h

@@ -70,6 +70,7 @@ typedef struct WOLFSSL_SESSION  WOLFSSL_SESSION;
 typedef struct WOLFSSL_METHOD   WOLFSSL_METHOD;
 typedef struct WOLFSSL_CTX      WOLFSSL_CTX;
 
+typedef struct WOLFSSL_STACK      WOLFSSL_STACK;
 typedef struct WOLFSSL_X509       WOLFSSL_X509;
 typedef struct WOLFSSL_X509_NAME  WOLFSSL_X509_NAME;
 typedef struct WOLFSSL_X509_NAME_ENTRY  WOLFSSL_X509_NAME_ENTRY;
@@ -422,7 +423,11 @@ WOLFSSL_API const char* wolfSSL_ERR_reason_error_string(unsigned long);
 
 /* extras */
 
-#define STACK_OF(x) x
+#define STACK_OF(x) WOLFSSL_STACK
+WOLFSSL_API int wolfSSL_sk_X509_push(STACK_OF(WOLFSSL_X509_NAME)* sk,
+                                                            WOLFSSL_X509* x509);
+WOLFSSL_API WOLFSSL_X509* wolfSSL_sk_X509_pop(STACK_OF(WOLFSSL_X509_NAME)* sk);
+WOLFSSL_API void wolfSSL_sk_X509_free(STACK_OF(WOLFSSL_X509_NAME)* sk);
 
 WOLFSSL_API int  wolfSSL_set_ex_data(WOLFSSL*, int, void*);
 WOLFSSL_API int  wolfSSL_get_shutdown(const WOLFSSL*);
@@ -982,6 +987,18 @@ WOLFSSL_API WOLFSSL_X509* wolfSSL_X509_load_certificate_buffer(
 /* connect enough to get peer cert */
 WOLFSSL_API int  wolfSSL_connect_cert(WOLFSSL* ssl);
 
+
+
+/* PKCS12 compatibility */
+typedef struct WC_PKCS12 WC_PKCS12;
+WOLFSSL_API WC_PKCS12* wolfSSL_d2i_PKCS12_bio(WOLFSSL_BIO* bio,
+                                       WC_PKCS12** pkcs12);
+WOLFSSL_API int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
+     WOLFSSL_EVP_PKEY** pkey, WOLFSSL_X509** cert, STACK_OF(WOLFSSL_X509)** ca);
+WOLFSSL_API void wolfSSL_PKCS12_PBE_add(void);
+
+
+
 #ifndef NO_DH
 /* server Diffie-Hellman parameters */
 WOLFSSL_API int  wolfSSL_SetTmpDH(WOLFSSL*, const unsigned char* p, int pSz,
@@ -1778,8 +1795,9 @@ WOLFSSL_API char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* time,
                                                             char* buf, int len);
 #endif /* WOLFSSL_MYSQL_COMPATIBLE */
 
-#ifdef OPENSSL_EXTRA /*lighttp compatibility */
+#ifdef OPENSSL_EXTRA
 
+ /*lighttp compatibility */
 #include <wolfssl/openssl/asn1.h>
 struct WOLFSSL_X509_NAME_ENTRY {
     WOLFSSL_ASN1_OBJECT* object; /* not defined yet */

+ 7 - 2
wolfssl/wolfcrypt/asn.h

@@ -195,7 +195,8 @@ enum Misc_ASN {
     MAX_PUBLIC_KEY_SZ   = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2,
                                    /* use bigger NTRU size */
     HEADER_ENCRYPTED_KEY_SIZE = 88,/* Extra header size for encrypted key */
-    TRAILING_ZERO       = 1        /* Used for size of zero pad */
+    TRAILING_ZERO       = 1,       /* Used for size of zero pad */
+    MIN_VERSION_SZ      = 3        /* Min bytes needed for GetMyVersion */
 };
 
 
@@ -633,6 +634,7 @@ WOLFSSL_LOCAL void    FreeTrustedPeerTable(TrustedPeerCert**, int, void*);
 
 WOLFSSL_LOCAL int ToTraditional(byte* buffer, word32 length);
 WOLFSSL_LOCAL int ToTraditionalEnc(byte* buffer, word32 length,const char*,int);
+WOLFSSL_LOCAL int DecryptContent(byte* input, word32 sz,const char* psw,int pswSz);
 
 typedef struct tm wolfssl_tm;
 #if defined(WOLFSSL_MYSQL_COMPATIBLE)
@@ -646,6 +648,8 @@ WOLFSSL_LOCAL int ValidateDate(const byte* date, byte format, int dateType);
 #ifdef WOLFSSL_CERT_GEN
 WOLFSSL_TEST_API int SetName(byte* output, word32 outputSz, CertName* name);
 #endif
+WOLFSSL_LOCAL int GetShortInt(const byte* input, word32* inOutIdx, int* number,
+                              word32 maxIdx);
 WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len,
                            word32 maxIdx);
 WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
@@ -653,7 +657,7 @@ WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len,
 WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len,
                         word32 maxIdx);
 WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx,
-                              int* version);
+                              int* version, word32 maxIdx);
 WOLFSSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx,
                         word32 maxIdx);
 #ifdef HAVE_OID_ENCODING
@@ -681,6 +685,7 @@ WOLFSSL_LOCAL int GetSerialNumber(const byte* input, word32* inOutIdx,
     byte* serial, int* serialSz, word32 maxIdx);
 WOLFSSL_LOCAL int GetNameHash(const byte* source, word32* idx, byte* hash,
                              int maxIdx);
+WOLFSSL_LOCAL int wc_CheckPrivateKey(byte* key, word32 keySz, DecodedCert* der);
 
 #ifdef HAVE_ECC
     /* ASN sig helpers */

+ 2 - 1
wolfssl/wolfcrypt/include.am

@@ -57,7 +57,8 @@ nobase_include_HEADERS+= \
                          wolfssl/wolfcrypt/mpi_class.h \
                          wolfssl/wolfcrypt/mpi_superclass.h \
                          wolfssl/wolfcrypt/mem_track.h \
-                         wolfssl/wolfcrypt/wolfevent.h
+                         wolfssl/wolfcrypt/wolfevent.h \
+                         wolfssl/wolfcrypt/pkcs12.h
 
 noinst_HEADERS+= \
                          wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h \

+ 114 - 0
wolfssl/wolfcrypt/pkcs12.h

@@ -0,0 +1,114 @@
+/* pkcs12.h
+ *
+ * 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
+ */
+
+
+#ifndef WOLF_CRYPT_PKCS12_H
+#define WOLF_CRYPT_PKCS12_H
+
+#include <wolfssl/wolfcrypt/types.h>
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+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 DerCertList DerCertList;
+typedef struct DerCertList {
+    byte* buffer;
+    word32 bufferSz;
+    DerCertList* next;
+} DerCertList;
+
+
+typedef struct ContentInfo ContentInfo;
+typedef struct ContentInfo {
+    byte* data;
+    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;
+
+
+/* for friendlyName, localKeyId .... */
+typedef struct WC_PKCS12_ATTRIBUTE {
+    byte* data;
+    word32 oid;
+    word32 dataSz;
+} WC_PKCS12_ATTRIBUTE;
+
+
+typedef struct WC_PKCS12 {
+    void* heap;
+    AuthenticatedSafe* safe;
+    MacData* signData;
+    word32 oid; /* DATA / Enveloped DATA ... */
+} WC_PKCS12;
+
+
+WOLFSSL_API WC_PKCS12* wc_PKCS12_new(void);
+WOLFSSL_API void wc_PKCS12_free(WC_PKCS12* pkcs12);
+WOLFSSL_API int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12);
+WOLFSSL_API int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
+        byte** pkey, word32* pkeySz, byte** cert, word32* certSz,
+        DerCertList** ca);
+
+WOLFSSL_LOCAL int wc_PKCS12_SetHeap(WC_PKCS12* pkcs12, void* heap);
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+#endif /* WOLF_CRYPT_PKCS12_H */
+