From 0f30790c9b31694bef01d6c4ce2352712fe6e8c8 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Fri, 27 Mar 2026 17:17:29 +0100 Subject: [PATCH 1/2] openssl compat: fix ASN1_STRING_{length,get0_data} for ASN1_INTEGER In OpenSSL, ASN1_INTEGER is typedef'd to ASN1_STRING (same struct), so calling ASN1_STRING_length() / ASN1_STRING_get0_data() on an ASN1_INTEGER* is valid and well-defined. wolfSSL has them as distinct, incompatible structs. This fixes the openvpn master failures introduced in https://github.com/OpenVPN/openvpn/pull/1003 --- src/ssl_asn1.c | 48 +++++++++++++++++++++++++++++++++++++++++++ wolfssl/openssl/ssl.h | 21 +++++++++++++++++++ wolfssl/ssl.h | 3 +++ 3 files changed, 72 insertions(+) diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index ca3c699fef5..4f9d12647fc 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -1000,6 +1000,54 @@ void wolfSSL_ASN1_INTEGER_free(WOLFSSL_ASN1_INTEGER* in) XFREE(in, NULL, DYNAMIC_TYPE_OPENSSL); } +/* Get the length of the raw integer value bytes, stripping the DER tag/length + * header if present. Required for OpenSSL compatibility where ASN1_INTEGER is + * typedef'd to ASN1_STRING and callers use ASN1_STRING_length() on integers. + * + * @param [in] ai ASN.1 INTEGER object. + * @return Length of the raw integer value on success. + * @return 0 when ai is NULL or data is invalid. + */ +int wolfSSL_ASN1_INTEGER_get_length(const WOLFSSL_ASN1_INTEGER* ai) +{ + if (ai == NULL || ai->data == NULL || ai->length <= 0) { + return 0; + } + if (ai->data[0] == ASN_INTEGER) { + word32 idx = 1; + int len = 0; + if (GetLength(ai->data, &idx, &len, (word32)ai->length) > 0) { + return len; + } + } + /* WOLFSSL_QT / WOLFSSL_HAPROXY format: raw bytes without DER header */ + return ai->length; +} + +/* Get a pointer to the raw integer value bytes, skipping the DER tag/length + * header if present. Required for OpenSSL compatibility where ASN1_INTEGER is + * typedef'd to ASN1_STRING and callers use ASN1_STRING_get0_data() on integers. + * + * @param [in] ai ASN.1 INTEGER object. + * @return Pointer to the raw integer value bytes on success. + * @return NULL when ai is NULL or data is invalid. + */ +const unsigned char* wolfSSL_ASN1_INTEGER_get0_data(const WOLFSSL_ASN1_INTEGER* ai) +{ + if (ai == NULL || ai->data == NULL || ai->length <= 0) { + return NULL; + } + if (ai->data[0] == ASN_INTEGER) { + word32 idx = 1; + int len = 0; + if (GetLength(ai->data, &idx, &len, (word32)ai->length) > 0) { + return ai->data + idx; + } + } + /* WOLFSSL_QT / WOLFSSL_HAPROXY format: raw bytes without DER header */ + return ai->data; +} + #if defined(OPENSSL_EXTRA) /* Reset the data of ASN.1 INTEGER object back to empty fixed array. * diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 2d4d6aaadda..e1304aa27be 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -1022,8 +1022,29 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define ASN1_STRING_cmp wolfSSL_ASN1_STRING_cmp #define ASN1_OCTET_STRING_cmp wolfSSL_ASN1_STRING_cmp #define ASN1_STRING_data wolfSSL_ASN1_STRING_data +/* In OpenSSL, ASN1_INTEGER and ASN1_BIT_STRING are typedef aliases of + * ASN1_STRING (same struct), so ASN1_STRING_length/get0_data work on all. + * In wolfSSL they are distinct structs, so dispatch by type using _Generic. */ +#if !defined(__cplusplus) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 201112L +#define ASN1_STRING_length(x) _Generic((x), \ + WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get_length( \ + (const WOLFSSL_ASN1_INTEGER*)(x)), \ + const WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get_length( \ + (const WOLFSSL_ASN1_INTEGER*)(x)), \ + default: wolfSSL_ASN1_STRING_length( \ + (const WOLFSSL_ASN1_STRING*)(x))) +#define ASN1_STRING_get0_data(x) _Generic((x), \ + WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get0_data( \ + (const WOLFSSL_ASN1_INTEGER*)(x)), \ + const WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get0_data( \ + (const WOLFSSL_ASN1_INTEGER*)(x)), \ + default: wolfSSL_ASN1_STRING_get0_data( \ + (const WOLFSSL_ASN1_STRING*)(x))) +#else #define ASN1_STRING_get0_data wolfSSL_ASN1_STRING_get0_data #define ASN1_STRING_length wolfSSL_ASN1_STRING_length +#endif #define ASN1_STRING_to_UTF8 wolfSSL_ASN1_STRING_to_UTF8 #define ASN1_UNIVERSALSTRING_to_string wolfSSL_ASN1_UNIVERSALSTRING_to_string #define ASN1_STRING_print_ex wolfSSL_ASN1_STRING_print_ex diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 1c0301ab66e..df5e2723657 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -2356,6 +2356,9 @@ WOLFSSL_API unsigned char* wolfSSL_ASN1_STRING_data(WOLFSSL_ASN1_STRING* asn); WOLFSSL_API const unsigned char* wolfSSL_ASN1_STRING_get0_data( const WOLFSSL_ASN1_STRING* asn); WOLFSSL_API int wolfSSL_ASN1_STRING_length(const WOLFSSL_ASN1_STRING* asn); +WOLFSSL_API int wolfSSL_ASN1_INTEGER_get_length(const WOLFSSL_ASN1_INTEGER* ai); +WOLFSSL_API const unsigned char* wolfSSL_ASN1_INTEGER_get0_data( + const WOLFSSL_ASN1_INTEGER* ai); WOLFSSL_API int wolfSSL_ASN1_STRING_copy(WOLFSSL_ASN1_STRING* dst, const WOLFSSL_ASN1_STRING* src); WOLFSSL_API int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx); From 22717a4672e965626c5d4c6f4b7cb03fe3f2375e Mon Sep 17 00:00:00 2001 From: Lealem Amedie Date: Fri, 27 Mar 2026 16:35:42 -0600 Subject: [PATCH 2/2] Address copilot feedback --- src/ssl_asn1.c | 14 ++++++++++---- wolfssl/openssl/ssl.h | 30 ++++++++++++++---------------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 4f9d12647fc..6a46c25d530 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -1016,11 +1016,14 @@ int wolfSSL_ASN1_INTEGER_get_length(const WOLFSSL_ASN1_INTEGER* ai) if (ai->data[0] == ASN_INTEGER) { word32 idx = 1; int len = 0; - if (GetLength(ai->data, &idx, &len, (word32)ai->length) > 0) { + if (GetLength(ai->data, &idx, &len, (word32)ai->length) > 0 && + idx + (word32)len == (word32)ai->length) { return len; } } - /* WOLFSSL_QT / WOLFSSL_HAPROXY format: raw bytes without DER header */ + /* WOLFSSL_QT / WOLFSSL_HAPROXY format: raw bytes without DER header, + * or data that coincidentally starts with 0x02 but whose header+value + * boundaries do not span exactly ai->length. */ return ai->length; } @@ -1040,11 +1043,14 @@ const unsigned char* wolfSSL_ASN1_INTEGER_get0_data(const WOLFSSL_ASN1_INTEGER* if (ai->data[0] == ASN_INTEGER) { word32 idx = 1; int len = 0; - if (GetLength(ai->data, &idx, &len, (word32)ai->length) > 0) { + if (GetLength(ai->data, &idx, &len, (word32)ai->length) > 0 && + idx + (word32)len == (word32)ai->length) { return ai->data + idx; } } - /* WOLFSSL_QT / WOLFSSL_HAPROXY format: raw bytes without DER header */ + /* WOLFSSL_QT / WOLFSSL_HAPROXY format: raw bytes without DER header, + * or data that coincidentally starts with 0x02 but whose header+value + * boundaries do not span exactly ai->length. */ return ai->data; } diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index e1304aa27be..063500675e1 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -1022,25 +1022,23 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define ASN1_STRING_cmp wolfSSL_ASN1_STRING_cmp #define ASN1_OCTET_STRING_cmp wolfSSL_ASN1_STRING_cmp #define ASN1_STRING_data wolfSSL_ASN1_STRING_data -/* In OpenSSL, ASN1_INTEGER and ASN1_BIT_STRING are typedef aliases of - * ASN1_STRING (same struct), so ASN1_STRING_length/get0_data work on all. +/* In OpenSSL, ASN1_INTEGER is a typedef alias of ASN1_STRING (same struct), + * so ASN1_STRING_length/get0_data work on ASN1_INTEGER* as well. * In wolfSSL they are distinct structs, so dispatch by type using _Generic. */ #if !defined(__cplusplus) && defined(__STDC_VERSION__) && \ __STDC_VERSION__ >= 201112L -#define ASN1_STRING_length(x) _Generic((x), \ - WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get_length( \ - (const WOLFSSL_ASN1_INTEGER*)(x)), \ - const WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get_length( \ - (const WOLFSSL_ASN1_INTEGER*)(x)), \ - default: wolfSSL_ASN1_STRING_length( \ - (const WOLFSSL_ASN1_STRING*)(x))) -#define ASN1_STRING_get0_data(x) _Generic((x), \ - WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get0_data( \ - (const WOLFSSL_ASN1_INTEGER*)(x)), \ - const WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get0_data( \ - (const WOLFSSL_ASN1_INTEGER*)(x)), \ - default: wolfSSL_ASN1_STRING_get0_data( \ - (const WOLFSSL_ASN1_STRING*)(x))) +#define ASN1_STRING_length(x) \ + _Generic((x), \ + WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get_length, \ + const WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get_length, \ + default: wolfSSL_ASN1_STRING_length \ + )(x) +#define ASN1_STRING_get0_data(x) \ + _Generic((x), \ + WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get0_data, \ + const WOLFSSL_ASN1_INTEGER*: wolfSSL_ASN1_INTEGER_get0_data, \ + default: wolfSSL_ASN1_STRING_get0_data \ + )(x) #else #define ASN1_STRING_get0_data wolfSSL_ASN1_STRING_get0_data #define ASN1_STRING_length wolfSSL_ASN1_STRING_length