From 1333485be89dfb7256ca145e971a90d8d6c4863d Mon Sep 17 00:00:00 2001 From: Eric Blankenhorn Date: Fri, 30 Oct 2026 14:41:30 -0500 Subject: [PATCH] Fix IPv6 text rendering in X509_VERIFY_PARAM_set1_ip --- src/x509.c | 70 +++++++++++++++++++---------------- tests/api/test_ossl_x509_vp.c | 31 ++++++++++++++++ 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/src/x509.c b/src/x509.c index 62159e99aac..ac020b39c95 100644 --- a/src/x509.c +++ b/src/x509.c @@ -11608,11 +11608,15 @@ int wolfSSL_X509_VERIFY_PARAM_set1_ip(WOLFSSL_X509_VERIFY_PARAM* param, int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); #ifndef NO_FILESYSTEM char* buf = NULL; - char* p = NULL; word32 val = 0; int i; + int n; + int runStart = 0; + int runLen = 0; + int zeroStart = -1; + int zeroLen = 0; + size_t idx = 0; const size_t max_ipv6_len = 40; - byte write_zero = 0; #endif /* sanity check */ @@ -11667,43 +11671,47 @@ int wolfSSL_X509_VERIFY_PARAM_set1_ip(WOLFSSL_X509_VERIFY_PARAM* param, WOLFSSL_MSG("failed malloc"); return ret; } - p = buf; - for (i = 0; i < 16; i += 2) { - val = (((word32)(ip[i]<<8)) | (ip[i+1])) & 0xFFFF; - if (val == 0) { - if (!write_zero) { - *p = ':'; + /* RFC 5952 4.2: compress only the first longest run of two or more + * zero groups, every other zero group is written as 0. */ + for (i = 0; i < 8; i++) { + if (ip[2 * i] == 0 && ip[2 * i + 1] == 0) { + if (runLen == 0) + runStart = i; + runLen++; + if (runLen > zeroLen) { + zeroStart = runStart; + zeroLen = runLen; } - p++; - *p = '\0'; - write_zero = 1; } else { - if (i != 0) { - *p++ = ':'; - } - (void)XSNPRINTF(p, max_ipv6_len - (size_t)(p - buf), "%x", val); + runLen = 0; + } + } + if (zeroLen < 2) { + zeroStart = -1; + zeroLen = 0; + } + + for (i = 0; i < 8 && buf != NULL; i++) { + if (i == zeroStart) { + n = XSNPRINTF(buf + idx, max_ipv6_len - idx, "::"); } - /* sanity check */ - if (XSTRLEN(buf) > max_ipv6_len) { + else if (i > zeroStart && i < zeroStart + zeroLen) { + n = 0; + } + else { + val = ((word32)ip[2 * i] << 8) | ip[2 * i + 1]; + n = XSNPRINTF(buf + idx, max_ipv6_len - idx, "%s%x", + (i == 0 || i == zeroStart + zeroLen) ? "" : ":", + (unsigned int)val); + } + if (n < 0 || (size_t)n >= max_ipv6_len - idx) { WOLFSSL_MSG("The target ip address exceeds buffer length(40)"); XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); buf = NULL; - break; } - /* move the pointer to the last */ - /* XSTRLEN includes NULL because of XSPRINTF use */ - p = buf + (XSTRLEN(buf)); - } - /* termination */ - if (i == 16 && buf) { - p--; - if ((*p) == ':') { - /* when the last character is :, the following segments are zero - * Therefore, adding : and null termination */ - p++; - *p++ = ':'; - *p = '\0'; + else { + idx += (size_t)n; } } } diff --git a/tests/api/test_ossl_x509_vp.c b/tests/api/test_ossl_x509_vp.c index 858dff87368..f9b1f966f30 100644 --- a/tests/api/test_ossl_x509_vp.c +++ b/tests/api/test_ossl_x509_vp.c @@ -250,6 +250,30 @@ int test_wolfSSL_X509_VERIFY_PARAM_set1_ip(void) #if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) unsigned char buf[16] = {0}; WOLFSSL_X509_VERIFY_PARAM* param = NULL; + int i; + static const struct { + unsigned char ip[16]; + const char* asc; + } ip6Tests[] = { + { { 0x20,0x01, 0x0d,0xb8, 0,0, 0,1, 0,0, 0,0, 0,0, 0,5 }, + "2001:db8:0:1::5" }, + { { 0x20,0x01, 0x0d,0xb8, 0,0, 0,1, 0,0, 0,0, 0,0, 0,0 }, + "2001:db8:0:1::" }, + { { 0,1, 0,0, 0,0, 0,2, 0,0, 0,0, 0,0, 0,3 }, + "1:0:0:2::3" }, + { { 0,0, 0,0, 0,0, 0,0, 0,1, 0,0, 0,0, 0,2 }, + "::1:0:0:2" }, + /* equal length runs compress the first one */ + { { 0,1, 0,0, 0,0, 0,2, 0,0, 0,0, 0,3, 0,4 }, + "1::2:0:0:3:4" }, + /* a single zero group is not compressed */ + { { 0x20,0x01, 0x0d,0xb8, 0,0, 0,1, 0,2, 0,3, 0,4, 0,5 }, + "2001:db8:0:1:2:3:4:5" }, + { { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }, + "::" }, + { { 0,0, 0,1, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }, + "0:1::" } + }; ExpectNotNull(param = X509_VERIFY_PARAM_new()); @@ -318,6 +342,13 @@ int test_wolfSSL_X509_VERIFY_PARAM_set1_ip(void) ExpectIntEQ(XSTRNCMP(param->ipasc, "2001:db8:1::ab9:c0a8:102", sizeof(param->ipasc)), 0); + /* Addresses with more than one zero run must not drop the later runs */ + for (i = 0; i < (int)(sizeof(ip6Tests) / sizeof(ip6Tests[0])); i++) { + ExpectIntEQ(X509_VERIFY_PARAM_set1_ip(param, ip6Tests[i].ip, 16), + SSL_SUCCESS); + ExpectStrEQ(param->ipasc, ip6Tests[i].asc); + } + XFREE(param, HEAP_HINT, DYNAMIC_TYPE_OPENSSL); #endif /* OPENSSL_EXTRA */ return EXPECT_RESULT();