diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 0963b8b57..a327d060a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -137,6 +137,14 @@ ASN Options: WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, word32 maxIdx) +{ + return GetLength_ex(input, inOutIdx, len, maxIdx, 1); +} + + +/* give option to check length value found against index. 1 to check 0 to not */ +WOLFSSL_LOCAL int GetLength_ex(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx, int check) { int length = 0; word32 idx = *inOutIdx; @@ -166,7 +174,7 @@ WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, else length = b; - if ((idx + length) > maxIdx) { /* for user of length */ + if (check && (idx + length) > maxIdx) { /* for user of length */ WOLFSSL_MSG("GetLength value exceeds buffer length"); return BUFFER_E; } @@ -179,6 +187,29 @@ WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, } +static int GetASNHeader_ex(const byte* input, byte tag, word32* inOutIdx, int* len, + word32 maxIdx, int check) +{ + word32 idx = *inOutIdx; + byte b; + int length; + + if ((idx + 1) > maxIdx) + return BUFFER_E; + + b = input[idx++]; + if (b != tag) + return ASN_PARSE_E; + + if (GetLength_ex(input, &idx, &length, maxIdx, check) < 0) + return ASN_PARSE_E; + + *len = length; + *inOutIdx = idx; + return length; +} + + /* Get the DER/BER encoding of an ASN.1 header. * * input Buffer holding DER/BER encoded data. @@ -193,25 +224,10 @@ WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, static int GetASNHeader(const byte* input, byte tag, word32* inOutIdx, int* len, word32 maxIdx) { - word32 idx = *inOutIdx; - byte b; - int length; - - if ((idx + 1) > maxIdx) - return BUFFER_E; - - b = input[idx++]; - if (b != tag) - return ASN_PARSE_E; - - if (GetLength(input, &idx, &length, maxIdx) < 0) - return ASN_PARSE_E; - - *len = length; - *inOutIdx = idx; - return length; + return GetASNHeader_ex(input, tag, inOutIdx, len, maxIdx, 1); } + WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, word32 maxIdx) { @@ -220,6 +236,14 @@ WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, } +WOLFSSL_LOCAL int GetSequence_ex(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx, int check) +{ + return GetASNHeader_ex(input, ASN_SEQUENCE | ASN_CONSTRUCTED, inOutIdx, len, + maxIdx, check); +} + + WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len, word32 maxIdx) { diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index b041687f3..8c5130380 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -58,6 +58,8 @@ typedef enum { WC_PKCS7_DECODE } pkcs7Direction; +#define NO_USER_CHECK 0 + #ifndef NO_PKCS7_STREAM #define MAX_PKCS7_STREAM_BUFFER 256 @@ -301,13 +303,13 @@ static int wc_PKCS7_AddDataToStream(PKCS7* pkcs7, byte* in, word32 inSz, * if no flag value is set then the stored max length is returned. * returns length found on success and defSz if no stored data is found */ -static word32 wc_PKCS7_GetMaxStream(PKCS7* pkcs7, byte flag, byte* in, +static long wc_PKCS7_GetMaxStream(PKCS7* pkcs7, byte flag, byte* in, word32 defSz) { /* check there is a buffer to read from */ if (pkcs7) { int length = 0, ret; - word32 idx = 0; + word32 idx = 0, maxIdx; byte* pt; if (flag != PKCS7_DEFAULT_PEEK) { @@ -319,13 +321,15 @@ static word32 wc_PKCS7_GetMaxStream(PKCS7* pkcs7, byte flag, byte* in, length = defSz; pt = in; } + maxIdx = (word32)length; if (length < MAX_SEQ_SZ) { WOLFSSL_MSG("PKCS7 Error not enough data for SEQ peek\n"); return 0; } if (flag == PKCS7_SEQ_PEEK) { - if ((ret = GetSequence(pt, &idx, &length, (word32)-1)) < 0) { + if ((ret = GetSequence_ex(pt, &idx, &length, maxIdx, + NO_USER_CHECK)) < 0) { return ret; } pkcs7->stream->maxLen = length + idx; @@ -3328,7 +3332,15 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, break; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + { + long rc; + rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + if (rc < 0) { + ret = (int)rc; + break; + } + } + pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz; #endif /* determine total message size */ @@ -3358,7 +3370,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, pkiMsg = pkcs7->der; pkiMsgSz = len; idx = 0; - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz, + NO_USER_CHECK) < 0) return ASN_PARSE_E; #else ret = BER_INDEF_E; @@ -3429,12 +3442,13 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, break; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz); wc_PKCS7_StreamGetVar(pkcs7, &totalSz, 0, 0); + pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz; #endif /* Get the inner ContentInfo sequence */ - if (GetSequence(pkiMsg, &idx, &length, totalSz) < 0) + if (GetSequence_ex(pkiMsg, &idx, &length, pkiMsgSz, + NO_USER_CHECK) < 0) ret = ASN_PARSE_E; /* Get the inner ContentInfo contentType */ @@ -3459,7 +3473,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, if (pkiMsg[localIdx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) ret = ASN_PARSE_E; - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) <= 0) + if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz, + NO_USER_CHECK) <= 0) ret = ASN_PARSE_E; @@ -3469,7 +3484,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, localIdx++; /* Get length of all OCTET_STRINGs. */ - if (GetLength(pkiMsg, &localIdx, &contentLen, totalSz) < 0) + if (GetLength_ex(pkiMsg, &localIdx, &contentLen, pkiMsgSz, + NO_USER_CHECK) < 0) ret = ASN_PARSE_E; /* Check whether there is one OCTET_STRING inside. */ @@ -3477,7 +3493,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, if (ret == 0 && pkiMsg[localIdx++] != ASN_OCTET_STRING) ret = ASN_PARSE_E; - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) + if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz, + NO_USER_CHECK) < 0) ret = ASN_PARSE_E; if (ret == 0) { @@ -3493,7 +3510,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, if (pkiMsg[localIdx++] != ASN_OCTET_STRING) ret = ASN_PARSE_E; - if (ret == 0 && GetLength(pkiMsg, &localIdx, &length, totalSz) < 0) + if (ret == 0 && GetLength_ex(pkiMsg, &localIdx, &length, pkiMsgSz, + NO_USER_CHECK) < 0) ret = ASN_PARSE_E; } @@ -3545,8 +3563,8 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, case WC_PKCS7_VERIFY_STAGE3: #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, pkcs7->stream->expected, - &pkiMsg, &idx)) != 0) { + if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz + in2Sz, + pkcs7->stream->expected, &pkiMsg, &idx)) != 0) { break; } @@ -3727,6 +3745,7 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, } XMEMCPY(pkcs7->stream->tmpCert, pkiMsg2 + idx, length); pkiMsg2 = pkcs7->stream->tmpCert; + pkiMsg2Sz = length; idx = 0; } #endif @@ -3740,18 +3759,26 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, word32 certIdx = idx; + if (length < MAX_LENGTH_SZ + ASN_TAG_SZ) + ret = BUFFER_E; + if (pkiMsg2[certIdx++] == (ASN_CONSTRUCTED | ASN_SEQUENCE)) { if (GetLength(pkiMsg2, &certIdx, &certSz, pkiMsg2Sz) < 0) ret = ASN_PARSE_E; cert = &pkiMsg2[idx]; certSz += (certIdx - idx); + if (certSz > length) { + ret = BUFFER_E; + break; + } } #ifdef ASN_BER_TO_DER der = pkcs7->der; #endif contentDynamic = pkcs7->contentDynamic; + if (ret == 0) { #ifndef NO_PKCS7_STREAM PKCS7State* stream = pkcs7->stream; @@ -3814,6 +3841,11 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, * used then don't advance idx. */ if (pkcs7->stream->flagOne && pkcs7->stream->length == 0) { idx = stateIdx + idx; + if (idx > inSz) { + /* index is more than input size */ + ret = BUFFER_E; + break; + } } else { stateIdx = idx; /* didn't read any from internal buffer */ @@ -3834,6 +3866,7 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, pkcs7->stream->expected = (pkcs7->stream->maxLen - pkcs7->stream->totalRd) + pkcs7->stream->length; + wc_PKCS7_StreamGetVar(pkcs7, &pkiMsg2Sz, 0, 0); wc_PKCS7_StreamStoreVar(pkcs7, pkiMsg2Sz, 0, length); #endif wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_VERIFY_STAGE5); @@ -4011,6 +4044,9 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, WOLFSSL_MSG("Failed to set public key OID from signature"); } + if (idx >= pkiMsg2Sz) + ret = BUFFER_E; + /* Get the signature */ if (ret == 0 && pkiMsg2[idx] == ASN_OCTET_STRING) { idx++; @@ -8469,7 +8505,15 @@ static int wc_PKCS7_ParseToRecipientInfoSet(PKCS7* pkcs7, byte* in, return ret; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + { + long rc; + rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + if (rc < 0) { + ret = (int)rc; + break; + } + pkiMsgSz = (word32)rc; + } #endif /* read past ContentInfo, verify type is envelopedData */ if (ret == 0 && GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0) @@ -8532,7 +8576,7 @@ static int wc_PKCS7_ParseToRecipientInfoSet(PKCS7* pkcs7, byte* in, return ret; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz); + pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length :inSz; #endif if (ret == 0 && wc_GetContentType(pkiMsg, idx, &contentType, pkiMsgSz) < 0) ret = ASN_PARSE_E; @@ -8552,7 +8596,8 @@ static int wc_PKCS7_ParseToRecipientInfoSet(PKCS7* pkcs7, byte* in, (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) ret = ASN_PARSE_E; - if (ret == 0 && GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0) + if (ret == 0 && GetLength_ex(pkiMsg, idx, &length, pkiMsgSz, + NO_USER_CHECK) < 0) ret = ASN_PARSE_E; if (ret < 0) @@ -8785,7 +8830,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, return ret; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz); #endif /* remove EncryptedContentInfo */ @@ -8849,7 +8894,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* in, return ret; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz); wc_PKCS7_StreamGetVar(pkcs7, 0, 0, &length); tmpIv = pkcs7->stream->tmpIv; #endif @@ -9612,7 +9657,7 @@ WOLFSSL_API int wc_PKCS7_DecodeAuthEnvelopedData(PKCS7* pkcs7, byte* in, break; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_DEFAULT_PEEK, in, inSz); #endif if (ret == 0 && GetLength(pkiMsg, &idx, &nonceSz, pkiMsgSz) < 0) { ret = ASN_PARSE_E; @@ -10313,7 +10358,15 @@ int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* in, word32 inSz, return ret; } - pkiMsgSz = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + { + long rc; + rc = wc_PKCS7_GetMaxStream(pkcs7, PKCS7_SEQ_PEEK, in, inSz); + if (rc < 0) { + ret = (int)rc; + break; + } + pkiMsgSz = (word32)rc; + } #endif /* read past ContentInfo, verify type is encrypted-data */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 19ee854e6..ad0400ad6 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1017,8 +1017,12 @@ WOLFSSL_LOCAL int GetShortInt(const byte* input, word32* inOutIdx, int* number, WOLFSSL_LOCAL char* GetSigName(int oid); WOLFSSL_LOCAL int GetLength(const byte* input, word32* inOutIdx, int* len, word32 maxIdx); +WOLFSSL_LOCAL int GetLength_ex(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx, int check); WOLFSSL_LOCAL int GetSequence(const byte* input, word32* inOutIdx, int* len, word32 maxIdx); +WOLFSSL_LOCAL int GetSequence_ex(const byte* input, word32* inOutIdx, int* len, + word32 maxIdx, int check); WOLFSSL_LOCAL int GetSet(const byte* input, word32* inOutIdx, int* len, word32 maxIdx); WOLFSSL_LOCAL int GetMyVersion(const byte* input, word32* inOutIdx,