diff --git a/.gitignore b/.gitignore index fd5def3b6..50703a8aa 100644 --- a/.gitignore +++ b/.gitignore @@ -91,7 +91,18 @@ ecc-key.pem certreq.der certreq.pem pkcs7cert.der -pkcs7signedData.der +pkcs7signedData_RSA_SHA.der +pkcs7signedData_RSA_SHA_noattr.der +pkcs7signedData_RSA_SHA224.der +pkcs7signedData_RSA_SHA256.der +pkcs7signedData_RSA_SHA384.der +pkcs7signedData_RSA_SHA512.der +pkcs7signedData_ECDSA_SHA.der +pkcs7signedData_ECDSA_SHA_noattr.der +pkcs7signedData_ECDSA_SHA224.der +pkcs7signedData_ECDSA_SHA256.der +pkcs7signedData_ECDSA_SHA384.der +pkcs7signedData_ECDSA_SHA512.der pkcs7envelopedDataDES3.der pkcs7envelopedDataAES128CBC.der pkcs7envelopedDataAES192CBC.der diff --git a/Makefile.am b/Makefile.am index 1f042dc3d..c81d7eca0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,7 +54,18 @@ CLEANFILES+= cert.der \ pkcs7envelopedDataAES128CBC.der \ pkcs7envelopedDataAES192CBC.der \ pkcs7envelopedDataAES256CBC.der \ - pkcs7signedData.der + pkcs7signedData_RSA_SHA.der \ + pkcs7signedData_RSA_SHA_noattr.der \ + pkcs7signedData_RSA_SHA224.der \ + pkcs7signedData_RSA_SHA256.der \ + pkcs7signedData_RSA_SHA384.der \ + pkcs7signedData_RSA_SHA512.der \ + pkcs7signedData_ECDSA_SHA.der \ + pkcs7signedData_ECDSA_SHA_noattr.der \ + pkcs7signedData_ECDSA_SHA224.der \ + pkcs7signedData_ECDSA_SHA256.der \ + pkcs7signedData_ECDSA_SHA384.der \ + pkcs7signedData_ECDSA_SHA512.der exampledir = $(docdir)/example dist_example_DATA= diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index b1a42597e..edfdf794a 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifndef NO_RSA #include #endif @@ -346,9 +347,10 @@ typedef struct EncodedAttrib { typedef struct ESD { - Sha sha; - byte contentDigest[SHA_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */ - byte contentAttribsDigest[SHA_DIGEST_SIZE]; + wc_HashAlg hash; + enum wc_HashType hashType; + byte contentDigest[WC_MAX_DIGEST_SIZE + 2]; /* content only + ASN.1 heading */ + byte contentAttribsDigest[WC_MAX_DIGEST_SIZE]; byte encContentDigest[512]; byte outerSeq[MAX_SEQ_SZ]; @@ -434,6 +436,8 @@ static int FlattenAttributes(byte* output, EncodedAttrib* ea, int eaSz) } +#ifndef NO_RSA + /* returns size of signature put into out, negative on error */ static int wc_PKCS7_RsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) { @@ -459,6 +463,7 @@ static int wc_PKCS7_RsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) ret = wc_InitRsaKey(privKey, pkcs7->heap); if (ret == 0) { + idx = 0; ret = wc_RsaPrivateKeyDecode(pkcs7->privateKey, &idx, privKey, pkcs7->privateKeySz); } @@ -477,6 +482,10 @@ static int wc_PKCS7_RsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) return ret; } +#endif /* NO_RSA */ + + +#ifdef HAVE_ECC /* returns size of signature put into out, negative on error */ static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) @@ -524,6 +533,8 @@ static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) return ret; } +#endif /* HAVE_ECC */ + /* builds up SignedData signed attributes, including default ones. * @@ -533,6 +544,7 @@ static int wc_PKCS7_EcdsaSign(PKCS7* pkcs7, byte* in, word32 inSz, ESD* esd) * return 0 on success, negative on error */ static int wc_PKCS7_BuildSignedAttributes(PKCS7* pkcs7, ESD* esd) { + int hashSz; byte contentTypeOid[] = { ASN_OBJECT_ID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0d, 0x01, @@ -547,9 +559,13 @@ static int wc_PKCS7_BuildSignedAttributes(PKCS7* pkcs7, ESD* esd) PKCS7Attrib cannedAttribs[2]; word32 cannedAttribsCount; - if (pkcs7 == NULL || esd == NULL) + if (pkcs7 == NULL || esd == NULL || &esd->hash == NULL) return BAD_FUNC_ARG; + hashSz = wc_HashGetDigestSize(esd->hashType); + if (hashSz < 0) + return hashSz; + cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib); cannedAttribs[0].oid = contentTypeOid; @@ -559,7 +575,7 @@ static int wc_PKCS7_BuildSignedAttributes(PKCS7* pkcs7, ESD* esd) cannedAttribs[1].oid = messageDigestOid; cannedAttribs[1].oidSz = sizeof(messageDigestOid); cannedAttribs[1].value = esd->contentDigest; - cannedAttribs[1].valueSz = sizeof(esd->contentDigest); + cannedAttribs[1].valueSz = hashSz + 2; /* ASN.1 heading */ esd->signedAttribsCount += cannedAttribsCount; esd->signedAttribsSz += EncodeAttributes(&esd->signedAttribs[0], 2, @@ -648,19 +664,24 @@ static int wc_PKCS7_BuildDigestInfo(PKCS7* pkcs7, byte* flatSignedAttribs, word32 flatSignedAttribsSz, ESD* esd, byte* digestInfo, word32* digestInfoSz) { - int ret, digIdx = 0; + int ret, hashSz, digIdx = 0; byte digestInfoSeq[MAX_SEQ_SZ]; byte digestStr[MAX_OCTET_STR_SZ]; byte attribSet[MAX_SET_SZ]; - word32 digestInfoSeqSz, digestStrSz; + byte algoId[MAX_ALGO_SZ]; + word32 digestInfoSeqSz, digestStrSz, algoIdSz; word32 attribSetSz; - if (pkcs7 == NULL || esd == NULL || &esd->sha == NULL || + if (pkcs7 == NULL || esd == NULL || &esd->hash == NULL || esd->contentDigest == NULL || esd->signerDigAlgoId == NULL || digestInfo == NULL || digestInfoSz == NULL) { return BAD_FUNC_ARG; } + hashSz = wc_HashGetDigestSize(esd->hashType); + if (hashSz < 0) + return hashSz; + if (pkcs7->signedAttribsSz != 0) { if (flatSignedAttribs == NULL) @@ -668,38 +689,49 @@ static int wc_PKCS7_BuildDigestInfo(PKCS7* pkcs7, byte* flatSignedAttribs, attribSetSz = SetSet(flatSignedAttribsSz, attribSet); - ret = wc_InitSha(&esd->sha); + ret = wc_HashInit(&esd->hash, esd->hashType); if (ret < 0) return ret; - wc_ShaUpdate(&esd->sha, attribSet, attribSetSz); - wc_ShaUpdate(&esd->sha, flatSignedAttribs, flatSignedAttribsSz); - wc_ShaFinal(&esd->sha, esd->contentAttribsDigest); + ret = wc_HashUpdate(&esd->hash, esd->hashType, + attribSet, attribSetSz); + if (ret < 0) + return ret; + + ret = wc_HashUpdate(&esd->hash, esd->hashType, + flatSignedAttribs, flatSignedAttribsSz); + if (ret < 0) + return ret; + + ret = wc_HashFinal(&esd->hash, esd->hashType, + esd->contentAttribsDigest); + if (ret < 0) + return ret; } else { /* when no attrs, digest is contentDigest without tag and length */ - XMEMCPY(esd->contentAttribsDigest, esd->contentDigest + 2, - SHA_DIGEST_SIZE); + XMEMCPY(esd->contentAttribsDigest, esd->contentDigest + 2, hashSz); } - digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr); - digestInfoSeqSz = SetSequence(esd->signerDigAlgoIdSz + - digestStrSz + SHA_DIGEST_SIZE, + /* set algoID, with NULL attributes */ + algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0); + + digestStrSz = SetOctetString(hashSz, digestStr); + digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz, digestInfoSeq); - if (*digestInfoSz < (digestInfoSeqSz + esd->signerDigAlgoIdSz + - digestStrSz + SHA_DIGEST_SIZE)) { + if (*digestInfoSz < (digestInfoSeqSz + algoIdSz + digestStrSz + hashSz)) { return BUFFER_E; } XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); digIdx += digestInfoSeqSz; - XMEMCPY(digestInfo + digIdx, esd->signerDigAlgoId, esd->signerDigAlgoIdSz); - digIdx += esd->signerDigAlgoIdSz; + XMEMCPY(digestInfo + digIdx, algoId, algoIdSz); + digIdx += algoIdSz; XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); digIdx += digestStrSz; - XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest, SHA_DIGEST_SIZE); - digIdx += SHA_DIGEST_SIZE; + XMEMCPY(digestInfo + digIdx, esd->contentAttribsDigest, hashSz); + digIdx += hashSz; *digestInfoSz = digIdx; @@ -721,8 +753,11 @@ static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7, ESD* esd) { int ret; +#ifdef HAVE_ECC + int hashSz; +#endif word32 digestInfoSz = MAX_SEQ_SZ + MAX_ALGO_SZ + - MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE; + MAX_OCTET_STR_SZ + WC_MAX_DIGEST_SIZE; #ifdef WOLFSSL_SMALL_STACK byte* digestInfo; #else @@ -752,16 +787,28 @@ static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7, /* sign digestInfo */ switch (pkcs7->publicKeyOID) { +#ifndef NO_RSA case RSAk: ret = wc_PKCS7_RsaSign(pkcs7, digestInfo, digestInfoSz, esd); break; +#endif +#ifdef HAVE_ECC case ECDSAk: /* CMS with ECDSA does not sign DigestInfo structure * like PKCS#7 with RSA does */ + hashSz = wc_HashGetDigestSize(esd->hashType); + if (hashSz < 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return hashSz; + } + ret = wc_PKCS7_EcdsaSign(pkcs7, esd->contentAttribsDigest, - SHA_DIGEST_SIZE, esd); + hashSz, esd); break; +#endif default: WOLFSSL_MSG("Unsupported public key type"); @@ -780,6 +827,53 @@ static int wc_PKCS7_SignedDataBuildSignature(PKCS7* pkcs7, } +/* sets the wc_HashType in ESD struct based on pkcs7->hashOID + * + * pkcs7 - pointer to initialized PKCS7 struct + * type - [OUT] pointer to wc_HashType for output + * + * returns hash digest size on success, negative on error */ +static enum wc_HashType wc_PKCS7_SetHashType(PKCS7* pkcs7, + enum wc_HashType* type) +{ + if (pkcs7 == NULL || type == NULL) + return BAD_FUNC_ARG; + + switch (pkcs7->hashOID) { + +#ifndef NO_SHA + case SHAh: + *type = WC_HASH_TYPE_SHA; + break; +#endif +#ifdef WOLFSSL_SHA224 + case SHA224h: + *type = WC_HASH_TYPE_SHA224; + break; +#endif +#ifndef NO_SHA256 + case SHA256h: + *type = WC_HASH_TYPE_SHA256; + break; +#endif +#ifdef WOLFSSL_SHA384 + case SHA384h: + *type = WC_HASH_TYPE_SHA384; + break; +#endif +#ifdef WOLFSSL_SHA512 + case SHA512h: + *type = WC_HASH_TYPE_SHA512; + break; +#endif + default: + return BAD_FUNC_ARG; + } + + return wc_HashGetDigestSize(*type); +} + + /* build PKCS#7 signedData content type */ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) { @@ -800,7 +894,7 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) word32 signerInfoSz = 0; word32 totalSz = 0; int idx = 0, ret = 0; - int digEncAlgoId, digEncAlgoType; + int digEncAlgoId, digEncAlgoType, hashSz; byte* flatSignedAttribs = NULL; word32 flatSignedAttribsSz = 0; word32 innerOidSz = sizeof(innerOid); @@ -820,7 +914,16 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) #endif XMEMSET(esd, 0, sizeof(ESD)); - ret = wc_InitSha(&esd->sha); + + hashSz = wc_PKCS7_SetHashType(pkcs7, &esd->hashType); + if (hashSz < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return hashSz; + } + + ret = wc_HashInit(&esd->hash, esd->hashType); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -830,10 +933,24 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) if (pkcs7->contentSz != 0) { - wc_ShaUpdate(&esd->sha, pkcs7->content, pkcs7->contentSz); + ret = wc_HashUpdate(&esd->hash, esd->hashType, + pkcs7->content, pkcs7->contentSz); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } esd->contentDigest[0] = ASN_OCTET_STRING; - esd->contentDigest[1] = SHA_DIGEST_SIZE; - wc_ShaFinal(&esd->sha, &esd->contentDigest[2]); + esd->contentDigest[1] = hashSz; + ret = wc_HashFinal(&esd->hash, esd->hashType, + &esd->contentDigest[2]); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } } esd->innerOctetsSz = SetOctetString(pkcs7->contentSz, esd->innerOctets); @@ -873,6 +990,12 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) /* build up signed attributes */ ret = wc_PKCS7_BuildSignedAttributes(pkcs7, esd); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(esd, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MEMORY_E; + } flatSignedAttribs = (byte*)XMALLOC(esd->signedAttribsSz, pkcs7->heap, DYNAMIC_TYPE_PKCS); @@ -1014,26 +1137,31 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) } +#ifndef NO_RSA + /* returns size of signature put into out, negative on error */ static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, byte* hash, word32 hashSz) { - (void)hash; - (void)hashSz; - + #define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ +\ + MAX_OCTET_STR_SZ + WC_MAX_DIGEST_SIZE) int ret = 0; word32 scratch = 0; - #define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ +\ - MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE) - - if (pkcs7 == NULL || pkcs7->publicKey == NULL || sig == NULL || - hash == NULL) - return BAD_FUNC_ARG; - #ifdef WOLFSSL_SMALL_STACK byte* digest; RsaKey* key; +#else + byte digest[MAX_PKCS7_DIGEST_SZ]; + RsaKey stack_key; + RsaKey* key = &stack_key; +#endif + if (pkcs7 == NULL || pkcs7->publicKey == NULL || + sig == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -1045,10 +1173,6 @@ static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; - RsaKey stack_key; - RsaKey* key = &stack_key; #endif XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); @@ -1061,6 +1185,7 @@ static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, #endif return ret; } + if (wc_RsaPublicKeyDecode(pkcs7->publicKey, &scratch, key, pkcs7->publicKeySz) < 0) { WOLFSSL_MSG("ASN RSA key decode error"); @@ -1075,8 +1200,9 @@ static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, wc_FreeRsaKey(key); - if (XMEMCMP(digest, hash, ret) != 0) + if (((int)hashSz != ret) || (XMEMCMP(digest, hash, ret) != 0)) { ret = SIG_VERIFY_E; + } #ifdef WOLFSSL_SMALL_STACK XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -1086,23 +1212,32 @@ static int wc_PKCS7_RsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, return ret; } +#endif /* NO_RSA */ + + +#ifdef HAVE_ECC /* returns size of signature put into out, negative on error */ static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, byte* hash, word32 hashSz) { + #define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ +\ + MAX_OCTET_STR_SZ + WC_MAX_DIGEST_SIZE) int ret = 0; int stat = 0; - #define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ +\ - MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE) +#ifdef WOLFSSL_SMALL_STACK + byte* digest; + ecc_key* key; +#else + byte digest[MAX_PKCS7_DIGEST_SZ]; + ecc_key stack_key; + ecc_key* key = &stack_key; +#endif if (pkcs7 == NULL || pkcs7->publicKey == NULL || sig == NULL) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK - byte* digest; - ecc_key* key; - digest = (byte*)XMALLOC(MAX_PKCS7_DIGEST_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -1114,10 +1249,6 @@ static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, XFREE(digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } -#else - byte digest[MAX_PKCS7_DIGEST_SZ]; - ecc_key stack_key; - ecc_key* key = &stack_key; #endif XMEMSET(digest, 0, MAX_PKCS7_DIGEST_SZ); @@ -1130,6 +1261,7 @@ static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, #endif return ret; } + if (wc_ecc_import_x963(pkcs7->publicKey, pkcs7->publicKeySz, key) < 0) { WOLFSSL_MSG("ASN ECDSA key decode error"); #ifdef WOLFSSL_SMALL_STACK @@ -1155,97 +1287,258 @@ static int wc_PKCS7_EcdsaVerify(PKCS7* pkcs7, byte* sig, int sigSz, return ret; } +#endif /* HAVE_ECC */ + +/* build SignedData digest, both in PKCS#7 DigestInfo format and + * as plain digest for CMS. + * + * pkcs7 - pointer to initialized PKCS7 struct + * signedAttrib - signed attributes + * signedAttribSz - size of signedAttrib, octets + * pkcs7Digest - [OUT] PKCS#7 DigestInfo + * pkcs7DigestSz - [IN/OUT] size of pkcs7Digest + * plainDigest - [OUT] pointer to plain digest, offset into pkcs7Digest + * plainDigestSz - [OUT] size of digest at plainDigest + * + * returns 0 on success, negative on error */ static int wc_PKCS7_BuildSignedDataDigest(PKCS7* pkcs7, byte* signedAttrib, - word32 signedAttribSz, byte* digAlgId, - word32 digAlgIdSz, byte* out, - word32 outSz) + word32 signedAttribSz, byte* pkcs7Digest, + word32* pkcs7DigestSz, byte** plainDigest, + word32* plainDigestSz) { - int ret = 0; + int ret = 0, digIdx = 0, hashSz; word32 attribSetSz; byte attribSet[MAX_SET_SZ]; - - byte digest[SHA_DIGEST_SIZE]; - - byte digestInfo[MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + - SHA_DIGEST_SIZE]; + byte digest[WC_MAX_DIGEST_SIZE]; byte digestInfoSeq[MAX_SEQ_SZ]; byte digestStr[MAX_OCTET_STR_SZ]; - word32 digestInfoSeqSz, digestStrSz; - int digIdx = 0; + byte algoId[MAX_ALGO_SZ]; + word32 digestInfoSeqSz, digestStrSz, algoIdSz; + word32 digestInfoSz = MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + + WC_MAX_DIGEST_SIZE; +#ifdef WOLFSSL_SMALL_STACK + byte* digestInfo; +#else + byte digestInfo[digestInfoSz]; +#endif - Sha sha; + wc_HashAlg hash; + enum wc_HashType hashType; - if (pkcs7 == NULL || digAlgId == NULL || out == NULL) + if (pkcs7 == NULL || pkcs7Digest == NULL || + pkcs7DigestSz == NULL || plainDigest == NULL) { return BAD_FUNC_ARG; + } - XMEMSET(out, 0, outSz); - XMEMSET(digest, 0, SHA_DIGEST_SIZE); +#ifdef WOLFSSL_SMALL_STACK + digestInfo = (byte*)XMALLOC(digestInfoSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (digestInfo == NULL) + return MEMORY_E; +#endif + + XMEMSET(pkcs7Digest, 0, *pkcs7DigestSz); + XMEMSET(digest, 0, WC_MAX_DIGEST_SIZE); + XMEMSET(digestInfo, 0, digestInfoSz); + + hashSz = wc_PKCS7_SetHashType(pkcs7, &hashType); + if (hashSz < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return hashSz; + } /* calculate digest */ - ret = wc_InitSha(&sha); - if (ret < 0) + ret = wc_HashInit(&hash, hashType); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif return ret; + } if (signedAttribSz > 0) { - if (signedAttrib == NULL) + if (signedAttrib == NULL) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif return BAD_FUNC_ARG; + } attribSetSz = SetSet(signedAttribSz, attribSet); - wc_ShaUpdate(&sha, attribSet, attribSetSz); - wc_ShaUpdate(&sha, signedAttrib, signedAttribSz); - wc_ShaFinal(&sha, digest); + ret = wc_HashUpdate(&hash, hashType, attribSet, attribSetSz); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + ret = wc_HashUpdate(&hash, hashType, signedAttrib, signedAttribSz); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + ret = wc_HashFinal(&hash, hashType, digest); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } } else { - if (pkcs7->content == NULL) + if (pkcs7->content == NULL) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif return BAD_FUNC_ARG; + } - wc_ShaUpdate(&sha, pkcs7->content, pkcs7->contentSz); - wc_ShaFinal(&sha, digest); + ret = wc_HashUpdate(&hash, hashType, pkcs7->content, pkcs7->contentSz); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } + + ret = wc_HashFinal(&hash, hashType, digest); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; + } } - /* form input to verify operation */ - if (pkcs7->publicKeyOID == RSAk) { + /* Set algoID, with NULL attributes */ + algoIdSz = SetAlgoID(pkcs7->hashOID, algoId, oidHashType, 0); - digestStrSz = SetOctetString(SHA_DIGEST_SIZE, digestStr); - digestInfoSeqSz = SetSequence(digAlgIdSz + digestStrSz + - SHA_DIGEST_SIZE, digestInfoSeq); + digestStrSz = SetOctetString(hashSz, digestStr); + digestInfoSeqSz = SetSequence(algoIdSz + digestStrSz + hashSz, + digestInfoSeq); - XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); - digIdx += digestInfoSeqSz; - XMEMCPY(digestInfo + digIdx, digAlgId, digAlgIdSz); - digIdx += digAlgIdSz; - XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); - digIdx += digestStrSz; - XMEMCPY(digestInfo + digIdx, digest, SHA_DIGEST_SIZE); - digIdx += SHA_DIGEST_SIZE; + XMEMCPY(digestInfo + digIdx, digestInfoSeq, digestInfoSeqSz); + digIdx += digestInfoSeqSz; + XMEMCPY(digestInfo + digIdx, algoId, algoIdSz); + digIdx += algoIdSz; + XMEMCPY(digestInfo + digIdx, digestStr, digestStrSz); + digIdx += digestStrSz; + XMEMCPY(digestInfo + digIdx, digest, hashSz); + digIdx += hashSz; - XMEMCPY(out, digestInfo, digIdx); + XMEMCPY(pkcs7Digest, digestInfo, digIdx); + *pkcs7DigestSz = digIdx; - } else if (pkcs7->publicKeyOID == ECDSAk) { + /* set plain digest pointer */ + *plainDigest = pkcs7Digest + digIdx - hashSz; + *plainDigestSz = hashSz; - XMEMCPY(out, digest, SHA_DIGEST_SIZE); - digIdx = SHA_DIGEST_SIZE; +#ifdef WOLFSSL_SMALL_STACK + XFREE(digestInfo, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return 0; +} + + +/* verifies SignedData signature, over either PKCS#7 DigestInfo or + * content digest. + * + * pkcs7 - pointer to initialized PKCS7 struct + * sig - signature to verify + * sigSz - size of sig + * signedAttrib - signed attributes, or null if empty + * signedAttribSz - size of signedAttributes + * + * return 0 on success, negative on error */ +static int wc_PKCS7_SignedDataVerifySignature(PKCS7* pkcs7, byte* sig, + word32 sigSz, byte* signedAttrib, + word32 signedAttribSz) +{ + int ret = 0; + word32 plainDigestSz, pkcs7DigestSz; + word32 maxDigestSz = MAX_SEQ_SZ + MAX_ALGO_SZ + MAX_OCTET_STR_SZ + + WC_MAX_DIGEST_SIZE; + + byte* plainDigest; /* offset into pkcs7Digest */ +#ifdef WOLFSSL_SMALL_STACK + byte* pkcs7Digest; +#else + byte pkcs7Digest[maxDigestSz]; +#endif + + if (pkcs7 == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + pkcs7Digest = (byte*)XMALLOC(maxDigestSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pkcs7Digest == NULL) + return MEMORY_E; +#endif + + /* build hash to verify against */ + pkcs7DigestSz = maxDigestSz; + ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib, + signedAttribSz, pkcs7Digest, + &pkcs7DigestSz, &plainDigest, + &plainDigestSz); + if (ret < 0) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(pkcs7Digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; } - return digIdx; + switch (pkcs7->publicKeyOID) { + +#ifndef NO_RSA + case RSAk: + ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, pkcs7Digest, + pkcs7DigestSz); + if (ret < 0) { + WOLFSSL_MSG("PKCS#7 verification failed, trying CMS"); + ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, plainDigest, + plainDigestSz); + } + break; +#endif + +#ifdef HAVE_ECC + case ECDSAk: + ret = wc_PKCS7_EcdsaVerify(pkcs7, sig, sigSz, plainDigest, + plainDigestSz); + break; +#endif + + default: + WOLFSSL_MSG("Unsupported public key type"); + ret = BAD_FUNC_ARG; + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(pkcs7Digest, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; } /* Finds the certificates in the message and saves it. */ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) { - word32 idx, contentType; + word32 idx, contentType, hashOID; int length, version, ret; byte* content = NULL; byte* sig = NULL; byte* cert = NULL; byte* signedAttrib = NULL; - byte* digAlgId = NULL; int contentSz = 0, sigSz = 0, certSz = 0, signedAttribSz = 0; - int digAlgIdSz = 0; if (pkcs7 == NULL || pkiMsg == NULL || pkiMsgSz == 0) return BAD_FUNC_ARG; @@ -1387,18 +1680,11 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) /* Skip it */ idx += length; - /* Get the sequence of digestAlgorithm, saving pointer */ - digAlgId = &pkiMsg[idx]; - digAlgIdSz = idx; - - if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) + /* Get the sequence of digestAlgorithm */ + if (GetAlgoId(pkiMsg, &idx, &hashOID, oidHashType, pkiMsgSz) < 0) { return ASN_PARSE_E; - - /* update digAlgIdSz with sequence and length */ - digAlgIdSz = length + (idx - digAlgIdSz); - - /* Skip it */ - idx += length; + } + pkcs7->hashOID = (int)hashOID; /* Get the IMPLICIT[0] SET OF signedAttributes */ if (pkiMsg[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { @@ -1438,34 +1724,8 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) pkcs7->content = content; pkcs7->contentSz = contentSz; - #define MAX_PKCS7_DIGEST_SZ (MAX_SEQ_SZ + MAX_ALGO_SZ +\ - MAX_OCTET_STR_SZ + SHA_DIGEST_SIZE) - - /* build hash to verify against */ - byte finalDigest[MAX_PKCS7_DIGEST_SZ]; - - ret = wc_PKCS7_BuildSignedDataDigest(pkcs7, signedAttrib, - signedAttribSz, digAlgId, - digAlgIdSz, finalDigest, - SHA_DIGEST_SIZE); - if (ret < 0) - return ret; - - switch (pkcs7->publicKeyOID) { - - case RSAk: - ret = wc_PKCS7_RsaVerify(pkcs7, sig, sigSz, finalDigest, ret); - break; - - case ECDSAk: - ret = wc_PKCS7_EcdsaVerify(pkcs7, sig, sigSz, finalDigest, ret); - break; - - default: - WOLFSSL_MSG("Unsupported public key type"); - ret = BAD_FUNC_ARG; - } - + ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz, + signedAttrib, signedAttribSz); if (ret < 0) return ret; } @@ -1474,6 +1734,8 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz) } +#ifdef HAVE_ECC + /* KARI == KeyAgreeRecipientInfo (key agreement) */ typedef struct WC_PKCS7_KARI { DecodedCert* decoded; /* decoded recip cert */ @@ -2199,6 +2461,8 @@ static int wc_CreateKeyAgreeRecipientInfo(PKCS7* pkcs7, const byte* cert, return idx; } +#endif /* HAVE_ECC */ + /* create ASN.1 formatted RecipientInfo structure, returns sequence size */ static int wc_CreateRecipientInfo(const byte* cert, word32 certSz, @@ -2729,6 +2993,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) MAX_RECIP_SZ, pkcs7->heap); break; +#ifdef HAVE_ECC case ECDSAk: recipSz = wc_CreateKeyAgreeRecipientInfo(pkcs7, pkcs7->singleCert, pkcs7->singleCertSz, @@ -2738,6 +3003,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) contentKeyPlain, contentKeyEnc, &contentKeyEncSz, recip, MAX_RECIP_SZ); break; +#endif default: WOLFSSL_MSG("Unsupported RecipientInfo public key type"); @@ -3081,6 +3347,8 @@ static int wc_PKCS7_DecodeKtri(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, } +#ifdef HAVE_ECC + /* remove ASN.1 OriginatorIdentifierOrKey, return 0 on success, <0 on error */ static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari, byte* pkiMsg, word32 pkiMsgSz, word32* idx) @@ -3290,6 +3558,8 @@ static int wc_PKCS7_KariGetRecipientEncryptedKeys(WC_PKCS7_KARI* kari, return 0; } +#endif /* HAVE_ECC */ + /* decode ASN.1 KeyAgreeRecipientInfo (kari), return 0 on success, * < 0 on error */ @@ -3297,6 +3567,7 @@ static int wc_PKCS7_DecodeKari(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, word32* idx, byte* decryptedKey, word32* decryptedKeySz, int* recipFound) { +#ifdef HAVE_ECC int ret, keySz; int encryptedKeySz; int direction = 0; @@ -3430,6 +3701,17 @@ static int wc_PKCS7_DecodeKari(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, #endif return 0; +#else + (void)pkcs7; + (void)pkiMsg; + (void)pkiMsgSz; + (void)idx; + (void)decryptedKey; + (void)decryptedKeySz; + (void)recipFound; + + return NOT_COMPILED_IN; +#endif /* HAVE_ECC */ } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index abdecb607..1c413e882 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -549,7 +549,7 @@ int wolfcrypt_test(void* args) #endif #endif -#ifdef HAVE_X963_KDF +#if defined(HAVE_X963_KDF) && defined(HAVE_ECC) if ( (ret = x963kdf_test()) != 0) return err_sys("X963-KDF test failed!\n", ret); else @@ -5266,7 +5266,7 @@ byte GetEntropy(ENTROPY_CMD cmd, byte* out) #ifndef NO_RSA static const char* clientKey = CERT_ROOT "client-key.der"; static const char* clientCert = CERT_ROOT "client-cert.der"; - #ifdef HAVE_PKCS7 + #if defined(HAVE_PKCS7) && defined(HAVE_ECC) static const char* eccClientKey = CERT_ROOT "ecc-client-key.der"; static const char* eccClientCert = CERT_ROOT "client-ecc-cert.der"; #endif @@ -9384,7 +9384,7 @@ int hkdf_test(void) #endif /* HAVE_HKDF */ -#if defined(HAVE_X963_KDF) +#if defined(HAVE_ECC) && defined(HAVE_X963_KDF) int x963kdf_test(void) { @@ -12266,6 +12266,10 @@ static int pkcs7_load_certs_keys(byte* rsaCert, word32* rsaCertSz, #endif /* USE_CERT_BUFFERS_256 */ #endif /* HAVE_ECC */ + (void)eccCert; + (void)eccCertSz; + (void)eccPrivKey; + (void)eccPrivKeySz; return 0; } @@ -12307,7 +12311,7 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, 0x72,0x6c,0x64 }; -#ifndef NO_AES +#if !defined(NO_AES) && defined(HAVE_ECC) byte optionalUkm[] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }; @@ -12409,8 +12413,11 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, if (!pkcs7File) return -213; - ret = (int)fwrite(enveloped, envelopedSz, 1, pkcs7File); + ret = (int)fwrite(enveloped, 1, envelopedSz, pkcs7File); fclose(pkcs7File); + if (ret != envelopedSz) { + return -214; + } #endif /* PKCS7_OUTPUT_TEST_BUNDLES */ wc_PKCS7_Free(&pkcs7); @@ -12722,6 +12729,7 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, byte* eccPrivKey, word32 eccPrivKeySz) { int ret, testSz, i; + int encodedSz; byte* out; word32 outSz; WC_RNG rng; @@ -12760,11 +12768,46 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, const pkcs7SignedVector testVectors[] = { +#ifndef NO_RSA + #ifndef NO_SHA /* RSA with SHA */ {data, (word32)sizeof(data), SHAh, RSAk, rsaPrivKey, rsaPrivKeySz, rsaCert, rsaCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), "pkcs7signedData_RSA_SHA.der"}, + /* RSA with SHA, no signed attributes */ + {data, (word32)sizeof(data), SHAh, RSAk, rsaPrivKey, rsaPrivKeySz, + rsaCert, rsaCertSz, NULL, 0, + "pkcs7signedData_RSA_SHA_noattr.der"}, + #endif + #ifdef WOLFSSL_SHA224 + /* RSA with SHA224 */ + {data, (word32)sizeof(data), SHA224h, RSAk, rsaPrivKey, rsaPrivKeySz, + rsaCert, rsaCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_RSA_SHA224.der"}, + #endif + #ifndef NO_SHA256 + /* RSA with SHA256 */ + {data, (word32)sizeof(data), SHA256h, RSAk, rsaPrivKey, rsaPrivKeySz, + rsaCert, rsaCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_RSA_SHA256.der"}, + #endif + #if defined(WOLFSSL_SHA384) + /* RSA with SHA384 */ + {data, (word32)sizeof(data), SHA384h, RSAk, rsaPrivKey, rsaPrivKeySz, + rsaCert, rsaCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_RSA_SHA384.der"}, + #endif + #if defined(WOLFSSL_SHA512) + /* RSA with SHA512 */ + {data, (word32)sizeof(data), SHA512h, RSAk, rsaPrivKey, rsaPrivKeySz, + rsaCert, rsaCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_RSA_SHA512.der"}, + #endif +#endif /* NO_RSA */ + +#ifdef HAVE_ECC + #ifndef NO_SHA /* ECDSA with SHA */ {data, (word32)sizeof(data), SHAh, ECDSAk, eccPrivKey, eccPrivKeySz, eccCert, eccCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), @@ -12774,6 +12817,32 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, {data, (word32)sizeof(data), SHAh, ECDSAk, eccPrivKey, eccPrivKeySz, eccCert, eccCertSz, NULL, 0, "pkcs7signedData_ECDSA_SHA_noattr.der"}, + #endif + #ifdef WOLFSSL_SHA224 + /* ECDSA with SHA224 */ + {data, (word32)sizeof(data), SHA224h, ECDSAk, eccPrivKey, eccPrivKeySz, + eccCert, eccCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_ECDSA_SHA224.der"}, + #endif + #ifndef NO_SHA256 + /* ECDSA with SHA256 */ + {data, (word32)sizeof(data), SHA256h, ECDSAk, eccPrivKey, eccPrivKeySz, + eccCert, eccCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_ECDSA_SHA256.der"}, + #endif + #ifdef WOLFSSL_SHA384 + /* ECDSA with SHA384 */ + {data, (word32)sizeof(data), SHA384h, ECDSAk, eccPrivKey, eccPrivKeySz, + eccCert, eccCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_ECDSA_SHA384.der"}, + #endif + #ifdef WOLFSSL_SHA512 + /* ECDSA with SHA512 */ + {data, (word32)sizeof(data), SHA512h, ECDSAk, eccPrivKey, eccPrivKeySz, + eccCert, eccCertSz, attribs, (sizeof(attribs)/sizeof(PKCS7Attrib)), + "pkcs7signedData_ECDSA_SHA512.der"}, + #endif +#endif /* HAVE_ECC */ }; testSz = sizeof(testVectors) / sizeof(pkcs7SignedVector); @@ -12848,14 +12917,12 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, } } - ret = wc_PKCS7_EncodeSignedData(&pkcs7, out, outSz); - if (ret < 0) { + encodedSz = wc_PKCS7_EncodeSignedData(&pkcs7, out, outSz); + if (encodedSz < 0) { XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); wc_PKCS7_Free(&pkcs7); return -214; } - else - outSz = ret; #ifdef PKCS7_OUTPUT_TEST_BUNDLES /* write PKCS#7 to output file for more testing */ @@ -12865,9 +12932,9 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, wc_PKCS7_Free(&pkcs7); return -215; } - ret = (int)fwrite(out, 1, outSz, file); + ret = (int)fwrite(out, 1, encodedSz, file); fclose(file); - if (ret != (int)outSz) { + if (ret != (int)encodedSz) { XFREE(out, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); wc_PKCS7_Free(&pkcs7); return -216; @@ -12910,6 +12977,10 @@ static int pkcs7signed_run_vectors(byte* rsaCert, word32 rsaCertSz, if (ret > 0) return 0; + (void)eccCert; + (void)eccCertSz; + (void)eccPrivKey; + (void)eccPrivKeySz; return ret; }