From cf843c8b8215e550cf05db52f9985fb6d9c5ef69 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 23 Jul 2025 21:39:18 -0400 Subject: [PATCH] Add wc_PKCS7_GetEnvelopedDataKariRid() Allow access to recipient ID before attempting to decrypt content. --- certs/renewcerts.sh | 8 ++ certs/test/client-ecc-cert-ski.hex | 1 + certs/test/include.am | 4 +- certs/test/kari-keyid-cms.msg | Bin 0 -> 275 bytes doc/dox_comments/header_files/pkcs7.h | 25 ++++++ tests/api.c | 67 ++++++++++++++++ wolfcrypt/src/pkcs7.c | 110 ++++++++++++++++++++++++++ wolfssl/wolfcrypt/pkcs7.h | 2 + 8 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 certs/test/client-ecc-cert-ski.hex create mode 100644 certs/test/kari-keyid-cms.msg diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 693a50cf8..609726cc1 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -523,6 +523,11 @@ run_renewcerts(){ openssl x509 -in client-ecc-cert.pem -text > tmp.pem check_result $? "Step 3" mv tmp.pem client-ecc-cert.pem + + # Extract the Subject Key Identifier from the generated certificate + # for unit test use. + openssl x509 -in client-ecc-cert.pem -noout -text | grep -A1 'Subject Key Identifier' | tail -n +2 | sed -e 's/[ :]//g' > test/client-ecc-cert-ski.hex + check_result $? "Step 4" echo "End of section" echo "---------------------------------------------------------------------" ############################################################ @@ -792,6 +797,9 @@ run_renewcerts(){ cd ./test || { echo "Failed to switch to dir ./test"; exit 1; } echo "test" | openssl cms -encrypt -binary -keyid -out ktri-keyid-cms.msg -outform der -recip ../client-cert.pem -nocerts check_result $? "generate ktri-keyid-cms.msg" + # Generate an EnvelopedData with KARI recipient for testing. + echo "testkari" | openssl cms -encrypt -binary -keyid -out kari-keyid-cms.msg -outform der -recip ../client-ecc-cert.pem -nocerts + check_result $? "generate kari-keyid-cms.msg" echo "testencrypt" | openssl cms -EncryptedData_encrypt -binary -keyid -aes-128-cbc -secretkey 0123456789ABCDEF0011223344556677 -out encrypteddata.msg -outform der -recip ../client-cert.pem -nocerts check_result $? "generate encrypteddata.msg" cd ../ || exit 1 diff --git a/certs/test/client-ecc-cert-ski.hex b/certs/test/client-ecc-cert-ski.hex new file mode 100644 index 000000000..d8f3582e8 --- /dev/null +++ b/certs/test/client-ecc-cert-ski.hex @@ -0,0 +1 @@ +EBD44B596B95613F5157B6044D894188445CABF2 diff --git a/certs/test/include.am b/certs/test/include.am index facc4a5c4..afe2aca67 100644 --- a/certs/test/include.am +++ b/certs/test/include.am @@ -36,7 +36,8 @@ EXTRA_DIST += \ certs/test/cert-over-max-altnames.cfg \ certs/test/cert-over-max-altnames.pem \ certs/test/cert-over-max-nc.cfg \ - certs/test/cert-over-max-nc.pem + certs/test/cert-over-max-nc.pem \ + certs/test/client-ecc-cert-ski.hex # The certs/server-cert with the last byte (signature byte) changed EXTRA_DIST += \ @@ -69,6 +70,7 @@ EXTRA_DIST += \ certs/test/server-localhost.pem \ certs/test/ossl-trusted-cert.pem \ certs/test/ktri-keyid-cms.msg \ + certs/test/kari-keyid-cms.msg \ certs/test/encrypteddata.msg \ certs/test/smime-test.p7s \ certs/test/smime-test-canon.p7s \ diff --git a/certs/test/kari-keyid-cms.msg b/certs/test/kari-keyid-cms.msg new file mode 100644 index 0000000000000000000000000000000000000000..9721cf7a3f8fda97f76437cad06dc00615e7e8cd GIT binary patch literal 275 zcmXqLV&rGz)N1o+`_9YA&b*+Bk-?zxFB2n^VdKt)joX+QnHK~u^f%ySW7lf)IA_bm z$n3Rx9^H-F||1Yif*TM+SyJ&ZoGf3 z*Kne=ZJA&52D`gw5KeEhI4uxk z5qW*ZJ2HD}qJ3caHWuGb#}1d6)t^{2jF+yMJTYSK3t8JKjVjjy{_T6e{lrC^+rp{5 z+^2bGE}D@uf-yu@ZnGIne+1`>l3W9tJ#_p8w6JFaadK~ PBLB?MSn>DFx 0); + if (cmsFile != XBADFILE) + XFCLOSE(cmsFile); + + skiHexFile = XFOPEN("./certs/test/client-ecc-cert-ski.hex", "rb"); + ExpectTrue(skiHexFile != XBADFILE); + skiHexSz = (word32)XFREAD(skiHex, 1, sizeof(skiHex), skiHexFile); + ExpectTrue(skiHexSz > 0); + if (skiHexFile != XBADFILE) + XFCLOSE(skiHexFile); + + ret = wc_PKCS7_GetEnvelopedDataKariRid(cms, cmsSz, rid, &ridSz); + ExpectIntEQ(ret, 0); + ExpectIntGT(ridSz, ridKeyIdentifierOffset); + /* The Subject Key Identifier hex file should have 2 hex characters for each + * byte of the key identifier in the returned recipient ID (rid), plus a + * terminating new line character. */ + ExpectIntGE(skiHexSz, ((ridSz - ridKeyIdentifierOffset) * 2) + 1); + for (i = 0; i < (ridSz - ridKeyIdentifierOffset); i++) + { + size_t j; + byte ridKeyIdByte = rid[ridKeyIdentifierOffset + i]; + byte skiByte = 0; + for (j = 0; j <= 1; j++) + { + byte hexChar = skiHex[i * 2 + j]; + skiByte = skiByte << 4; + if ('0' <= hexChar && hexChar <= '9') + skiByte |= (hexChar - '0'); + else if ('A' <= hexChar && hexChar <= 'F') + skiByte |= (hexChar - 'A' + 10); + else + ExpectTrue(0); + } + ExpectIntEQ(ridKeyIdByte, skiByte); + } +#endif +#endif /* HAVE_PKCS7 */ + return EXPECT_RESULT(); +} /* END test_wc_PKCS7_GetEnvelopedDataKariRid() */ + + /* * Testing wc_PKCS7_EncodeEncryptedData() */ @@ -68404,6 +68470,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wc_PKCS7_DecodeEnvelopedData_stream), TEST_DECL(test_wc_PKCS7_EncodeDecodeEnvelopedData), TEST_DECL(test_wc_PKCS7_SetAESKeyWrapUnwrapCb), + TEST_DECL(test_wc_PKCS7_GetEnvelopedDataKariRid), TEST_DECL(test_wc_PKCS7_EncodeEncryptedData), TEST_DECL(test_wc_PKCS7_DecodeEncryptedKeyPackage), TEST_DECL(test_wc_PKCS7_DecodeSymmetricKeyPackage), diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index e9d4d548f..3807a8709 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -12957,6 +12957,116 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in, } +int wc_PKCS7_GetEnvelopedDataKariRid(const byte * in, word32 inSz, + byte * out, word32 * outSz) +{ + int ret = 0; + word32 idx = 0; + int length = 0; + word32 contentType = 0; + word32 ridIdx = 0; + byte ridTag = 0; + + if (in == NULL || inSz == 0 || out == NULL || outSz == NULL) { + ret = BAD_FUNC_ARG; + } + /* Consume ContentInfo SEQUENCE header. */ + else if (GetSequence(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Validate the EnvelopedData OBJECT IDENTIFIER. */ + else if (wc_GetContentType(in, &idx, &contentType, inSz) < 0) { + ret = ASN_PARSE_E; + } + else if (contentType != ENVELOPED_DATA) { + WOLFSSL_MSG("PKCS#7 input not of type EnvelopedData"); + ret = PKCS7_OID_E; + } + /* Consume EXPLICIT content [0] header. */ + else if (GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, &idx, + &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume EnvelopedData SEQUENCE header. */ + else if (GetSequence(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume version. */ + else if (GetMyVersion(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume originatorInfo if present. */ + else if (GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, &idx, + &length, inSz) >= 0) { + idx += (word32)length; + } + /* Consume recipientInfos SET OF header. */ + if (ret == 0 && GetSet(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume kari [1] header. */ + if (ret == 0 && GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1, + &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume KARI version. */ + if (ret == 0 && GetMyVersion(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume KARI originator [0] header. */ + if (ret == 0 && GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED, + &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Skip originator [0] content. */ + if (ret == 0) + idx += (word32)length; + /* Consume KARI ukm [1] if present. */ + if (ret == 0 && GetASNHeader(in, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1, + &idx, &length, inSz) >= 0) { + idx += (word32) length; + } + /* Consume KARI keyEncryptionAlgorithm. */ + if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Skip keyEncryptionAlgorithm content. */ + if (ret == 0) + idx += (word32)length; + /* Consume RecipientEncryptedKeys SEQUENCE OF header. */ + if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume RecipientEncryptedKey SEQUENCE header. */ + if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + if (ret == 0) + ridIdx = idx; + /* Consume KeyAgreeRecipientIdentifier tag. */ + if (ret == 0 && GetASNTag(in, &idx, &ridTag, inSz) < 0) { + ret = ASN_PARSE_E; + } + /* Consume KeyAgreeRecipientIdentifier length. */ + if (ret == 0 && GetLength(in, &idx, &length, inSz) < 0) { + ret = ASN_PARSE_E; + } + if (ret == 0) { + word32 ridSz = (idx + (word32)length) - ridIdx; + if (ridSz > *outSz) { + /* Not enough room in output buffer. */ + ret = BUFFER_E; + } + else { + /* Copy KeyAgreeRecipientIdentifier to output buffer. */ + XMEMCPY(out, &in[ridIdx], ridSz); + *outSz = ridSz; + } + } + return ret; +} + + /* build PKCS#7 authEnvelopedData content type, return enveloped size */ int wc_PKCS7_EncodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz) diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index e69dc955d..b65c442c6 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -516,6 +516,8 @@ WOLFSSL_API int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* output, word32 outputSz); +WOLFSSL_API int wc_PKCS7_GetEnvelopedDataKariRid(const byte * in, word32 inSz, + byte * out, word32 * outSz); /* CMS/PKCS#7 AuthEnvelopedData */ WOLFSSL_API int wc_PKCS7_EncodeAuthEnvelopedData(wc_PKCS7* pkcs7,