From c30b9a4b6e3f3b6377c02964a936352f9e206a20 Mon Sep 17 00:00:00 2001
From: Neil Horman <nhorman@openssl.org>
Date: Mon, 16 Mar 2026 13:49:07 -0400
Subject: [PATCH] Fix NULL deref in [ec]dh_cms_set_shared_info
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Multiple independent reports indicated a SIGSEGV was possible in CMS
processing when a crafted CMS EnvelopedData message using A Key
Agreement Recipient Info field.  If the
KeyEncryptionAlgorithmIdentifier omits the optional parameter field, the
referenced functions above will attempt to dereference the
alg->parameter data prior to checking if the parameter field is NULL.

Confirmed to resolve the issues using the reproducers provided in the
security reports.

Co-authored-by: Tomas Mraz <tomas@openssl.foundation>

Fixes CVE-2026-28389

Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
MergeDate: Mon Apr  6 19:07:41 2026
---
 crypto/cms/cms_dh.c | 13 +++++++++----
 crypto/cms/cms_ec.c | 14 ++++++++++----
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/crypto/cms/cms_dh.c b/crypto/cms/cms_dh.c
index b49e5f7f53..9b19e675da 100644
--- a/crypto/cms/cms_dh.c
+++ b/crypto/cms/cms_dh.c
@@ -89,16 +89,21 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
     int keylen, plen;
     EVP_CIPHER *kekcipher = NULL;
     EVP_CIPHER_CTX *kekctx;
+    const ASN1_OBJECT *aoid;
+    const void *parameter = NULL;
+    int ptype = 0;
     char name[OSSL_MAX_NAME_SIZE];
 
     if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
         goto err;
 
+    X509_ALGOR_get0(&aoid, &ptype, &parameter, alg);
+
     /*
      * For DH we only have one OID permissible. If ever any more get defined
      * we will need something cleverer.
      */
-    if (OBJ_obj2nid(alg->algorithm) != NID_id_smime_alg_ESDH) {
+    if (OBJ_obj2nid(aoid) != NID_id_smime_alg_ESDH) {
         ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR);
         goto err;
     }
@@ -107,11 +112,11 @@ static int dh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
             || EVP_PKEY_CTX_set_dh_kdf_md(pctx, EVP_sha1()) <= 0)
         goto err;
 
-    if (alg->parameter->type != V_ASN1_SEQUENCE)
+    if (ptype != V_ASN1_SEQUENCE)
         goto err;
 
-    p = alg->parameter->value.sequence->data;
-    plen = alg->parameter->value.sequence->length;
+    p = ASN1_STRING_get0_data(parameter);
+    plen = ASN1_STRING_length(parameter);
     kekalg = d2i_X509_ALGOR(NULL, &p, plen);
     if (kekalg == NULL)
         goto err;
diff --git a/crypto/cms/cms_ec.c b/crypto/cms/cms_ec.c
index 6e9962ed6e..07456dcaa1 100644
--- a/crypto/cms/cms_ec.c
+++ b/crypto/cms/cms_ec.c
@@ -166,21 +166,27 @@ static int ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri)
     int plen, keylen;
     EVP_CIPHER *kekcipher = NULL;
     EVP_CIPHER_CTX *kekctx;
+    const ASN1_OBJECT *aoid = NULL;
+    int ptype = 0;
+    const void *parameter = NULL;
+
     char name[OSSL_MAX_NAME_SIZE];
 
     if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm))
         return 0;
 
-    if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) {
+    X509_ALGOR_get0(&aoid, &ptype, &parameter, alg);
+
+    if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(aoid))) {
         ERR_raise(ERR_LIB_CMS, CMS_R_KDF_PARAMETER_ERROR);
         return 0;
     }
 
-    if (alg->parameter->type != V_ASN1_SEQUENCE)
+    if (ptype != V_ASN1_SEQUENCE)
         return 0;
 
-    p = alg->parameter->value.sequence->data;
-    plen = alg->parameter->value.sequence->length;
+    p = ASN1_STRING_get0_data(parameter);
+    plen = ASN1_STRING_length(parameter);
     kekalg = d2i_X509_ALGOR(NULL, &p, plen);
     if (kekalg == NULL)
         goto err;
-- 
2.53.0

