package/grpc: fix build with OpenSSL 4.0.0

Signed-off-by: Bernd Kuhls <bernd@kuhls.net>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
This commit is contained in:
Bernd Kuhls
2026-09-27 12:42:24 +02:00
committed by Thomas Petazzoni
parent e2f49a31c8
commit ce1bde641b

View File

@@ -0,0 +1,327 @@
From fb056ab0bb3ed003febe82f069ff41514288a4f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Svensson?= <bjorn.a.svensson@est.tech>
Date: Mon, 31 Aug 2026 09:52:46 -0700
Subject: [PATCH] [OpenSSL] Add support for OpenSSL 4 (#41932)
OpenSSL 4.0 removes several deprecated APIs and changes return types of various getter functions to `const`.
This PR fixes all affected code in gRPC's SSL transport layer, credentials, and tests.
To handle the `const` return type differences across OpenSSL versions without version-specific `#if` guards at every call site, `auto*` is used to let the compiler deduce the correct type.
Where downstream serialization and copy functions (`i2d_X509_NAME`, `i2d_ASN1_OCTET_STRING`, `X509_NAME_dup`) have not yet been constified, `const_cast` is used at the call site to bridge the gap. These functions only read the data, so the cast is safe.
Tested by building and running SSL tests against BoringSSL and OpenSSL 1.0.2u, 1.1.1w, 3.0.13, and 4.0.0.
Each commit message in this PR has some more details.
RELEASE NOTES:
* Add OpenSSL 4.0 compatibility.
Closes #41932
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/41932 from Nordix:openssl4 c2edc3d46ab7e87ced5d9d95710885a8a8c7a3e2
PiperOrigin-RevId: 973935241
Upstream: https://github.com/grpc/grpc/commit/fb056ab0bb3ed003febe82f069ff41514288a4f3
Signed-off-by: Bernd Kuhls <bernd@kuhls.net>
---
.../call/external/aws_request_signer.cc | 16 ++++++++++
.../transport/tls/grpc_tls_crl_provider.cc | 4 +--
src/core/tsi/ssl_transport_security.cc | 32 +++++++++++++------
src/core/tsi/ssl_transport_security_utils.cc | 14 ++++----
test/core/handshake/client_ssl.cc | 4 ++-
test/core/handshake/server_ssl_common.cc | 4 ++-
test/core/tsi/ssl_transport_security_test.cc | 10 ++++++
7 files changed, 65 insertions(+), 19 deletions(-)
diff --git a/src/core/credentials/call/external/aws_request_signer.cc b/src/core/credentials/call/external/aws_request_signer.cc
index f7fb7a25b1d0b..d3f506d095abf 100644
--- a/src/core/credentials/call/external/aws_request_signer.cc
+++ b/src/core/credentials/call/external/aws_request_signer.cc
@@ -18,12 +18,15 @@
#include <grpc/support/port_platform.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
#include <openssl/hmac.h>
+#endif
#include <openssl/sha.h>
#include <utility>
#include <vector>
+#include "src/core/util/grpc_check.h"
#include "absl/status/statusor.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
@@ -41,6 +44,7 @@ namespace {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
const char kSha256[] = "SHA256";
+const char kHmacName[] = "HMAC";
#endif
const char kAlgorithm[] = "AWS4-HMAC-SHA256";
const char kDateFormat[] = "%a, %d %b %E4Y %H:%M:%S %Z";
@@ -67,12 +71,24 @@ std::string SHA256Hex(const std::string& str) {
}
std::string HMAC(const std::string& key, const std::string& msg) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
unsigned int len;
unsigned char digest[EVP_MAX_MD_SIZE];
HMAC(EVP_sha256(), key.c_str(), key.length(),
reinterpret_cast<const unsigned char*>(msg.c_str()), msg.length(),
digest, &len);
return std::string(digest, digest + len);
+#else
+ size_t len = 0;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ GRPC_CHECK_NE(EVP_Q_mac(nullptr, kHmacName, nullptr, kSha256, nullptr,
+ reinterpret_cast<const unsigned char*>(key.c_str()),
+ key.length(),
+ reinterpret_cast<const unsigned char*>(msg.c_str()),
+ msg.length(), digest, sizeof(digest), &len),
+ nullptr);
+ return std::string(digest, digest + len);
+#endif
}
} // namespace
diff --git a/src/core/credentials/transport/tls/grpc_tls_crl_provider.cc b/src/core/credentials/transport/tls/grpc_tls_crl_provider.cc
index 5e24c18ee6127..dc95ba8457121 100644
--- a/src/core/credentials/transport/tls/grpc_tls_crl_provider.cc
+++ b/src/core/credentials/transport/tls/grpc_tls_crl_provider.cc
@@ -56,12 +56,12 @@ absl::StatusOr<std::string> IssuerFromCrl(X509_CRL* crl) {
if (crl == nullptr) {
return absl::InvalidArgumentError("crl cannot be null");
}
- X509_NAME* issuer = X509_CRL_get_issuer(crl);
+ auto* issuer = X509_CRL_get_issuer(crl);
if (issuer == nullptr) {
return absl::InvalidArgumentError("crl cannot have null issuer");
}
unsigned char* buf = nullptr;
- int len = i2d_X509_NAME(issuer, &buf);
+ int len = i2d_X509_NAME(const_cast<X509_NAME*>(issuer), &buf);
if (len < 0 || buf == nullptr) {
return absl::InvalidArgumentError("crl cannot have null issuer");
}
diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc
index 6c1f20ebb5374..29ec47eeeef41 100644
--- a/src/core/tsi/ssl_transport_security.cc
+++ b/src/core/tsi/ssl_transport_security.cc
@@ -49,7 +49,9 @@
#include <grpc/support/thd_id.h>
#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>
@@ -1021,9 +1023,7 @@ static int looks_like_ip_address(absl::string_view name) {
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) {
VLOG(2) << "Could not get subject name from certificate.";
@@ -1035,12 +1035,13 @@ static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
VLOG(2) << "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) {
LOG(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) {
LOG(ERROR) << "Could not get common name entry asn1 from certificate.";
return TSI_INTERNAL_ERROR;
@@ -1081,7 +1082,7 @@ static tsi_result peer_property_from_x509_common_name(
static tsi_result peer_property_from_x509_subject(X509* cert,
tsi_peer_property* property,
bool is_verified_root_cert) {
- X509_NAME* subject_name = X509_get_subject_name(cert);
+ auto* subject_name = X509_get_subject_name(cert);
if (subject_name == nullptr) {
GRPC_TRACE_LOG(tsi, INFO) << "Could not get subject name from certificate.";
return TSI_NOT_FOUND;
@@ -1177,17 +1178,30 @@ static tsi_result add_subject_alt_names_properties_to_peer(
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 {
LOG(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) {
LOG(ERROR) << "Could not get IP string from asn1 octet.";
result = TSI_INTERNAL_ERROR;
@@ -1472,13 +1486,13 @@ static tsi_result x509_store_load_certs(X509_STORE* cert_store,
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) {
LOG(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;
diff --git a/src/core/tsi/ssl_transport_security_utils.cc b/src/core/tsi/ssl_transport_security_utils.cc
index 7318bc3f78057..9bf292821565c 100644
--- a/src/core/tsi/ssl_transport_security_utils.cc
+++ b/src/core/tsi/ssl_transport_security_utils.cc
@@ -282,11 +282,11 @@ bool VerifyCrlCertIssuerNamesMatch(X509_CRL* crl, X509* cert) {
if (cert == nullptr || crl == nullptr) {
return false;
}
- X509_NAME* cert_issuer_name = X509_get_issuer_name(cert);
+ auto* cert_issuer_name = X509_get_issuer_name(cert);
if (cert_issuer_name == nullptr) {
return false;
}
- X509_NAME* crl_issuer_name = X509_CRL_get_issuer(crl);
+ auto* crl_issuer_name = X509_CRL_get_issuer(crl);
if (crl_issuer_name == nullptr) {
return false;
}
@@ -317,9 +317,9 @@ absl::StatusOr<std::string> IssuerFromCert(X509* cert) {
if (cert == nullptr) {
return absl::InvalidArgumentError("cert cannot be null");
}
- X509_NAME* issuer = X509_get_issuer_name(cert);
+ auto* issuer = X509_get_issuer_name(cert);
unsigned char* buf = nullptr;
- int len = i2d_X509_NAME(issuer, &buf);
+ int len = i2d_X509_NAME(const_cast<X509_NAME*>(issuer), &buf);
if (len < 0 || buf == nullptr) {
return absl::InvalidArgumentError("could not read issuer name from cert");
}
@@ -339,7 +339,8 @@ absl::StatusOr<std::string> AkidFromCertificate(X509* cert) {
if (X509_get_ext_by_NID(cert, NID_authority_key_identifier, j) != -1) {
return absl::InvalidArgumentError("Could not get AKID from certificate.");
}
- akid = X509_EXTENSION_get_data(X509_get_ext(cert, j));
+ akid = const_cast<ASN1_OCTET_STRING*>(
+ X509_EXTENSION_get_data(X509_get_ext(cert, j)));
} else {
return absl::InvalidArgumentError("Could not get AKID from certificate.");
}
@@ -364,7 +365,8 @@ absl::StatusOr<std::string> AkidFromCrl(X509_CRL* crl) {
if (X509_CRL_get_ext_by_NID(crl, NID_authority_key_identifier, j) != -1) {
return absl::InvalidArgumentError("Could not get AKID from crl.");
}
- akid = X509_EXTENSION_get_data(X509_CRL_get_ext(crl, j));
+ akid = const_cast<ASN1_OCTET_STRING*>(
+ X509_EXTENSION_get_data(X509_CRL_get_ext(crl, j)));
} else {
return absl::InvalidArgumentError("Could not get AKID from crl.");
}
diff --git a/test/core/handshake/client_ssl.cc b/test/core/handshake/client_ssl.cc
index 1952c6055094f..c985c0de926f1 100644
--- a/test/core/handshake/client_ssl.cc
+++ b/test/core/handshake/client_ssl.cc
@@ -197,13 +197,15 @@ static void server_thread(void* arg) {
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) {
diff --git a/test/core/handshake/server_ssl_common.cc b/test/core/handshake/server_ssl_common.cc
index ece1b6f50109e..7cb8f95e578f3 100644
--- a/test/core/handshake/server_ssl_common.cc
+++ b/test/core/handshake/server_ssl_common.cc
@@ -187,13 +187,15 @@ bool server_ssl_test(const char* alpn_list[], unsigned int alpn_list_len,
// 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) {
diff --git a/test/core/tsi/ssl_transport_security_test.cc b/test/core/tsi/ssl_transport_security_test.cc
index 806495f87ccca..8c3f4677495ec 100644
--- a/test/core/tsi/ssl_transport_security_test.cc
+++ b/test/core/tsi/ssl_transport_security_test.cc
@@ -23,6 +23,7 @@
#include <grpc/support/string_util.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
+#include <openssl/evp.h>
#include <openssl/pem.h>
#include <stdbool.h>
#include <stdio.h>
@@ -985,7 +986,16 @@ TEST_P(SslTransportSecurityTest, DoRoundTripForAllConfigs) {
TEST_P(SslTransportSecurityTest, DoRoundTripWithErrorOnStack) {
// 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);
SetUpSslFixture(/*tls_version=*/std::get<0>(GetParam()),
/*send_client_ca_list=*/std::get<1>(GetParam()));