From cbe418ae978539cf14a398a207dba834c0e93e83 Mon Sep 17 00:00:00 2001
From: Viktor Dukhovni <viktor@openssl.org>
Date: Fri, 15 May 2026 04:19:32 +1000
Subject: [PATCH] Avoid length truncation in ASN1_STRING_set

The ASN1_STRING_set() function takes an `int` length, make sure the
argument is not inadvertently truncated when it is called from
asn1_ex_c2i().

Fixes CVE-2026-34180

Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Mon Jun  8 14:16:40 2026
---
 crypto/asn1/tasn_dec.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index 1119808..50a1582 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -59,7 +59,7 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
                                  const ASN1_ITEM *it,
                                  int tag, int aclass, char opt,
                                  ASN1_TLC *ctx);
-static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len,
                        int utype, char *free_cont, const ASN1_ITEM *it);
 
 /* Table to convert tags to bit values, used for MSTRING type */
@@ -828,19 +828,24 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval,
 
 /* Translate ASN1 content octets into a structure */
 
-static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
+static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len,
                        int utype, char *free_cont, const ASN1_ITEM *it)
 {
     ASN1_VALUE **opval = NULL;
     ASN1_STRING *stmp;
     ASN1_TYPE *typ = NULL;
     int ret = 0;
+    int ilen = (int)len;
     const ASN1_PRIMITIVE_FUNCS *pf;
     ASN1_INTEGER **tint;
     pf = it->funcs;
 
-    if (pf && pf->prim_c2i)
-        return pf->prim_c2i(pval, cont, len, utype, free_cont, it);
+    if (pf && pf->prim_c2i) {
+        if (len == (long)ilen)
+            return pf->prim_c2i(pval, cont, ilen, utype, free_cont, it);
+        ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
+        return 0;
+    }
     /* If ANY type clear type and set pointer to internal value */
     if (it->utype == V_ASN1_ANY) {
         if (*pval == NULL) {
@@ -858,7 +863,8 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
     }
     switch (utype) {
     case V_ASN1_OBJECT:
-        if (!ossl_c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len))
+        if (len != (long)ilen
+            || !ossl_c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, ilen))
             goto err;
         break;
 
@@ -913,6 +919,10 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
     case V_ASN1_SET:
     case V_ASN1_SEQUENCE:
     default:
+        if (len != (long)ilen) {
+            ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
+            goto err;
+        }
         if (utype == V_ASN1_BMPSTRING && (len & 1)) {
             ERR_raise(ERR_LIB_ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH);
             goto err;
@@ -937,10 +947,10 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
         if (*free_cont) {
             OPENSSL_free(stmp->data);
             stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */
-            stmp->length = len;
+            stmp->length = ilen;
             *free_cont = 0;
         } else {
-            if (!ASN1_STRING_set(stmp, cont, len)) {
+            if (!ASN1_STRING_set(stmp, cont, ilen)) {
                 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
                 ASN1_STRING_free(stmp);
                 *pval = NULL;