186 lines
5.7 KiB
Diff
186 lines
5.7 KiB
Diff
From 001e01db3e996e13ffc72386fe79d03a6683b5ac Mon Sep 17 00:00:00 2001
|
|
From: Nikola Pajkovsky <nikolap@openssl.org>
|
|
Date: Thu, 19 Mar 2026 12:16:08 +0100
|
|
Subject: [PATCH 1/2] rsa_kem: validate RSA_public_encrypt() result in RSASVE
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
RSA_public_encrypt() returns the number of bytes written on success and
|
|
-1 on failure. With the existing `if (ret)` check, a provider-side RSA KEM
|
|
encapsulation can incorrectly succeed when the underlying RSA public
|
|
encrypt operation fails. In that case the code reports success, returns
|
|
lengths as if encapsulation completed normally, and leaves the freshly
|
|
generated secret available instead of discarding it.
|
|
|
|
Tighten the success condition so RSASVE only succeeds when
|
|
RSA_public_encrypt() returns a positive value equal to the modulus-sized
|
|
output expected for RSA_NO_PADDING. Any other return value is treated as
|
|
failure, and the generated secret is cleansed before returning.
|
|
|
|
Fixes CVE-2026-31790
|
|
Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>
|
|
|
|
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
|
|
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
|
|
MergeDate: Mon Apr 6 19:51:30 2026
|
|
---
|
|
providers/implementations/kem/rsa_kem.c | 20 +++++++++++---------
|
|
1 file changed, 11 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/providers/implementations/kem/rsa_kem.c b/providers/implementations/kem/rsa_kem.c
|
|
index f7bf368a0d..74dfafddd9 100644
|
|
--- a/providers/implementations/kem/rsa_kem.c
|
|
+++ b/providers/implementations/kem/rsa_kem.c
|
|
@@ -316,17 +316,19 @@ static int rsasve_generate(PROV_RSA_CTX *prsactx,
|
|
return 0;
|
|
|
|
/* Step(3): out = RSAEP((n,e), z) */
|
|
- ret = RSA_public_encrypt(nlen, secret, out, prsactx->rsa, RSA_NO_PADDING);
|
|
- if (ret) {
|
|
- ret = 1;
|
|
- if (outlen != NULL)
|
|
- *outlen = nlen;
|
|
- if (secretlen != NULL)
|
|
- *secretlen = nlen;
|
|
- } else {
|
|
+ ret = RSA_public_encrypt((int)nlen, secret, out, prsactx->rsa,
|
|
+ RSA_NO_PADDING);
|
|
+ if (ret <= 0 || ret != (int)nlen) {
|
|
OPENSSL_cleanse(secret, nlen);
|
|
+ return 0;
|
|
}
|
|
- return ret;
|
|
+
|
|
+ if (outlen != NULL)
|
|
+ *outlen = nlen;
|
|
+ if (secretlen != NULL)
|
|
+ *secretlen = nlen;
|
|
+
|
|
+ return 1;
|
|
}
|
|
|
|
/**
|
|
--
|
|
2.53.0
|
|
|
|
|
|
From c61bbd3f873d28e098f503f0187459ed488977c9 Mon Sep 17 00:00:00 2001
|
|
From: Nikola Pajkovsky <nikolap@openssl.org>
|
|
Date: Mon, 23 Mar 2026 08:41:20 +0100
|
|
Subject: [PATCH 2/2] rsa_kem: test RSA_public_encrypt() result in RSASVE
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
RSA_public_encrypt() returns the number of bytes written on success and
|
|
-1 on failure.
|
|
|
|
Add regression coverage in evp_extra_test using invalid RSA pubkey
|
|
which triggers -1 in RSA_public_encrypt() using encapsulation.
|
|
|
|
Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>
|
|
|
|
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
|
|
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
|
|
MergeDate: Mon Apr 6 19:51:31 2026
|
|
---
|
|
test/evp_extra_test.c | 67 +++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 67 insertions(+)
|
|
|
|
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
|
|
index 5ea95c0dfa..573732bfec 100644
|
|
--- a/test/evp_extra_test.c
|
|
+++ b/test/evp_extra_test.c
|
|
@@ -929,6 +929,32 @@ static EVP_PKEY *load_example_ec_key(void)
|
|
#endif
|
|
|
|
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
|
+
|
|
+static EVP_PKEY *make_bad_rsa_pubkey(void)
|
|
+{
|
|
+ RSA *rsa = NULL;
|
|
+ BIGNUM *n = NULL, *e = NULL;
|
|
+ EVP_PKEY *pkey = NULL;
|
|
+
|
|
+ /* Deliberately invalid public key: n = 17, e = 17 */
|
|
+ if (!TEST_ptr(pkey = EVP_PKEY_new())
|
|
+ || !TEST_ptr(rsa = RSA_new())
|
|
+ || !TEST_ptr(n = BN_new())
|
|
+ || !TEST_ptr(e = BN_new())
|
|
+ || !TEST_true(BN_set_word(n, 17))
|
|
+ || !TEST_true(BN_set_word(e, 17))
|
|
+ || !TEST_true(RSA_set0_key(rsa, n, e, NULL))
|
|
+ || !EVP_PKEY_assign_RSA(pkey, rsa))
|
|
+ goto err;
|
|
+
|
|
+ return pkey;
|
|
+err:
|
|
+ BN_free(n);
|
|
+ BN_free(e);
|
|
+ RSA_free(rsa);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
#ifndef OPENSSL_NO_DH
|
|
static EVP_PKEY *load_example_dh_key(void)
|
|
{
|
|
@@ -5898,6 +5924,46 @@ err:
|
|
return testresult;
|
|
}
|
|
|
|
+static int test_rsasve_kem_with_invalid_pub_key(void)
|
|
+{
|
|
+ RSA *rsa = NULL;
|
|
+ EVP_PKEY *pkey = NULL;
|
|
+ EVP_PKEY_CTX *ctx = NULL;
|
|
+ unsigned char *ct = NULL;
|
|
+ unsigned char *secret = NULL;
|
|
+ size_t ctlen = 0, secretlen = 0;
|
|
+ int testresult = 0;
|
|
+
|
|
+ if (nullprov != NULL) {
|
|
+ testresult = TEST_skip("Test does not support a non-default library context");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ if (!TEST_ptr(pkey = make_bad_rsa_pubkey()))
|
|
+ goto err;
|
|
+
|
|
+ if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(testctx, pkey, NULL))
|
|
+ || !TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, NULL), 1)
|
|
+ || !TEST_int_eq(EVP_PKEY_CTX_set_kem_op(ctx, "RSASVE"), 1)
|
|
+ || !TEST_int_eq(EVP_PKEY_encapsulate(ctx, NULL, &ctlen, NULL, &secretlen), 1)
|
|
+ || !TEST_ptr(ct = OPENSSL_malloc(ctlen))
|
|
+ || !TEST_ptr(secret = OPENSSL_malloc(secretlen)))
|
|
+ goto err;
|
|
+
|
|
+ if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, ct, &ctlen, secret, &secretlen), 0))
|
|
+ goto err;
|
|
+
|
|
+ testresult = 1;
|
|
+
|
|
+err:
|
|
+ OPENSSL_free(secret);
|
|
+ OPENSSL_free(ct);
|
|
+ EVP_PKEY_CTX_free(ctx);
|
|
+ RSA_free(rsa);
|
|
+ EVP_PKEY_free(pkey);
|
|
+ return testresult;
|
|
+}
|
|
+
|
|
#ifndef OPENSSL_NO_DYNAMIC_ENGINE
|
|
/* Test we can create a signature keys with an associated ENGINE */
|
|
static int test_signatures_with_engine(int tst)
|
|
@@ -6893,6 +6959,7 @@ int setup_tests(void)
|
|
ADD_TEST(test_evp_md_cipher_meth);
|
|
ADD_TEST(test_custom_md_meth);
|
|
ADD_TEST(test_custom_ciph_meth);
|
|
+ ADD_TEST(test_rsasve_kem_with_invalid_pub_key);
|
|
|
|
#ifndef OPENSSL_NO_DYNAMIC_ENGINE
|
|
/* Tests only support the default libctx */
|
|
--
|
|
2.53.0
|
|
|