Commit 4c92661c45 for openssl.org
commit 4c92661c45b6af78a901ee97db6f29a2ce90ae29
Author: Nikola Pajkovsky <nikolap@openssl.org>
Date: Thu Mar 19 12:17:45 2026 +0100
rsa_kem: test RSA_public_encrypt() result in RSASVE
RSA_public_encrypt() returns the number of bytes written on success and
-1 on failure.
Add regression coverage in evp_extra_test using custom low-level RSA
methods to exercise the provider/legacy boundary. The new tests verify
that encapsulation fails when RSA_public_encrypt() returns:
* -1, which is the documented failure result, and
* a short positive length, which is also invalid for RSASVE with
RSA_NO_PADDING because the ciphertext must be exactly nlen bytes.
Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Mon Apr 6 19:45:39 2026
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 3dba83c273..51843a9f81 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -6385,6 +6385,8 @@ end:
#ifndef OPENSSL_NO_DEPRECATED_3_0
static int sign_hits = 0;
+static int encap_hits = 0;
+static int flen_ne_ret_hits = 0;
static int do_sign_with_method(EVP_PKEY *pkey)
{
@@ -6427,6 +6429,28 @@ static int tst_rsa_priv_enc(int flen, const unsigned char *from, unsigned char *
return orig_rsa_priv_enc(flen, from, to, rsa, padding);
}
+static int tst_rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to,
+ RSA *rsa, int padding)
+{
+ const char *marker = RSA_get_ex_data(rsa, rsa_ex_idx);
+
+ if (marker == NULL || strcmp(marker, "kem-test") != 0)
+ return 0;
+ encap_hits++;
+ return -1;
+}
+
+static int tst_rsa_pub_enc_flen_ne_ret(int flen, const unsigned char *from, unsigned char *to,
+ RSA *rsa, int padding)
+{
+ const char *marker = RSA_get_ex_data(rsa, rsa_ex_idx);
+
+ if (marker == NULL || strcmp(marker, "kem-test-flen-ne-ret") != 0)
+ return 0;
+ flen_ne_ret_hits++;
+ return flen - 1;
+}
+
/* Test that a low level RSA method still gets used even with a provider */
static int test_low_level_rsa_method(void)
{
@@ -6483,6 +6507,86 @@ err:
return testresult;
}
+static int test_low_level_rsa_kem_public_encrypt_failure(int idx)
+{
+ RSA *rsa = NULL;
+ const RSA_METHOD *def = RSA_get_default_method();
+ RSA_METHOD *method = RSA_meth_dup(def);
+ 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(method)
+ || !TEST_ptr(pkey = load_example_rsa_key()))
+ goto err;
+
+ rsa_ex_idx = RSA_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ if (!TEST_int_ne(rsa_ex_idx, -1) || !TEST_ptr(rsa = EVP_PKEY_get1_RSA(pkey)))
+ goto err;
+
+ switch (idx) {
+ case 0:
+ if (!TEST_true(RSA_set_ex_data(rsa, rsa_ex_idx, (void *)"kem-test"))
+ || !TEST_true(RSA_meth_set_pub_enc(method, tst_rsa_pub_enc)))
+ goto err;
+ break;
+ case 1:
+ if (!TEST_true(RSA_set_ex_data(rsa, rsa_ex_idx, (void *)"kem-test-flen-ne-ret"))
+ || !TEST_true(RSA_meth_set_pub_enc(method, tst_rsa_pub_enc_flen_ne_ret)))
+ goto err;
+ break;
+ default:
+ goto err;
+ };
+ if (!TEST_true(RSA_set_method(rsa, method))
+ || !TEST_int_gt(EVP_PKEY_assign_RSA(pkey, rsa), 0))
+ goto err;
+ rsa = NULL;
+
+ 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;
+
+ encap_hits = flen_ne_ret_hits = 0;
+ if (!TEST_int_eq(EVP_PKEY_encapsulate(ctx, ct, &ctlen, secret, &secretlen), 0))
+ goto err;
+
+ switch (idx) {
+ case 0:
+ if (!TEST_int_eq(encap_hits, 1))
+ goto err;
+ break;
+ case 1:
+ if (!TEST_int_eq(flen_ne_ret_hits, 1))
+ goto err;
+ break;
+ default:
+ goto err;
+ }
+ testresult = 1;
+
+err:
+ OPENSSL_free(secret);
+ OPENSSL_free(ct);
+ EVP_PKEY_CTX_free(ctx);
+ RSA_free(rsa);
+ EVP_PKEY_free(pkey);
+ RSA_meth_free(method);
+ return testresult;
+}
+
#ifndef OPENSSL_NO_DSA
static int dsa_ex_idx = -1;
@@ -6921,6 +7025,7 @@ int setup_tests(void)
#ifndef OPENSSL_NO_DEPRECATED_3_0
ADD_TEST(test_low_level_rsa_method);
+ ADD_ALL_TESTS(test_low_level_rsa_kem_public_encrypt_failure, 2);
#ifndef OPENSSL_NO_DSA
ADD_TEST(test_low_level_dsa_method);
#endif