From 0829af7a05642f1e1131a84117b45bd909c8b4de Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Tue, 2 Oct 2018 11:50:47 +1000 Subject: [PATCH] Support constructed OCTET_STRING in PKCS#7 signed data --- wolfcrypt/src/pkcs7.c | 141 +++++++++++++++++++++++++++++++------- wolfssl/wolfcrypt/pkcs7.h | 1 + 2 files changed, 117 insertions(+), 25 deletions(-) diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 02f2803ac..bdb61af19 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -376,6 +376,8 @@ void wc_PKCS7_Free(PKCS7* pkcs7) if (pkcs7->der != NULL) XFREE(pkcs7->der, pkcs7->heap, DYNAMIC_TYPE_PKCS7); #endif + if (pkcs7->contentDynamic != NULL) + XFREE(pkcs7->contentDynamic, pkcs7->heap, DYNAMIC_TYPE_PKCS7); if (pkcs7->isDynamic) { pkcs7->isDynamic = 0; @@ -1903,15 +1905,18 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, word32 idx, contentType, hashOID, sigOID, totalSz; int length, version, ret; byte* content = NULL; + byte* contentDynamic = NULL; byte* sig = NULL; byte* cert = NULL; byte* signedAttrib = NULL; int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0; - word32 localIdx; + word32 localIdx, start; byte degenerate; #ifdef ASN_BER_TO_DER byte* der; #endif + int multiPart = 0, keepContent; + int contentLen; if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0) return BAD_FUNC_ARG; @@ -2011,43 +2016,127 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) <= 0) ret = ASN_PARSE_E; - if (ret == 0 && pkiMsg[localIdx++] != ASN_OCTET_STRING) - ret = ASN_PARSE_E; + if (ret == 0 && pkiMsg[localIdx] == (ASN_OCTET_STRING | ASN_CONSTRUCTED)) { + multiPart = 1; - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) - ret = ASN_PARSE_E; + localIdx++; + /* Get length of all OCTET_STRINGs. */ + if (GetLength(pkiMsg, &localIdx, &contentLen, totalSz) < 0) + ret = ASN_PARSE_E; - /* Save the inner data as the content. */ - if (ret == 0 && length > 0) { - contentSz = length; + /* Check whether there is one OCTET_STRING inside. */ + start = localIdx; + if (ret == 0 && pkiMsg[localIdx++] != ASN_OCTET_STRING) + ret = ASN_PARSE_E; - /* support using header and footer without content */ - if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) { - /* Content not provided, use provided pkiMsg2 footer */ - content = NULL; - localIdx = 0; - if (contentSz != (int)pkcs7->contentSz) { - WOLFSSL_MSG("Data signed does not match contentSz provided"); - return BUFFER_E; + if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) + ret = ASN_PARSE_E; + + if (ret == 0) { + /* Use single OCTET_STRING directly. */ + if (localIdx - start + length == (word32)contentLen) + multiPart = 0; + localIdx = start; + } + } + if (ret == 0 && multiPart) { + int i = 0; + keepContent = !(pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0); + + if (keepContent) { + /* Create a buffer to hold content of OCTET_STRINGs. */ + pkcs7->contentDynamic = XMALLOC(contentLen, pkcs7->heap, + DYNAMIC_TYPE_PKCS7); + if (pkcs7->contentDynamic == NULL) + ret = MEMORY_E; + } + + start = localIdx; + /* Use the data from each OCTET_STRING. */ + while (ret == 0 && localIdx < start + contentLen) { + if (pkiMsg[localIdx++] != ASN_OCTET_STRING) + ret = ASN_PARSE_E; + + if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) + ret = ASN_PARSE_E; + if (ret == 0 && length + localIdx > start + contentLen) + ret = ASN_PARSE_E; + + if (ret == 0) { + if (keepContent) { + XMEMCPY(pkcs7->contentDynamic + i, pkiMsg + localIdx, + length); + } + i += length; + localIdx += length; + } + } + + length = i; + if (ret == 0 && length > 0) { + contentSz = length; + + /* support using header and footer without content */ + if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) { + /* Content not provided, use provided pkiMsg2 footer */ + content = NULL; + localIdx = 0; + if (contentSz != (int)pkcs7->contentSz) { + WOLFSSL_MSG("Data signed does not match contentSz provided"); + return BUFFER_E; + } + } + else { + /* Content pointer for calculating hashes later */ + content = pkcs7->contentDynamic; + pkiMsg2 = pkiMsg; + pkiMsg2Sz = pkiMsgSz; } } else { - /* Content pointer for calculating hashes later */ - content = &pkiMsg[localIdx]; - localIdx += length; - pkiMsg2 = pkiMsg; - pkiMsg2Sz = pkiMsgSz; } } - else { - pkiMsg2 = pkiMsg; + if (ret == 0 && !multiPart) { + if (pkiMsg[localIdx++] != ASN_OCTET_STRING) + ret = ASN_PARSE_E; + + if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) + ret = ASN_PARSE_E; + + /* Save the inner data as the content. */ + if (ret == 0 && length > 0) { + contentSz = length; + + /* support using header and footer without content */ + if (pkiMsg2 && pkiMsg2Sz > 0 && hashBuf && hashSz > 0) { + /* Content not provided, use provided pkiMsg2 footer */ + content = NULL; + localIdx = 0; + if (contentSz != (int)pkcs7->contentSz) { + WOLFSSL_MSG("Data signed does not match contentSz provided"); + return BUFFER_E; + } + } + else { + /* Content pointer for calculating hashes later */ + content = &pkiMsg[localIdx]; + localIdx += length; + + pkiMsg2 = pkiMsg; + pkiMsg2Sz = pkiMsgSz; + } + } + else { + pkiMsg2 = pkiMsg; + } } /* update idx if successful */ - if (ret == 0) { + if (ret == 0) idx = localIdx; - } + else + pkiMsg2 = pkiMsg; /* If getting the content info failed with non degenerate then return the * error case. Otherwise with a degenerate it is ok if the content @@ -2082,8 +2171,10 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, #ifdef ASN_BER_TO_DER der = pkcs7->der; #endif + contentDynamic = pkcs7->contentDynamic; /* This will reset PKCS7 structure and then set the certificate */ wc_PKCS7_InitWithCert(pkcs7, cert, certSz); + pkcs7->contentDynamic = contentDynamic; #ifdef ASN_BER_TO_DER pkcs7->der = der; #endif diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 2f8531b78..5c1c14587 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -102,6 +102,7 @@ typedef struct PKCS7 { WC_RNG* rng; PKCS7Attrib* signedAttribs; byte* content; /* inner content, not owner */ + byte* contentDynamic; /* content if constructed OCTET_STRING */ byte* singleCert; /* recipient cert, DER, not owner */ const byte* issuer; /* issuer name of singleCert */ byte* privateKey; /* private key, DER, not owner */