mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-06 02:10:48 +02:00
Harden PKCS#7 EnvelopedData key unwrap
This commit is contained in:
@@ -829,6 +829,7 @@ WOLFSSL_NO_KCAPI_HMAC_SHA256
|
|||||||
WOLFSSL_NO_KCAPI_HMAC_SHA384
|
WOLFSSL_NO_KCAPI_HMAC_SHA384
|
||||||
WOLFSSL_NO_KCAPI_HMAC_SHA512
|
WOLFSSL_NO_KCAPI_HMAC_SHA512
|
||||||
WOLFSSL_NO_KCAPI_SHA224
|
WOLFSSL_NO_KCAPI_SHA224
|
||||||
|
WOLFSSL_NO_KTRI_ORACLE_WARNING
|
||||||
WOLFSSL_NO_OCSP_DATE_CHECK
|
WOLFSSL_NO_OCSP_DATE_CHECK
|
||||||
WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
|
WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
|
||||||
WOLFSSL_NO_OCSP_OPTIONAL_CERTS
|
WOLFSSL_NO_OCSP_OPTIONAL_CERTS
|
||||||
|
|||||||
+245
-6
@@ -1118,6 +1118,229 @@ int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bleichenbacher padding-oracle regression: wc_PKCS7_DecryptKtri must not
|
||||||
|
* return a distinguishable error when RSA PKCS#1 v1.5 unwrap of the
|
||||||
|
* encrypted CEK fails vs. when it succeeds with a wrong key. The
|
||||||
|
* mitigation substitutes a deterministic pseudo-random CEK on RSA failure
|
||||||
|
* so content decryption fails indistinguishably. This test corrupts the
|
||||||
|
* encryptedKey in a valid EnvelopedData and asserts the error matches
|
||||||
|
* content corruption rather than surfacing an RSA/recipient-level code.
|
||||||
|
* Runs for AES-128 and AES-256 because the fake CEK is a fixed 32 bytes:
|
||||||
|
* AES-128 (key size 16) exercises the path where the fake size differs
|
||||||
|
* from the real CEK size.
|
||||||
|
*/
|
||||||
|
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
|
||||||
|
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
|
||||||
|
defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
|
||||||
|
!defined(WOLFSSL_NO_MALLOC) && \
|
||||||
|
(defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
|
||||||
|
!defined(NO_FILESYSTEM))
|
||||||
|
static int pkcs7_ktri_bad_pad_case(int encryptOID, byte* rsaCert,
|
||||||
|
word32 rsaCertSz, byte* rsaPrivKey,
|
||||||
|
word32 rsaPrivKeySz, byte* encrypted,
|
||||||
|
word32 encryptedCap, byte* decoded,
|
||||||
|
word32 decodedCap)
|
||||||
|
{
|
||||||
|
EXPECT_DECLS;
|
||||||
|
PKCS7* pkcs7 = NULL;
|
||||||
|
byte data[] = "PKCS7 KTRI bad-RSA-padding regression payload.";
|
||||||
|
int encryptedSz = 0;
|
||||||
|
int badKeyRet = 0;
|
||||||
|
int badContentRet = 0;
|
||||||
|
byte savedKeyByte = 0;
|
||||||
|
byte savedContentByte = 0;
|
||||||
|
word32 i;
|
||||||
|
word32 encryptedKeyOff = 0;
|
||||||
|
static const byte rsaEncOid[] = {
|
||||||
|
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
|
||||||
|
0x01, 0x01, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
||||||
|
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
|
||||||
|
if (pkcs7 != NULL) {
|
||||||
|
pkcs7->content = data;
|
||||||
|
pkcs7->contentSz = (word32)sizeof(data);
|
||||||
|
pkcs7->contentOID = DATA;
|
||||||
|
pkcs7->encryptOID = encryptOID;
|
||||||
|
}
|
||||||
|
ExpectIntGT(encryptedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7,
|
||||||
|
encrypted, encryptedCap), 0);
|
||||||
|
wc_PKCS7_Free(pkcs7);
|
||||||
|
pkcs7 = NULL;
|
||||||
|
|
||||||
|
/* Locate the KTRI encryptedKey OCTET STRING. After the rsaEncryption
|
||||||
|
* OID there are NULL algorithm parameters (05 00), then a 256-byte
|
||||||
|
* OCTET STRING (tag 04, long-form length 82 01 00 for RSA-2048). */
|
||||||
|
for (i = 0; (int)(i + sizeof(rsaEncOid)) < encryptedSz; i++) {
|
||||||
|
if (XMEMCMP(&encrypted[i], rsaEncOid, sizeof(rsaEncOid)) == 0) {
|
||||||
|
word32 p = i + (word32)sizeof(rsaEncOid);
|
||||||
|
if (p + 2 < (word32)encryptedSz &&
|
||||||
|
encrypted[p] == 0x05 && encrypted[p + 1] == 0x00) {
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
if (p + 4 < (word32)encryptedSz && encrypted[p] == 0x04) {
|
||||||
|
if (encrypted[p + 1] == 0x82) {
|
||||||
|
encryptedKeyOff = p + 4;
|
||||||
|
}
|
||||||
|
else if (encrypted[p + 1] == 0x81) {
|
||||||
|
encryptedKeyOff = p + 3;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encryptedKeyOff = p + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExpectIntGT(encryptedKeyOff, 0);
|
||||||
|
ExpectIntLT(encryptedKeyOff + 32, (word32)encryptedSz);
|
||||||
|
|
||||||
|
/* Case 1: corrupt a byte inside the RSA ciphertext, decode, restore. */
|
||||||
|
savedKeyByte = encrypted[encryptedKeyOff + 16];
|
||||||
|
encrypted[encryptedKeyOff + 16] ^= 0xA5;
|
||||||
|
|
||||||
|
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
||||||
|
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
|
||||||
|
if (pkcs7 != NULL) {
|
||||||
|
pkcs7->privateKey = rsaPrivKey;
|
||||||
|
pkcs7->privateKeySz = rsaPrivKeySz;
|
||||||
|
}
|
||||||
|
badKeyRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted,
|
||||||
|
(word32)encryptedSz, decoded, decodedCap);
|
||||||
|
wc_PKCS7_Free(pkcs7);
|
||||||
|
pkcs7 = NULL;
|
||||||
|
encrypted[encryptedKeyOff + 16] = savedKeyByte;
|
||||||
|
|
||||||
|
/* Case 2: corrupt a byte in the second-to-last AES ciphertext block.
|
||||||
|
* In CBC mode this deterministically XOR-flips the corresponding byte
|
||||||
|
* in the last plaintext block, invalidating the PKCS#7 padding
|
||||||
|
* (original pad byte 0x01 becomes 0x01^0xA5 = 0xA4 > blockSz).
|
||||||
|
* Corrupting the last ciphertext block directly would randomize the
|
||||||
|
* entire last plaintext block, giving ~1/256 chance of accidentally
|
||||||
|
* valid padding and intermittent test failures. */
|
||||||
|
savedContentByte = encrypted[encryptedSz - 17];
|
||||||
|
encrypted[encryptedSz - 17] ^= 0xA5;
|
||||||
|
|
||||||
|
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
||||||
|
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
|
||||||
|
if (pkcs7 != NULL) {
|
||||||
|
pkcs7->privateKey = rsaPrivKey;
|
||||||
|
pkcs7->privateKeySz = rsaPrivKeySz;
|
||||||
|
}
|
||||||
|
badContentRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted,
|
||||||
|
(word32)encryptedSz, decoded, decodedCap);
|
||||||
|
wc_PKCS7_Free(pkcs7);
|
||||||
|
pkcs7 = NULL;
|
||||||
|
encrypted[encryptedSz - 17] = savedContentByte;
|
||||||
|
|
||||||
|
/* Case 2 must always fail: the CBC-chain corruption deterministically
|
||||||
|
* invalidates the PKCS#7 padding. */
|
||||||
|
ExpectIntLT(badContentRet, 0);
|
||||||
|
/* Bad-key must NOT leak as an RSA- or recipient-level error. */
|
||||||
|
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(PKCS7_RECIP_E));
|
||||||
|
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_PAD_E));
|
||||||
|
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_BUFFER_E));
|
||||||
|
ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(BAD_PADDING_E));
|
||||||
|
/* Case 1 (bad RSA key) decrypts content with a random fake CEK,
|
||||||
|
* producing fully random plaintext. With ~1/256 probability the
|
||||||
|
* PKCS#7 padding accidentally looks valid, causing a positive
|
||||||
|
* garbage-length return instead of an error. This does not leak
|
||||||
|
* RSA key information, so it is acceptable. When both cases do
|
||||||
|
* fail, verify they fail at the same content-decryption layer. */
|
||||||
|
if (badKeyRet < 0) {
|
||||||
|
ExpectIntEQ(badKeyRet, badContentRet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXPECT_RESULT();
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void)
|
||||||
|
{
|
||||||
|
EXPECT_DECLS;
|
||||||
|
byte encrypted[FOURK_BUF];
|
||||||
|
byte decoded[FOURK_BUF];
|
||||||
|
byte* rsaCert = NULL;
|
||||||
|
byte* rsaPrivKey = NULL;
|
||||||
|
word32 rsaCertSz = 0;
|
||||||
|
word32 rsaPrivKeySz = 0;
|
||||||
|
#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) && \
|
||||||
|
!defined(NO_FILESYSTEM)
|
||||||
|
XFILE f = XBADFILE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Load RSA cert and key */
|
||||||
|
#if defined(USE_CERT_BUFFERS_1024)
|
||||||
|
rsaCertSz = (word32)sizeof_client_cert_der_1024;
|
||||||
|
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER));
|
||||||
|
if (rsaCert != NULL)
|
||||||
|
XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz);
|
||||||
|
rsaPrivKeySz = (word32)sizeof_client_key_der_1024;
|
||||||
|
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER));
|
||||||
|
if (rsaPrivKey != NULL)
|
||||||
|
XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz);
|
||||||
|
#elif defined(USE_CERT_BUFFERS_2048)
|
||||||
|
rsaCertSz = (word32)sizeof_client_cert_der_2048;
|
||||||
|
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER));
|
||||||
|
if (rsaCert != NULL)
|
||||||
|
XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz);
|
||||||
|
rsaPrivKeySz = (word32)sizeof_client_key_der_2048;
|
||||||
|
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER));
|
||||||
|
if (rsaPrivKey != NULL)
|
||||||
|
XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz);
|
||||||
|
#elif !defined(NO_FILESYSTEM)
|
||||||
|
rsaCertSz = FOURK_BUF;
|
||||||
|
ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER));
|
||||||
|
ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE);
|
||||||
|
ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0);
|
||||||
|
if (f != XBADFILE) {
|
||||||
|
XFCLOSE(f);
|
||||||
|
f = XBADFILE;
|
||||||
|
}
|
||||||
|
rsaPrivKeySz = FOURK_BUF;
|
||||||
|
ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER));
|
||||||
|
ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE);
|
||||||
|
ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1,
|
||||||
|
rsaPrivKeySz, f)) > 0);
|
||||||
|
if (f != XBADFILE)
|
||||||
|
XFCLOSE(f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rsaCert == NULL || rsaPrivKey == NULL) {
|
||||||
|
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
return TEST_SKIPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AES-128: 32-byte fake CEK larger than real CEK size (16 bytes). */
|
||||||
|
ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES128CBCb, rsaCert, rsaCertSz,
|
||||||
|
rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
|
||||||
|
decoded, sizeof(decoded)), TEST_SUCCESS);
|
||||||
|
#ifdef WOLFSSL_AES_192
|
||||||
|
/* AES-192: fake CEK (32) vs real CEK (24) - another size mismatch. */
|
||||||
|
ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES192CBCb, rsaCert, rsaCertSz,
|
||||||
|
rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
|
||||||
|
decoded, sizeof(decoded)), TEST_SUCCESS);
|
||||||
|
#endif
|
||||||
|
/* AES-256: fake CEK size matches real CEK size (32 bytes). */
|
||||||
|
ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES256CBCb, rsaCert, rsaCertSz,
|
||||||
|
rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
|
||||||
|
decoded, sizeof(decoded)), TEST_SUCCESS);
|
||||||
|
|
||||||
|
XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
return EXPECT_RESULT();
|
||||||
|
} /* END test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex()
|
* Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex()
|
||||||
*/
|
*/
|
||||||
@@ -2503,6 +2726,8 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
|
|||||||
bytes */
|
bytes */
|
||||||
size_t testDerBufferSz = 0;
|
size_t testDerBufferSz = 0;
|
||||||
byte decodedData[8192];
|
byte decodedData[8192];
|
||||||
|
byte serverDecodedData[8192];
|
||||||
|
int serverRet = 0;
|
||||||
|
|
||||||
ExpectTrue((f = XFOPEN(testFile, "rb")) != XBADFILE);
|
ExpectTrue((f = XFOPEN(testFile, "rb")) != XBADFILE);
|
||||||
if (f != XBADFILE) {
|
if (f != XBADFILE) {
|
||||||
@@ -2522,12 +2747,13 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
|
|||||||
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)server_key_der_2048,
|
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)server_key_der_2048,
|
||||||
sizeof_server_key_der_2048), 0);
|
sizeof_server_key_der_2048), 0);
|
||||||
|
|
||||||
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
|
serverRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
|
||||||
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
|
(word32)testDerBufferSz, serverDecodedData,
|
||||||
|
sizeof(serverDecodedData));
|
||||||
#if defined(NO_AES) || defined(NO_AES_256)
|
#if defined(NO_AES) || defined(NO_AES_256)
|
||||||
ExpectIntEQ(ret, ALGO_ID_E);
|
ExpectIntEQ(serverRet, ALGO_ID_E);
|
||||||
#else
|
#else
|
||||||
ExpectIntGT(ret, 0);
|
ExpectIntGT(serverRet, 0);
|
||||||
#endif
|
#endif
|
||||||
wc_PKCS7_Free(pkcs7);
|
wc_PKCS7_Free(pkcs7);
|
||||||
pkcs7 = NULL;
|
pkcs7 = NULL;
|
||||||
@@ -2553,7 +2779,14 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
|
|||||||
pkcs7 = NULL;
|
pkcs7 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* test with ca cert recipient (which should fail) */
|
/* Test with ca cert recipient. The ca cert is not a listed recipient,
|
||||||
|
* so RSA unwrap fails. The Bleichenbacher mitigation substitutes a
|
||||||
|
* pseudo-random fake CEK on unwrap failure, so the call normally
|
||||||
|
* returns a negative error when content decryption rejects the
|
||||||
|
* resulting garbage padding - but around 1/256 of the time the random
|
||||||
|
* CEK yields plaintext with accidentally-valid PKCS#7 padding and the
|
||||||
|
* call returns a non-negative "decrypted" size. That case must not
|
||||||
|
* produce the real plaintext. */
|
||||||
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
|
||||||
if (pkcs7) {
|
if (pkcs7) {
|
||||||
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)ca_cert_der_2048,
|
ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)ca_cert_der_2048,
|
||||||
@@ -2562,9 +2795,15 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
|
|||||||
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)ca_key_der_2048,
|
ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)ca_key_der_2048,
|
||||||
sizeof_ca_key_der_2048), 0);
|
sizeof_ca_key_der_2048), 0);
|
||||||
|
|
||||||
|
XMEMSET(decodedData, 0, sizeof(decodedData));
|
||||||
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
|
ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
|
||||||
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
|
(word32)testDerBufferSz, decodedData, sizeof(decodedData));
|
||||||
ExpectIntLT(ret, 0);
|
#if defined(NO_AES) || defined(NO_AES_256)
|
||||||
|
ExpectIntEQ(ret, ALGO_ID_E);
|
||||||
|
#else
|
||||||
|
ExpectTrue(ret < 0 || ret != serverRet ||
|
||||||
|
XMEMCMP(decodedData, serverDecodedData, (size_t)ret) != 0);
|
||||||
|
#endif
|
||||||
wc_PKCS7_Free(pkcs7);
|
wc_PKCS7_Free(pkcs7);
|
||||||
pkcs7 = NULL;
|
pkcs7 = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,14 @@ int test_wc_PKCS7_EncodeSignedData_RSA_PSS(void);
|
|||||||
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
|
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
|
||||||
int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void);
|
int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
|
||||||
|
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
|
||||||
|
defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
|
||||||
|
!defined(WOLFSSL_NO_MALLOC) && \
|
||||||
|
(defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
|
||||||
|
!defined(NO_FILESYSTEM))
|
||||||
|
int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void);
|
||||||
|
#endif
|
||||||
int test_wc_PKCS7_EncodeSignedData_ex(void);
|
int test_wc_PKCS7_EncodeSignedData_ex(void);
|
||||||
int test_wc_PKCS7_VerifySignedData_RSA(void);
|
int test_wc_PKCS7_VerifySignedData_RSA(void);
|
||||||
int test_wc_PKCS7_VerifySignedData_ECC(void);
|
int test_wc_PKCS7_VerifySignedData_ECC(void);
|
||||||
@@ -82,6 +90,18 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
|
|||||||
#define TEST_PKCS7_RSA_PSS_ED_DECL
|
#define TEST_PKCS7_RSA_PSS_ED_DECL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
|
||||||
|
!defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
|
||||||
|
defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
|
||||||
|
!defined(WOLFSSL_NO_MALLOC) && \
|
||||||
|
(defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
|
||||||
|
!defined(NO_FILESYSTEM))
|
||||||
|
#define TEST_PKCS7_KTRI_BADRSAPAD_DECL \
|
||||||
|
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad),
|
||||||
|
#else
|
||||||
|
#define TEST_PKCS7_KTRI_BADRSAPAD_DECL
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TEST_PKCS7_SIGNED_DATA_DECLS \
|
#define TEST_PKCS7_SIGNED_DATA_DECLS \
|
||||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert), \
|
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert), \
|
||||||
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData), \
|
TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData), \
|
||||||
@@ -100,6 +120,7 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
|
|||||||
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \
|
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream), \
|
||||||
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData), \
|
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData), \
|
||||||
TEST_PKCS7_RSA_PSS_ED_DECL \
|
TEST_PKCS7_RSA_PSS_ED_DECL \
|
||||||
|
TEST_PKCS7_KTRI_BADRSAPAD_DECL \
|
||||||
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \
|
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb), \
|
||||||
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid), \
|
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid), \
|
||||||
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData), \
|
TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData), \
|
||||||
|
|||||||
+243
-7
@@ -44,6 +44,9 @@
|
|||||||
|
|
||||||
#include <wolfssl/wolfcrypt/pkcs7.h>
|
#include <wolfssl/wolfcrypt/pkcs7.h>
|
||||||
#include <wolfssl/wolfcrypt/hash.h>
|
#include <wolfssl/wolfcrypt/hash.h>
|
||||||
|
#ifndef NO_HMAC
|
||||||
|
#include <wolfssl/wolfcrypt/hmac.h>
|
||||||
|
#endif
|
||||||
#ifndef NO_RSA
|
#ifndef NO_RSA
|
||||||
#include <wolfssl/wolfcrypt/rsa.h>
|
#include <wolfssl/wolfcrypt/rsa.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -207,6 +210,8 @@ static void wc_PKCS7_ResetStream(wc_PKCS7* pkcs7)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* free any buffers that may be allocated */
|
/* free any buffers that may be allocated */
|
||||||
|
if (pkcs7->stream->aad != NULL && pkcs7->stream->aadSz > 0)
|
||||||
|
ForceZero(pkcs7->stream->aad, pkcs7->stream->aadSz);
|
||||||
XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
||||||
XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
||||||
XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
||||||
@@ -7741,6 +7746,9 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
|
|||||||
secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7);
|
secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7);
|
||||||
if (secret == NULL)
|
if (secret == NULL)
|
||||||
return MEMORY_E;
|
return MEMORY_E;
|
||||||
|
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||||
|
wc_MemZero_Add("wc_PKCS7_KariGenerateKEK secret", secret, secretSz);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
|
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
|
||||||
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
|
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
|
||||||
@@ -10608,6 +10616,81 @@ int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_RSA
|
#ifndef NO_RSA
|
||||||
|
#if !defined(NO_HMAC) && !defined(NO_SHA256)
|
||||||
|
/* Bleichenbacher padding-oracle mitigation for PKCS#7/CMS KTRI: produce a
|
||||||
|
* WC_SHA256_DIGEST_SIZE-byte pseudo-random CEK derived from a fresh
|
||||||
|
* random seed and the encrypted-key ciphertext. The output is random per
|
||||||
|
* call (driven by the RNG seed); deriving via HMAC of the ciphertext
|
||||||
|
* simply gives the same value within one call regardless of where it is
|
||||||
|
* referenced. Called unconditionally so the work is in the timing path
|
||||||
|
* regardless of RSA padding validity. */
|
||||||
|
static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey,
|
||||||
|
word32 encryptedKeySz, byte* out)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
byte seed[WC_SHA256_DIGEST_SIZE];
|
||||||
|
WC_RNG* rng = NULL;
|
||||||
|
int ownRng = 0;
|
||||||
|
WC_DECLARE_VAR(localRng, WC_RNG, 1, pkcs7->heap);
|
||||||
|
WC_DECLARE_VAR(hmac, Hmac, 1, pkcs7->heap);
|
||||||
|
|
||||||
|
if (pkcs7 == NULL || encryptedKey == NULL || out == NULL) {
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
WC_ALLOC_VAR_EX(hmac, Hmac, 1, pkcs7->heap, DYNAMIC_TYPE_HMAC,
|
||||||
|
return MEMORY_E);
|
||||||
|
|
||||||
|
/* Prefer a caller-provided RNG to avoid paying a DRBG init/reseed cost
|
||||||
|
* on every decrypt (and to keep the timing envelope flatter on FIPS /
|
||||||
|
* HW-RNG builds). Fall back to a one-shot RNG when pkcs7->rng is not
|
||||||
|
* set. */
|
||||||
|
if (pkcs7->rng != NULL) {
|
||||||
|
rng = pkcs7->rng;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WC_ALLOC_VAR_EX(localRng, WC_RNG, 1, pkcs7->heap, DYNAMIC_TYPE_RNG,
|
||||||
|
WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
|
||||||
|
return MEMORY_E);
|
||||||
|
ret = wc_InitRng_ex(localRng, pkcs7->heap, pkcs7->devId);
|
||||||
|
if (ret != 0) {
|
||||||
|
WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG);
|
||||||
|
WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
rng = localRng;
|
||||||
|
ownRng = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wc_RNG_GenerateBlock(rng, seed, (word32)sizeof(seed));
|
||||||
|
|
||||||
|
if (ownRng) {
|
||||||
|
wc_FreeRng(localRng);
|
||||||
|
WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wc_HmacInit(hmac, pkcs7->heap, pkcs7->devId);
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = wc_HmacSetKey(hmac, WC_SHA256, seed, (word32)sizeof(seed));
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = wc_HmacUpdate(hmac, encryptedKey, encryptedKeySz);
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = wc_HmacFinal(hmac, out);
|
||||||
|
}
|
||||||
|
wc_HmacFree(hmac);
|
||||||
|
}
|
||||||
|
ForceZero(seed, sizeof(seed));
|
||||||
|
WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* !NO_HMAC && !NO_SHA256 */
|
||||||
|
|
||||||
/* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */
|
/* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */
|
||||||
static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
|
static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
|
||||||
word32* idx, byte* decryptedKey,
|
word32* idx, byte* decryptedKey,
|
||||||
@@ -10967,25 +11050,146 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
|
|||||||
}
|
}
|
||||||
wc_FreeRsaKey(privKey);
|
wc_FreeRsaKey(privKey);
|
||||||
|
|
||||||
|
#if !defined(NO_HMAC) && !defined(NO_SHA256)
|
||||||
|
{
|
||||||
|
/* Bleichenbacher padding-oracle mitigation: always compute
|
||||||
|
* a pseudo-random fallback CEK so timing and error
|
||||||
|
* behaviour do not depend on RSA padding validity. On
|
||||||
|
* unwrap failure we substitute the fallback and let
|
||||||
|
* content decryption fail indistinguishably from "unwrap
|
||||||
|
* succeeded but CEK is wrong". */
|
||||||
|
byte fakeKey[WC_SHA256_DIGEST_SIZE];
|
||||||
|
int fakeRet = wc_PKCS7_KtriFakeCEK(pkcs7, encryptedKey,
|
||||||
|
(word32)encryptedKeySz,
|
||||||
|
fakeKey);
|
||||||
|
|
||||||
|
if (fakeRet != 0) {
|
||||||
|
/* Fallback generation failed (e.g. RNG/HMAC error).
|
||||||
|
* Return the fallback-generation status, which does
|
||||||
|
* not depend on RSA padding validity, rather than the
|
||||||
|
* RSA status which would re-open the oracle. */
|
||||||
|
ForceZero(fakeKey, sizeof(fakeKey));
|
||||||
|
/* In the non-OAEP path RSA is decrypted in-place via
|
||||||
|
* wc_RsaPrivateDecryptInline, so encryptedKey holds
|
||||||
|
* the (possibly valid) plaintext CEK. Zero it before
|
||||||
|
* free. */
|
||||||
|
ForceZero(encryptedKey, (word32)encryptedKeySz);
|
||||||
|
XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
|
||||||
|
WC_FREE_VAR_EX(privKey, pkcs7->heap,
|
||||||
|
DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
#ifndef WC_NO_RSA_OAEP
|
||||||
|
if (encOID == RSAESOAEPk) {
|
||||||
|
if (outKey != NULL) {
|
||||||
|
ForceZero(outKey, outKeySz);
|
||||||
|
XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return fakeRet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constant-time select between fake and real CEK. On RSA
|
||||||
|
* failure outKey may be NULL or keySz may be <= 0; in
|
||||||
|
* both cases the mask selects fakeKey for every byte.
|
||||||
|
*
|
||||||
|
* To avoid data-dependent branches that leak realLen,
|
||||||
|
* copy the real key into a fixed-size zero-padded buffer
|
||||||
|
* first, then select byte-by-byte in constant time. */
|
||||||
|
{
|
||||||
|
word32 i;
|
||||||
|
byte useFake;
|
||||||
|
int realLen = keySz;
|
||||||
|
byte realPad[WC_SHA256_DIGEST_SIZE];
|
||||||
|
|
||||||
|
XMEMSET(realPad, 0, sizeof(realPad));
|
||||||
|
/* Constant-time copy: avoid data-dependent branches
|
||||||
|
* that could leak whether RSA padding was valid.
|
||||||
|
* When outKey is NULL (inline RSA failure), use
|
||||||
|
* encryptedKey as a safe readable source; the mask
|
||||||
|
* will zero out all bytes anyway. Both encryptedKey
|
||||||
|
* and outKey (when non-NULL) are at least
|
||||||
|
* sizeof(realPad) bytes for any RSA key size.
|
||||||
|
*
|
||||||
|
* Use constant-time pointer selection to avoid
|
||||||
|
* branching on outKey nullity, which would leak
|
||||||
|
* whether RSA PKCS#1 v1.5 padding was valid. */
|
||||||
|
{
|
||||||
|
byte haveSrc = ctMaskGTE(realLen, 1);
|
||||||
|
const byte* srcTbl[2];
|
||||||
|
const byte* src;
|
||||||
|
word32 j = 0;
|
||||||
|
word32 safeJ = 0;
|
||||||
|
|
||||||
|
/* Select source without integer pointer synthesis.
|
||||||
|
* Some safety-oriented compilers (e.g. Fil-C) treat
|
||||||
|
* int-to-pointer reconstruction as a null-object
|
||||||
|
* pointer on dereference. */
|
||||||
|
srcTbl[0] = encryptedKey;
|
||||||
|
srcTbl[1] = outKey;
|
||||||
|
src = srcTbl[haveSrc & 1];
|
||||||
|
|
||||||
|
/* safeJ is clamped to max(0, realLen-1): it
|
||||||
|
* only advances while the next index would
|
||||||
|
* still be inside realLen, so src[safeJ] is
|
||||||
|
* always in bounds. Bytes at j >= realLen are
|
||||||
|
* masked to zero by inBounds anyway. */
|
||||||
|
for (j = 0; j < (word32)sizeof(realPad); j++) {
|
||||||
|
byte inBounds = ctMaskLT((int)j, realLen);
|
||||||
|
byte advance = ctMaskLT((int)(safeJ + 1),
|
||||||
|
realLen);
|
||||||
|
realPad[j] = src[safeJ] & haveSrc & inBounds;
|
||||||
|
safeJ += (word32)(advance & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
useFake = ctMaskLT(realLen, 1); /* 0xFF if realLen<=0 */
|
||||||
|
|
||||||
|
for (i = 0; i < (word32)sizeof(fakeKey); i++) {
|
||||||
|
decryptedKey[i] = ctMaskSel(useFake, fakeKey[i],
|
||||||
|
realPad[i]);
|
||||||
|
}
|
||||||
|
/* Report the real key size on success; on RSA
|
||||||
|
* failure (realLen <= 0) report sizeof(fakeKey).
|
||||||
|
* Constant-time select avoids branching on RSA
|
||||||
|
* padding validity. */
|
||||||
|
*decryptedKeySz = (word32)ctMaskSelInt(useFake,
|
||||||
|
(int)sizeof(fakeKey), realLen);
|
||||||
|
ForceZero(realPad, sizeof(realPad));
|
||||||
|
}
|
||||||
|
ForceZero(fakeKey, sizeof(fakeKey));
|
||||||
|
/* In the non-OAEP path RSA is decrypted in-place via
|
||||||
|
* wc_RsaPrivateDecryptInline, so encryptedKey holds the
|
||||||
|
* plaintext CEK after the unwrap. Zero it before free. */
|
||||||
|
ForceZero(encryptedKey, (word32)encryptedKeySz);
|
||||||
|
}
|
||||||
|
#else /* NO_HMAC || NO_SHA256: mitigation unavailable */
|
||||||
|
#if !defined(WOLFSSL_NO_KTRI_ORACLE_WARNING)
|
||||||
|
#warning "PKCS7 KTRI Bleichenbacher mitigation requires HMAC " \
|
||||||
|
"and SHA256; build without them leaves the RSA unwrap " \
|
||||||
|
"error path observable to callers. " \
|
||||||
|
"Define WOLFSSL_NO_KTRI_ORACLE_WARNING to silence."
|
||||||
|
#endif
|
||||||
|
|
||||||
if (keySz <= 0 || outKey == NULL) {
|
if (keySz <= 0 || outKey == NULL) {
|
||||||
ForceZero(encryptedKey, (word32)encryptedKeySz);
|
ForceZero(encryptedKey, (word32)encryptedKeySz);
|
||||||
XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
|
XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
|
||||||
WC_FREE_VAR_EX(privKey, pkcs7->heap,
|
WC_FREE_VAR_EX(privKey, pkcs7->heap,
|
||||||
DYNAMIC_TYPE_TMP_BUFFER);
|
DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
#ifndef WC_NO_RSA_OAEP
|
#ifndef WC_NO_RSA_OAEP
|
||||||
if (encOID == RSAESOAEPk) {
|
if (encOID == RSAESOAEPk) {
|
||||||
if (outKey) {
|
if (outKey) {
|
||||||
ForceZero(outKey, outKeySz);
|
ForceZero(outKey, outKeySz);
|
||||||
XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return keySz;
|
return keySz;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
*decryptedKeySz = (word32)keySz;
|
*decryptedKeySz = (word32)keySz;
|
||||||
XMEMCPY(decryptedKey, outKey, (word32)keySz);
|
XMEMCPY(decryptedKey, outKey, (word32)keySz);
|
||||||
ForceZero(encryptedKey, (word32)encryptedKeySz);
|
ForceZero(encryptedKey, (word32)encryptedKeySz);
|
||||||
}
|
}
|
||||||
|
#endif /* !NO_HMAC && !NO_SHA256 */
|
||||||
|
|
||||||
XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
|
XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
|
||||||
WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||||
@@ -12888,6 +13092,11 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
|
|||||||
DYNAMIC_TYPE_PKCS7);
|
DYNAMIC_TYPE_PKCS7);
|
||||||
if (decryptedKey == NULL)
|
if (decryptedKey == NULL)
|
||||||
return MEMORY_E;
|
return MEMORY_E;
|
||||||
|
XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
|
||||||
|
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||||
|
wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey,
|
||||||
|
MAX_ENCRYPTED_KEY_SZ);
|
||||||
|
#endif
|
||||||
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2);
|
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2);
|
||||||
tmpIdx = idx;
|
tmpIdx = idx;
|
||||||
recipientSetSz = (word32)ret;
|
recipientSetSz = (word32)ret;
|
||||||
@@ -13130,10 +13339,18 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
|
|||||||
wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet);
|
wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet);
|
||||||
|
|
||||||
if (explicitOctet) {
|
if (explicitOctet) {
|
||||||
/* initialize decryption state in preparation */
|
/* initialize decryption state in preparation. Use
|
||||||
|
* contentSz (blockKeySz from the content algorithm) as
|
||||||
|
* the AES key size rather than aadSz (the unwrapped CEK
|
||||||
|
* length): the two are equal for well-formed messages,
|
||||||
|
* but using blockKeySz avoids BAD_FUNC_ARG on crafted
|
||||||
|
* messages where the CEK length does not match the
|
||||||
|
* content cipher, which would otherwise be a
|
||||||
|
* distinguishable error. */
|
||||||
if (pkcs7->decryptionCb == NULL) {
|
if (pkcs7->decryptionCb == NULL) {
|
||||||
ret = wc_PKCS7_DecryptContentInit(pkcs7, encOID,
|
ret = wc_PKCS7_DecryptContentInit(pkcs7, encOID,
|
||||||
pkcs7->stream->aad, pkcs7->stream->aadSz,
|
pkcs7->stream->aad,
|
||||||
|
(word32)pkcs7->stream->contentSz,
|
||||||
pkcs7->stream->tmpIv, expBlockSz,
|
pkcs7->stream->tmpIv, expBlockSz,
|
||||||
pkcs7->devId, pkcs7->heap);
|
pkcs7->devId, pkcs7->heap);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@@ -13409,8 +13626,13 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
|
|||||||
|
|
||||||
ret = (int)pkcs7->totalEncryptedContentSz - padLen;
|
ret = (int)pkcs7->totalEncryptedContentSz - padLen;
|
||||||
#ifndef NO_PKCS7_STREAM
|
#ifndef NO_PKCS7_STREAM
|
||||||
pkcs7->stream->aad = NULL;
|
/* decryptedKey (just freed) is the same buffer stream->aad
|
||||||
pkcs7->stream->aadSz = 0;
|
* aliases. Null the stream handle so ResetStream doesn't
|
||||||
|
* double-free it. */
|
||||||
|
if (pkcs7->stream != NULL) {
|
||||||
|
pkcs7->stream->aad = NULL;
|
||||||
|
pkcs7->stream->aadSz = 0;
|
||||||
|
}
|
||||||
wc_PKCS7_ResetStream(pkcs7);
|
wc_PKCS7_ResetStream(pkcs7);
|
||||||
#endif
|
#endif
|
||||||
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
|
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
|
||||||
@@ -13423,6 +13645,16 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
|
|||||||
|
|
||||||
#ifndef NO_PKCS7_STREAM
|
#ifndef NO_PKCS7_STREAM
|
||||||
if (ret < 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
|
if (ret < 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
|
||||||
|
/* stream->aad aliases the MAX_ENCRYPTED_KEY_SZ decryptedKey
|
||||||
|
* buffer in this flow. ResetStream only zeros aadSz bytes, so
|
||||||
|
* explicitly zero and release the full buffer here to satisfy
|
||||||
|
* WOLFSSL_CHECK_MEM_ZERO and avoid leaking key material. */
|
||||||
|
if (pkcs7->stream != NULL && pkcs7->stream->aad != NULL) {
|
||||||
|
ForceZero(pkcs7->stream->aad, MAX_ENCRYPTED_KEY_SZ);
|
||||||
|
XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
|
||||||
|
pkcs7->stream->aad = NULL;
|
||||||
|
pkcs7->stream->aadSz = 0;
|
||||||
|
}
|
||||||
wc_PKCS7_ResetStream(pkcs7);
|
wc_PKCS7_ResetStream(pkcs7);
|
||||||
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
|
wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
|
||||||
if (pkcs7->cachedEncryptedContent != NULL) {
|
if (pkcs7->cachedEncryptedContent != NULL) {
|
||||||
@@ -14196,6 +14428,10 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
|
XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
|
||||||
|
#ifdef WOLFSSL_CHECK_MEM_ZERO
|
||||||
|
wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey,
|
||||||
|
MAX_ENCRYPTED_KEY_SZ);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#ifndef NO_PKCS7_STREAM
|
#ifndef NO_PKCS7_STREAM
|
||||||
pkcs7->stream->key = decryptedKey;
|
pkcs7->stream->key = decryptedKey;
|
||||||
|
|||||||
Reference in New Issue
Block a user