Commit 41a3fdde52 for openssl.org

commit 41a3fdde524ad26f09fbfe36018b656532722f81
Author: Norbert Pocs <norbertp@openssl.org>
Date:   Tue Mar 31 16:41:39 2026 +0200

    Deprecate ASN1_BIT_STRING_set()

    Replacement: ASN1_BIT_STRING_set1

    Signed-off-by: Norbert Pocs <norbertp@openssl.org>

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Richard Levitte <levitte@openssl.org>
    MergeDate: Sun Apr 26 11:45:27 2026
    (Merged from https://github.com/openssl/openssl/pull/30692)

diff --git a/CHANGES.md b/CHANGES.md
index 871e4d36a3..a4c2185ab0 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -109,6 +109,10 @@ OpenSSL Releases

    *Helen Zhang*

+ * Deprecated `ASN1_BIT_STRING_set()` in favour of `ASN1_BIT_STRING_set1()`.
+
+   *Norbert Pócs*
+
 ### Changes between 3.6 and 4.0.0 [14 Apr 2026]

  * Added `-expected-rpks` option to the `openssl s_client`
diff --git a/crypto/asn1/a_bitstr.c b/crypto/asn1/a_bitstr.c
index ebd1417923..9976cc478e 100644
--- a/crypto/asn1/a_bitstr.c
+++ b/crypto/asn1/a_bitstr.c
@@ -15,10 +15,12 @@

 #include <crypto/asn1.h>

+#ifndef OPENSSL_NO_DEPRECATED_4_1
 int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
 {
     return ASN1_STRING_set(x, d, len);
 }
+#endif

 int ossl_i2c_ASN1_BIT_STRING(const ASN1_BIT_STRING *a, unsigned char **pp)
 {
diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c
index 28e1310778..b0f52e9f36 100644
--- a/crypto/cmp/cmp_protect.c
+++ b/crypto/cmp/cmp_protect.c
@@ -88,8 +88,7 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx,
         if (sig_len > INT_MAX || (prot = ASN1_BIT_STRING_new()) == NULL)
             goto end;
         /* OpenSSL by default encodes all bit strings as ASN.1 NamedBitList */
-        ossl_asn1_bit_string_set_unused_bits(prot, 0);
-        if (!ASN1_BIT_STRING_set(prot, protection, (int)sig_len)) {
+        if (!ASN1_BIT_STRING_set1(prot, protection, (int)sig_len, 0)) {
             ASN1_BIT_STRING_free(prot);
             prot = NULL;
         }
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index 8c25b8ea53..b839e9d2a2 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -348,9 +348,8 @@ static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve)
                 ERR_raise(ERR_LIB_EC, ERR_R_ASN1_LIB);
                 goto err;
             }
-        ossl_asn1_bit_string_set_unused_bits(curve->seed, 0);
-        if (!ASN1_BIT_STRING_set(curve->seed, group->seed,
-                (int)group->seed_len)) {
+        if (!ASN1_BIT_STRING_set1(curve->seed, group->seed,
+                (int)group->seed_len, 0)) {
             ERR_raise(ERR_LIB_EC, ERR_R_ASN1_LIB);
             goto err;
         }
diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c
index a2efd763e3..1871a221a2 100644
--- a/crypto/x509/v3_addr.c
+++ b/crypto/x509/v3_addr.c
@@ -417,7 +417,10 @@ static int make_addressPrefix(IPAddressOrRange **result, unsigned char *addr,
     aor->type = IPAddressOrRange_addressPrefix;
     if (aor->u.addressPrefix == NULL && (aor->u.addressPrefix = ASN1_BIT_STRING_new()) == NULL)
         goto err;
-    if (!ASN1_BIT_STRING_set(aor->u.addressPrefix, addr, bytelen))
+    /* BIT_STRING is a typedef of STRING
+     * this function allows to set value without checking invalid bits
+     * as they are nullified after setting */
+    if (!ASN1_STRING_set(aor->u.addressPrefix, addr, bytelen))
         goto err;
     if (bitlen > 0)
         aor->u.addressPrefix->data[bytelen - 1] &= ~(0xFF >> bitlen);
@@ -461,9 +464,8 @@ static int make_addressRange(IPAddressOrRange **result,

     for (i = length; i > 0 && min[i - 1] == 0x00; --i)
         ;
-    if (!ASN1_BIT_STRING_set(aor->u.addressRange->min, min, i))
+    if (!ASN1_BIT_STRING_set1(aor->u.addressRange->min, min, i, 0))
         goto err;
-    ossl_asn1_bit_string_set_unused_bits(aor->u.addressRange->min, 0);
     if (i > 0) {
         unsigned char b = min[i - 1];
         int j = 1;
@@ -475,9 +477,8 @@ static int make_addressRange(IPAddressOrRange **result,

     for (i = length; i > 0 && max[i - 1] == 0xFF; --i)
         ;
-    if (!ASN1_BIT_STRING_set(aor->u.addressRange->max, max, i))
+    if (!ASN1_BIT_STRING_set1(aor->u.addressRange->max, max, i, 0))
         goto err;
-    ossl_asn1_bit_string_set_unused_bits(aor->u.addressRange->max, 0);
     if (i > 0) {
         unsigned char b = max[i - 1];
         int j = 1;
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index 6071069a19..d085d74992 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -295,9 +295,8 @@ X509_PUBKEY *X509_PUBKEY_dup(const X509_PUBKEY *a)
     }
     if ((pubkey->algor = X509_ALGOR_dup(a->algor)) == NULL
         || (pubkey->public_key = ASN1_BIT_STRING_new()) == NULL
-        || !ASN1_BIT_STRING_set(pubkey->public_key,
-            a->public_key->data,
-            a->public_key->length)) {
+        || !ASN1_BIT_STRING_set1(pubkey->public_key,
+            a->public_key->data, a->public_key->length, 0)) {
         x509_pubkey_ex_free((ASN1_VALUE **)&pubkey,
             ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL));
         ERR_raise(ERR_LIB_X509, ERR_R_ASN1_LIB);
diff --git a/doc/man3/ASN1_BIT_STRING_get_length.pod b/doc/man3/ASN1_BIT_STRING_get_length.pod
index 4ca43c1834..bb3cabab79 100644
--- a/doc/man3/ASN1_BIT_STRING_get_length.pod
+++ b/doc/man3/ASN1_BIT_STRING_get_length.pod
@@ -2,6 +2,7 @@

 =head1 NAME

+ASN1_BIT_STRING_set,
 ASN1_BIT_STRING_set1,
 ASN1_BIT_STRING_set_bit,
 ASN1_BIT_STRING_get_bit,
@@ -36,6 +37,12 @@ ASN1_BIT_STRING_get_length - ASN1_BIT_STRING accessors
   int ASN1_BIT_STRING_set1(ASN1_BIT_STRING *bitstr, const uint8_t *data,
     size_t length, int unused_bits);

+The following function have been deprecated since OpenSSL 4.1, and can be
+hidden entirely by defining B<OPENSSL_API_COMPAT> with a suitable version value,
+see L<openssl_user_macros(7)>:
+
+  int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length);
+
 =head1 DESCRIPTION

 The ASN.1 BIT STRING type holds a bit string of arbitrary bit length.
@@ -71,6 +78,9 @@ containing bit values in I<length> and the number of unused bits in
 the last octet in I<unused_bits>. The value returned in
 I<unused_bits> is guaranteed to be between 0 and 7, inclusive.

+ASN1_BIT_STRING_set() sets the octets of I<a> to the bits in the
+byte string I<d> of I<length> octets.
+
 ASN1_BIT_STRING_set1() sets the type of I<bitstr> to
 I<V_ASN1_BIT_STRING> and its octets to the bits in the byte string
 I<data> of length I<length> octets, making sure that the last
@@ -99,8 +109,12 @@ ASN1_BIT_STRING_get_length() returns 1 on success or 0 if the encoding
 of I<bitstr> is internally inconsistent, or if one of I<bitstr>,
 I<length>, or I<unused_bits> is NULL.

+ASN1_BIT_STRING_set() returns 1 on success or 0 if memory allocation fails,
+I<length> is not specified (value less than 0) and I<d> is NULL or
+I<length> is larger than INT_MAX-1.
+
 ASN1_BIT_STRING_set1() returns 1 on success or 0 if memory allocation
-fails or if I<bitstr> is NULL , I<length> is too large, I<length>is
+fails or if I<bitstr> is NULL, I<length> is too large, I<length> is
 zero and I<unused_bits> is nonzero, I<unused_bits> is less than 0 or
 greater than 7, or any unused bit in the last octet of I<data> is
 nonzero.
@@ -110,6 +124,9 @@ nonzero.
 Functions ASN1_BIT_STRING_get_length() and ASN1_BIT_STRING_set1() were
 added in OpenSSL version 4.0.

+ASN1_BIT_STRING_set() was deprecated in OpenSSL 4.1 in favour of
+ASN1_BIT_STRING_set1().
+
 =head1 COPYRIGHT

 Copyright 2025-2026 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man7/ossl-guide-migration.pod b/doc/man7/ossl-guide-migration.pod
index 3619c1fe57..b8a981b62d 100644
--- a/doc/man7/ossl-guide-migration.pod
+++ b/doc/man7/ossl-guide-migration.pod
@@ -30,6 +30,13 @@ expose this information. If required the state should be set and get
 via an OSSL_PARAM, bearing in mind that the bounds must be checked if setting
 this value.

+=head3 Deprecation of ASN1_BIT_STRING_set()
+
+This function was deprecated in OpenSSL 4.1 in favour of
+ASN1_BIT_STRING_set1(). The new functions in addition to what
+ASN1_BIT_STRING_set() does, validates the function arguments and sets
+unused bits after setting the BIT STRING value.
+
 =head1 OPENSSL 4.0

 =head2 Main Changes from OpenSSL 3.6
diff --git a/include/openssl/asn1.h.in b/include/openssl/asn1.h.in
index 17075b8a7c..b2e8b501a8 100644
--- a/include/openssl/asn1.h.in
+++ b/include/openssl/asn1.h.in
@@ -545,7 +545,11 @@ int ASN1_STRING_type(const ASN1_STRING *x);
 const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x);

 DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
-int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length);
+#ifndef OPENSSL_NO_DEPRECATED_4_1
+OSSL_DEPRECATEDIN_4_1_FOR("use ASN1_BIT_STRING_set1()")
+int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a,
+    unsigned char *d, int length);
+#endif
 int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value);
 int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n);
 int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
diff --git a/test/ocspapitest.c b/test/ocspapitest.c
index ce8f172494..c4baca4a7d 100644
--- a/test/ocspapitest.c
+++ b/test/ocspapitest.c
@@ -84,7 +84,7 @@ static OCSP_BASICRESP *make_dummy_resp(void)
         || !TEST_true(X509_NAME_add_entry_by_NID(name, NID_commonName,
             MBSTRING_ASC,
             namestr, -1, -1, 1))
-        || !TEST_true(ASN1_BIT_STRING_set(key, keybytes, sizeof(keybytes)))
+        || !TEST_true(ASN1_BIT_STRING_set1(key, keybytes, sizeof(keybytes), 0))
         || !TEST_true(ASN1_INTEGER_set_uint64(serial, (uint64_t)1)))
         goto err;
     cid = OCSP_cert_id_new(EVP_sha256(), name, key, serial);
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 977df0d226..a2205681c2 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -2582,7 +2582,7 @@ i2d_ASN1_BIT_STRING                     2580	4_0_0	EXIST::FUNCTION:
 ASN1_BIT_STRING_free                    2581	4_0_0	EXIST::FUNCTION:
 ASN1_BIT_STRING_new                     2582	4_0_0	EXIST::FUNCTION:
 ASN1_BIT_STRING_it                      2583	4_0_0	EXIST::FUNCTION:
-ASN1_BIT_STRING_set                     2584	4_0_0	EXIST::FUNCTION:
+ASN1_BIT_STRING_set                     2584	4_0_0	EXIST::FUNCTION:DEPRECATEDIN_4_1
 ASN1_BIT_STRING_set_bit                 2585	4_0_0	EXIST::FUNCTION:
 ASN1_BIT_STRING_get_bit                 2586	4_0_0	EXIST::FUNCTION:
 ASN1_BIT_STRING_check                   2587	4_0_0	EXIST::FUNCTION:
diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt
index 652ee6f0d0..69aab337c8 100644
--- a/util/missingcrypto.txt
+++ b/util/missingcrypto.txt
@@ -21,7 +21,6 @@ ASIdentifierChoice_it(3)
 ASIdentifiers_it(3)
 ASN1_ANY_it(3)
 ASN1_BIT_STRING_it(3)
-ASN1_BIT_STRING_set(3)
 ASN1_BMPSTRING_free(3)
 ASN1_BMPSTRING_it(3)
 ASN1_BMPSTRING_new(3)