Commit 37246734f6 for openssl.org
commit 37246734f6e824b558b1a267301adee3b0104974
Author: Bob Beck <beck@openssl.org>
Date: Wed Jun 17 19:39:07 2026 -0600
Convert BIO_snprintf() in ossl_ipaddr_to_asc() to snprintf() and guard the loop advance.
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
MergeDate: Wed Aug 26 16:20:22 2026
(Merged from https://github.com/openssl/openssl/pull/31640)
diff --git a/crypto/bio/bio_addr.c b/crypto/bio/bio_addr.c
index a92ce03269..cc80beba5d 100644
--- a/crypto/bio/bio_addr.c
+++ b/crypto/bio/bio_addr.c
@@ -22,6 +22,7 @@
#undef UNICODE
#include <assert.h>
+#include <stdio.h>
#include <string.h>
#include "bio_local.h"
diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c
index 0e78b7b516..88c19ab7d2 100644
--- a/crypto/x509/v3_utl.c
+++ b/crypto/x509/v3_utl.c
@@ -1108,11 +1108,11 @@ char *ossl_ipaddr_to_asc(const unsigned char *p, int len)
break;
case 16: /* IPv6 */
for (out = buf, i = 8, remain = sizeof(buf);
- i-- > 0 && bytes >= 0;
+ i-- > 0 && bytes >= 0 && remain > 0;
remain -= bytes, out += bytes) {
const char *template = (i > 0 ? "%X:" : "%X");
- bytes = BIO_snprintf(out, remain, template, p[0] << 8 | p[1]);
+ bytes = snprintf(out, remain, template, p[0] << 8 | p[1]);
p += 2;
}
break;
diff --git a/test/x509_internal_test.c b/test/x509_internal_test.c
index c68e44d118..1c266ad0d1 100644
--- a/test/x509_internal_test.c
+++ b/test/x509_internal_test.c
@@ -16,6 +16,7 @@
#include <openssl/x509v3.h>
#include <openssl/x509_vfy.h>
#include "testutil.h"
+#include "internal/cryptlib.h"
#include "internal/nelem.h"
#include "crypto/x509.h"
@@ -172,6 +173,64 @@ static int test_a2i_ipaddress(int idx)
return good;
}
+/**
+ * @struct ip_asc_testdata_st
+ * @brief One ossl_ipaddr_to_asc() case: input bytes and expected output.
+ */
+typedef struct ip_asc_testdata_st {
+ const char *data; /**< The address bytes to convert */
+ int length; /**< The number of bytes at data */
+ const char *expected; /**< The string the conversion should produce */
+} IP_ASC_TESTDATA;
+
+/*-
+ * ossl_ipaddr_to_asc() is not the inverse of a2i_IPADDRESS(): it neither
+ * elides a run of zero groups as "::" nor emits lowercase hex, so the
+ * expected strings below are not the RFC 5952 canonical presentation
+ * forms of these addresses.
+ */
+static IP_ASC_TESTDATA ipaddr_to_asc_tests[] = {
+ { "\x7f\x00\x00\x01", 4, "127.0.0.1" },
+ { "\x01\x02\x03\x04", 4, "1.2.3.4" },
+ { "\xff\xff\xff\xff", 4, "255.255.255.255" },
+
+ { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16,
+ "0:0:0:0:0:0:0:0" },
+ { "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", 16,
+ "0:0:0:0:0:0:0:1" },
+ { "\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\xff\x00\x00\x42\x83\x29", 16,
+ "2001:DB8:0:0:0:FF00:42:8329" },
+
+ /*
+ * The longest output ossl_ipaddr_to_asc() can produce: 39 characters
+ * and a nul exactly fill its 40-byte buffer, so the last group is
+ * written with no room to spare. A truncation guard that is off by
+ * one drops that group.
+ */
+ { "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 16,
+ "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF" },
+
+ /* Only 4 and 16 are addresses; every other length is reported back. */
+ { "", 0, "<invalid length=0>" },
+ { "\x01\x02\x03", 3, "<invalid length=3>" },
+ { "\x01\x02\x03\x04\x05", 5, "<invalid length=5>" },
+};
+
+/**
+ * @brief Check ossl_ipaddr_to_asc() against one ipaddr_to_asc_tests entry.
+ * @param idx index into ipaddr_to_asc_tests of the case to run
+ * @returns 1 if the conversion produced the expected string, 0 otherwise
+ */
+static int test_ipaddr_to_asc(int idx)
+{
+ const IP_ASC_TESTDATA *t = &ipaddr_to_asc_tests[idx];
+ char *asc = ossl_ipaddr_to_asc((const unsigned char *)t->data, t->length);
+ int good = TEST_ptr(asc) && TEST_str_eq(asc, t->expected);
+
+ OPENSSL_free(asc);
+ return good;
+}
+
static int ck_purp(ossl_unused const X509_PURPOSE *purpose,
ossl_unused const X509 *x, int ca)
{
@@ -990,6 +1049,7 @@ int setup_tests(void)
{
ADD_TEST(test_standard_exts);
ADD_ALL_TESTS(test_a2i_ipaddress, OSSL_NELEM(a2i_ipaddress_tests));
+ ADD_ALL_TESTS(test_ipaddr_to_asc, OSSL_NELEM(ipaddr_to_asc_tests));
ADD_TEST(tests_X509_PURPOSE);
ADD_TEST(tests_X509_check_time);
ADD_TEST(tests_X509_check_crypto);