Merge pull request #8976 from holtrop/decode-encrypted-key-package

Add wc_PKCS7_DecodeEncryptedKeyPackage()
This commit is contained in:
JacobBarthelmeh
2025-07-10 17:08:06 -06:00
committed by GitHub
8 changed files with 358 additions and 16 deletions

View File

@@ -792,6 +792,8 @@ 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"
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
echo "End of section"
echo "---------------------------------------------------------------------"

Binary file not shown.

View File

@@ -69,6 +69,7 @@ EXTRA_DIST += \
certs/test/server-localhost.pem \
certs/test/ossl-trusted-cert.pem \
certs/test/ktri-keyid-cms.msg \
certs/test/encrypteddata.msg \
certs/test/smime-test.p7s \
certs/test/smime-test-canon.p7s \
certs/test/smime-test-multipart.p7s \

View File

@@ -312,8 +312,7 @@ int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf,
\return 0 Returned on successfully extracting the information
from the message
\return BAD_FUNC_ARG Returned if one of the input parameters is invalid
\return ASN_PARSE_E Returned if there is an error parsing from the
given pkiMsg
\return ASN_PARSE_E Returned if there is an error parsing the given pkiMsg
\return PKCS7_OID_E Returned if the given pkiMsg is not a signed data type
\return ASN_VERSION_E Returned if the PKCS7 signer info is not version 1
\return MEMORY_E Returned if there is an error allocating memory
@@ -390,8 +389,7 @@ int wc_PKCS7_VerifySignedData(PKCS7* pkcs7,
\return 0 Returned on successfully extracting the information
from the message
\return BAD_FUNC_ARG Returned if one of the input parameters is invalid
\return ASN_PARSE_E Returned if there is an error parsing from the
given pkiMsg
\return ASN_PARSE_E Returned if there is an error parsing the given pkiMsg
\return PKCS7_OID_E Returned if the given pkiMsg is not a signed data type
\return ASN_VERSION_E Returned if the PKCS7 signer info is not version 1
\return MEMORY_E Returned if there is an error allocating memory
@@ -522,7 +520,7 @@ int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf,
... etc.
ret = wc_PKCS7_EncodeEnvelopedData(&pkcs7, pkcs7Buff, sizeof(pkcs7Buff));
if ( ret != 0 ) {
if ( ret < 0 ) {
// error encoding into output buffer
}
\endcode
@@ -543,8 +541,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7,
\return On successfully extracting the information from the message,
returns the bytes written to output
\return BAD_FUNC_ARG Returned if one of the input parameters is invalid
\return ASN_PARSE_E Returned if there is an error parsing from the
given pkiMsg
\return ASN_PARSE_E Returned if there is an error parsing the given pkiMsg
\return PKCS7_OID_E Returned if the given pkiMsg is not an enveloped
data type
\return ASN_VERSION_E Returned if the PKCS7 signer info is not version 0
@@ -599,15 +596,119 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7,
pkcs7.privateKeySz = keySz;
decodedSz = wc_PKCS7_DecodeEnvelopedData(&pkcs7, received,
sizeof(received),decoded, sizeof(decoded));
if ( decodedSz != 0 ) {
// error decoding message
sizeof(received),decoded, sizeof(decoded));
if ( decodedSz < 0 ) {
// error decoding message
}
\endcode
\sa wc_PKCS7_InitWithCert
\sa wc_PKCS7_EncodeEnvelopedData
*/
int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
word32 pkiMsgSz, byte* output,
word32 outputSz);
int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg,
word32 pkiMsgSz, byte* output, word32 outputSz);
/*!
\ingroup PKCS7
\brief This function unwraps and decrypts a PKCS7 encrypted data content
type, decoding the message into output. It uses the encryption key of the
PKCS7 object passed in via pkcs7->encryptionKey and
pkcs7->encryptionKeySz to decrypt the message.
\return On successfully extracting the information from the message,
returns the bytes written to output
\return BAD_FUNC_ARG Returned if one of the input parameters is invalid
\return ASN_PARSE_E Returned if there is an error parsing the given pkiMsg
\return PKCS7_OID_E Returned if the given pkiMsg is not an encrypted
data type
\return ASN_VERSION_E Returned if the PKCS7 signer info is not version 0
\return MEMORY_E Returned if there is an error allocating memory
\return BUFFER_E Returned if the encrypted content size is invalid
\param pkcs7 pointer to the PKCS7 structure containing the encryption key with
which to decode the encrypted data package
\param pkiMsg pointer to the buffer containing the encrypted data package
\param pkiMsgSz size of the encrypted data package
\param output pointer to the buffer in which to store the decoded message
\param outputSz size available in the output buffer
_Example_
\code
PKCS7 pkcs7;
byte received[] = { }; // initialize with received encrypted data message
byte decoded[FOURK_BUF];
int decodedSz;
// initialize pkcs7 with certificate
// update key
pkcs7.encryptionKey = key;
pkcs7.encryptionKeySz = keySz;
decodedSz = wc_PKCS7_DecodeEncryptedData(&pkcs7, received,
sizeof(received), decoded, sizeof(decoded));
if ( decodedSz < 0 ) {
// error decoding message
}
\endcode
\sa wc_PKCS7_InitWithCert
*/
int wc_PKCS7_DecodeEncryptedData(PKCS7* pkcs7, byte* pkiMsg,
word32 pkiMsgSz, byte* output, word32 outputSz);
/*!
\ingroup PKCS7
\brief This function unwraps and decrypts a PKCS7 encrypted key package
content type, decoding the message into output. If the wrapped content
type is EncryptedData, the encryption key must be set in the pkcs7 input
structure (via pkcs7->encryptionKey and pkcs7->encryptionKeySz). If the
wrapped content type is EnvelopedData, the private key must be set in the
pkcs7 input structure (via pkcs7->privateKey and pkcs7->privateKeySz).
A wrapped content type of AuthEnvelopedData is not currently supported.
This function will automatically call either wc_PKCS7_DecodeEnvelopedData()
or wc_PKCS7_DecodeEncryptedData() depending on the wrapped content type.
This function could also return any error code from either of those
functions in addition to the error codes listed here.
\return On successfully extracting the information from the message,
returns the bytes written to output
\return BAD_FUNC_ARG Returned if one of the input parameters is invalid
\return ASN_PARSE_E Returned if there is an error parsing the given pkiMsg
or if the wrapped content type is EncryptedData and support for
EncryptedData is not compiled in (e.g. NO_PKCS7_ENCRYPTED_DATA is set)
\return PKCS7_OID_E Returned if the given pkiMsg is not an encrypted
key package data type
\param pkcs7 pointer to the PKCS7 structure containing the private key or
encryption key with which to decode the encrypted key package
\param pkiMsg pointer to the buffer containing the encrypted key package message
\param pkiMsgSz size of the encrypted key package message
\param output pointer to the buffer in which to store the decoded output
\param outputSz size available in the output buffer
_Example_
\code
PKCS7 pkcs7;
byte received[] = { }; // initialize with received encrypted data message
byte decoded[FOURK_BUF];
int decodedSz;
// initialize pkcs7 with certificate
// update key for expected EnvelopedData (example)
pkcs7.privateKey = key;
pkcs7.privateKeySz = keySz;
decodedSz = wc_PKCS7_DecodeEncryptedKeyPackage(&pkcs7, received,
sizeof(received), decoded, sizeof(decoded));
if ( decodedSz < 0 ) {
// error decoding message
}
\endcode
\sa wc_PKCS7_InitWithCert
*/
int wc_PKCS7_DecodeEncryptedKeyPackage(wc_PKCS7 * pkcs7,
byte * pkiMsg, word32 pkiMsgSz, byte * output, word32 outputSz);

View File

@@ -17494,7 +17494,7 @@ static int test_wc_PKCS7_DecodeEnvelopedData_stream(void)
} /* END test_wc_PKCS7_DecodeEnvelopedData_stream() */
/*
* Testing wc_PKCS7_EncodeEnvelopedData()
* Testing wc_PKCS7_EncodeEnvelopedData(), wc_PKCS7_DecodeEnvelopedData()
*/
static int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
{
@@ -18185,6 +18185,179 @@ static int test_wc_PKCS7_EncodeEncryptedData(void)
return EXPECT_RESULT();
} /* END test_wc_PKCS7_EncodeEncryptedData() */
#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_DES3) && !defined(NO_RSA) && !defined(NO_SHA)
static void build_test_EncryptedKeyPackage(byte * out, word32 * out_size, byte * in_data, word32 in_size, size_t in_content_type, size_t test_vector)
{
/* EncryptedKeyPackage ContentType TLV DER */
static const byte ekp_oid_tlv[] = {0x06U, 10U,
0X60U, 0X86U, 0X48U, 0X01U, 0X65U, 0X02U, 0X01U, 0X02U, 0X4EU, 0X02U};
if (in_content_type == ENCRYPTED_DATA) {
/* EncryptedData subtype */
size_t ekp_content_der_size = 2U + in_size;
size_t ekp_content_info_size = sizeof(ekp_oid_tlv) + ekp_content_der_size;
/* EncryptedKeyPackage ContentType */
out[0] = 0x30U;
out[1] = ekp_content_info_size & 0x7FU;
/* EncryptedKeyPackage ContentInfo */
XMEMCPY(&out[2], ekp_oid_tlv, sizeof(ekp_oid_tlv));
/* EncryptedKeyPackage content [0] */
out[14] = 0xA0U;
out[15] = in_size & 0x7FU;
XMEMCPY(&out[16], in_data, in_size);
*out_size = 16U + in_size;
switch (test_vector)
{
case 1: out[0] = 0x20U; break;
case 2: out[2] = 0x01U; break;
case 3: out[7] = 0x42U; break;
case 4: out[14] = 0xA2U; break;
}
}
else if (in_content_type == ENVELOPED_DATA) {
/* EnvelopedData subtype */
size_t ekp_choice_der_size = 4U + in_size;
size_t ekp_content_der_size = 4U + ekp_choice_der_size;
size_t ekp_content_info_size = sizeof(ekp_oid_tlv) + ekp_content_der_size;
/* EncryptedKeyPackage ContentType */
out[0] = 0x30U;
out[1] = 0x82U;
out[2] = ekp_content_info_size >> 8U;
out[3] = ekp_content_info_size & 0xFFU;
/* EncryptedKeyPackage ContentInfo */
XMEMCPY(&out[4], ekp_oid_tlv, sizeof(ekp_oid_tlv));
/* EncryptedKeyPackage content [0] */
out[16] = 0xA0U;
out[17] = 0x82U;
out[18] = ekp_choice_der_size >> 8U;
out[19] = ekp_choice_der_size & 0xFFU;
/* EncryptedKeyPackage CHOICE [0] EnvelopedData */
out[20] = 0xA0U;
out[21] = 0x82U;
out[22] = in_size >> 8U;
out[23] = in_size & 0xFFU;
XMEMCPY(&out[24], in_data, in_size);
*out_size = 24U + in_size;
switch (test_vector)
{
case 1: out[0] = 0x20U; break;
case 2: out[4] = 0x01U; break;
case 3: out[9] = 0x42U; break;
case 4: out[16] = 0xA2U; break;
}
}
}
#endif /* HAVE_PKCS7 && USE_CERT_BUFFERS_2048 && !NO_DES3 && !NO_RSA && !NO_SHA */
/*
* Test wc_PKCS7_DecodeEncryptedKeyPackage().
*/
static int test_wc_PKCS7_DecodeEncryptedKeyPackage(void)
{
EXPECT_DECLS;
#if defined(HAVE_PKCS7) && defined(USE_CERT_BUFFERS_2048) && !defined(NO_DES3) && !defined(NO_RSA) && !defined(NO_SHA)
static const struct {
const char * msg_file_name;
word32 msg_content_type;
} test_messages[] = {
{"./certs/test/ktri-keyid-cms.msg", ENVELOPED_DATA},
{"./certs/test/encrypteddata.msg", ENCRYPTED_DATA},
};
static const int test_vectors[] = {
0,
WC_NO_ERR_TRACE(ASN_PARSE_E),
WC_NO_ERR_TRACE(ASN_PARSE_E),
WC_NO_ERR_TRACE(PKCS7_OID_E),
WC_NO_ERR_TRACE(ASN_PARSE_E),
};
static const byte key[] = {
0x01U, 0x23U, 0x45U, 0x67U, 0x89U, 0xABU, 0xCDU, 0xEFU,
0x00U, 0x11U, 0x22U, 0x33U, 0x44U, 0x55U, 0x66U, 0x77U,
};
size_t test_msg = 0U;
size_t test_vector = 0U;
for (test_msg = 0U; test_msg < (sizeof(test_messages)/sizeof(test_messages[0])); test_msg++)
{
for (test_vector = 0U; test_vector < (sizeof(test_vectors)/sizeof(test_vectors[0])); test_vector++)
{
byte * ekp_cms_der = NULL;
word32 ekp_cms_der_size = 0U;
byte * inner_cms_der = NULL;
word32 inner_cms_der_size = (word32)FOURK_BUF;
XFILE inner_cms_file = XBADFILE;
PKCS7 * pkcs7 = NULL;
byte out[15] = {0};
int result = 0;
ExpectNotNull(ekp_cms_der = (byte *)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER));
/* Check for possible previous test failure. */
if (ekp_cms_der == NULL) {
break;
}
ExpectNotNull(inner_cms_der = (byte *)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER));
ExpectTrue((inner_cms_file = XFOPEN(test_messages[test_msg].msg_file_name, "rb")) != XBADFILE);
ExpectTrue((inner_cms_der_size = (word32)XFREAD(inner_cms_der, 1, inner_cms_der_size, inner_cms_file)) > 0);
if (inner_cms_file != XBADFILE) {
XFCLOSE(inner_cms_file);
}
if (test_messages[test_msg].msg_content_type == ENVELOPED_DATA) {
/* Verify that the build_test_EncryptedKeyPackage can format as expected. */
ExpectIntGT(inner_cms_der_size, 127);
}
if (test_messages[test_msg].msg_content_type == ENCRYPTED_DATA) {
/* Verify that the build_test_EncryptedKeyPackage can format as expected. */
ExpectIntLT(inner_cms_der_size, 124);
}
build_test_EncryptedKeyPackage(ekp_cms_der, &ekp_cms_der_size, inner_cms_der, inner_cms_der_size, test_messages[test_msg].msg_content_type, test_vector);
XFREE(inner_cms_der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte *)client_cert_der_2048, sizeof_client_cert_der_2048), 0);
if (pkcs7 != NULL) {
if (test_messages[test_msg].msg_content_type == ENVELOPED_DATA) {
/* To test EnvelopedData, set private key. */
pkcs7->privateKey = (byte *)client_key_der_2048;
pkcs7->privateKeySz = sizeof_client_key_der_2048;
}
if (test_messages[test_msg].msg_content_type == ENCRYPTED_DATA) {
/* To test EncryptedData, set symmetric encryption key. */
pkcs7->encryptionKey = (byte *)key;
pkcs7->encryptionKeySz = sizeof(key);
}
}
ExpectIntEQ(wc_PKCS7_DecodeEncryptedKeyPackage(pkcs7, NULL, ekp_cms_der_size, out, sizeof(out)), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
result = wc_PKCS7_DecodeEncryptedKeyPackage(pkcs7, ekp_cms_der, ekp_cms_der_size, out, sizeof(out));
if (result == WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
result = wc_PKCS7_DecodeEncryptedKeyPackage(pkcs7, ekp_cms_der, ekp_cms_der_size, out, sizeof(out));
}
if (test_vectors[test_vector] == 0U) {
if (test_messages[test_msg].msg_content_type == ENVELOPED_DATA) {
ExpectIntGT(result, 0);
ExpectIntEQ(XMEMCMP(out, "test", 4), 0);
}
if (test_messages[test_msg].msg_content_type == ENCRYPTED_DATA) {
#ifndef NO_PKCS7_ENCRYPTED_DATA
ExpectIntGT(result, 0);
ExpectIntEQ(XMEMCMP(out, "testencrypt", 11), 0);
#else
ExpectIntEQ(result, WC_NO_ERR_TRACE(ASN_PARSE_E));
#endif
}
}
else {
ExpectIntEQ(result, test_vectors[test_vector]);
}
XFREE(ekp_cms_der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
wc_PKCS7_Free(pkcs7);
}
}
#endif /* HAVE_PKCS7 && USE_CERT_BUFFERS_2048 && !NO_DES3 && !NO_RSA && !NO_SHA */
return EXPECT_RESULT();
} /* END test_wc_PKCS7_DecodeEncryptedKeyPackage() */
/*
* Testing wc_PKCS7_Degenerate()
*/
@@ -67609,6 +67782,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wc_PKCS7_DecodeEnvelopedData_stream),
TEST_DECL(test_wc_PKCS7_EncodeDecodeEnvelopedData),
TEST_DECL(test_wc_PKCS7_EncodeEncryptedData),
TEST_DECL(test_wc_PKCS7_DecodeEncryptedKeyPackage),
TEST_DECL(test_wc_PKCS7_Degenerate),
TEST_DECL(test_wc_PKCS7_BER),
TEST_DECL(test_wc_PKCS7_signed_enveloped),

View File

@@ -14878,6 +14878,62 @@ int wc_PKCS7_SetDecodeEncryptedCtx(wc_PKCS7* pkcs7, void* ctx)
#endif /* NO_PKCS7_ENCRYPTED_DATA */
/* Unwrap and decrypt PKCS#7/CMS EncryptedKeyPackage object, return the
* decoded size. */
int wc_PKCS7_DecodeEncryptedKeyPackage(wc_PKCS7 * pkcs7,
byte * pkiMsg, word32 pkiMsgSz, byte * output, word32 outputSz)
{
int ret = 0;
word32 pkiIndex = 0;
word32 contentType = 0;
int length = 0;
if (pkiMsg == NULL) {
ret = BAD_FUNC_ARG;
}
/* Expect a SEQUENCE header to start the EncryptedKeyPackage
* ContentInfo. */
else if (GetSequence_ex(pkiMsg, &pkiIndex, &length, pkiMsgSz, 1) < 0) {
ret = ASN_PARSE_E;
}
/* Validate the EncryptedKeyPackage OBJECT IDENTIFIER. */
else if (wc_GetContentType(pkiMsg, &pkiIndex, &contentType, pkiMsgSz) < 0) {
ret = ASN_PARSE_E;
}
else if (contentType != ENCRYPTED_KEY_PACKAGE) {
WOLFSSL_MSG("PKCS#7 input not of type EncryptedKeyPackage");
ret = PKCS7_OID_E;
}
/* Expect content [0] tag */
else if (GetASNHeader(pkiMsg, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED,
&pkiIndex, &length, pkiMsgSz) < 0) {
ret = ASN_PARSE_E;
}
/* Check for an EncryptedKeyPackage explicit CHOICE [0] tag, indicating
* an EnvelopedData subtype. */
else if (GetASNHeader(pkiMsg, ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED,
&pkiIndex, &length, pkiMsgSz) >= 0) {
/* An explicit CHOICE [0] tag was found. pkiIndex now should point
* to the EnvelopedData ContentInfo object within the
* EncryptedKeyPackage. */
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, &pkiMsg[pkiIndex],
pkiMsgSz - pkiIndex, output, outputSz);
}
else {
#ifndef NO_PKCS7_ENCRYPTED_DATA
/* An explicit CHOICE [0] tag was not found. Check if we have an
* EncryptedData blob. */
ret = wc_PKCS7_DecodeEncryptedData(pkcs7, &pkiMsg[pkiIndex],
pkiMsgSz - pkiIndex, output, outputSz);
#else
ret = ASN_PARSE_E;
#endif
}
return ret;
}
/* set stream mode for encoding and signing
* returns 0 on success */
int wc_PKCS7_SetStreamMode(wc_PKCS7* pkcs7, byte flag,

View File

@@ -1685,7 +1685,9 @@ enum PKCS7_TYPES {
/* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x01,0x10 */
FIRMWARE_PKG_DATA = 685, /* 1.2.840.113549.1.9.16.1.16 */
/* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x01,0x17 */
AUTH_ENVELOPED_DATA = 692 /* 1.2.840.113549.1.9.16.1.23 */
AUTH_ENVELOPED_DATA = 692, /* 1.2.840.113549.1.9.16.1.23 */
/* 0x60,0x86,0x48,0x01,0x65,0x02,0x01,0x02,0x4E,0x02 */
ENCRYPTED_KEY_PACKAGE = 489 /* 2.16.840.1.101.2.1.2.78.2 */
#else
/* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x07 */
PKCS7_MSG = 0x01498bdd, /* 1.2.840.113549.1.7 */
@@ -1706,7 +1708,9 @@ enum PKCS7_TYPES {
/* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x01,0x10 */
FIRMWARE_PKG_DATA = 0x70a68a32, /* 1.2.840.113549.1.9.16.1.16 */
/* 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x09,0x10,0x01,0x17 */
AUTH_ENVELOPED_DATA = 0x70a18a32 /* 1.2.840.113549.1.9.16.1.23 */
AUTH_ENVELOPED_DATA = 0x70a18a32, /* 1.2.840.113549.1.9.16.1.23 */
/* 0x60,0x86,0x48,0x01,0x65,0x02,0x01,0x02,0x4E,0x02 */
ENCRYPTED_KEY_PACKAGE = 0x034986B4 /* 2.16.840.1.101.2.1.2.78.2 */
#endif
};

View File

@@ -530,6 +530,10 @@ WOLFSSL_API int wc_PKCS7_SetDecodeEncryptedCb(wc_PKCS7* pkcs7,
WOLFSSL_API int wc_PKCS7_SetDecodeEncryptedCtx(wc_PKCS7* pkcs7, void* ctx);
#endif /* NO_PKCS7_ENCRYPTED_DATA */
/* CMS/PKCS#7 EncryptedKeyPackage */
WOLFSSL_API int wc_PKCS7_DecodeEncryptedKeyPackage(wc_PKCS7 * pkcs7,
byte * pkiMsg, word32 pkiMsgSz, byte * output, word32 outputSz);
/* stream and certs */
WOLFSSL_LOCAL int wc_PKCS7_WriteOut(wc_PKCS7* pkcs7, byte* output,
const byte* input, word32 inputSz);