Commit 90eb7db527 for openssl.org

commit 90eb7db527023b399aa850fa0a46c73a4ac370e8
Author: Bernd Edlinger <bernd.edlinger@hotmail.de>
Date:   Tue Jun 23 16:35:05 2026 +0200

    Restore the check for missing IV param in evp_cipher_asn1_to_param_ex

    STREAM ciphers (RC4) and WRAP MODE ciphers (CMS3DESwrap) do not have an IV
    parameter value, all other ciphers need an IV value, previously the missing
    IV param value was handled as an error condition.
    The check that an IV value is there was accidentally removed for all ciphers.
    This restores the check for all ciphers except RC4.

    Fixes: 114d99b46bfb ("Fix incomplete checks for EVP_CIPHER_asn1_to_param")

    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    MergeDate: Tue Aug 18 15:37:24 2026
    (Merged from https://github.com/openssl/openssl/pull/31676)

diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 644772bf37..35a44e878c 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -180,7 +180,9 @@ int evp_cipher_asn1_to_param_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
             break;

         default:
-            ret = EVP_CIPHER_get_asn1_iv(c, type) >= 0 ? 1 : -1;
+            ret = EVP_CIPHER_get_asn1_iv(c, type);
+            if (ret == 0 && EVP_CIPHER_CTX_get_iv_length(c) == 0)
+                ret = 1;
         }
     } else if (cipher->prov != NULL) {
         /* We cheat, there's no need for an object ID for this use */
diff --git a/test/cmsapitest.c b/test/cmsapitest.c
index d1851b4121..e791e70098 100644
--- a/test/cmsapitest.c
+++ b/test/cmsapitest.c
@@ -24,6 +24,7 @@ static EVP_PKEY *ed448_privkey = NULL;
 static char *derin = NULL;
 static char *too_long_iv_cms_in = NULL;
 static char *pwri_kek_oob_der_in = NULL;
+static char *pwri_kek_no_iv_in = NULL;

 /*
  * This is our bad cms data, it contains an AuthEnvelopedData field
@@ -820,7 +821,40 @@ end:
     return ret;
 }

-OPT_TEST_DECLARE_USAGE("certfile privkeyfile derfile tooLongIVpem pwriKekOobDer [ed448certfile ed448privkeyfile]\n")
+static int test_pwri_kek_unwrap_no_iv_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_no_iv_in, "rb"))
+        || !TEST_ptr(cms = d2i_CMS_bio(in, NULL)))
+        goto end;
+
+    /*
+     * Due to the missing IV, the unwrap must fail with
+     * CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR.
+     */
+    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_CIPHER_PARAMETER_INITIALISATION_ERROR))
+        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 pwriKekNoIv [ed448certfile ed448privkeyfile]\n")

 int setup_tests(void)
 {
@@ -836,7 +870,8 @@ int setup_tests(void)
         || !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(pwri_kek_oob_der_in = test_get_argument(4)))
+        || !TEST_ptr(pwri_kek_oob_der_in = test_get_argument(4))
+        || !TEST_ptr(pwri_kek_no_iv_in = test_get_argument(5)))
         return 0;

     if (!TEST_ptr(cert = load_cert_pem(certin, NULL))
@@ -848,9 +883,9 @@ int setup_tests(void)
         return 0;
     }

-    if (test_get_argument_count() >= 7) {
-        ed448_certin = test_get_argument(5);
-        ed448_privkeyin = test_get_argument(6);
+    if (test_get_argument_count() >= 8) {
+        ed448_certin = test_get_argument(6);
+        ed448_privkeyin = test_get_argument(7);

         if (!TEST_ptr(ed448_cert = load_cert_pem(ed448_certin, NULL))
             || !TEST_ptr(ed448_privkey = load_pkey_pem(ed448_privkeyin, NULL))) {
@@ -878,6 +913,7 @@ int setup_tests(void)
     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);
+    ADD_TEST(test_pwri_kek_unwrap_no_iv_key);
     if (ed448_cert != NULL && ed448_privkey != NULL) {
         ADD_TEST(test_CMS_add1_signer_ed448_signed_attrs);
         ADD_TEST(test_CMS_add1_signer_ed448_signed_attrs_md);
diff --git a/test/recipes/80-test_cmsapi.t b/test/recipes/80-test_cmsapi.t
index 2813e46b26..03bed6efa8 100644
--- a/test/recipes/80-test_cmsapi.t
+++ b/test/recipes/80-test_cmsapi.t
@@ -25,5 +25,6 @@ ok(run(test(["cmsapitest", srctop_file("test", "certs", "servercert.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", "cms_pwri_kek_oob.der"),
+             srctop_file("test", "recipes", "80-test_cmsapi_data", "cms_pwri_kek_NoIV.der"),
              @ed448_args])),
              "running cmsapitest");
diff --git a/test/recipes/80-test_cmsapi_data/cms_pwri_kek_NoIV.der b/test/recipes/80-test_cmsapi_data/cms_pwri_kek_NoIV.der
new file mode 100644
index 0000000000..c3ef3abd10
Binary files /dev/null and b/test/recipes/80-test_cmsapi_data/cms_pwri_kek_NoIV.der differ