forked from wolfSSL/wolfssl
Merge pull request #6160 from lealem47/indefPKCS12
Adding support for indefinite length PKCS12
This commit is contained in:
@@ -9670,6 +9670,9 @@ static int test_wolfSSL_PKCS12(void)
|
|||||||
AssertNotNull(pkey);
|
AssertNotNull(pkey);
|
||||||
AssertNotNull(cert);
|
AssertNotNull(cert);
|
||||||
|
|
||||||
|
wolfSSL_EVP_PKEY_free(pkey);
|
||||||
|
wolfSSL_X509_free(cert);
|
||||||
|
|
||||||
/* check parse with extra certs kept */
|
/* check parse with extra certs kept */
|
||||||
ret = PKCS12_parse(pkcs12, "wolfSSL test", &pkey, &cert, &ca);
|
ret = PKCS12_parse(pkcs12, "wolfSSL test", &pkey, &cert, &ca);
|
||||||
AssertIntEQ(ret, WOLFSSL_SUCCESS);
|
AssertIntEQ(ret, WOLFSSL_SUCCESS);
|
||||||
|
@@ -110,6 +110,13 @@ struct WC_PKCS12 {
|
|||||||
AuthenticatedSafe* safe;
|
AuthenticatedSafe* safe;
|
||||||
MacData* signData;
|
MacData* signData;
|
||||||
word32 oid; /* DATA / Enveloped DATA ... */
|
word32 oid; /* DATA / Enveloped DATA ... */
|
||||||
|
byte indefinite;
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
byte* safeDer; /* der encoded version of message */
|
||||||
|
byte* der; /* der encoded version of message */
|
||||||
|
word32 safeDersz;
|
||||||
|
word32 derSz;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -149,11 +156,14 @@ static void freeSafe(AuthenticatedSafe* safe, void* heap)
|
|||||||
ContentInfo* ci = safe->CI;
|
ContentInfo* ci = safe->CI;
|
||||||
safe->CI = ci->next;
|
safe->CI = ci->next;
|
||||||
XFREE(ci, heap, DYNAMIC_TYPE_PKCS);
|
XFREE(ci, heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
ci = NULL;
|
||||||
}
|
}
|
||||||
if (safe->data != NULL) {
|
if (safe->data != NULL) {
|
||||||
XFREE(safe->data, heap, DYNAMIC_TYPE_PKCS);
|
XFREE(safe->data, heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
safe->data = NULL;
|
||||||
}
|
}
|
||||||
XFREE(safe, heap, DYNAMIC_TYPE_PKCS);
|
XFREE(safe, heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
safe = NULL;
|
||||||
|
|
||||||
(void)heap;
|
(void)heap;
|
||||||
}
|
}
|
||||||
@@ -188,7 +198,19 @@ void wc_PKCS12_free(WC_PKCS12* pkcs12)
|
|||||||
pkcs12->signData = NULL;
|
pkcs12->signData = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
if (pkcs12->der != NULL) {
|
||||||
|
XFREE(pkcs12->der, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
pkcs12->der = NULL;
|
||||||
|
}
|
||||||
|
if (pkcs12->safeDer != NULL) {
|
||||||
|
XFREE(pkcs12->safeDer, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
pkcs12->safeDer = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
XFREE(pkcs12, NULL, DYNAMIC_TYPE_PKCS);
|
XFREE(pkcs12, NULL, DYNAMIC_TYPE_PKCS);
|
||||||
|
pkcs12 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -269,15 +291,38 @@ static int GetSafeContent(WC_PKCS12* pkcs12, const byte* input,
|
|||||||
XMEMCPY(safe->data, input + localIdx, size);
|
XMEMCPY(safe->data, input + localIdx, size);
|
||||||
*idx = localIdx;
|
*idx = localIdx;
|
||||||
|
|
||||||
|
localIdx = 0;
|
||||||
|
input = safe->data;
|
||||||
|
size = safe->dataSz;
|
||||||
|
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
if (pkcs12->indefinite) {
|
||||||
|
if ((ret = wc_BerToDer(input, safe->dataSz, NULL,
|
||||||
|
&pkcs12->safeDersz)) != LENGTH_ONLY_E) {
|
||||||
|
WOLFSSL_MSG("Not BER sequence");
|
||||||
|
return ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkcs12->safeDer = (byte*)XMALLOC(pkcs12->safeDersz, pkcs12->heap,
|
||||||
|
DYNAMIC_TYPE_PKCS);
|
||||||
|
if (pkcs12->safeDer == NULL) {
|
||||||
|
freeSafe(safe, pkcs12->heap);
|
||||||
|
return MEMORY_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wc_BerToDer(input, safe->dataSz, pkcs12->safeDer, &pkcs12->safeDersz);
|
||||||
|
|
||||||
|
input = pkcs12->safeDer;
|
||||||
|
}
|
||||||
|
#endif /* ASN_BER_TO_DER */
|
||||||
|
|
||||||
/* an instance of AuthenticatedSafe is created from
|
/* an instance of AuthenticatedSafe is created from
|
||||||
* ContentInfo's strung together in a SEQUENCE. Here we iterate
|
* ContentInfo's strung together in a SEQUENCE. Here we iterate
|
||||||
* through the ContentInfo's and add them to our
|
* through the ContentInfo's and add them to our
|
||||||
* AuthenticatedSafe struct */
|
* AuthenticatedSafe struct */
|
||||||
localIdx = 0;
|
|
||||||
input = safe->data;
|
|
||||||
{
|
{
|
||||||
int CISz;
|
int CISz;
|
||||||
ret = GetSequence(input, &localIdx, &CISz, safe->dataSz);
|
ret = GetSequence(input, &localIdx, &CISz, size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
freeSafe(safe, pkcs12->heap);
|
freeSafe(safe, pkcs12->heap);
|
||||||
return ASN_PARSE_E;
|
return ASN_PARSE_E;
|
||||||
@@ -292,8 +337,7 @@ static int GetSafeContent(WC_PKCS12* pkcs12, const byte* input,
|
|||||||
printf("\t\tlooking for Content Info.... ");
|
printf("\t\tlooking for Content Info.... ");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((ret = GetSequence(input, &localIdx, &curSz, safe->dataSz))
|
if ((ret = GetSequence(input, &localIdx, &curSz, size)) < 0) {
|
||||||
< 0) {
|
|
||||||
freeSafe(safe, pkcs12->heap);
|
freeSafe(safe, pkcs12->heap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -306,7 +350,7 @@ static int GetSafeContent(WC_PKCS12* pkcs12, const byte* input,
|
|||||||
|
|
||||||
curIdx = localIdx;
|
curIdx = localIdx;
|
||||||
if ((ret = GetObjectId(input, &localIdx, &oid, oidIgnoreType,
|
if ((ret = GetObjectId(input, &localIdx, &oid, oidIgnoreType,
|
||||||
safe->dataSz)) < 0) {
|
size)) < 0) {
|
||||||
WOLFSSL_LEAVE("Get object id failed", ret);
|
WOLFSSL_LEAVE("Get object id failed", ret);
|
||||||
freeSafe(safe, pkcs12->heap);
|
freeSafe(safe, pkcs12->heap);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -651,7 +695,7 @@ int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12)
|
|||||||
}
|
}
|
||||||
|
|
||||||
totalSz = derSz;
|
totalSz = derSz;
|
||||||
if (GetSequence(der, &idx, &size, totalSz) <= 0) {
|
if (GetSequence(der, &idx, &size, totalSz) < 0) {
|
||||||
WOLFSSL_MSG("Failed to get PKCS12 sequence");
|
WOLFSSL_MSG("Failed to get PKCS12 sequence");
|
||||||
return ASN_PARSE_E;
|
return ASN_PARSE_E;
|
||||||
}
|
}
|
||||||
@@ -661,6 +705,46 @@ int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
if (size == 0) {
|
||||||
|
if ((ret = wc_BerToDer(der, totalSz, NULL,
|
||||||
|
(word32*)&size)) != LENGTH_ONLY_E) {
|
||||||
|
WOLFSSL_MSG("Not BER sequence");
|
||||||
|
return ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkcs12->der = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
if (pkcs12->der == NULL)
|
||||||
|
return MEMORY_E;
|
||||||
|
ret = wc_BerToDer(der, derSz, pkcs12->der, (word32*)&size);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
der = pkcs12->der;
|
||||||
|
derSz = pkcs12->derSz = size;
|
||||||
|
totalSz = size;
|
||||||
|
idx = 0;
|
||||||
|
|
||||||
|
if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
|
||||||
|
WOLFSSL_MSG("Failed to get PKCS12 sequence");
|
||||||
|
return ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get version */
|
||||||
|
if ((ret = GetMyVersion(der, &idx, &version, totalSz)) < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkcs12->indefinite = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* ASN_BER_TO_DER */
|
||||||
|
{
|
||||||
|
pkcs12->indefinite = 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WOLFSSL_DEBUG_PKCS12
|
#ifdef WOLFSSL_DEBUG_PKCS12
|
||||||
printf("\nBEGIN: PKCS12 size = %d\n", totalSz);
|
printf("\nBEGIN: PKCS12 size = %d\n", totalSz);
|
||||||
printf("version = %d\n", version);
|
printf("version = %d\n", version);
|
||||||
@@ -685,6 +769,15 @@ int wc_d2i_PKCS12(const byte* der, word32 derSz, WC_PKCS12* pkcs12)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
/* If indef, skip EOF */
|
||||||
|
if (pkcs12->indefinite) {
|
||||||
|
while(der[idx] == ASN_EOC && idx < totalSz) {
|
||||||
|
idx+=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* if more buffer left check for MAC data */
|
/* if more buffer left check for MAC data */
|
||||||
if (idx < totalSz) {
|
if (idx < totalSz) {
|
||||||
if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
|
if ((ret = GetSequence(der, &idx, &size, totalSz)) < 0) {
|
||||||
@@ -1060,6 +1153,141 @@ static WARN_UNUSED_RESULT int freeDecCertList(WC_DerCertList** list,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
/* append data to encrypted content cache in PKCS12 structure
|
||||||
|
* return buffer on success, NULL on error */
|
||||||
|
static byte* PKCS12_ConcatonateContent(WC_PKCS12* pkcs12,byte* mergedData,
|
||||||
|
word32* mergedSz, byte* in, word32 inSz)
|
||||||
|
{
|
||||||
|
byte* oldContent;
|
||||||
|
word32 oldContentSz;
|
||||||
|
|
||||||
|
if (mergedData == NULL || in == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* save pointer to old cache */
|
||||||
|
oldContent = mergedData;
|
||||||
|
oldContentSz = *mergedSz;
|
||||||
|
|
||||||
|
/* re-allocate new buffer to fit appended data */
|
||||||
|
mergedData = (byte*)XMALLOC(oldContentSz + inSz, pkcs12->heap,
|
||||||
|
DYNAMIC_TYPE_PKCS);
|
||||||
|
|
||||||
|
if (oldContent != NULL) {
|
||||||
|
XMEMCPY(mergedData, oldContent, oldContentSz);
|
||||||
|
}
|
||||||
|
XMEMCPY(mergedData + oldContentSz, in, inSz);
|
||||||
|
*mergedSz += inSz;
|
||||||
|
|
||||||
|
XFREE(oldContent, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
|
||||||
|
return mergedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if constructed [0] is seen after wc_BerToDer() or not.
|
||||||
|
* returns 1 if seen, 0 if not, ASN_PARSE_E on error */
|
||||||
|
static int PKCS12_CheckConstructedZero(byte* data, word32 dataSz, word32* idx)
|
||||||
|
{
|
||||||
|
word32 oid;
|
||||||
|
int ret = 0;
|
||||||
|
int number, size;
|
||||||
|
byte tag;
|
||||||
|
|
||||||
|
if (GetSequence(data, idx, &size, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0 && GetObjectId(data, idx, &oid, oidIgnoreType, dataSz)) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0 && GetSequence(data, idx, &size, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0 && GetOctetString(data, idx, &size, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
*idx += size;
|
||||||
|
if (ret == 0 && GetShortInt(data, idx, &number, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if wc_BerToDer() handled constructed [0] and octet
|
||||||
|
* strings properly, manually fix it if not. */
|
||||||
|
if (ret == 0 && GetASNTag(data, idx, &tag, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
else if (ret == 0 && tag == 0xa0) {
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manually coalesce definite length octet strings into one unconstructed
|
||||||
|
* definite length octet string.
|
||||||
|
* returns 0 on success, negative on failure */
|
||||||
|
static int PKCS12_CoalesceOctetStrings(WC_PKCS12* pkcs12, byte* data,
|
||||||
|
word32 dataSz, word32* idx, int* curIdx)
|
||||||
|
{
|
||||||
|
byte* mergedData = NULL; /* buffer for concatonated strings */
|
||||||
|
word32 mergedSz = 0; /* total size of merged strings */
|
||||||
|
int encryptedContentSz = 0;
|
||||||
|
int originalEncSz = 0;
|
||||||
|
int ret = 0;
|
||||||
|
int saveIdx;
|
||||||
|
byte tag;
|
||||||
|
|
||||||
|
saveIdx = *idx;
|
||||||
|
|
||||||
|
if (GetLength(data, idx, &originalEncSz, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop through octet strings and concatonate them without
|
||||||
|
* the tags and length */
|
||||||
|
while ((int)*idx < originalEncSz + *curIdx) {
|
||||||
|
if (GetASNTag(data, idx, &tag, dataSz) < 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
if (ret == 0 && (tag != ASN_OCTET_STRING)) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
if (ret == 0 && GetLength(data, idx,
|
||||||
|
&encryptedContentSz, dataSz) <= 0) {
|
||||||
|
ret = ASN_PARSE_E;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
if (mergedData == NULL) {
|
||||||
|
mergedData = (byte*)XMALLOC(encryptedContentSz,
|
||||||
|
pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
if (mergedData == NULL) {
|
||||||
|
ret = MEMORY_E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mergedData = PKCS12_ConcatonateContent(pkcs12, mergedData,
|
||||||
|
&mergedSz, &data[*idx], encryptedContentSz);
|
||||||
|
}
|
||||||
|
if (ret != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*idx += encryptedContentSz;
|
||||||
|
}
|
||||||
|
|
||||||
|
*idx = saveIdx;
|
||||||
|
|
||||||
|
*idx += SetLength(mergedSz, &data[*idx]);
|
||||||
|
|
||||||
|
/* Copy over concatonated octet strings into data buffer */
|
||||||
|
XMEMCPY(&data[*idx], mergedData, mergedSz);
|
||||||
|
|
||||||
|
XFREE(mergedData, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* return 0 on success and negative on failure.
|
/* return 0 on success and negative on failure.
|
||||||
* By side effect returns private key, cert, and optionally ca.
|
* By side effect returns private key, cert, and optionally ca.
|
||||||
@@ -1083,8 +1311,11 @@ int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
|
|||||||
WC_DerCertList* tailList = NULL;
|
WC_DerCertList* tailList = NULL;
|
||||||
byte* buf = NULL;
|
byte* buf = NULL;
|
||||||
word32 i, oid;
|
word32 i, oid;
|
||||||
int ret, pswSz;
|
|
||||||
word32 algId;
|
word32 algId;
|
||||||
|
int ret, pswSz;
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
int curIdx;
|
||||||
|
#endif
|
||||||
|
|
||||||
WOLFSSL_ENTER("wc_PKCS12_parse");
|
WOLFSSL_ENTER("wc_PKCS12_parse");
|
||||||
|
|
||||||
@@ -1123,11 +1354,12 @@ int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
|
|||||||
int size, totalSz;
|
int size, totalSz;
|
||||||
byte tag;
|
byte tag;
|
||||||
|
|
||||||
|
data = ci->data;
|
||||||
|
|
||||||
if (ci->type == WC_PKCS12_ENCRYPTED_DATA) {
|
if (ci->type == WC_PKCS12_ENCRYPTED_DATA) {
|
||||||
int number;
|
int number;
|
||||||
|
|
||||||
WOLFSSL_MSG("Decrypting PKCS12 Content Info Container");
|
WOLFSSL_MSG("Decrypting PKCS12 Content Info Container");
|
||||||
data = ci->data;
|
|
||||||
if (GetASNTag(data, &idx, &tag, ci->dataSz) < 0) {
|
if (GetASNTag(data, &idx, &tag, ci->dataSz) < 0) {
|
||||||
ERROR_OUT(ASN_PARSE_E, exit_pk12par);
|
ERROR_OUT(ASN_PARSE_E, exit_pk12par);
|
||||||
}
|
}
|
||||||
@@ -1161,7 +1393,24 @@ int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
|
|||||||
ERROR_OUT(ASN_PARSE_E, exit_pk12par);
|
ERROR_OUT(ASN_PARSE_E, exit_pk12par);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decrypted content overwrites input buffer */
|
|
||||||
|
#ifdef ASN_BER_TO_DER
|
||||||
|
curIdx = idx;
|
||||||
|
/* If indefinite length format, ensure it is in the ASN format
|
||||||
|
* the DecryptContent() expects */
|
||||||
|
if (pkcs12->indefinite && PKCS12_CheckConstructedZero(data,
|
||||||
|
ci->dataSz, &idx) == 1) {
|
||||||
|
data[idx-1] = ASN_LONG_LENGTH;
|
||||||
|
ret = PKCS12_CoalesceOctetStrings(pkcs12, data, ci->dataSz,
|
||||||
|
&idx, &curIdx);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto exit_pk12par;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idx = curIdx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* decrypted content overwrites input buffer */
|
||||||
size = ci->dataSz - idx;
|
size = ci->dataSz - idx;
|
||||||
buf = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
buf = (byte*)XMALLOC(size, pkcs12->heap, DYNAMIC_TYPE_PKCS);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
@@ -1189,7 +1438,6 @@ int wc_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw,
|
|||||||
}
|
}
|
||||||
else { /* type DATA */
|
else { /* type DATA */
|
||||||
WOLFSSL_MSG("Parsing PKCS12 DATA Content Info Container");
|
WOLFSSL_MSG("Parsing PKCS12 DATA Content Info Container");
|
||||||
data = ci->data;
|
|
||||||
if (GetASNTag(data, &idx, &tag, ci->dataSz) < 0) {
|
if (GetASNTag(data, &idx, &tag, ci->dataSz) < 0) {
|
||||||
ERROR_OUT(ASN_PARSE_E, exit_pk12par);
|
ERROR_OUT(ASN_PARSE_E, exit_pk12par);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user