diff --git a/example/plugins/c-api/client_context_dump/client_context_dump.cc b/example/plugins/c-api/client_context_dump/client_context_dump.cc index f8572d775ce..6dcb94919bb 100644 --- a/example/plugins/c-api/client_context_dump/client_context_dump.cc +++ b/example/plugins/c-api/client_context_dump/client_context_dump.cc @@ -65,7 +65,7 @@ dump_context(const char *ca_path, const char *ck_path) // expiration date, serial number, common name, and subject alternative names const ASN1_TIME *not_after = X509_get_notAfter(cert); const ASN1_INTEGER *serial = X509_get_serialNumber(cert); - X509_NAME *subject_name = X509_get_subject_name(cert); + auto *subject_name = X509_get_subject_name(cert); // Subject name BIO *subject_bio = BIO_new(BIO_s_mem()); diff --git a/include/cripts/Certs.hpp b/include/cripts/Certs.hpp index f19fb8f41b0..19e94c3a09e 100644 --- a/include/cripts/Certs.hpp +++ b/include/cripts/Certs.hpp @@ -107,10 +107,17 @@ class CertBase } } - void _load_name(X509_NAME *(*getter)(const X509 *)) const; + // OpenSSL 4.0 returns a pointer to const from X509_get_subject_name() and + // X509_get_issuer_name(), and dropped the const from the X509 parameter of + // X509_get_notBefore()/X509_get_notAfter(). Deduce the function pointer types so + // these match on any OpenSSL version. + using NameGetter = decltype(&X509_get_subject_name); + using TimeGetter = decltype(&X509_get_notBefore); + + void _load_name(NameGetter getter) const; void _load_integer(ASN1_INTEGER *(*getter)(X509 *)) const; void _load_long(long (*getter)(const X509 *)) const; - void _load_time(ASN1_TIME *(*getter)(const X509 *)) const; + void _load_time(TimeGetter getter) const; CertBase *_owner = nullptr; mutable std::unique_ptr _bio{nullptr, BIO_free}; diff --git a/plugins/certifier/certifier.cc b/plugins/certifier/certifier.cc index 563a39bd40f..4915333c51f 100644 --- a/plugins/certifier/certifier.cc +++ b/plugins/certifier/certifier.cc @@ -88,10 +88,11 @@ template <> struct default_delete { } // namespace std /// Name aliases for unique pts to openSSL objects -using scoped_X509 = std::unique_ptr; -using scoped_X509_REQ = std::unique_ptr; -using scoped_EVP_PKEY = std::unique_ptr; -using scoped_SSL_CTX = std::unique_ptr; +using scoped_X509 = std::unique_ptr; +using scoped_X509_REQ = std::unique_ptr; +using scoped_EVP_PKEY = std::unique_ptr; +using scoped_SSL_CTX = std::unique_ptr; +using scoped_X509_NAME = std::unique_ptr; class SslLRUList { @@ -400,13 +401,22 @@ mkcrt(const std::string &commonName, int serial) X509_gmtime_adj(X509_get_notBefore(cert.get()), 0); X509_gmtime_adj(X509_get_notAfter(cert.get()), static_cast(3650) * 24 * 3600); - // Get handle to subject name - X509_NAME *n = X509_get_subject_name(cert.get()); + // Get a mutable copy of the subject name. OpenSSL 4.0 returns a pointer to const + // from X509_get_subject_name(), so the name cannot be modified in place. + scoped_X509_NAME n{X509_NAME_dup(X509_get_subject_name(cert.get())), X509_NAME_free}; + if (n == nullptr) { + TSError("[%s] %s: failed to duplicate certificate subject", PLUGIN_NAME, __func__); + return nullptr; + } // Set common name field - if (X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, (unsigned char *)commonName.c_str(), -1, -1, 0) != 1) { + if (X509_NAME_add_entry_by_txt(n.get(), "CN", MBSTRING_ASC, (unsigned char *)commonName.c_str(), -1, -1, 0) != 1) { TSError("[%s] %s: failed to add certificate subject CN", PLUGIN_NAME, __func__); return nullptr; } + if (X509_set_subject_name(cert.get(), n.get()) != 1) { + TSError("[%s] %s: failed to set certificate subject", PLUGIN_NAME, __func__); + return nullptr; + } // Set Traffic Server public key if (X509_set_pubkey(cert.get(), ca_pkey_scoped.get()) == 0) { diff --git a/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc b/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc index fd1d49f1486..3613508890a 100644 --- a/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc +++ b/plugins/experimental/cert_reporting_tool/cert_reporting_tool.cc @@ -65,7 +65,7 @@ dump_context(const char *ca_path, const char *ck_path) // expiration date, serial number, common name, and subject alternative names const ASN1_TIME *not_after = X509_get_notAfter(cert); const ASN1_INTEGER *serial = X509_get_serialNumber(cert); - X509_NAME *subject_name = X509_get_subject_name(cert); + const X509_NAME *subject_name = X509_get_subject_name(cert); // Subject name BIO *subject_bio = BIO_new(BIO_s_mem()); diff --git a/plugins/experimental/sslheaders/expand.cc b/plugins/experimental/sslheaders/expand.cc index f6a8a0c7548..cbba6594240 100644 --- a/plugins/experimental/sslheaders/expand.cc +++ b/plugins/experimental/sslheaders/expand.cc @@ -49,14 +49,14 @@ x509_expand_certificate(X509 *x509, BIO *bio) static void x509_expand_subject(X509 *x509, BIO *bio) { - X509_NAME *name = X509_get_subject_name(x509); + const X509_NAME *name = X509_get_subject_name(x509); X509_NAME_print_ex(bio, name, 0 /* indent */, XN_FLAG_ONELINE); } static void x509_expand_issuer(X509 *x509, BIO *bio) { - X509_NAME *name = X509_get_issuer_name(x509); + const X509_NAME *name = X509_get_issuer_name(x509); X509_NAME_print_ex(bio, name, 0 /* indent */, XN_FLAG_ONELINE); } @@ -72,8 +72,8 @@ x509_expand_signature(X509 *x509, BIO *bio) { const ASN1_BIT_STRING *sig; X509_get0_signature(&sig, nullptr, x509); - const char *ptr = reinterpret_cast(sig->data); - const char *end = ptr + sig->length; + const char *ptr = reinterpret_cast(ASN1_STRING_get0_data(sig)); + const char *end = ptr + ASN1_STRING_length(sig); // The canonical OpenSSL way to format the signature seems to be // X509_signature_dump(). However that separates each byte with a ':', which is diff --git a/plugins/experimental/txn_box/plugin/src/ts_util.cc b/plugins/experimental/txn_box/plugin/src/ts_util.cc index a1881768956..d4d97d43864 100644 --- a/plugins/experimental/txn_box/plugin/src/ts_util.cc +++ b/plugins/experimental/txn_box/plugin/src/ts_util.cc @@ -1111,8 +1111,14 @@ ssl_nid(swoc::TextView const &name) namespace { + // OpenSSL 4.0 returns a pointer to const from X509_get_subject_name() and + // X509_get_issuer_name() while earlier versions do not, and + // X509_NAME_get_index_by_NID() only accepts a pointer to const as of 3.0. Deduce + // the parameter type from the accessor so this compiles against either. + using X509_NAME_ptr = decltype(X509_get_subject_name(nullptr)); + TextView - ssl_value_for(X509_NAME *name, int nid) + ssl_value_for(X509_NAME_ptr name, int nid) { if (int loc = X509_NAME_get_index_by_NID(name, nid, -1); loc >= 0) { if (auto entry = X509_NAME_get_entry(name, loc); entry != nullptr) { diff --git a/plugins/lua/ts_lua_client_cert_helpers.h b/plugins/lua/ts_lua_client_cert_helpers.h index c7f20b50ebc..dbf741e3260 100644 --- a/plugins/lua/ts_lua_client_cert_helpers.h +++ b/plugins/lua/ts_lua_client_cert_helpers.h @@ -18,7 +18,7 @@ // Helper functions for certificate data extraction static std::string -get_x509_name_string(X509_NAME *name) +get_x509_name_string(const X509_NAME *name) { if (!name) { return ""; @@ -157,12 +157,15 @@ get_x509_signature_string(X509 *cert) return ""; } - for (int i = 0; i < sig->length; i++) { - if (BIO_printf(bio, "%02x", sig->data[i]) <= 0) { + const int siglen = ASN1_STRING_length(sig); + const unsigned char *sigdata = ASN1_STRING_get0_data(sig); + + for (int i = 0; i < siglen; i++) { + if (BIO_printf(bio, "%02x", sigdata[i]) <= 0) { BIO_free(bio); return ""; } - if (i < sig->length - 1) { + if (i < siglen - 1) { if (BIO_printf(bio, ":") <= 0) { BIO_free(bio); return ""; diff --git a/src/api/InkAPI.cc b/src/api/InkAPI.cc index 6d085befbb4..dc364760650 100644 --- a/src/api/InkAPI.cc +++ b/src/api/InkAPI.cc @@ -8316,10 +8316,10 @@ TSSslServerCertUpdate(const char *cert_path, const char *key_path) } // Extract common name - int pos = X509_NAME_get_index_by_NID(X509_get_subject_name(cert.get()), NID_commonName, -1); - X509_NAME_ENTRY *common_name = X509_NAME_get_entry(X509_get_subject_name(cert.get()), pos); - ASN1_STRING *common_name_asn1 = X509_NAME_ENTRY_get_data(common_name); - char *common_name_str = reinterpret_cast(const_cast(ASN1_STRING_get0_data(common_name_asn1))); + int pos = X509_NAME_get_index_by_NID(X509_get_subject_name(cert.get()), NID_commonName, -1); + auto *common_name = X509_NAME_get_entry(X509_get_subject_name(cert.get()), pos); + auto *common_name_asn1 = X509_NAME_ENTRY_get_data(common_name); + char *common_name_str = reinterpret_cast(const_cast(ASN1_STRING_get0_data(common_name_asn1))); if (ASN1_STRING_length(common_name_asn1) != static_cast(strlen(common_name_str))) { // Embedded null char return TS_ERROR; diff --git a/src/cripts/Certs.cc b/src/cripts/Certs.cc index 8f893c14dc2..cd4a6820e95 100644 --- a/src/cripts/Certs.cc +++ b/src/cripts/Certs.cc @@ -54,8 +54,8 @@ CertBase::Signature::_load() const if (!_ready && _owner->_x509) { const ASN1_BIT_STRING *sig; X509_get0_signature(&sig, nullptr, _owner->_x509); - const char *ptr = reinterpret_cast(sig->data); - const char *end = ptr + sig->length; + const char *ptr = reinterpret_cast(ASN1_STRING_get0_data(sig)); + const char *end = ptr + ASN1_STRING_length(sig); super_type::_load(); for (; ptr < end; ++ptr) { @@ -78,7 +78,7 @@ CertBase::X509Value::_update_value() const } void -CertBase::X509Value::_load_name(X509_NAME *(*getter)(const X509 *)) const +CertBase::X509Value::_load_name(NameGetter getter) const { if (!_ready && _owner->_x509) { auto *name = getter(_owner->_x509); @@ -119,7 +119,7 @@ CertBase::X509Value::_load_long(long (*getter)(const X509 *)) const } void -CertBase::X509Value::_load_time(ASN1_TIME *(*getter)(const X509 *)) const +CertBase::X509Value::_load_time(TimeGetter getter) const { if (!_ready && _owner->_x509) { auto *time = getter(_owner->_x509); @@ -153,8 +153,8 @@ namespace _write_ip_address(const ASN1_OCTET_STRING *ip, BIO *_bio) { char buffer[INET6_ADDRSTRLEN]; - const unsigned char *raw = ip->data; - int len = ip->length; + const unsigned char *raw = ASN1_STRING_get0_data(ip); + int len = ASN1_STRING_length(ip); if (inet_ntop(len == 4 ? AF_INET : AF_INET6, raw, buffer, sizeof(buffer))) { BIO_printf(_bio, "%s", buffer); diff --git a/src/iocore/net/OCSPStapling.cc b/src/iocore/net/OCSPStapling.cc index 9a0592f49b3..e07f18418aa 100644 --- a/src/iocore/net/OCSPStapling.cc +++ b/src/iocore/net/OCSPStapling.cc @@ -490,7 +490,7 @@ TS_OCSP_cert_id_new(const EVP_MD *dgst, const X509_NAME *issuerName, const ASN1_ } /* Calculate the issuerKey hash, excluding tag and length */ - if (!EVP_Digest(issuerKey->data, issuerKey->length, md, &i, dgst, nullptr)) { + if (!EVP_Digest(ASN1_STRING_get0_data(issuerKey), ASN1_STRING_length(issuerKey), md, &i, dgst, nullptr)) { goto err; } @@ -514,9 +514,9 @@ TS_OCSP_cert_id_new(const EVP_MD *dgst, const X509_NAME *issuerName, const ASN1_ TS_OCSP_CERTID * TS_OCSP_cert_to_id(const EVP_MD *dgst, const X509 *subject, const X509 *issuer) { - const X509_NAME *iname; - const ASN1_INTEGER *serial; - ASN1_BIT_STRING *ikey; + const X509_NAME *iname; + const ASN1_INTEGER *serial; + const ASN1_BIT_STRING *ikey; if (!dgst) { dgst = EVP_sha1(); diff --git a/src/iocore/net/SSLNetVConnection.cc b/src/iocore/net/SSLNetVConnection.cc index bb7ccb5ddec..8d2abaf7af0 100644 --- a/src/iocore/net/SSLNetVConnection.cc +++ b/src/iocore/net/SSLNetVConnection.cc @@ -167,7 +167,7 @@ SSLNetVConnection::_unbindSSLObject() } static void -debug_certificate_name(const char *msg, X509_NAME *name) +debug_certificate_name(const char *msg, const X509_NAME *name) { BIO *bio; diff --git a/src/iocore/net/SSLUtils.cc b/src/iocore/net/SSLUtils.cc index a88bdceb564..b3abd781c2a 100644 --- a/src/iocore/net/SSLUtils.cc +++ b/src/iocore/net/SSLUtils.cc @@ -1004,7 +1004,7 @@ SSLMultiCertConfigLoader::check_server_cert_now(X509 *cert, const char *certname } /* CheckServerCertNow() */ static char * -asn1_strdup(ASN1_STRING *s) +asn1_strdup(const ASN1_STRING *s) { // Make sure we have an 8-bit encoding. ink_assert(ASN1_STRING_type(s) == V_ASN1_IA5STRING || ASN1_STRING_type(s) == V_ASN1_UTF8STRING || @@ -2212,10 +2212,12 @@ SSLMultiCertConfigLoader::load_certs_and_cross_reference_names( std::set name_set; // Grub through the names in the certs - X509_NAME *subject = nullptr; // Insert a key for the subject CN. - subject = X509_get_subject_name(cert); + // Let the constness of the X509_NAME pointer be deduced: OpenSSL 4.0 returns a + // pointer to const here while earlier versions do not, and + // X509_NAME_get_index_by_NID() below only accepts a pointer to const as of 3.0. + auto *subject = X509_get_subject_name(cert); ats_scoped_str subj_name; if (subject) { int pos = -1; @@ -2225,9 +2227,9 @@ SSLMultiCertConfigLoader::load_certs_and_cross_reference_names( break; } - X509_NAME_ENTRY *e = X509_NAME_get_entry(subject, pos); - ASN1_STRING *cn = X509_NAME_ENTRY_get_data(e); - subj_name = asn1_strdup(cn); + auto *e = X509_NAME_get_entry(subject, pos); + auto *cn = X509_NAME_ENTRY_get_data(e); + subj_name = asn1_strdup(cn); Dbg(dbg_ctl_ssl_load, "subj '%s' in certificate %s %p", subj_name.get(), data.cert_names_list[i].c_str(), cert); name_set.insert(subj_name.get()); diff --git a/src/iocore/net/unit_tests/test_SSLDHParams.cc b/src/iocore/net/unit_tests/test_SSLDHParams.cc index 3e75f5fe097..a3964e0514a 100644 --- a/src/iocore/net/unit_tests/test_SSLDHParams.cc +++ b/src/iocore/net/unit_tests/test_SSLDHParams.cc @@ -132,9 +132,15 @@ make_cert_and_key(EVP_CIPHER const *cipher = nullptr, char *pass = nullptr) X509_gmtime_adj(X509_getm_notAfter(x509), 60L * 60L * 24L * 365L); REQUIRE(X509_set_pubkey(x509, pkey) == 1); - X509_NAME *name = X509_get_subject_name(x509); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast("ats-test"), -1, -1, 0); + // OpenSSL 4.0 returns a pointer to const from X509_get_subject_name(), so the name + // has to be duplicated before it can be modified and stored back. + X509_NAME *name = X509_NAME_dup(X509_get_subject_name(x509)); + REQUIRE(name != nullptr); + REQUIRE(X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast("ats-test"), -1, -1, 0) == + 1); + REQUIRE(X509_set_subject_name(x509, name) == 1); REQUIRE(X509_set_issuer_name(x509, name) == 1); + X509_NAME_free(name); REQUIRE(X509_sign(x509, pkey, EVP_sha256()) > 0); BIO *cert_bio = BIO_new(BIO_s_mem()); diff --git a/src/tscore/X509HostnameValidator.cc b/src/tscore/X509HostnameValidator.cc index 0efbcac99df..dc1f2773ff0 100644 --- a/src/tscore/X509HostnameValidator.cc +++ b/src/tscore/X509HostnameValidator.cc @@ -206,12 +206,12 @@ do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, const unsigned cha { bool retval = false; - if (!a->data || !a->length || cmp_type != a->type) { + if (!ASN1_STRING_get0_data(a) || !ASN1_STRING_length(a) || cmp_type != ASN1_STRING_type(a)) { return false; } - retval = equal(a->data, a->length, b, blen); + retval = equal(ASN1_STRING_get0_data(a), ASN1_STRING_length(a), b, blen); if (retval && peername) { - *peername = ats_strndup((char *)a->data, a->length); + *peername = ats_strndup(reinterpret_cast(ASN1_STRING_get0_data(a)), ASN1_STRING_length(a)); } return retval; } @@ -220,7 +220,6 @@ bool validate_hostname(X509 *x, std::string_view hostname, bool is_ip, char **peername) { GENERAL_NAMES *gens = nullptr; - X509_NAME *name = nullptr; int i; int alt_type; bool retval = false; @@ -269,14 +268,16 @@ validate_hostname(X509 *x, std::string_view hostname, bool is_ip, char **peernam } } // No SAN match -- check the subject - i = -1; - name = X509_get_subject_name(x); + i = -1; + // Let the constness of the X509_NAME pointer be deduced: OpenSSL 4.0 returns a + // pointer to const here while earlier versions do not, and + // X509_NAME_get_index_by_NID() below only accepts a pointer to const as of 3.0. + auto *name = X509_get_subject_name(x); while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) { - ASN1_STRING *str; + auto *str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); int astrlen; unsigned char *astr; - str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); // Convert to UTF-8 astrlen = ASN1_STRING_to_UTF8(&astr, str); diff --git a/tests/tools/plugins/ssl_client_verify_test.cc b/tests/tools/plugins/ssl_client_verify_test.cc index 7f3ae7c3759..2365c472641 100644 --- a/tests/tools/plugins/ssl_client_verify_test.cc +++ b/tests/tools/plugins/ssl_client_verify_test.cc @@ -57,8 +57,10 @@ check_names(X509 *cert) { bool retval = false; - // Check the common name - X509_NAME *subject = X509_get_subject_name(cert); + // Check the common name. Let the constness of the X509_NAME pointer be deduced: + // OpenSSL 4.0 returns a pointer to const here while earlier versions do not, and + // X509_NAME_get_index_by_NID() below only accepts a pointer to const as of 3.0. + auto *subject = X509_get_subject_name(cert); if (subject) { int pos = -1; for (; !retval;) { @@ -67,11 +69,10 @@ check_names(X509 *cert) break; } - X509_NAME_ENTRY *e = X509_NAME_get_entry(subject, pos); - ASN1_STRING *cn = X509_NAME_ENTRY_get_data(e); - char *subj_name = strndup(reinterpret_cast(ASN1_STRING_get0_data(cn)), ASN1_STRING_length(cn)); - retval = check_name(subj_name); - free(subj_name); + auto *e = X509_NAME_get_entry(subject, pos); + auto *cn = X509_NAME_ENTRY_get_data(e); + std::string subj_name{reinterpret_cast(ASN1_STRING_get0_data(cn)), static_cast(ASN1_STRING_length(cn))}; + retval = check_name(subj_name); } } if (!retval) {