Commit 3a19032449 for openssl.org

commit 3a19032449a22ed115651cdd0212ccab19ac9a83
Author: Eugene Syromiatnikov <esyr@openssl.org>
Date:   Mon Sep 14 15:38:16 2026 +0200

    crypto/asn1: add checks for possibly negative ASN1_STRING length

    ASN1_STRING_length_set() allows setting ASN1_STRING's length
    to an arbitrary int value, including negative ones.  While some places
    do perform sanity checks of the length value, others do not;  add some
    missing checks.

    Signed-off-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Bob Beck <beck@openssl.org>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Merge-date: Thu Sep 17 14:00:09 2026
    Merged-from: https://github.com/openssl/openssl/pull/32825

diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c
index fdefb80e26..02180541ea 100644
--- a/crypto/asn1/a_bitstr.c
+++ b/crypto/asn1/a_bitstr.c
@@ -32,7 +32,7 @@ int ossl_i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a, unsigned char **pp)

     len = a->length;

-    if (len > INT_MAX - 1)
+    if (len > INT_MAX - 1 || len < 0)
         goto err;

     if ((len > 0) && (a->flags & ASN1_STRING_FLAG_BITS_LEFT))
@@ -224,7 +224,7 @@ int ASN1_BIT_STRING_get_length(const ASN1_BIT_STRING *abs, size_t *out_length,
     if (abs == NULL || abs->type != V_ASN1_BIT_STRING)
         return 0;

-    if (out_length == NULL || out_unused_bits == NULL)
+    if (out_length == NULL || out_unused_bits == NULL || abs->length < 0)
         return 0;

     length = abs->length;
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index 5f1b14bf3e..4bf03be0b4 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -374,7 +374,10 @@ int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in)
 void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
 {
     if (!(str->flags & ASN1_STRING_FLAG_DATA_NOT_OWNED)) {
-        OPENSSL_clear_free(str->data, str->length);
+        if (str->length > 0)
+            OPENSSL_clear_free(str->data, str->length);
+        else
+            OPENSSL_free(str->data);
     }
     str->flags &= ~ASN1_STRING_FLAG_DATA_NOT_OWNED;
     str->data = data;
@@ -455,7 +458,7 @@ void ossl_asn1_string_free_internal(ASN1_STRING *a, int clear, int embed)
     }

     if (!(a->flags & ASN1_STRING_FLAG_NDEF)) {
-        if (clear)
+        if (clear && a->length > 0)
             OPENSSL_clear_free(a->data, a->length);
         else
             OPENSSL_free(a->data);
@@ -514,7 +517,7 @@ int ASN1_STRING_length(const ASN1_STRING *x)

 size_t ASN1_STRING_get_length(const ASN1_STRING *x)
 {
-    return (size_t)x->length;
+    return x->length >= 0 ? (size_t)x->length : 0U;
 }

 #ifndef OPENSSL_NO_DEPRECATED_3_0