]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Avoid length truncation in ASN1_STRING_set
authorViktor Dukhovni <openssl-users@dukhovni.org>
Tue, 7 Apr 2026 12:40:55 +0000 (22:40 +1000)
committerTomas Mraz <tomas@openssl.foundation>
Thu, 11 Jun 2026 15:08:41 +0000 (17:08 +0200)
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: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Mon Jun  8 14:13:56 2026

crypto/asn1/tasn_dec.c

index 70ea5f08798bf1b3e9d07bc1086ae97cf885cd3d..197fd241054657fe4fc7edfd4167d7928f64e855 100644 (file)
@@ -54,7 +54,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 */
@@ -855,19 +855,24 @@ err:
 
 /* 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) {
@@ -885,7 +890,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;
 
@@ -940,6 +946,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;
@@ -970,10 +980,10 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
         }
         /* If we've already allocated a buffer use it */
         if (*free_cont) {
-            ASN1_STRING_set0(stmp, (unsigned char *)cont /* UGLY CAST! */, len);
+            ASN1_STRING_set0(stmp, (unsigned char *)cont /* UGLY CAST! */, 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_ASN1_LIB);
                 ASN1_STRING_free(stmp);
                 *pval = NULL;