diff --git a/tests/api.c b/tests/api.c index bb0877d10..39b9933c0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -38789,6 +38789,167 @@ static int test_wc_PKCS7_EncodeSignedData(void) return EXPECT_RESULT(); } /* END test_wc_PKCS7_EncodeSignedData */ +static int test_wc_PKCS7_EncodeSignedData_absent(void) +{ + EXPECT_DECLS; +#if defined(HAVE_PKCS7) + PKCS7* pkcs7 = NULL; + WC_RNG rng; + byte output[FOURK_BUF]; + word32 outputSz = (word32)sizeof(output); + int withParamsLen = 0; + int withoutParamsLen = 0; + byte data[] = "Test data to encode."; +#ifndef NO_RSA + #if defined(USE_CERT_BUFFERS_2048) + byte key[sizeof(client_key_der_2048)]; + byte cert[sizeof(client_cert_der_2048)]; + word32 keySz = (word32)sizeof(key); + word32 certSz = (word32)sizeof(cert); + XMEMSET(key, 0, keySz); + XMEMSET(cert, 0, certSz); + XMEMCPY(key, client_key_der_2048, keySz); + XMEMCPY(cert, client_cert_der_2048, certSz); + #elif defined(USE_CERT_BUFFERS_1024) + byte key[sizeof_client_key_der_1024]; + byte cert[sizeof(sizeof_client_cert_der_1024)]; + word32 keySz = (word32)sizeof(key); + word32 certSz = (word32)sizeof(cert); + XMEMSET(key, 0, keySz); + XMEMSET(cert, 0, certSz); + XMEMCPY(key, client_key_der_1024, keySz); + XMEMCPY(cert, client_cert_der_1024, certSz); + #else + unsigned char cert[ONEK_BUF]; + unsigned char key[ONEK_BUF]; + XFILE fp = XBADFILE; + int certSz; + int keySz; + + ExpectTrue((fp = XFOPEN("./certs/1024/client-cert.der", "rb")) != + XBADFILE); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, sizeof_client_cert_der_1024, + fp), 0); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectTrue((fp = XFOPEN("./certs/1024/client-key.der", "rb")) != + XBADFILE); + ExpectIntGT(keySz = (int)XFREAD(key, 1, sizeof_client_key_der_1024, fp), + 0); + if (fp != XBADFILE) + XFCLOSE(fp); + #endif +#elif defined(HAVE_ECC) + #if defined(USE_CERT_BUFFERS_256) + unsigned char cert[sizeof(cliecc_cert_der_256)]; + unsigned char key[sizeof(ecc_clikey_der_256)]; + int certSz = (int)sizeof(cert); + int keySz = (int)sizeof(key); + XMEMSET(cert, 0, certSz); + XMEMSET(key, 0, keySz); + XMEMCPY(cert, cliecc_cert_der_256, certSz); + XMEMCPY(key, ecc_clikey_der_256, keySz); + #else + unsigned char cert[ONEK_BUF]; + unsigned char key[ONEK_BUF]; + XFILE fp = XBADFILE; + int certSz; + int keySz; + + ExpectTrue((fp = XFOPEN("./certs/client-ecc-cert.der", "rb")) != + XBADFILE); + ExpectIntGT(certSz = (int)XFREAD(cert, 1, ONEK_BUF, fp), 0); + if (fp != XBADFILE) { + XFCLOSE(fp); + fp = XBADFILE; + } + + ExpectTrue((fp = XFOPEN("./certs/client-ecc-key.der", "rb")) != + XBADFILE); + ExpectIntGT(keySz = (int)XFREAD(key, 1, ONEK_BUF, fp), 0); + if (fp != XBADFILE) + XFCLOSE(fp); + #endif +#endif + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + + XMEMSET(output, 0, outputSz); + ExpectIntEQ(wc_InitRng(&rng), 0); + + /* First generate and verify with NULL params */ + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->privateKey = key; + pkcs7->privateKeySz = (word32)sizeof(key); + pkcs7->encryptOID = RSAk; + #ifdef NO_SHA + pkcs7->hashOID = SHA256h; + #else + pkcs7->hashOID = SHAh; + #endif + pkcs7->rng = &rng; + } + + withParamsLen = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz); + ExpectIntGT(withParamsLen, 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); + ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, output, withParamsLen), 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + XMEMSET(output, 0, outputSz); + + /* Now generate again without params */ + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_Init(pkcs7, HEAP_HINT, INVALID_DEVID), 0); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, cert, certSz), 0); + + if (pkcs7 != NULL) { + pkcs7->content = data; + pkcs7->contentSz = (word32)sizeof(data); + pkcs7->privateKey = key; + pkcs7->privateKeySz = (word32)sizeof(key); + pkcs7->encryptOID = RSAk; + #ifdef NO_SHA + pkcs7->hashOID = SHA256h; + #else + pkcs7->hashOID = SHAh; + #endif + pkcs7->rng = &rng; + pkcs7->hashParamsAbsent = TRUE; + } + + withoutParamsLen = wc_PKCS7_EncodeSignedData(pkcs7, output, outputSz); + ExpectIntGT(withoutParamsLen, 0); + wc_PKCS7_Free(pkcs7); + pkcs7 = NULL; + + ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId)); + ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0); + ExpectIntEQ(wc_PKCS7_VerifySignedData(pkcs7, output, withoutParamsLen), 0); + + /* Both are valid PKCS7 with non-zero len, ensure without is shorter */ + ExpectIntLT(withoutParamsLen, withParamsLen); + + wc_PKCS7_Free(pkcs7); + DoExpectIntEQ(wc_FreeRng(&rng), 0); + +#endif + return EXPECT_RESULT(); +} /* * Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex() @@ -84809,6 +84970,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wc_PKCS7_EncodeData), TEST_DECL(test_wc_PKCS7_EncodeSignedData), TEST_DECL(test_wc_PKCS7_EncodeSignedData_ex), + TEST_DECL(test_wc_PKCS7_EncodeSignedData_absent), TEST_DECL(test_wc_PKCS7_VerifySignedData_RSA), TEST_DECL(test_wc_PKCS7_VerifySignedData_ECC), TEST_DECL(test_wc_PKCS7_EncodeDecodeEnvelopedData), diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 59235b940..58391e31a 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -6061,22 +6061,8 @@ enum { #define algoIdASN_Length (sizeof(algoIdASN) / sizeof(ASNItem)) #endif -/* Get the OID id/sum from the BER encoding of an algorithm identifier. - * - * NULL tag is skipped if present. - * - * @param [in] input Buffer holding BER encoded data. - * @param [in, out] inOutIdx On in, start of algorithm identifier. - * On out, start of ASN.1 item after algorithm id. - * @param [out] oid Id of OID in algorithm identifier data. - * @param [in] oidType Type of OID to expect. - * @param [in] maxIdx Maximum index of data in buffer. - * @return 0 on success. - * @return ASN_PARSE_E when encoding is invalid. - * @return ASN_UNKNOWN_OID_E when the OID cannot be verified. - */ -int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, - word32 oidType, word32 maxIdx) +static int GetAlgoIdImpl(const byte* input, word32* inOutIdx, word32* oid, + word32 oidType, word32 maxIdx, byte *absentParams) { #ifndef WOLFSSL_ASN_TEMPLATE int length; @@ -6102,6 +6088,10 @@ int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, ret = GetASNNull(input, &idx, maxIdx); if (ret != 0) return ret; + + if (absentParams != NULL) { + *absentParams = FALSE; + } } } } @@ -6126,6 +6116,11 @@ int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, if (ret == 0) { /* Return the OID id/sum. */ *oid = dataASN[ALGOIDASN_IDX_OID].data.oid.sum; + + if ((absentParams != NULL) && + (dataASN[ALGOIDASN_IDX_NULL].tag == ASN_TAG_NULL)) { + *absentParams = FALSE; + } } FREE_ASNGETDATA(dataASN, NULL); @@ -6133,6 +6128,37 @@ int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, #endif /* WOLFSSL_ASN_TEMPLATE */ } +/* Get the OID id/sum from the BER encoding of an algorithm identifier. + * + * NULL tag is skipped if present. + * + * @param [in] input Buffer holding BER encoded data. + * @param [in, out] inOutIdx On in, start of algorithm identifier. + * On out, start of ASN.1 item after algorithm id. + * @param [out] oid Id of OID in algorithm identifier data. + * @param [in] oidType Type of OID to expect. + * @param [in] maxIdx Maximum index of data in buffer. + * @return 0 on success. + * @return ASN_PARSE_E when encoding is invalid. + * @return ASN_UNKNOWN_OID_E when the OID cannot be verified. + */ +int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, + word32 oidType, word32 maxIdx) +{ + return GetAlgoIdImpl(input, inOutIdx, oid, oidType, maxIdx, NULL); +} + +int GetAlgoIdEx(const byte* input, word32* inOutIdx, word32* oid, + word32 oidType, word32 maxIdx, byte *absentParams) +{ + /* Assume absent until proven otherwise */ + if (absentParams != NULL) { + *absentParams = TRUE; + } + + return GetAlgoIdImpl(input, inOutIdx, oid, oidType, maxIdx, absentParams); +} + #ifndef NO_RSA #ifdef WC_RSA_PSS @@ -16077,7 +16103,7 @@ static WC_INLINE int IsSigAlgoECC(word32 algoOID) * @return Encoded data size on success. * @return 0 when dynamic memory allocation fails. */ -word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) +static word32 SetAlgoIDImpl(int algoOID, byte* output, int type, int curveSz, byte absentParams) { #ifndef WOLFSSL_ASN_TEMPLATE word32 tagSz, idSz, seqSz, algoSz = 0; @@ -16086,9 +16112,10 @@ word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */ word32 length = 0; - tagSz = (type == oidHashType || + tagSz = ((type == oidHashType || (type == oidSigType && !IsSigAlgoECC((word32)algoOID)) || - (type == oidKeyType && algoOID == RSAk)) ? 2U : 0U; + (type == oidKeyType && algoOID == RSAk)) && + (absentParams == FALSE)) ? 2U : 0U; algoName = OidFromId((word32)algoOID, (word32)type, &algoSz); if (algoName == NULL) { WOLFSSL_MSG("Unknown Algorithm"); @@ -16144,6 +16171,10 @@ word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) /* Don't put out NULL DER item. */ dataASN[ALGOIDASN_IDX_NULL].noOut = 1; } + /* Override for absent (not NULL) params */ + if (TRUE == absentParams) { + dataASN[ALGOIDASN_IDX_NULL].noOut = 1; + } if (algoOID == DSAk) { /* Don't include SEQUENCE for DSA keys. */ o = 1; @@ -16186,6 +16217,27 @@ word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) #endif /* WOLFSSL_ASN_TEMPLATE */ } +/* Encode an algorithm identifier. + * + * [algoOID, type] is unique. + * + * @param [in] algoOID Algorithm identifier. + * @param [out] output Buffer to hold encoding. + * @param [in] type Type of OID being encoded. + * @param [in] curveSz Add extra space for curve data. + * @return Encoded data size on success. + * @return 0 when dynamic memory allocation fails. + */ +word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) +{ + return SetAlgoIDImpl(algoOID, output, type, curveSz, FALSE); +} + +word32 SetAlgoIDEx(int algoOID, byte* output, int type, int curveSz, byte absentParams) +{ + return SetAlgoIDImpl(algoOID, output, type, curveSz, absentParams); +} + #ifdef WOLFSSL_ASN_TEMPLATE /* Always encode PKCS#1 v1.5 RSA signature and compare to encoded data. */ /* ASN.1 template for DigestInfo for a PKCS#1 v1.5 RSA signature. diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 9d2704b98..84bea8613 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -2322,8 +2322,9 @@ static int wc_PKCS7_BuildDigestInfo(PKCS7* pkcs7, byte* flatSignedAttribs, XMEMCPY(esd->contentAttribsDigest, esd->contentDigest + 2, hashSz); } - /* set algoID, with NULL attributes */ - algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0); + /* Set algoID, allow absent hash params */ + algoIdSz = SetAlgoIDEx(pkcs7->hashOID, algoId, oidHashType, + 0, pkcs7->hashParamsAbsent); digestStrSz = SetOctetString(hashSz, digestStr); digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz, @@ -2932,8 +2933,8 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, if (pkcs7->sidType != DEGENERATE_SID) { signerInfoSz += esd->signerVersionSz; - esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId, - oidHashType, 0); + esd->signerDigAlgoIdSz = SetAlgoIDEx(pkcs7->hashOID, esd->signerDigAlgoId, + oidHashType, 0, pkcs7->hashParamsAbsent); signerInfoSz += esd->signerDigAlgoIdSz; /* set signatureAlgorithm */ @@ -2943,8 +2944,8 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, idx = ret; goto out; } - esd->digEncAlgoIdSz = SetAlgoID(digEncAlgoId, esd->digEncAlgoId, - digEncAlgoType, 0); + esd->digEncAlgoIdSz = SetAlgoIDEx(digEncAlgoId, esd->digEncAlgoId, + digEncAlgoType, 0, pkcs7->hashParamsAbsent); signerInfoSz += esd->digEncAlgoIdSz; /* build up signed attributes, include contentType, signingTime, and @@ -3018,8 +3019,8 @@ static int PKCS7_EncodeSigned(PKCS7* pkcs7, esd->certsSetSz = SetImplicit(ASN_SET, 0, certSetSz, esd->certsSet, 0); if (pkcs7->sidType != DEGENERATE_SID) { - esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId, - oidHashType, 0); + esd->singleDigAlgoIdSz = SetAlgoIDEx(pkcs7->hashOID, esd->singleDigAlgoId, + oidHashType, 0, pkcs7->hashParamsAbsent); } esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet); @@ -4323,8 +4324,9 @@ static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, } } - /* Set algoID, with NULL attributes */ - algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0); + /* Set algoID, match whatever was input to match either NULL or absent */ + algoIdSz = SetAlgoIDEx(pkcs7->hashOID, algoId, oidHashType, + 0, pkcs7->hashParamsAbsent); digestStrSz = SetOctetString(hashSz, digestStr); digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz, @@ -4868,6 +4870,7 @@ static int wc_PKCS7_ParseSignerInfo(PKCS7* pkcs7, byte* in, word32 inSz, word32 sigOID = 0, hashOID = 0; word32 idx = *idxIn, localIdx; byte tag; + byte absentParams = FALSE; WOLFSSL_ENTER("wc_PKCS7_ParseSignerInfo"); /* require a signer if degenerate case not allowed */ @@ -4969,10 +4972,12 @@ static int wc_PKCS7_ParseSignerInfo(PKCS7* pkcs7, byte* in, word32 inSz, } /* Get the sequence of digestAlgorithm */ - if (ret == 0 && GetAlgoId(in, &idx, &hashOID, oidHashType, inSz) < 0) { + if (ret == 0 && GetAlgoIdEx(in, &idx, &hashOID, oidHashType, + inSz, &absentParams) < 0) { ret = ASN_PARSE_E; } pkcs7->hashOID = (int)hashOID; + pkcs7->hashParamsAbsent = absentParams; /* Get the IMPLICIT[0] SET OF signedAttributes */ localIdx = idx; @@ -5334,9 +5339,11 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, switch (pkcs7->state) { case WC_PKCS7_START: #ifndef NO_PKCS7_STREAM - if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, MAX_SEQ_SZ + + /* The expected size calculation originally assumed digest OID + * with NULL params, -2 to also accept with absent params */ + if ((ret = wc_PKCS7_AddDataToStream(pkcs7, in, inSz, (MAX_SEQ_SZ + MAX_VERSION_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ + - ASN_TAG_SZ + MAX_OID_SZ + MAX_SEQ_SZ, + ASN_TAG_SZ + MAX_OID_SZ + MAX_SEQ_SZ) - 2, &pkiMsg, &idx)) != 0) { break; } diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index acee9e427..4d8c63721 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2328,6 +2328,8 @@ WOLFSSL_LOCAL int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, word32 oidType, word32 maxIdx); WOLFSSL_LOCAL int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid, word32 oidType, word32 maxIdx); +WOLFSSL_LOCAL int GetAlgoIdEx(const byte* input, word32* inOutIdx, word32* oid, + word32 oidType, word32 maxIdx, byte *absentParams); WOLFSSL_LOCAL int GetASNTag(const byte* input, word32* idx, byte* tag, word32 inputSz); @@ -2354,6 +2356,8 @@ WOLFSSL_LOCAL word32 SetExplicit(byte number, word32 len, byte* output, byte isIndef); WOLFSSL_LOCAL word32 SetSet(word32 len, byte* output); WOLFSSL_API word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz); +WOLFSSL_LOCAL word32 SetAlgoIDEx(int algoOID, byte* output, int type, int curveSz, + byte absentParams); WOLFSSL_LOCAL int SetMyVersion(word32 version, byte* output, int header); WOLFSSL_LOCAL int SetSerialNumber(const byte* sn, word32 snSz, byte* output, word32 outputSz, int maxSnSz); diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 59011091b..85b1a1fae 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -358,6 +358,7 @@ struct PKCS7 { word32 cachedEncryptedContentSz; word16 contentCRLF:1; /* have content line endings been converted to CRLF */ word16 contentIsPkcs7Type:1; /* eContent follows PKCS#7 RFC not CMS */ + word16 hashParamsAbsent:1; /* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */ };