Package: openvpn3-client
Followup-For: Bug #1138369
X-Debbugs-Cc: [email protected]
Control: tags -1 patch ftbfs

Dear Maintainer,

The upstream has a patch of their own. I have attached it.

-- System Information:
Debian Release: trixie/sid
  APT prefers noble-updates
  APT policy: (500, 'noble-updates'), (500, 'noble-security'), (500, 'noble'), 
(100, 'noble-backports')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 6.8.0-124-generic (SMP w/12 CPU threads; PREEMPT)
Kernel taint flags: TAINT_WARN
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
>From 33985a9e6d8941f54eb2d8ddf0c1643d9756e695 Mon Sep 17 00:00:00 2001
From: Arne Schwabe <[email protected]>
Date: Wed, 25 Mar 2026 12:01:35 +0100
Subject: [PATCH] Support OpenSSL 4.0

ASN1 integers are now opaque, so use the proper methods to access them. A
few methods now return const pointers.

Jira: OVPN3-1420
Signed-off-by: Arne Schwabe <[email protected]>

Origin: upstream, 
https://github.com/schwabe/openvpn3/commit/33985a9e6d8941f54eb2d8ddf0c1643d9756e695
Bug-Ubuntu: https://launchpad.net/bugs/2154917
Bug-Debian: https://bugs.debian.org/1138369
Last-Update: 2026-08-04

diff --git a/openvpn3-core/openvpn/openssl/pki/x509certinfo.hpp 
b/openvpn3-core/openvpn/openssl/pki/x509certinfo.hpp
index 9eed7a708..0311e4ea2 100644
--- a/openvpn3-core/openvpn/openssl/pki/x509certinfo.hpp
+++ b/openvpn3-core/openvpn/openssl/pki/x509certinfo.hpp
@@ -29,6 +29,8 @@
 
 namespace openvpn::OpenSSLPKI {
 
+using BIGNUM_ptr = std::unique_ptr<::BIGNUM, decltype(&::BN_free)>;
+
 /**
  *  Retrieve the complete X.509 Certificate Subject field
  *
@@ -137,14 +139,14 @@ static inline std::string x509_get_field(::X509 *cert, 
const int nid)
 {
     static const char nullc = '\0';
     std::string ret;
-    X509_NAME *x509_name = X509_get_subject_name(cert);
+    const X509_NAME *x509_name = X509_get_subject_name(cert);
     int i = X509_NAME_get_index_by_NID(x509_name, nid, -1);
     if (i >= 0)
     {
-        X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
+        const X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
         if (ent)
         {
-            ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent);
+            const ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent);
             unsigned char *buf;
             buf = (unsigned char *)1; // bug in OpenSSL 0.9.6b 
ASN1_STRING_to_UTF8
                                       // requires this workaround
@@ -162,7 +164,9 @@ static inline std::string x509_get_field(::X509 *cert, 
const int nid)
         i = X509_get_ext_by_NID(cert, nid, -1);
         if (i >= 0)
         {
-            X509_EXTENSION *ext = X509_get_ext(cert, i);
+            /* auto is used here to get const with newer OpenSSL 4.0 and 
without const
+             * otherwise to match the call to X509V3_EXT_print */
+            auto *ext = X509_get_ext(cert, i);
             if (ext)
             {
                 BIO *bio = BIO_new(BIO_s_mem());
@@ -194,21 +198,28 @@ static inline std::string x509_get_field(::X509 *cert, 
const int nid)
  *
  * @return Returns the numeric representation of the certificate serial number
  *         as a std::string.
+ *
+ *         In case of failure, an empty string is returned.
  */
 static inline std::string x509_get_serial(::X509 *cert)
 {
     const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
-    BIGNUM *bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
-    char *openssl_serial = BN_bn2dec(bignum);
-    BN_free(bignum);
+    const OpenSSLPKI::BIGNUM_ptr bignum(ASN1_INTEGER_to_BN(asn1_i, nullptr), 
BN_free);
+    if (!bignum)
+    {
+        return {};
+    }
 
-    if (openssl_serial)
+    char *openssl_serial = BN_bn2dec(bignum.get());
+
+    if (!openssl_serial)
     {
-        const std::string ret = openssl_serial;
-        OPENSSL_free(openssl_serial);
-        return ret;
+        return {};
     }
-    return std::string();
+
+    const std::string ret = openssl_serial;
+    OPENSSL_free(openssl_serial);
+    return ret;
 }
 
 /**
@@ -219,11 +230,23 @@ static inline std::string x509_get_serial(::X509 *cert)
  *
  * @return Returns the hexadecimal representation of the certificate
  *         serial number as a std::string.
+ *
+ *         In case of failure, an empty string is returned.
  */
 static inline std::string x509_get_serial_hex(::X509 *cert)
 {
-    const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
-    return render_hex_sep(asn1_i->data, asn1_i->length, ':', false);
+    const ASN1_INTEGER *asn1_i = X509_get0_serialNumber(cert);
+    const OpenSSLPKI::BIGNUM_ptr serial(ASN1_INTEGER_to_BN(asn1_i, nullptr), 
BN_free);
+
+    if (!serial)
+        return {};
+
+    int numbytesoutput = BN_num_bytes(serial.get());
+
+    std::unique_ptr<unsigned char[]> buf(new unsigned char[numbytesoutput]);
+
+    BN_bn2binpad(serial.get(), buf.get(), numbytesoutput);
+    return render_hex_sep(buf.get(), numbytesoutput, ':', false);
 }
 
 /**
diff --git a/openvpn3-core/openvpn/openssl/ssl/sslctx.hpp 
b/openvpn3-core/openvpn/openssl/ssl/sslctx.hpp
index bf612b894..63be115a1 100644
--- a/openvpn3-core/openvpn/openssl/ssl/sslctx.hpp
+++ b/openvpn3-core/openvpn/openssl/ssl/sslctx.hpp
@@ -1824,16 +1824,17 @@ class OpenSSLContext : public SSLFactoryAPI
         const ASN1_INTEGER *ai = X509_get_serialNumber(cert);
         if (!ai)
             return;
-        if (ai->type == V_ASN1_NEG_INTEGER) // negative serial number is 
considered to be undefined
+
+        OpenSSLPKI::BIGNUM_ptr bn(ASN1_INTEGER_to_BN(ai, nullptr), BN_free);
+        if (!bn)
             return;
-        if (!is_safe_conversion<int>(authcert.serial.size()))
+        if (BN_is_negative(bn.get())) // negative serial number is considered 
to be undefined
             return;
-        BIGNUM *bn = ASN1_INTEGER_to_BN(ai, NULL);
-        if (!bn)
+
+        if (!is_safe_conversion<int>(authcert.serial.size()))
             return;
 
-        BN_bn2binpad(bn, authcert.serial.number(), 
static_cast<int>(authcert.serial.size()));
-        BN_free(bn);
+        BN_bn2binpad(bn.get(), authcert.serial.number(), 
static_cast<int>(authcert.serial.size()));
     }
 
     static std::string cert_status_line(int preverify_ok,

Reply via email to