Commit 5df7d33922 for openssl.org

commit 5df7d33922d8a18e77bee28aeadbe2628fc34a7b
Author: Bob Beck <beck@openssl.org>
Date:   Mon Sep 14 09:56:07 2026 -0600

    NUL-terminate ASN1_STRING data built inside libcrypto

    Add ossl_asn1_string_set1_data() and ossl_asn1_string_set1_string(),
    copies of the public setters that also write a NUL byte after the data,
    and switch all libcrypto callers to them. The ecosystem still treats
    ASN1_STRING data as C strings; this keeps it working while it is fixed.
    Removing the terminator later is a one-argument change in one function.

    Reviewed-by: Neil Horman <nhorman@openssl.org>
    Reviewed-by: Andrew Dinh <andrewd@openssl.org>
    Reviewed-by: Milan Broz <mbroz@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Merge-date: Fri Sep 18 09:05:58 2026
    Merged-from: https://github.com/openssl/openssl/pull/32829

diff --git a/crypto/asn1/a_int.c b/crypto/asn1/a_int.c
index 8349443419..5dd1205862 100644
--- a/crypto/asn1/a_int.c
+++ b/crypto/asn1/a_int.c
@@ -316,7 +316,7 @@ ASN1_INTEGER *ossl_c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
     } else
         ret = *a;

-    if (ASN1_STRING_set1_data(ret, NULL, r) == 0) {
+    if (ossl_asn1_string_set1_data(ret, NULL, r) == 0) {
         ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
         goto err;
     }
@@ -371,7 +371,7 @@ static int asn1_string_set_int64(ASN1_STRING *a, int64_t r, int itype)
         off = asn1_put_uint64(tbuf, r);
         a->type &= ~V_ASN1_NEG;
     }
-    return ASN1_STRING_set1_data(a, tbuf + off, (sizeof(tbuf) - off));
+    return ossl_asn1_string_set1_data(a, tbuf + off, (sizeof(tbuf) - off));
 }

 static int asn1_string_get_uint64(uint64_t *pr, const ASN1_STRING *a,
@@ -399,7 +399,7 @@ static int asn1_string_set_uint64(ASN1_STRING *a, uint64_t r, int itype)

     a->type = itype;
     off = asn1_put_uint64(tbuf, r);
-    return ASN1_STRING_set1_data(a, tbuf + off, (sizeof(tbuf) - off));
+    return ossl_asn1_string_set1_data(a, tbuf + off, (sizeof(tbuf) - off));
 }

 /*
@@ -503,7 +503,7 @@ static ASN1_STRING *bn_to_asn1_string(const BIGNUM *bn, ASN1_STRING *ai,
     if (len == 0)
         len = 1;

-    if (ASN1_STRING_set1_data(ret, NULL, len) == 0) {
+    if (ossl_asn1_string_set1_data(ret, NULL, len) == 0) {
         ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
         goto err;
     }
diff --git a/crypto/asn1/a_octet.c b/crypto/asn1/a_octet.c
index 581792511a..ebafaa72b4 100644
--- a/crypto/asn1/a_octet.c
+++ b/crypto/asn1/a_octet.c
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/asn1.h>
+#include "crypto/asn1.h"

 ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *x)
 {
@@ -30,6 +31,6 @@ int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d,
         return 0;
     }
     if (len == -1)
-        return ASN1_STRING_set1_string(x, (const char *)d);
-    return ASN1_STRING_set1_data(x, d, len);
+        return ossl_asn1_string_set1_string(x, (const char *)d);
+    return ossl_asn1_string_set1_data(x, d, len);
 }
diff --git a/crypto/asn1/a_time.c b/crypto/asn1/a_time.c
index d5f69d547b..5a1207dc85 100644
--- a/crypto/asn1/a_time.c
+++ b/crypto/asn1/a_time.c
@@ -272,7 +272,7 @@ ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type)
     if (tmps == NULL)
         return NULL;

-    if (!ASN1_STRING_set1_data(tmps, NULL, len))
+    if (!ossl_asn1_string_set1_data(tmps, NULL, len))
         goto err;

     tmps->type = type;
diff --git a/crypto/asn1/asn1_gen.c b/crypto/asn1/asn1_gen.c
index 7dfe661977..351bdafe7f 100644
--- a/crypto/asn1/asn1_gen.c
+++ b/crypto/asn1/asn1_gen.c
@@ -657,7 +657,7 @@ static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
             ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
             goto bad_str;
         }
-        if (!ASN1_STRING_set1_string(atmp->value.asn1_string, str)) {
+        if (!ossl_asn1_string_set1_string(atmp->value.asn1_string, str)) {
             ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
             goto bad_str;
         }
@@ -712,7 +712,7 @@ static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
             atmp->value.asn1_string->length = rdlen;
             atmp->value.asn1_string->type = utype;
         } else if (format == ASN1_GEN_FORMAT_ASCII) {
-            if (!ASN1_STRING_set1_string(atmp->value.asn1_string, str)) {
+            if (!ossl_asn1_string_set1_string(atmp->value.asn1_string, str)) {
                 ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
                 goto bad_str;
             }
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index 4bf03be0b4..159e084c52 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -404,6 +404,27 @@ int ASN1_STRING_set1_string(ASN1_STRING *str, const char *c_string)
         strlen(c_string));
 }

+int ossl_asn1_string_set1_data(ASN1_STRING *str, const uint8_t *data,
+    size_t len_in)
+{
+    if (str->type == V_ASN1_BIT_STRING) {
+        ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
+        return 0;
+    }
+    /* This will go away once ASN1_STRING can size_t internally */
+    if (len_in > INT_MAX) {
+        ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
+        return 0;
+    }
+    return ossl_asn1_string_set_internal(str, data, (int)len_in, /*add_nul_byte=*/1);
+}
+
+int ossl_asn1_string_set1_string(ASN1_STRING *str, const char *c_string)
+{
+    return ossl_asn1_string_set1_data(str, (const uint8_t *)c_string,
+        strlen(c_string));
+}
+
 ASN1_STRING *ASN1_STRING_new(void)
 {
     return ASN1_STRING_type_new(V_ASN1_OCTET_STRING);
diff --git a/crypto/asn1/p5_scrypt.c b/crypto/asn1/p5_scrypt.c
index 6eed32e8e9..6d4ef040d9 100644
--- a/crypto/asn1/p5_scrypt.c
+++ b/crypto/asn1/p5_scrypt.c
@@ -173,7 +173,7 @@ static X509_ALGOR *pkcs5_scrypt_set(const unsigned char *salt, int saltlen,
         saltlen = PKCS5_DEFAULT_PBE2_SALT_LEN;

     /* This will either copy salt or grow the buffer */
-    if (ASN1_STRING_set1_data(sparam->salt, salt, saltlen) == 0) {
+    if (ossl_asn1_string_set1_data(sparam->salt, salt, saltlen) == 0) {
         ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
         goto err;
     }
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index 1c8acffb6e..f1a08d27b1 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -983,7 +983,7 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, long len,
             ASN1_STRING_set0(stmp, (unsigned char *)cont /* UGLY CAST! */, ilen);
             *free_cont = 0;
         } else {
-            if (!ASN1_STRING_set1_data(stmp, cont, len)) {
+            if (!ossl_asn1_string_set1_data(stmp, cont, len)) {
                 ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
                 ASN1_STRING_free(stmp);
                 *pval = NULL;
diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c
index e7f4a76316..428d163f81 100644
--- a/crypto/cmp/cmp_protect.c
+++ b/crypto/cmp/cmp_protect.c
@@ -206,7 +206,7 @@ static X509_ALGOR *pbmac_algor(const OSSL_CMP_CTX *ctx)
         goto err;
     if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0)
         goto err;
-    if (!ASN1_STRING_set1_data(pbm_str, pbm_der, pbm_der_len))
+    if (!ossl_asn1_string_set1_data(pbm_str, pbm_der, pbm_der_len))
         goto err;
     alg = ossl_X509_ALGOR_from_nid(NID_id_PasswordBasedMAC,
         V_ASN1_SEQUENCE, pbm_str);
diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c
index 84d3ad2c3e..b052c91246 100644
--- a/crypto/cmp/cmp_status.c
+++ b/crypto/cmp/cmp_status.c
@@ -278,7 +278,7 @@ OSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info,

     if (text != NULL) {
         if ((utf8_text = ASN1_UTF8STRING_new()) == NULL
-            || !ASN1_STRING_set1_string(utf8_text, text))
+            || !ossl_asn1_string_set1_string(utf8_text, text))
             goto err;
         if ((si->statusString = sk_ASN1_UTF8STRING_new_null()) == NULL)
             goto err;
diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c
index 2632abb339..d32106266e 100644
--- a/crypto/cmp/cmp_util.c
+++ b/crypto/cmp/cmp_util.c
@@ -229,7 +229,7 @@ int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk,
         return 0;
     if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
         return 0;
-    if (!ASN1_STRING_set1_data(utf8string, (const uint8_t *)text, len))
+    if (!ossl_asn1_string_set1_data(utf8string, (const uint8_t *)text, len))
         goto err;
     if (!sk_ASN1_UTF8STRING_push(sk, utf8string))
         goto err;
diff --git a/crypto/cms/cms_dd.c b/crypto/cms/cms_dd.c
index 69661e3b40..6449bf83ea 100644
--- a/crypto/cms/cms_dd.c
+++ b/crypto/cms/cms_dd.c
@@ -92,7 +92,7 @@ int ossl_cms_DigestedData_do_final(const CMS_ContentInfo *cms, BIO *chain,
         else
             r = 1;
     } else {
-        if (!ASN1_STRING_set1_data(dd->digest, md, mdlen))
+        if (!ossl_asn1_string_set1_data(dd->digest, md, mdlen))
             goto err;
         r = 1;
     }
diff --git a/crypto/cms/cms_ess.c b/crypto/cms/cms_ess.c
index b1647b03b7..cd4ab27eaa 100644
--- a/crypto/cms/cms_ess.c
+++ b/crypto/cms/cms_ess.c
@@ -131,7 +131,7 @@ CMS_ReceiptRequest *CMS_ReceiptRequest_create0_ex(
     if (id)
         ASN1_STRING_set0(rr->signedContentIdentifier, id, idlen);
     else {
-        if (!ASN1_STRING_set1_data(rr->signedContentIdentifier, NULL, 32)) {
+        if (!ossl_asn1_string_set1_data(rr->signedContentIdentifier, NULL, 32)) {
             ERR_raise(ERR_LIB_CMS, ERR_R_ASN1_LIB);
             goto err;
         }
diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c
index dec83eeeec..f0d581e8ed 100644
--- a/crypto/cms/cms_sd.c
+++ b/crypto/cms/cms_sd.c
@@ -304,7 +304,7 @@ static int ossl_cms_add1_signing_cert(CMS_SignerInfo *si,

     p = pp;
     i2d_ESS_SIGNING_CERT(sc, &p);
-    if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set1_data(seq, pp, len)) {
+    if (!(seq = ASN1_STRING_new()) || !ossl_asn1_string_set1_data(seq, pp, len)) {
         ASN1_STRING_free(seq);
         OPENSSL_free(pp);
         return 0;
@@ -329,7 +329,7 @@ static int ossl_cms_add1_signing_cert_v2(CMS_SignerInfo *si,

     p = pp;
     i2d_ESS_SIGNING_CERT_V2(sc, &p);
-    if (!(seq = ASN1_STRING_new()) || !ASN1_STRING_set1_data(seq, pp, len)) {
+    if (!(seq = ASN1_STRING_new()) || !ossl_asn1_string_set1_data(seq, pp, len)) {
         ASN1_STRING_free(seq);
         OPENSSL_free(pp);
         return 0;
diff --git a/crypto/ocsp/ocsp_ext.c b/crypto/ocsp/ocsp_ext.c
index ad5a9cdf4e..2d21a94dca 100644
--- a/crypto/ocsp/ocsp_ext.c
+++ b/crypto/ocsp/ocsp_ext.c
@@ -360,7 +360,7 @@ X509_EXTENSION *OCSP_crlID_new(const char *url, long *n, char *tim)
     if (url) {
         if ((cid->crlUrl = ASN1_IA5STRING_new()) == NULL)
             goto err;
-        if (!(ASN1_STRING_set1_string(cid->crlUrl, url)))
+        if (!(ossl_asn1_string_set1_string(cid->crlUrl, url)))
             goto err;
     }
     if (n) {
@@ -446,7 +446,7 @@ X509_EXTENSION *OCSP_url_svcloc_new(const X509_NAME *issuer, const char **urls)
             goto err;
         if ((ia5 = ASN1_IA5STRING_new()) == NULL)
             goto err;
-        if (!ASN1_STRING_set1_string((ASN1_STRING *)ia5, *urls))
+        if (!ossl_asn1_string_set1_string((ASN1_STRING *)ia5, *urls))
             goto err;
         /* ad->location is allocated inside ACCESS_DESCRIPTION_new */
         ad->location->type = GEN_URI;
diff --git a/crypto/pkcs7/pk7_attr.c b/crypto/pkcs7/pk7_attr.c
index 601956af9d..ac7a4cb4af 100644
--- a/crypto/pkcs7/pk7_attr.c
+++ b/crypto/pkcs7/pk7_attr.c
@@ -132,7 +132,7 @@ int PKCS7_add1_attrib_digest(PKCS7_SIGNER_INFO *si,
     os = ASN1_OCTET_STRING_new();
     if (os == NULL)
         return 0;
-    if (!ASN1_STRING_set1_data(os, md, mdlen)
+    if (!ossl_asn1_string_set1_data(os, md, mdlen)
         || !PKCS7_add_signed_attribute(si, NID_pkcs9_messageDigest,
             V_ASN1_OCTET_STRING, os)) {
         ASN1_OCTET_STRING_free(os);
diff --git a/crypto/ts/ts_rsp_sign.c b/crypto/ts/ts_rsp_sign.c
index 27a4455fcb..0495e59408 100644
--- a/crypto/ts/ts_rsp_sign.c
+++ b/crypto/ts/ts_rsp_sign.c
@@ -18,6 +18,7 @@
 #include "internal/cryptlib.h"
 #include "internal/sizes.h"
 #include "internal/time.h"
+#include "crypto/asn1.h"
 #include "crypto/ess.h"
 #include "ts_local.h"

@@ -300,7 +301,7 @@ int TS_RESP_CTX_set_status_info(TS_RESP_CTX *ctx,
     }
     if (text) {
         if ((utf8_text = ASN1_UTF8STRING_new()) == NULL
-            || !ASN1_STRING_set1_string(utf8_text, text)) {
+            || !ossl_asn1_string_set1_string(utf8_text, text)) {
             ERR_raise(ERR_LIB_TS, ERR_R_ASN1_LIB);
             goto err;
         }
@@ -647,7 +648,7 @@ static int ossl_ess_add1_signing_cert(PKCS7_SIGNER_INFO *si,

     p = pp;
     i2d_ESS_SIGNING_CERT(sc, &p);
-    if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set1_data(seq, pp, len)) {
+    if ((seq = ASN1_STRING_new()) == NULL || !ossl_asn1_string_set1_data(seq, pp, len)) {
         ASN1_STRING_free(seq);
         OPENSSL_free(pp);
         return 0;
@@ -678,7 +679,7 @@ static int ossl_ess_add1_signing_cert_v2(PKCS7_SIGNER_INFO *si,

     p = pp;
     i2d_ESS_SIGNING_CERT_V2(sc, &p);
-    if ((seq = ASN1_STRING_new()) == NULL || !ASN1_STRING_set1_data(seq, pp, len)) {
+    if ((seq = ASN1_STRING_new()) == NULL || !ossl_asn1_string_set1_data(seq, pp, len)) {
         ASN1_STRING_free(seq);
         OPENSSL_free(pp);
         return 0;
diff --git a/crypto/x509/v3_cpols.c b/crypto/x509/v3_cpols.c
index c45bbc2c81..0414f3d387 100644
--- a/crypto/x509/v3_cpols.c
+++ b/crypto/x509/v3_cpols.c
@@ -208,7 +208,7 @@ static POLICYINFO *policy_section(X509V3_CTX *ctx,
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
-            if (!ASN1_STRING_set1_string(qual->d.cpsuri, cnf->value)) {
+            if (!ossl_asn1_string_set1_string(qual->d.cpsuri, cnf->value)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
@@ -324,7 +324,7 @@ static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
             if (tag_len != 0)
                 value += tag_len + 1;
             len = (int)strlen(value);
-            if (!ASN1_STRING_set1_data(not->exptext, (uint8_t *)value, len)) {
+            if (!ossl_asn1_string_set1_data(not->exptext, (uint8_t *)value, len)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
@@ -343,7 +343,7 @@ static POLICYQUALINFO *notice_section(X509V3_CTX *ctx,
                 nref->organization->type = V_ASN1_IA5STRING;
             else
                 nref->organization->type = V_ASN1_VISIBLESTRING;
-            if (!ASN1_STRING_set1_string(nref->organization, cnf->value)) {
+            if (!ossl_asn1_string_set1_string(nref->organization, cnf->value)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
diff --git a/crypto/x509/v3_ia5.c b/crypto/x509/v3_ia5.c
index 06b06ff70e..35cc81a2ea 100644
--- a/crypto/x509/v3_ia5.c
+++ b/crypto/x509/v3_ia5.c
@@ -52,7 +52,7 @@ ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method,
         ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
         return NULL;
     }
-    if (!ASN1_STRING_set1_string((ASN1_STRING *)ia5, str)) {
+    if (!ossl_asn1_string_set1_string((ASN1_STRING *)ia5, str)) {
         ASN1_IA5STRING_free(ia5);
         return NULL;
     }
diff --git a/crypto/x509/v3_ist.c b/crypto/x509/v3_ist.c
index ee54384c1f..aaaa91aacb 100644
--- a/crypto/x509/v3_ist.c
+++ b/crypto/x509/v3_ist.c
@@ -52,28 +52,28 @@ static ISSUER_SIGN_TOOL *v2i_issuer_sign_tool(X509V3_EXT_METHOD *method, X509V3_
         if (strcmp(cnf->name, "signTool") == 0) {
             if (ist->signTool == NULL
                 || cnf->value == NULL
-                || !ASN1_STRING_set1_string(ist->signTool, cnf->value)) {
+                || !ossl_asn1_string_set1_string(ist->signTool, cnf->value)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
         } else if (strcmp(cnf->name, "cATool") == 0) {
             if (ist->cATool == NULL
                 || cnf->value == NULL
-                || !ASN1_STRING_set1_string(ist->cATool, cnf->value)) {
+                || !ossl_asn1_string_set1_string(ist->cATool, cnf->value)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
         } else if (strcmp(cnf->name, "signToolCert") == 0) {
             if (ist->signToolCert == NULL
                 || cnf->value == NULL
-                || !ASN1_STRING_set1_string(ist->signToolCert, cnf->value)) {
+                || !ossl_asn1_string_set1_string(ist->signToolCert, cnf->value)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
         } else if (strcmp(cnf->name, "cAToolCert") == 0) {
             if (ist->cAToolCert == NULL
                 || cnf->value == NULL
-                || !ASN1_STRING_set1_string(ist->cAToolCert, cnf->value)) {
+                || !ossl_asn1_string_set1_string(ist->cAToolCert, cnf->value)) {
                 ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
                 goto err;
             }
diff --git a/crypto/x509/v3_san.c b/crypto/x509/v3_san.c
index 52d8eb498c..0defca074d 100644
--- a/crypto/x509/v3_san.c
+++ b/crypto/x509/v3_san.c
@@ -586,7 +586,7 @@ GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out,

     if (is_string) {
         if ((gen->d.ia5 = ASN1_IA5STRING_new()) == NULL
-            || !ASN1_STRING_set1_string(gen->d.ia5, value)) {
+            || !ossl_asn1_string_set1_string(gen->d.ia5, value)) {
             ASN1_IA5STRING_free(gen->d.ia5);
             gen->d.ia5 = NULL;
             ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
diff --git a/crypto/x509/v3_utf8.c b/crypto/x509/v3_utf8.c
index aa80d7455e..fcc932f766 100644
--- a/crypto/x509/v3_utf8.c
+++ b/crypto/x509/v3_utf8.c
@@ -55,7 +55,7 @@ ASN1_UTF8STRING *s2i_ASN1_UTF8STRING(X509V3_EXT_METHOD *method,
         ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
         return NULL;
     }
-    if (!ASN1_STRING_set1_string(utf8, str)) {
+    if (!ossl_asn1_string_set1_string(utf8, str)) {
         ERR_raise(ERR_LIB_X509V3, ERR_R_ASN1_LIB);
         ASN1_UTF8STRING_free(utf8);
         return NULL;
diff --git a/crypto/x509/x509_att.c b/crypto/x509/x509_att.c
index a88f5d8279..ae4b71c05b 100644
--- a/crypto/x509/x509_att.c
+++ b/crypto/x509/x509_att.c
@@ -370,7 +370,7 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
         }
         if (attrtype == V_ASN1_BIT_STRING) {
             /*
-             * ASN1_STRING_set1_data() rejects bit strings, so use the
+             * ossl_asn1_string_set1_data() rejects bit strings, so use the
              * dedicated bit string setter, with zero unused bits.
              */
             if (data == NULL && len > 0) {
@@ -381,7 +381,7 @@ int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype,
                 ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
                 goto err;
             }
-        } else if (!ASN1_STRING_set1_data(stmp, data, len)) {
+        } else if (!ossl_asn1_string_set1_data(stmp, data, len)) {
             ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
             goto err;
         }
diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c
index e5766d1b49..1cb9ad00f4 100644
--- a/crypto/x509/x509name.c
+++ b/crypto/x509/x509name.c
@@ -336,9 +336,9 @@ int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
     if (len < -1)
         return 0;
     if (len == -1)
-        i = ASN1_STRING_set1_string(ne->value, (const char *)bytes);
+        i = ossl_asn1_string_set1_string(ne->value, (const char *)bytes);
     else
-        i = ASN1_STRING_set1_data(ne->value, bytes, (size_t)len);
+        i = ossl_asn1_string_set1_data(ne->value, bytes, (size_t)len);
     if (!i)
         return 0;
     if (type != V_ASN1_UNDEF) {
diff --git a/crypto/x509/x_x509a.c b/crypto/x509/x_x509a.c
index 9ac7626577..07f15009bf 100644
--- a/crypto/x509/x_x509a.c
+++ b/crypto/x509/x_x509a.c
@@ -72,7 +72,7 @@ int X509_alias_set1(X509 *x, const unsigned char *name, int len)

     if (aux->alias == NULL && (aux->alias = ASN1_UTF8STRING_new()) == NULL)
         return 0;
-    return ASN1_STRING_set1_data(aux->alias, name, len_s);
+    return ossl_asn1_string_set1_data(aux->alias, name, len_s);
 }

 int X509_keyid_set1(X509 *x, const unsigned char *id, int len)
@@ -101,7 +101,7 @@ int X509_keyid_set1(X509 *x, const unsigned char *id, int len)
     if (aux->keyid == NULL
         && (aux->keyid = ASN1_OCTET_STRING_new()) == NULL)
         return 0;
-    return ASN1_STRING_set1_data(aux->keyid, id, len_s);
+    return ossl_asn1_string_set1_data(aux->keyid, id, len_s);
 }

 const unsigned char *X509_alias_get0(const X509 *x, int *len)
diff --git a/include/crypto/asn1.h b/include/crypto/asn1.h
index 7000d7d33d..ef5b836313 100644
--- a/include/crypto/asn1.h
+++ b/include/crypto/asn1.h
@@ -181,6 +181,28 @@ X509_ALGOR *ossl_X509_ALGOR_from_nid(int nid, int ptype, void *pval);
 void ossl_asn1_bit_string_clear_unused_bits(ASN1_STRING *str);
 void ossl_asn1_bit_string_set_unused_bits(ASN1_STRING *str, unsigned int num);

+/**
+ * @brief Set str's data as ASN1_STRING_set1_data() does, and NUL-terminate it.
+ * The terminator is not counted in str->length.
+ * @param str the string to set
+ * @param data the bytes to copy, or NULL to allocate len bytes unset
+ * @param len the number of bytes at data
+ * @returns 1 on success, 0 on failure
+ * @see ASN1_STRING_set1_data(3)
+ */
+int ossl_asn1_string_set1_data(ASN1_STRING *str, const uint8_t *data,
+    size_t len);
+
+/**
+ * @brief Set str's data as ASN1_STRING_set1_string() does, and NUL-terminate it.
+ * The terminator is not counted in str->length.
+ * @param str the string to set
+ * @param c_string the NUL-terminated string to copy
+ * @returns 1 on success, 0 on failure
+ * @see ASN1_STRING_set1_string(3)
+ */
+int ossl_asn1_string_set1_string(ASN1_STRING *str, const char *c_string);
+
 int asn1_item_embed_d2i(ASN1_VALUE **pval, const unsigned char **in,
     long len, const ASN1_ITEM *it, int tag, int aclass,
     char opt, ASN1_TLC *ctx, int depth,
diff --git a/test/build.info b/test/build.info
index e1b972bc55..20e2ef19ea 100644
--- a/test/build.info
+++ b/test/build.info
@@ -954,9 +954,9 @@ IF[{- !$disabled{tests} -}]
   SOURCE[ca_internals_test]=ca_internals_test.c ../apps/ca.c ../apps/lib/apps.c \
                             ../apps/lib/app_rand.c ../apps/lib/app_provider.c \
                             ../apps/lib/app_libctx.c ../apps/lib/fmt.c ../apps/lib/apps_ui.c \
-                            ../apps/lib/app_x509.c ../crypto/asn1/a_time.c ../crypto/ctype.c
+                            ../apps/lib/app_x509.c
   INCLUDE[ca_internals_test]=.. ../include ../apps/include
-  DEPEND[ca_internals_test]=libtestutil.a ../libssl
+  DEPEND[ca_internals_test]=libtestutil.a ../libssl.a ../libcrypto.a

   # Internal test programs.  These are essentially a collection of internal
   # test routines.  Some of them need to reach internal symbols that aren't
@@ -1262,10 +1262,9 @@ IF[{- !$disabled{tests} -}]
   ENDIF

   PROGRAMS{noinst}=asn1_time_test
-  SOURCE[asn1_time_test]=asn1_time_test.c ../crypto/ctype.c \
-                         ../crypto/asn1/a_time.c
+  SOURCE[asn1_time_test]=asn1_time_test.c
   INCLUDE[asn1_time_test]=../include ../apps/include
-  DEPEND[asn1_time_test]=../libcrypto libtestutil.a
+  DEPEND[asn1_time_test]=../libcrypto.a libtestutil.a

   PROGRAMS{noinst}=asn1_string_test
   SOURCE[asn1_string_test]=asn1_string_test.c