Package: grpc
Followup-For: Bug #1138463
X-Debbugs-Cc: [email protected]
Control: tags -1 patch ftbfs

Dear Maintainer,

The patch fixes the build issue.

-- 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-117-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 9eaf2c5e572608c63132739c1f17302e6582511e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Svensson?= <[email protected]>
Date: Tue, 24 Mar 2026 12:34:24 +0100
Subject: [PATCH 1/6] tsi: Fix OpenSSL 4.0 compatibility in SSL transport
 security
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Update ssl_transport_security.cc and ssl_transport_security_utils.cc
for OpenSSL 4.0 API changes:

- Add OPENSSL_cleanup() in atexit handler for OpenSSL 4.0+
  OpenSSL 4.0 no longer registers OPENSSL_cleanup() via atexit(),
  so gRPC must call it explicitly after its own shutdown completes.

- Guard ENGINE API usage behind OPENSSL_NO_ENGINE, add OSSL_STORE-based
  private key loading for OpenSSL 3.0+
  OpenSSL 4.0 always defines OPENSSL_NO_ENGINE.

- Replace direct ASN1_OCTET_STRING field access with ASN1_STRING_length()
  and ASN1_STRING_get0_data() accessors for opaque struct in OpenSSL 4.0

- Adapt to const-correctness changes

On OpenSSL 4.0 since ENGINE is gone: "engine:"-prefixed keys will fall
through to ssl_ctx_use_pem_private_key() which will fail with an error.

Signed-off-by: Björn Svensson <[email protected]>

Origin: upstream, https://github.com/grpc/grpc/pull/41932
Bug-Debian: https://bugs.debian.org/1138463
Bug-Ubuntu: https://bugs.launchpad.net/bugs/2155015
---
 src/core/tsi/ssl_transport_security.cc       | 35 ++++++++++++--------
 src/core/tsi/ssl_transport_security_utils.cc | 14 ++++----
 2 files changed, 29 insertions(+), 20 deletions(-)

--- a/test/core/handshake/client_ssl.cc
+++ b/test/core/handshake/client_ssl.cc
@@ -208,13 +208,15 @@
   OpenSSL_add_ssl_algorithms();
   args->ssl_library_info->Notify();
 
-  const SSL_METHOD* method = TLSv1_2_server_method();
+  const SSL_METHOD* method = TLS_server_method();
   SSL_CTX* ctx = SSL_CTX_new(method);
   if (!ctx) {
     perror("Unable to create SSL context");
     ERR_print_errors_fp(stderr);
     abort();
   }
+  SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
+  SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
 
   // Load key pair.
   if (SSL_CTX_use_certificate_file(ctx, SSL_CERT_PATH, SSL_FILETYPE_PEM) < 0) {
--- a/test/core/handshake/server_ssl_common.cc
+++ b/test/core/handshake/server_ssl_common.cc
@@ -196,13 +196,15 @@
   // server port.
   s.Await();
 
-  const SSL_METHOD* method = TLSv1_2_client_method();
+  const SSL_METHOD* method = TLS_client_method();
   SSL_CTX* ctx = SSL_CTX_new(method);
   if (!ctx) {
     perror("Unable to create SSL context");
     ERR_print_errors_fp(stderr);
     abort();
   }
+  SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
+  SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
 
   // Load key pair.
   if (SSL_CTX_use_certificate_file(ctx, SSL_CERT_PATH, SSL_FILETYPE_PEM) < 0) {
--- a/test/core/tsi/ssl_transport_security_test.cc
+++ b/test/core/tsi/ssl_transport_security_test.cc
@@ -25,6 +25,7 @@
 #include <gtest/gtest.h>
 #include <openssl/crypto.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
 #include <openssl/pem.h>
 
 #include <grpc/grpc.h>
@@ -712,7 +713,16 @@
   gpr_log(GPR_INFO, "ssl_tsi_test_do_round_trip_with_error_on_stack");
   // Invoke an SSL function that causes an error, and ensure the error
   // makes it to the stack.
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
   ASSERT_FALSE(EC_KEY_new_by_curve_name(NID_rsa));
+#else
+  // Use EVP_PKEY_CTX with an invalid operation to push an error.
+  EVP_PKEY_CTX* err_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
+  ASSERT_NE(err_ctx, nullptr);
+  // Calling sign_init without a key will fail and push an error.
+  ASSERT_LE(EVP_PKEY_sign_init(err_ctx), 0);
+  EVP_PKEY_CTX_free(err_ctx);
+#endif
   ASSERT_NE(ERR_peek_error(), 0);
   tsi_test_fixture* fixture = ssl_tsi_test_fixture_create();
   tsi_test_do_round_trip(fixture);
--- a/src/core/tsi/ssl_transport_security.cc
+++ b/src/core/tsi/ssl_transport_security.cc
@@ -37,7 +37,9 @@
 
 #include <openssl/bio.h>
 #include <openssl/crypto.h> /* For OPENSSL_free */
+#if !defined(OPENSSL_NO_ENGINE)
 #include <openssl/engine.h>
+#endif
 #include <openssl/err.h>
 #include <openssl/ssl.h>
 #include <openssl/tls1.h>
@@ -270,9 +272,7 @@
 static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
                                            size_t* utf8_size) {
   int common_name_index = -1;
-  X509_NAME_ENTRY* common_name_entry = nullptr;
-  ASN1_STRING* common_name_asn1 = nullptr;
-  X509_NAME* subject_name = X509_get_subject_name(cert);
+  auto* subject_name = X509_get_subject_name(cert);
   int utf8_returned_size = 0;
   if (subject_name == nullptr) {
     gpr_log(GPR_INFO, "Could not get subject name from certificate.");
@@ -284,12 +284,13 @@
     gpr_log(GPR_INFO, "Could not get common name of subject from 
certificate.");
     return TSI_NOT_FOUND;
   }
-  common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
+  auto* common_name_entry =
+      X509_NAME_get_entry(subject_name, common_name_index);
   if (common_name_entry == nullptr) {
     gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
     return TSI_INTERNAL_ERROR;
   }
-  common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
+  auto* common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
   if (common_name_asn1 == nullptr) {
     gpr_log(GPR_ERROR,
             "Could not get common name entry asn1 from certificate.");
@@ -330,7 +331,7 @@
 /* Gets the subject of an X509 cert as a tsi_peer_property. */
 static tsi_result peer_property_from_x509_subject(X509* cert,
                                                   tsi_peer_property* property) 
{
-  X509_NAME* subject_name = X509_get_subject_name(cert);
+  auto* subject_name = X509_get_subject_name(cert);
   if (subject_name == nullptr) {
     gpr_log(GPR_INFO, "Could not get subject name from certificate.");
     return TSI_NOT_FOUND;
@@ -419,17 +420,30 @@
       char ntop_buf[INET6_ADDRSTRLEN];
       int af;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      if (ASN1_STRING_length(subject_alt_name->d.iPAddress) == 4) {
+        af = AF_INET;
+      } else if (ASN1_STRING_length(subject_alt_name->d.iPAddress) == 16) {
+        af = AF_INET6;
+#else
       if (subject_alt_name->d.iPAddress->length == 4) {
         af = AF_INET;
       } else if (subject_alt_name->d.iPAddress->length == 16) {
         af = AF_INET6;
+#endif
       } else {
         gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
         result = TSI_INTERNAL_ERROR;
         break;
       }
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+      const char* name =
+          inet_ntop(af, ASN1_STRING_get0_data(subject_alt_name->d.iPAddress),
+                    ntop_buf, INET6_ADDRSTRLEN);
+#else
       const char* name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
                                    ntop_buf, INET6_ADDRSTRLEN);
+#endif
       if (name == nullptr) {
         gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
         result = TSI_INTERNAL_ERROR;
@@ -776,13 +790,13 @@
       break; /* We're at the end of stream. */
     }
     if (root_names != nullptr) {
-      root_name = X509_get_subject_name(root);
-      if (root_name == nullptr) {
+      auto* root_subject = X509_get_subject_name(root);
+      if (root_subject == nullptr) {
         gpr_log(GPR_ERROR, "Could not get name from root certificate.");
         result = TSI_INVALID_ARGUMENT;
         break;
       }
-      root_name = X509_NAME_dup(root_name);
+      root_name = X509_NAME_dup(const_cast<X509_NAME*>(root_subject));
       if (root_name == nullptr) {
         result = TSI_OUT_OF_RESOURCES;
         break;

Reply via email to