From 1ee9b453533aa733b1f1ec3c8a0cfc5dadf5edd2 Mon Sep 17 00:00:00 2001
From: yangwu <yangwu29@h-partners.com>
Date: Sat, 20 Jun 2026 12:34:44 +0800
Subject: [PATCH 3/4] Reject oversized inputs in ASN1_mbstring_ncopy() In
 ASN1_mbstring_ncopy() the destination size for BMPSTRING and UNIVERSALSTRING
 output was computed by a signed left shift on an int:

    outlen = nchar << 1;        /* MBSTRING_BMP  */
    outlen = nchar << 2;        /* MBSTRING_UNIV */

For nchar large enough the result is not representable in int.  In
the worst case (nchar == 0x40000000) nchar << 2 wraps to zero,
OPENSSL_malloc(1) is called, and traverse_string() then writes
4*nchar bytes into the one-byte allocation: a heap buffer
overflow.  The MBSTRING_UTF8 path computes outlen by summing
per-character byte counts in out_utf8(), and that sum can overflow
the same int under similarly large inputs.

Neither path is reachable from code that processes X.509
certificates through the DIRSTRING_TYPE mask used by
ASN1_STRING_set_by_NID(): UNIVERSALSTRING is absent from that
mask, and the UTF-8 sum requires inputs on the order of half a
gigabyte.  Reaching them needs an application that calls
ASN1_mbstring_copy()/ASN1_mbstring_ncopy() directly, or registers
a custom NID via ASN1_STRING_TABLE_add(), with an oversized
attacker-controlled input.

Add range checks before each shift and in out_utf8(), raising
ASN1_R_STRING_TOO_LONG at the point of detection.  Move the
existing ASN1_R_INVALID_UTF8STRING raise into out_utf8() too so
the two failure modes report distinct codes; the MBSTRING_UTF8
caller is left with cleanup only and now frees dest on error,
matching the BMP/UNIV branches.

Fixes CVE-2026-7383

Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Daniel Kubec <kubec@openssl.foundation>
MergeDate: Mon Jun  8 13:59:47 2026
(cherry picked from commit d32350a)

origin:https://github.com/openssl/openssl/commit/4f8d2bddaa2c8e06f9c33390ee1717059a6e4be6
---
 .../OpensslLib/openssl/crypto/asn1/a_mbstr.c  | 33 +++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c
index 22dea873..5701c8e4 100644
--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c
+++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/asn1/a_mbstr.c
@@ -169,18 +169,41 @@ int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
         break;
 
     case MBSTRING_BMP:
+        if (nchar > INT_MAX / 2) {
+            ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG);
+            if (free_out) {
+                ASN1_STRING_free(dest);
+                *out = NULL;
+            }
+            return -1;
+        }
         outlen = nchar << 1;
         cpyfunc = cpy_bmp;
         break;
 
     case MBSTRING_UNIV:
+        if (nchar > INT_MAX / 4) {
+            ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG);
+            if (free_out) {
+                ASN1_STRING_free(dest);
+                *out = NULL;
+            }
+            return -1;
+        }
         outlen = nchar << 2;
         cpyfunc = cpy_univ;
         break;
 
     case MBSTRING_UTF8:
         outlen = 0;
-        traverse_string(in, len, inform, out_utf8, &outlen);
+        ret = traverse_string(in, len, inform, out_utf8, &outlen);
+        if (ret < 0) { /* error already raised in out_utf8() */
+            if (free_out) {
+                ASN1_STRING_free(dest);
+                *out = NULL;
+            }
+            return -1;
+        }
         cpyfunc = cpy_utf8;
         break;
     }
@@ -260,9 +283,15 @@ static int out_utf8(unsigned long value, void *arg)
     int *outlen, len;
 
     len = UTF8_putc(NULL, -1, value);
-    if (len <= 0)
+    if (len <= 0) {
+        ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING);
         return len;
+    }
     outlen = arg;
+    if (*outlen > INT_MAX - len) {
+        ERR_raise(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG);
+        return -1;
+    }
     *outlen += len;
     return 1;
 }
-- 
2.43.0