From 19ce41c3cc30ffe531a4c1ad52bf46671f5493f8 Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Fri, 2 Feb 2018 09:01:32 -0700 Subject: [PATCH 1/2] pkcs7 attribute parsing --- wolfcrypt/src/pkcs7.c | 259 ++++++++++++++++++++++++++++---------- wolfcrypt/test/test.c | 38 +++++- wolfssl/wolfcrypt/pkcs7.h | 4 +- 3 files changed, 233 insertions(+), 68 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index a9858ae79..d3a991310 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -341,6 +341,87 @@ void wc_PKCS7_Free(PKCS7* pkcs7) } +/* helper function for parsing through attributes and finding a specific one. + * returns PKCS7DecodedAttrib pointer on success */ +static PKCS7DecodedAttrib* findAttrib(PKCS7* pkcs7, const byte* oid, word32 oidSz) +{ + PKCS7DecodedAttrib* list; + + if (pkcs7 == NULL || oid == NULL) { + return NULL; + } + + /* search attributes for pkiStatus */ + list = pkcs7->decodedAttrib; + while (list != NULL) { + word32 sz = oidSz; + word32 idx = 0; + int length = 0; + + if (list->oid[idx++] != ASN_OBJECT_ID) { + WOLFSSL_MSG("Bad attribute ASN1 syntax"); + return NULL; + } + + if (GetLength(list->oid, &idx, &length, list->oidSz) < 0) { + WOLFSSL_MSG("Bad attribute length"); + return NULL; + } + + sz = (sz < (word32)length)? sz : (word32)length; + if (XMEMCMP(oid, list->oid + idx, sz) == 0) { + return list; + } + list = list->next; + } + return NULL; +} + + +/* Searches through decoded attributes and returns the value for the first one + * matching the oid passed in. Note that this value includes the leading ASN1 + * syntax. So for a printable string of "3" this would be something like + * + * 0x13, 0x01, 0x33 + * ID SIZE "3" + * + * pkcs7 structure to get value from + * oid OID value to search for with attributes + * oidSz size of oid buffer + * out buffer to hold result + * outSz size of out buffer (if out is NULL this is set to needed size and + LENGTH_ONLY_E is returned) + * + * returns size of value on success + */ +int wc_PKCS7_GetAttributeValue(PKCS7* pkcs7, const byte* oid, word32 oidSz, + byte* out, word32* outSz) +{ + PKCS7DecodedAttrib* attrib; + + if (pkcs7 == NULL || oid == NULL || outSz == NULL) { + return BAD_FUNC_ARG; + } + + attrib = findAttrib(pkcs7, oid, oidSz); + if (attrib == NULL) { + return ASN_PARSE_E; + } + + if (out == NULL) { + *outSz = attrib->valueSz; + return LENGTH_ONLY_E; + } + + if (*outSz < attrib->valueSz) { + return BUFFER_E; + } + + XMEMCPY(out, attrib->value, attrib->valueSz); + return attrib->valueSz; +} + + /* build PKCS#7 data content type */ int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz) { @@ -1647,6 +1728,101 @@ static int wc_PKCS7_SetPublicKeyOID(PKCS7* pkcs7, int sigOID) } +/* Parses through the attributes and adds them to the PKCS7 structure + * Creates dynamic attribute structures that are free'd with calling + * wc_PKCS7_Free() + * + * NOTE: An attribute has the ASN1 format of + ** Sequence + ****** Object ID + ****** Set + ********** {PritnableString, UTCTime, OCTET STRING ...} + * + * pkcs7 the PKCS7 structure to put the parsed attributes into + * in buffer holding all attributes + * inSz size of in buffer + * + * returns the number of attributes parsed on success + */ +static int wc_PKCS7_ParseAttribs(PKCS7* pkcs7, byte* in, int inSz) +{ + int found = 0; + word32 idx = 0; + word32 oid; + + if (pkcs7 == NULL || in == NULL || inSz < 0) { + return BAD_FUNC_ARG; + } + + while (idx < (word32)inSz) { + int length = 0; + int oidIdx; + PKCS7DecodedAttrib* attrib; + + if (GetSequence(in, &idx, &length, inSz) < 0) + return ASN_PARSE_E; + + attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib), + pkcs7->heap, DYNAMIC_TYPE_PKCS7); + if (attrib == NULL) { + return MEMORY_E; + } + XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); + + oidIdx = idx; + if (GetObjectId(in, &idx, &oid, oidIgnoreType, inSz) + < 0) { + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ASN_PARSE_E; + } + attrib->oidSz = idx - oidIdx; + attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (attrib->oid == NULL) { + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + XMEMCPY(attrib->oid, in + oidIdx, attrib->oidSz); + + + /* Get Set that contains the printable string value */ + if (GetSet(in, &idx, &length, inSz) < 0) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ASN_PARSE_E; + } + + if ((inSz - idx) < (word32)length) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return ASN_PARSE_E; + } + + attrib->valueSz = (word32)length; + attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (attrib->value == NULL) { + XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); + return MEMORY_E; + } + XMEMCPY(attrib->value, in + idx, attrib->valueSz); + idx += length; + + /* store attribute in linked list */ + if (pkcs7->decodedAttrib != NULL) { + attrib->next = pkcs7->decodedAttrib; + pkcs7->decodedAttrib = attrib; + } else { + pkcs7->decodedAttrib = attrib; + } + found++; + } + + return found; +} + + /* Finds the certificates in the message and saves it. */ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) { @@ -1737,8 +1913,8 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) /* Save the inner data as the content. */ if (length > 0) { /* Local pointer for calculating hashes later */ - pkcs7->content = content = &pkiMsg[localIdx]; - pkcs7->contentSz = contentSz = length; + content = &pkiMsg[localIdx]; + contentSz = length; localIdx += length; } @@ -1777,11 +1953,17 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) cert = &pkiMsg[idx]; certSz += (certIdx - idx); } + + /* This will reset PKCS7 structure and then set the certificate */ wc_PKCS7_InitWithCert(pkcs7, cert, certSz); } idx += length; } + /* set content and size after init of PKCS7 structure */ + pkcs7->content = content; + pkcs7->contentSz = contentSz; + /* Get the implicit[1] set of crls */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 1)) { idx++; @@ -1834,6 +2016,11 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) signedAttrib = &pkiMsg[idx]; signedAttribSz = length; + if (wc_PKCS7_ParseAttribs(pkcs7, signedAttrib, signedAttribSz) <0) { + WOLFSSL_MSG("Error parsing signed attributes"); + return ASN_PARSE_E; + } + idx += length; } @@ -4512,9 +4699,8 @@ int wc_PKCS7_EncodeEncryptedData(PKCS7* pkcs7, byte* output, word32 outputSz) static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, word32* inOutIdx) { - int length, attribLen; - word32 oid, savedIdx, idx; - PKCS7DecodedAttrib* attrib = NULL; + int ret, attribLen; + word32 idx; if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0 || inOutIdx == NULL) @@ -4530,67 +4716,8 @@ static int wc_PKCS7_DecodeUnprotectedAttributes(PKCS7* pkcs7, byte* pkiMsg, return ASN_PARSE_E; /* loop through attributes */ - while (attribLen > 0) { - - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) - return ASN_PARSE_E; - - attribLen -= (length + 2); /* TAG + LENGTH + DATA */ - savedIdx = idx; - - attrib = (PKCS7DecodedAttrib*)XMALLOC(sizeof(PKCS7DecodedAttrib), - pkcs7->heap, DYNAMIC_TYPE_PKCS7); - if (attrib == NULL) { - return MEMORY_E; - } - XMEMSET(attrib, 0, sizeof(PKCS7DecodedAttrib)); - - /* save attribute OID bytes and size */ - if (GetObjectId(pkiMsg, &idx, &oid, oidIgnoreType, pkiMsgSz) < 0) { - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - attrib->oidSz = idx - savedIdx; - attrib->oid = (byte*)XMALLOC(attrib->oidSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (attrib->oid == NULL) { - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - XMEMCPY(attrib->oid, pkiMsg + savedIdx, attrib->oidSz); - - /* save attribute value bytes and size */ - if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) { - XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - if ((pkiMsgSz - idx) < (word32)length) { - XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return ASN_PARSE_E; - } - - attrib->valueSz = (word32)length; - attrib->value = (byte*)XMALLOC(attrib->valueSz, pkcs7->heap, - DYNAMIC_TYPE_PKCS7); - if (attrib->value == NULL) { - XFREE(attrib->oid, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - XFREE(attrib, pkcs7->heap, DYNAMIC_TYPE_PKCS7); - return MEMORY_E; - } - XMEMCPY(attrib->value, pkiMsg + idx, attrib->valueSz); - idx += length; - - /* store attribute in linked list */ - if (pkcs7->decodedAttrib != NULL) { - attrib->next = pkcs7->decodedAttrib; - pkcs7->decodedAttrib = attrib; - } else { - pkcs7->decodedAttrib = attrib; - } + if ((ret = wc_PKCS7_ParseAttribs(pkcs7, pkiMsg + idx, attribLen)) < 0) { + return ret; } *inOutIdx = idx; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a67148fe5..93b5a598e 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -16560,12 +16560,48 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, return -7709; } + + { + /* check getting signed attributes */ + #ifndef NO_SHA + byte buf[(WC_SHA_DIGEST_SIZE + 1) * 2 + 1]; + #else + byte buf[(WC_SHA256_DIGEST_SIZE + 1) * 2 + 1]; + #endif + byte* oidPt = transIdOid + 2; /* skip object id tag and size */ + int oidSz = (int)sizeof(transIdOid) - 2; + int bufSz = 0; + + if (testVectors[i].signedAttribs != NULL && + wc_PKCS7_GetAttributeValue(&pkcs7, oidPt, oidSz, + NULL, (word32*)&bufSz) != LENGTH_ONLY_E) { + XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + wc_PKCS7_Free(&pkcs7); + return -7710; + } + + if (bufSz > (int)sizeof(buf)) { + XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + wc_PKCS7_Free(&pkcs7); + return -7711; + } + + bufSz = wc_PKCS7_GetAttributeValue(&pkcs7, oidPt, oidSz, + buf, (word32*)&bufSz); + if ((testVectors[i].signedAttribs != NULL && bufSz < 0) || + (testVectors[i].signedAttribs == NULL && bufSz > 0)) { + XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + wc_PKCS7_Free(&pkcs7); + return -7712; + } + } + #ifdef PKCS7_OUTPUT_TEST_BUNDLES file = fopen("./pkcs7cert.der", "wb"); if (!file) { XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); wc_PKCS7_Free(&pkcs7); - return -7710; + return -7713; } ret = (int)fwrite(pkcs7.singleCert, 1, pkcs7.singleCertSz, file); fclose(file); diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 45c7bd9d2..bc7e111a3 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -108,7 +108,7 @@ typedef struct PKCS7 { byte issuerSn[MAX_SN_SZ]; /* singleCert's serial number */ word32 issuerSnSz; /* length of serial number */ - byte publicKey[512]; + byte publicKey[MAX_RSA_INT_SZ + MAX_RSA_E_SZ ];/*MAX RSA key size (m + e)*/ word32 publicKeySz; word32 publicKeyOID; /* key OID (RSAk, ECDSAk, etc) */ byte* privateKey; /* private key, DER, not owner */ @@ -134,6 +134,8 @@ WOLFSSL_API int wc_PKCS7_Init(PKCS7* pkcs7, void* heap, int devId); WOLFSSL_API int wc_PKCS7_InitWithCert(PKCS7* pkcs7, byte* cert, word32 certSz); WOLFSSL_API void wc_PKCS7_Free(PKCS7* pkcs7); +WOLFSSL_API int wc_PKCS7_GetAttributeValue(PKCS7* pkcs7, const byte* oid, + word32 oidSz, byte* out, word32* outSz); WOLFSSL_API int wc_PKCS7_EncodeData(PKCS7* pkcs7, byte* output, word32 outputSz); WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, From a196fac0c2c23794559c70f17f6bf4b8472f636e Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Mon, 5 Feb 2018 10:52:54 -0700 Subject: [PATCH 2/2] itterate through certificates with PKCS7 --- wolfcrypt/src/pkcs7.c | 29 +++++++++++++++++++++++++++++ wolfssl/wolfcrypt/pkcs7.h | 7 +++++++ 2 files changed, 36 insertions(+) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index d3a991310..0ad100948 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -970,6 +970,11 @@ static int wc_PKCS7_SetHashType(PKCS7* pkcs7, enum wc_HashType* type) switch (pkcs7->hashOID) { +#ifndef NO_MD5 + case MD5h: + *type = WC_HASH_TYPE_MD5; + break; +#endif #ifndef NO_SHA case SHAh: *type = WC_HASH_TYPE_SHA; @@ -1956,6 +1961,30 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) /* This will reset PKCS7 structure and then set the certificate */ wc_PKCS7_InitWithCert(pkcs7, cert, certSz); + + /* iterate through any additional certificates */ + if (MAX_PKCS7_CERTS > 0) { + word32 localIdx; + int sz = 0; + int i; + + pkcs7->cert[0] = cert; + pkcs7->certSz[0] = certSz; + certIdx = idx + certSz; + + for (i = 1; i < MAX_PKCS7_CERTS && certIdx + 1 < pkiMsgSz; i++) { + localIdx = certIdx; + + if (pkiMsg[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { + if (GetLength(pkiMsg, &certIdx, &sz, pkiMsgSz) < 0) + return ASN_PARSE_E; + + pkcs7->cert[i] = &pkiMsg[localIdx]; + pkcs7->certSz[i] = sz + (certIdx - localIdx); + certIdx += sz; + } + } + } } idx += length; } diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index bc7e111a3..1cb37cc84 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -43,6 +43,11 @@ extern "C" { #endif +/* Max number of certificates that PKCS7 structure can parse */ +#ifndef MAX_PKCS7_CERTS +#define MAX_PKCS7_CERTS 4 +#endif + /* PKCS#7 content types, ref RFC 2315 (Section 14) */ enum PKCS7_TYPES { PKCS7_MSG = 650, /* 1.2.840.113549.1.7 */ @@ -100,6 +105,8 @@ typedef struct PKCS7 { int keyAgreeOID; /* key agreement algorithm OID */ void* heap; /* heap hint for dynamic memory */ + byte* cert[MAX_PKCS7_CERTS]; + word32 certSz[MAX_PKCS7_CERTS]; byte* singleCert; /* recipient cert, DER, not owner */ word32 singleCertSz; /* size of recipient cert buffer, bytes */ byte issuerHash[KEYID_SIZE]; /* hash of all alt Names */