From cf843c8b8215e550cf05db52f9985fb6d9c5ef69 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 23 Jul 2025 21:39:18 -0400 Subject: [PATCH 1/5] 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, From 6309b241cdd6e6f312528aa459c08d635d836588 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 24 Jul 2025 15:42:55 -0400 Subject: [PATCH 2/5] Fix some clang-tidy warnings in unit test --- tests/api.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/api.c b/tests/api.c index 7190f1812..e81283f58 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18325,17 +18325,16 @@ static int test_wc_PKCS7_GetEnvelopedDataKariRid(void) size_t i; const word32 ridKeyIdentifierOffset = 4; - cmsFile = XFOPEN("./certs/test/kari-keyid-cms.msg", "rb"); - ExpectTrue(cmsFile != XBADFILE); - cmsSz = (word32)XFREAD(cms, 1, sizeof(cms), cmsFile); - ExpectTrue(cmsSz > 0); + ExpectTrue((cmsFile = XFOPEN("./certs/test/kari-keyid-cms.msg", "rb")) + != XBADFILE); + ExpectTrue((cmsSz = (word32)XFREAD(cms, 1, sizeof(cms), cmsFile)) > 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); + ExpectTrue((skiHexFile = XFOPEN("./certs/test/client-ecc-cert-ski.hex", + "rb")) != XBADFILE); + ExpectTrue((skiHexSz = (word32)XFREAD(skiHex, 1, sizeof(skiHex), + skiHexFile)) > 0); if (skiHexFile != XBADFILE) XFCLOSE(skiHexFile); From 71bd9e2f6e27349f394c27030e5256745cc4547b Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 24 Jul 2025 15:46:01 -0400 Subject: [PATCH 3/5] Make unit test more resilient to earlier errors --- tests/api.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/tests/api.c b/tests/api.c index e81283f58..c66f2170f 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18338,30 +18338,34 @@ static int test_wc_PKCS7_GetEnvelopedDataKariRid(void) if (skiHexFile != XBADFILE) XFCLOSE(skiHexFile); - ret = wc_PKCS7_GetEnvelopedDataKariRid(cms, cmsSz, rid, &ridSz); + if (EXPECT_SUCCESS()) { + 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++) + if (EXPECT_SUCCESS()) { + for (i = 0; i < (ridSz - ridKeyIdentifierOffset); i++) { - 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); + 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); } - ExpectIntEQ(ridKeyIdByte, skiByte); } #endif #endif /* HAVE_PKCS7 */ From 1226dedeb897496c28c33bda0a88f543f75a9983 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 24 Jul 2025 15:52:34 -0400 Subject: [PATCH 4/5] Check that we don't run out of space for the RID structure --- tests/api.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/api.c b/tests/api.c index c66f2170f..6fb012986 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18313,6 +18313,8 @@ static int test_wc_PKCS7_GetEnvelopedDataKariRid(void) #if defined(HAVE_PKCS7) #if defined(HAVE_ECC) && (!defined(NO_AES) || (!defined(NO_SHA) || \ !defined(NO_SHA256) || defined(WOLFSSL_SHA512))) + /* The kari-keyid-cms.msg generated by openssl has a 68 byte RID structure. + * Reserve a bit more than that in case it might grow. */ byte rid[256]; byte cms[1024]; XFILE cmsFile = XBADFILE; @@ -18342,6 +18344,7 @@ static int test_wc_PKCS7_GetEnvelopedDataKariRid(void) ret = wc_PKCS7_GetEnvelopedDataKariRid(cms, cmsSz, rid, &ridSz); } ExpectIntEQ(ret, 0); + ExpectIntLT(ridSz, sizeof(rid)); 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 From 804c4f20b518e98a5698c1507b238b35c1970a9c Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Thu, 24 Jul 2025 18:51:58 -0400 Subject: [PATCH 5/5] Explicitly initialize some unit test variables to avoid warnings --- tests/api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/api.c b/tests/api.c index 6fb012986..f37b03d90 100644 --- a/tests/api.c +++ b/tests/api.c @@ -18322,9 +18322,9 @@ static int test_wc_PKCS7_GetEnvelopedDataKariRid(void) word32 ridSz = sizeof(rid); XFILE skiHexFile = XBADFILE; byte skiHex[256]; - word32 cmsSz; - word32 skiHexSz; - size_t i; + word32 cmsSz = 0; + word32 skiHexSz = 0; + size_t i = 0; const word32 ridKeyIdentifierOffset = 4; ExpectTrue((cmsFile = XFOPEN("./certs/test/kari-keyid-cms.msg", "rb"))