Commit 4f183765aa for openssl.org

commit 4f183765aab81df08aa53baf483b26d02ad677bb
Author: Bob Beck <beck@openssl.org>
Date:   Wed Aug 5 15:54:01 2026 -0600

    Sweep for printf UB - don't printf %s NULL

    As an asn1_string of length 0 will have NULL data, don't
    printf %s NULL.

    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Merge-date: Thu Aug 27 13:52:48 2026
    Merged-from: https://github.com/openssl/openssl/pull/32178

diff --git a/apps/pkcs12.c b/apps/pkcs12.c
index 7c2c77d4ff..2deb87a1f8 100644
--- a/apps/pkcs12.c
+++ b/apps/pkcs12.c
@@ -1289,7 +1289,9 @@ void print_attribute(BIO *out, const ASN1_TYPE *av)

     case V_ASN1_UTF8STRING:
         BIO_printf(out, "%.*s\n", (int)ASN1_STRING_get_length(av->value.utf8string),
-            ASN1_STRING_get0_data(av->value.utf8string));
+            ASN1_STRING_get_length(av->value.utf8string)
+                ? ASN1_STRING_get0_data(av->value.utf8string)
+                : (const unsigned char *)"");
         break;

     case V_ASN1_OCTET_STRING:
diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c
index 8483dd290e..6ea36528c9 100644
--- a/crypto/cmp/cmp_status.c
+++ b/crypto/cmp/cmp_status.c
@@ -217,7 +217,8 @@ static char *snprint_PKIStatusInfo_parts(int status, int fail_info,
             text = sk_ASN1_UTF8STRING_value(status_strings, i);
             printed_chars = snprintf(write_ptr, bufsize, "\"%.*s\"%s",
                 (int)ASN1_STRING_get_length(text),
-                ASN1_STRING_get0_data(text),
+                ASN1_STRING_get_length(text) ? ASN1_STRING_get0_data(text)
+                                             : (const unsigned char *)"",
                 i < n_status_strings - 1 ? ", " : "");
             ADVANCE_BUFFER;
         }
diff --git a/crypto/x509/v3_attrdesc.c b/crypto/x509/v3_attrdesc.c
index 997241fac0..142343bab2 100644
--- a/crypto/x509/v3_attrdesc.c
+++ b/crypto/x509/v3_attrdesc.c
@@ -100,7 +100,11 @@ static int i2r_OSSL_INFO_SYNTAX(X509V3_EXT_METHOD *method,
     case OSSL_INFO_SYNTAX_TYPE_CONTENT:
         if (BIO_printf(out, "%*sContent: ", indent, "") <= 0)
             return 0;
-        if (BIO_printf(out, "%.*s", info->choice.content->length, info->choice.content->data) <= 0)
+        if (BIO_printf(out, "%.*s", info->choice.content->length,
+                info->choice.content->length
+                    ? info->choice.content->data
+                    : (const unsigned char *)"")
+            <= 0)
             return 0;
         if (BIO_puts(out, "\n") <= 0)
             return 0;
@@ -145,18 +149,28 @@ static int i2r_OSSL_ATTRIBUTE_DESCRIPTOR(X509V3_EXT_METHOD *method,
     if (BIO_printf(out, "%*sSyntax:\n", indent, "") <= 0)
         return 0;
     if (BIO_printf(out, "%*s%.*s", indent + 4, "",
-            ad->attributeSyntax->length, ad->attributeSyntax->data)
+            ad->attributeSyntax->length,
+            ad->attributeSyntax->length
+                ? ad->attributeSyntax->data
+                : (const unsigned char *)"")
         <= 0)
         return 0;
     if (BIO_puts(out, "\n\n") <= 0)
         return 0;
     if (ad->name != NULL) {
-        if (BIO_printf(out, "%*sName: %.*s\n", indent, "", ad->name->length, ad->name->data) <= 0)
+        if (BIO_printf(out, "%*sName: %.*s\n", indent, "", ad->name->length,
+                ad->name->length
+                    ? ad->name->data
+                    : (const unsigned char *)"")
+            <= 0)
             return 0;
     }
     if (ad->description != NULL) {
         if (BIO_printf(out, "%*sDescription: %.*s\n", indent, "",
-                ad->description->length, ad->description->data)
+                ad->description->length,
+                ad->description->length
+                    ? ad->description->data
+                    : (const unsigned char *)"")
             <= 0)
             return 0;
     }
diff --git a/crypto/x509/v3_cpols.c b/crypto/x509/v3_cpols.c
index f9abeaa959..c45bbc2c81 100644
--- a/crypto/x509/v3_cpols.c
+++ b/crypto/x509/v3_cpols.c
@@ -444,7 +444,9 @@ static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals,
         case NID_id_qt_cps:
             BIO_printf(out, "%*sCPS: %.*s", indent, "",
                 qualinfo->d.cpsuri->length,
-                qualinfo->d.cpsuri->data);
+                qualinfo->d.cpsuri->length
+                    ? qualinfo->d.cpsuri->data
+                    : (const unsigned char *)"");
             break;

         case NID_id_qt_unotice:
@@ -469,7 +471,9 @@ static void print_notice(BIO *out, USERNOTICE *notice, int indent)
         ref = notice->noticeref;
         BIO_printf(out, "%*sOrganization: %.*s\n", indent, "",
             ref->organization->length,
-            ref->organization->data);
+            ref->organization->length
+                ? ref->organization->data
+                : (const unsigned char *)"");
         BIO_printf(out, "%*sNumber%s: ", indent, "",
             sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : "");
         for (i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) {
@@ -494,7 +498,9 @@ static void print_notice(BIO *out, USERNOTICE *notice, int indent)
     if (notice->exptext)
         BIO_printf(out, "%*sExplicit Text: %.*s", indent, "",
             notice->exptext->length,
-            notice->exptext->data);
+            notice->exptext->length
+                ? notice->exptext->data
+                : (const unsigned char *)"");
 }

 void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent)
diff --git a/crypto/x509/v3_san.c b/crypto/x509/v3_san.c
index 025cd25ca9..52d8eb498c 100644
--- a/crypto/x509/v3_san.c
+++ b/crypto/x509/v3_san.c
@@ -225,27 +225,37 @@ int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
         case NID_id_on_SmtpUTF8Mailbox:
             BIO_printf(out, "othername:SmtpUTF8Mailbox:%.*s",
                 gen->d.otherName->value->value.utf8string->length,
-                gen->d.otherName->value->value.utf8string->data);
+                gen->d.otherName->value->value.utf8string->length
+                    ? gen->d.otherName->value->value.utf8string->data
+                    : (const unsigned char *)"");
             break;
         case NID_XmppAddr:
             BIO_printf(out, "othername:XmppAddr:%.*s",
                 gen->d.otherName->value->value.utf8string->length,
-                gen->d.otherName->value->value.utf8string->data);
+                gen->d.otherName->value->value.utf8string->length
+                    ? gen->d.otherName->value->value.utf8string->data
+                    : (const unsigned char *)"");
             break;
         case NID_SRVName:
             BIO_printf(out, "othername:SRVName:%.*s",
                 gen->d.otherName->value->value.ia5string->length,
-                gen->d.otherName->value->value.ia5string->data);
+                gen->d.otherName->value->value.ia5string->length
+                    ? gen->d.otherName->value->value.ia5string->data
+                    : (const unsigned char *)"");
             break;
         case NID_ms_upn:
             BIO_printf(out, "othername:UPN:%.*s",
                 gen->d.otherName->value->value.utf8string->length,
-                gen->d.otherName->value->value.utf8string->data);
+                gen->d.otherName->value->value.utf8string->length
+                    ? gen->d.otherName->value->value.utf8string->data
+                    : (const unsigned char *)"");
             break;
         case NID_NAIRealm:
             BIO_printf(out, "othername:NAIRealm:%.*s",
                 gen->d.otherName->value->value.utf8string->length,
-                gen->d.otherName->value->value.utf8string->data);
+                gen->d.otherName->value->value.utf8string->length
+                    ? gen->d.otherName->value->value.utf8string->data
+                    : (const unsigned char *)"");
             break;
         default:
             BIO_printf(out, "othername:<unsupported>");
diff --git a/crypto/x509/v3_timespec.c b/crypto/x509/v3_timespec.c
index f29265f4be..79dfdbe0a8 100644
--- a/crypto/x509/v3_timespec.c
+++ b/crypto/x509/v3_timespec.c
@@ -142,7 +142,11 @@ static int i2r_OSSL_TIME_SPEC_ABSOLUTE(X509V3_EXT_METHOD *method,
             return 0;
         if (!ossl_asn1_time_print_ex(out, time->startTime, 0))
             return 0;
-        if (BIO_printf(out, "%.*s", time->startTime->length, time->startTime->data) <= 0)
+        if (BIO_printf(out, "%.*s", time->startTime->length,
+                time->startTime->length
+                    ? time->startTime->data
+                    : (const unsigned char *)"")
+            <= 0)
             return 0;
     } else if (time->endTime != NULL) {
         if (!BIO_puts(out, "Any time until "))
diff --git a/crypto/x509/v3_usernotice.c b/crypto/x509/v3_usernotice.c
index 8a53eff96e..ce6627bf23 100644
--- a/crypto/x509/v3_usernotice.c
+++ b/crypto/x509/v3_usernotice.c
@@ -29,7 +29,9 @@ static int print_notice(BIO *out, USERNOTICE *notice, int indent)
         ref = notice->noticeref;
         if (BIO_printf(out, "%*sOrganization: %.*s\n", indent, "",
                 ref->organization->length,
-                ref->organization->data)
+                ref->organization->length
+                    ? ref->organization->data
+                    : (const unsigned char *)"")
             <= 0)
             return 0;
         if (BIO_printf(out, "%*sNumber%s: ", indent, "",
@@ -61,7 +63,9 @@ static int print_notice(BIO *out, USERNOTICE *notice, int indent)

     return BIO_printf(out, "%*sExplicit Text: %.*s", indent, "",
                notice->exptext->length,
-               notice->exptext->data)
+               notice->exptext->length
+                   ? notice->exptext->data
+                   : (const unsigned char *)"")
         >= 0;
 }

diff --git a/crypto/x509/x_attrib.c b/crypto/x509/x_attrib.c
index 648d64bcf3..98a99cc43b 100644
--- a/crypto/x509/x_attrib.c
+++ b/crypto/x509/x_attrib.c
@@ -135,7 +135,9 @@ int ossl_print_attribute_value(BIO *out,
     case V_ASN1_OBJECT_DESCRIPTOR:
         return BIO_printf(out, "%*s%.*s", indent, "",
                    av->value.generalstring->length,
-                   av->value.generalstring->data)
+                   av->value.generalstring->length
+                       ? av->value.generalstring->data
+                       : (const unsigned char *)"")
             >= 0;

         /* EXTERNAL would go here. */
@@ -144,7 +146,9 @@ int ossl_print_attribute_value(BIO *out,
     case V_ASN1_UTF8STRING:
         return BIO_printf(out, "%*s%.*s", indent, "",
                    av->value.utf8string->length,
-                   av->value.utf8string->data)
+                   av->value.utf8string->length
+                       ? av->value.utf8string->data
+                       : (const unsigned char *)"")
             >= 0;

     case V_ASN1_REAL:
@@ -208,25 +212,33 @@ int ossl_print_attribute_value(BIO *out,
     case V_ASN1_NUMERICSTRING:
         return BIO_printf(out, "%*s%.*s", indent, "",
                    av->value.visiblestring->length,
-                   av->value.visiblestring->data)
+                   av->value.visiblestring->length
+                       ? av->value.visiblestring->data
+                       : (const unsigned char *)"")
             >= 0;

     case V_ASN1_PRINTABLESTRING:
         return BIO_printf(out, "%*s%.*s", indent, "",
                    av->value.printablestring->length,
-                   av->value.printablestring->data)
+                   av->value.printablestring->length
+                       ? av->value.printablestring->data
+                       : (const unsigned char *)"")
             >= 0;

     case V_ASN1_T61STRING:
         return BIO_printf(out, "%*s%.*s", indent, "",
                    av->value.t61string->length,
-                   av->value.t61string->data)
+                   av->value.t61string->length
+                       ? av->value.t61string->data
+                       : (const unsigned char *)"")
             >= 0;

     case V_ASN1_IA5STRING:
         return BIO_printf(out, "%*s%.*s", indent, "",
                    av->value.ia5string->length,
-                   av->value.ia5string->data)
+                   av->value.ia5string->length
+                       ? av->value.ia5string->data
+                       : (const unsigned char *)"")
             >= 0;

     /* UniversalString would go here. */