openssl/0061-CVE-2026-9076.patch
2026-06-11 13:21:23 -04:00

182 lines
6.8 KiB
Diff

From ae233967cf40b15fe80c70c17438d391158171b3 Mon Sep 17 00:00:00 2001
From: Nikola Pajkovsky <nikolap@openssl.org>
Date: Thu, 21 May 2026 11:53:09 +0200
Subject: [PATCH 1/2] cms: kek_unwrap_key: Fix out-of-bounds read in check-byte
validation
the check-byte test in kek_unwrap_key() reads tmp[1] through tmp[6]
unconditionally, so the decrypted buffer must hold at least seven
octets. The pre-decryption size check enforces inlen >= 2 * blocklen,
which yields the required seven octets only when blocklen >= 4. For
a KEK cipher with a smaller block size, inlen can be as small as
2 * blocklen and the check-byte read overruns the inlen-sized tmp
allocation.
Reject blocklen < 4 in the early sanity check. All block ciphers
appropriate for CMS PasswordRecipientInfo key wrapping have a block
size of at least 8 octets (DES/3DES = 8, AES = 16), so this only
forbids ciphers that would not be valid KEK choices anyway, and the
existing inlen >= 2 * blocklen check then guarantees the seven-octet
lower bound the check-byte test relies on.
Fixes CVE-2026-9076
Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>
---
crypto/cms/cms_pwri.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/crypto/cms/cms_pwri.c b/crypto/cms/cms_pwri.c
index d62dbbde881..4bb06b406eb 100644
--- a/crypto/cms/cms_pwri.c
+++ b/crypto/cms/cms_pwri.c
@@ -200,18 +200,18 @@ static int kek_unwrap_key(unsigned char *out, size_t *outlen,
const unsigned char *in, size_t inlen,
EVP_CIPHER_CTX *ctx)
{
- size_t blocklen = EVP_CIPHER_CTX_get_block_size(ctx);
+ int blocklen = EVP_CIPHER_CTX_get_block_size(ctx);
unsigned char *tmp;
int outl, rv = 0;
- if (blocklen == 0)
+ if (blocklen < 4)
return 0;
- if (inlen < 2 * blocklen) {
+ if (inlen < 2 * (size_t)blocklen) {
/* too small */
return 0;
}
- if (inlen % blocklen) {
+ if (inlen > INT_MAX || inlen % blocklen) {
/* Invalid size */
return 0;
}
From 4a35e3c194ceb0af30fcbe42d65c95e08d5758a5 Mon Sep 17 00:00:00 2001
From: Nikola Pajkovsky <nikolap@openssl.org>
Date: Thu, 21 May 2026 14:18:11 +0200
Subject: [PATCH 2/2] cms: kek_unwrap_key: test for fix out-of-bounds read in
check-byte validation
added EnvelopedData blob with a PasswordRecipientInfo using
id-alg-PWRI-KEK and an AES-128-CFB key encryption cipher. CFB's 1-byte
effective block size let the inlen >= 2 * blocklen guard in
kek_unwrap_key() accept a wrapped key shorter than the seven octets
the check-byte test reads from tmp[1..6]; the encryptedKey OCTET
STRING here is only two bytes.
Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>
---
test/cmsapitest.c | 48 +++++++++++++++++-
test/recipes/80-test_cmsapi.t | 3 +-
.../80-test_cmsapi_data/cms_pwri_kek_oob.der | Bin 0 -> 193 bytes
3 files changed, 48 insertions(+), 3 deletions(-)
create mode 100644 test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.der
diff --git a/test/cmsapitest.c b/test/cmsapitest.c
index 0752d14df09..d908bc6fc4c 100644
--- a/test/cmsapitest.c
+++ b/test/cmsapitest.c
@@ -21,6 +21,7 @@ static X509 *cert = NULL;
static EVP_PKEY *privkey = NULL;
static char *derin = NULL;
static char *too_long_iv_cms_in = NULL;
+static char *pwri_kek_oob_der_in = NULL;
static int test_encrypt_decrypt(const EVP_CIPHER *cipher)
{
@@ -512,7 +513,48 @@ static int test_cms_aesgcm_iv_too_long(void)
return ret;
}
-OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile\n")
+/*
+ * CMS EnvelopedData with a single PasswordRecipientInfo using
+ * id-alg-PWRI-KEK and an AES-128-CFB key encryption cipher
+ * (1-byte effective block size). The encryptedKey OCTET STRING is
+ * only two bytes long, so the wrapped key buffer is shorter than
+ * the seven octets read by the check-byte test in kek_unwrap_key().
+ * Prior to CVE-2026-9076 this triggered an out-of-bounds heap read;
+ * CMS_decrypt() must now fail cleanly.
+ */
+static int test_pwri_kek_unwrap_short_encrypted_key(void)
+{
+ BIO *in = NULL;
+ CMS_ContentInfo *cms = NULL;
+ unsigned long err = 0;
+ int ret = 0;
+
+ if (!TEST_ptr(in = BIO_new_file(pwri_kek_oob_der_in, "rb"))
+ || !TEST_ptr(cms = d2i_CMS_bio(in, NULL)))
+ goto end;
+
+ /*
+ * The unwrap is attempted eagerly inside CMS_decrypt_set1_password().
+ * It must fail cleanly (no OOB read) and report CMS_R_UNWRAP_FAILURE.
+ */
+ if (!TEST_false(CMS_decrypt_set1_password(cms,
+ (unsigned char *)"password", -1)))
+ goto end;
+
+ err = ERR_peek_last_error();
+ if (!TEST_int_eq(ERR_GET_LIB(err), ERR_LIB_CMS)
+ || !TEST_int_eq(ERR_GET_REASON(err), CMS_R_UNWRAP_FAILURE))
+ goto end;
+
+ ERR_clear_error();
+ ret = 1;
+end:
+ CMS_ContentInfo_free(cms);
+ BIO_free(in);
+ return ret;
+}
+
+OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile tooLongIVpem pwriKekOobDer\n")
int setup_tests(void)
{
@@ -527,7 +569,8 @@ int setup_tests(void)
if (!TEST_ptr(certin = test_get_argument(0))
|| !TEST_ptr(privkeyin = test_get_argument(1))
|| !TEST_ptr(derin = test_get_argument(2))
- || !TEST_ptr(too_long_iv_cms_in = test_get_argument(3)))
+ || !TEST_ptr(too_long_iv_cms_in = test_get_argument(3))
+ || !TEST_ptr(pwri_kek_oob_der_in = test_get_argument(4)))
return 0;
certbio = BIO_new_file(certin, "r");
@@ -564,6 +607,7 @@ int setup_tests(void)
ADD_TEST(test_encrypted_data_aead);
ADD_ALL_TESTS(test_d2i_CMS_decode, 2);
ADD_TEST(test_cms_aesgcm_iv_too_long);
+ ADD_TEST(test_pwri_kek_unwrap_short_encrypted_key);
return 1;
}
diff --git a/test/recipes/80-test_cmsapi.t b/test/recipes/80-test_cmsapi.t
index 8d9371e005c..3d1dae84646 100644
--- a/test/recipes/80-test_cmsapi.t
+++ b/test/recipes/80-test_cmsapi.t
@@ -19,5 +19,6 @@ plan tests => 1;
ok(run(test(["cmsapitest", srctop_file("test", "certs", "servercert.pem"),
srctop_file("test", "certs", "serverkey.pem"),
srctop_file("test", "recipes", "80-test_cmsapi_data", "encryptedData.der"),
- srctop_file("test", "recipes", "80-test_cmsapi_data", "encDataWithTooLongIV.pem")])),
+ srctop_file("test", "recipes", "80-test_cmsapi_data", "encDataWithTooLongIV.pem"),
+ srctop_file("test", "recipes", "80-test_cmsapi_data", "cms_pwri_kek_oob.der")])),
"running cmsapitest");
diff --git a/test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.der b/test/recipes/80-test_cmsapi_data/cms_pwri_kek_oob.der
new file mode 100644
index 0000000000000000000000000000000000000000..c3ef3abd10e6b0a57b1eef985b0c8c43cb057371
GIT binary patch
literal 193
zcmXqL+{ebL)#lOmotKfFc|qd_gT}Q?jLe2!i#?ba85StRC0Th4#8?FEa~A$hV(x0n
zFrRcQQS~(+6B7r6ffO4z)C5ieW=;ccHqL}L55`nx7Dg5pCI$wB7`P$qj0Um@Stb?%
z*}W&;-kY#&W8?d>8TmW9IT{Q$uJ-6FX$+dodfRzpO2J!$Gg}?F()_mBI35*0&tMe5
VHoNtcLX?S)y&B`}phcqR3jwDUJP7~*
literal 0
HcmV?d00001