Merge pull request #1349 from JacobBarthelmeh/PKCS7

pkcs7 attribute parsing
This commit is contained in:
toddouska 2018-02-19 15:36:55 -08:00 committed by GitHub
commit 08696449f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 269 additions and 68 deletions

View File

@ -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)
{
@ -889,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;
@ -1647,6 +1733,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 +1918,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 +1958,41 @@ 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);
/* 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;
}
/* 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 +2045,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;
}
@ -4516,9 +4732,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)
@ -4534,67 +4749,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;

View File

@ -16863,12 +16863,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);

View File

@ -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 */
@ -108,7 +115,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 +141,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,