diff --git a/.gitignore b/.gitignore index 03350bac4..2152a24dd 100644 --- a/.gitignore +++ b/.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/ diff --git a/certs/include.am b/certs/include.am index bcd88c2c9..d9156eaa8 100644 --- a/certs/include.am +++ b/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 \ diff --git a/certs/test-servercert.p12 b/certs/test-servercert.p12 new file mode 100644 index 000000000..9a1ffd7d5 Binary files /dev/null and b/certs/test-servercert.p12 differ diff --git a/rpm/spec.in b/rpm/spec.in index 40b68ce50..8d19ce753 100644 --- a/rpm/spec.in +++ b/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 +- Added header for pkcs12 * Fri Sep 23 2016 John Safranek - Add the dtls-sctp example sources * Mon Jun 14 2016 Jacob Barthelmeh diff --git a/src/include.am b/src/include.am index a8bb2c386..5503fac1e 100644 --- a/src/include.am +++ b/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 diff --git a/src/ssl.c b/src/ssl.c index b10d7c37b..f03d9bb2b 100644 --- a/src/ssl.c +++ b/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; diff --git a/tests/api.c b/tests/api.c index b5d348ca0..67428715b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -45,6 +45,7 @@ #ifdef OPENSSL_EXTRA #include + #include #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); diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 8944d33d9..a37420f40 100644 --- a/wolfcrypt/src/asn.c +++ b/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; } diff --git a/wolfcrypt/src/pkcs12.c b/wolfcrypt/src/pkcs12.c new file mode 100644 index 000000000..c2f675bf3 --- /dev/null +++ b/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 +#endif + +#include + +#if !defined(NO_ASN) && !defined(NO_PWDBASED) + +#include +#include +#include +#include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif +#include +#include + +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) */ + diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 68675572d..f9c4f1861 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/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; } diff --git a/wolfssl.vcproj b/wolfssl.vcproj index 1ee588bbc..106ba29fe 100755 --- a/wolfssl.vcproj +++ b/wolfssl.vcproj @@ -259,6 +259,10 @@ RelativePath=".\wolfcrypt\src\pkcs7.c" > + + diff --git a/wolfssl.vcxproj b/wolfssl.vcxproj index 6592024ac..985f3383b 100644 --- a/wolfssl.vcxproj +++ b/wolfssl.vcxproj @@ -305,6 +305,7 @@ + diff --git a/wolfssl/internal.h b/wolfssl/internal.h index ba2a6e89f..0ac8d1be8 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -45,6 +45,7 @@ #endif #ifndef NO_ASN #include + #include #endif #ifndef NO_MD5 #include @@ -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]; diff --git a/wolfssl/openssl/pkcs12.h b/wolfssl/openssl/pkcs12.h index 544b6f092..ca1e4220c 100644 --- a/wolfssl/openssl/pkcs12.h +++ b/wolfssl/openssl/pkcs12.h @@ -1,2 +1,14 @@ /* pkcs12.h for openssl */ +#include + +/* 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 + diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 15e473402..756321b93 100644 --- a/wolfssl/openssl/ssl.h +++ b/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 diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 5e0c50d12..c29371ad7 100644 --- a/wolfssl/ssl.h +++ b/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 struct WOLFSSL_X509_NAME_ENTRY { WOLFSSL_ASN1_OBJECT* object; /* not defined yet */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index bf8ab1248..901196553 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/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 */ diff --git a/wolfssl/wolfcrypt/include.am b/wolfssl/wolfcrypt/include.am index 43d9c227b..bc94891a4 100644 --- a/wolfssl/wolfcrypt/include.am +++ b/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 \ diff --git a/wolfssl/wolfcrypt/pkcs12.h b/wolfssl/wolfcrypt/pkcs12.h new file mode 100644 index 000000000..fed79c4b9 --- /dev/null +++ b/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 + +#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 */ +