https://bugs.gentoo.org/979437 https://github.com/squid-cache/squid/pull/2441 https://github.com/squid-cache/squid/pull/2501 From 00a8938a5561ae11c6e4d563c67ee85621499e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= Date: Wed, 6 May 2026 17:18:58 +0200 Subject: [PATCH] Fix OpenSSL 4.0 compatibility Replace direct ASN1 structure field access with accessor functions. and use ASN1_STRING_set() instead of direct field assignment. Fix issues caused by X509* API constness changes; in some cases, casting the const away is necessary to keep compatibility with OpenSSL 3. --- .../cert_generators/file/certificate_db.cc | 2 +- src/ssl/gadgets.cc | 92 +++++++++++-------- src/ssl/gadgets.h | 4 +- src/ssl/support.cc | 18 ++-- 4 files changed, 66 insertions(+), 50 deletions(-) diff --git a/src/security/cert_generators/file/certificate_db.cc b/src/security/cert_generators/file/certificate_db.cc index 4b729b3..35849aa 100644 --- a/src/security/cert_generators/file/certificate_db.cc +++ b/src/security/cert_generators/file/certificate_db.cc @@ -335,7 +335,7 @@ Ssl::CertificateDb::addCertAndPrivateKey(std::string const &useKey, const Securi } const auto tm = X509_getm_notAfter(cert.get()); - row.setValue(cnlExp_date, std::string(reinterpret_cast(tm->data), tm->length).c_str()); + row.setValue(cnlExp_date, std::string(reinterpret_cast(ASN1_STRING_get0_data(tm)), ASN1_STRING_length(tm)).c_str()); const auto subject = OneLineSummary(*X509_get_subject_name(cert.get())); row.setValue(cnlName, subject.get()); row.setValue(cnlKey, useKey.c_str()); diff --git a/src/ssl/gadgets.cc b/src/ssl/gadgets.cc index 06b8b79..100ee6a 100644 --- a/src/ssl/gadgets.cc +++ b/src/ssl/gadgets.cc @@ -259,20 +259,31 @@ static bool replaceCommonName(Security::CertPointer & cert, std::string const &r if (cn.length() > 2 && *cn.begin() == '[' && *cn.rbegin() == ']') cn = cn.substr(1, cn.size()-2); - X509_NAME *name = X509_get_subject_name(cert.get()); + const X509_NAME *subject = X509_get_subject_name(cert.get()); + if (!subject) + return false; + + X509_NAME *name = X509_NAME_dup(subject); if (!name) return false; + // Remove the CN part: int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1); - if (loc >=0) { - X509_NAME_ENTRY *tmp = X509_NAME_get_entry(name, loc); - X509_NAME_delete_entry(name, loc); + if (loc >= 0) { + X509_NAME_ENTRY *tmp = X509_NAME_delete_entry(name, loc); X509_NAME_ENTRY_free(tmp); } // Add a new CN - return X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC, - (unsigned char *)(cn.c_str()), -1, -1, 0); + if (!X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC, + (unsigned char *)(cn.c_str()), -1, -1, 0)) { + X509_NAME_free(name); + return false; + } + + int ret = X509_set_subject_name(cert.get(), name); + X509_NAME_free(name); + return ret; } const char *Ssl::CertSignAlgorithmStr[] = { @@ -301,9 +312,9 @@ static void printX509Signature(const Security::CertPointer &cert, std::string &out) { const ASN1_BIT_STRING *sig = Ssl::X509_get_signature(cert); - if (sig && sig->data) { - const unsigned char *s = sig->data; - for (int i = 0; i < sig->length; ++i) { + if (sig && ASN1_STRING_get0_data(sig)) { + const unsigned char *s = ASN1_STRING_get0_data(sig); + for (int i = 0; i < ASN1_STRING_length(sig); ++i) { char hex[3]; snprintf(hex, sizeof(hex), "%02x", s[i]); out.append(hex); @@ -377,7 +388,7 @@ mimicAuthorityKeyId(Security::CertPointer &cert, Security::CertPointer const &mi X509_EXTENSION *ext; // Check if the issuer has the Subject Key Identifier extension const int indx = X509_get_ext_by_NID(issuerCert.get(), NID_subject_key_identifier, -1); - if (indx >= 0 && (ext = X509_get_ext(issuerCert.get(), indx))) { + if (indx >= 0 && (ext = const_cast(X509_get_ext(issuerCert.get(), indx)))) { issuerKeyId.reset((ASN1_OCTET_STRING *)X509V3_EXT_d2i(ext)); } } @@ -418,8 +429,7 @@ mimicAuthorityKeyId(Security::CertPointer &cert, Security::CertPointer const &mi unsigned char *ext_der = nullptr; int ext_len = ASN1_item_i2d((ASN1_VALUE *)theAuthKeyId.get(), &ext_der, ASN1_ITEM_ptr(method->it)); Ssl::ASN1_OCTET_STRING_Pointer extOct(ASN1_OCTET_STRING_new()); - extOct.get()->data = ext_der; - extOct.get()->length = ext_len; + ASN1_STRING_set(extOct.get(), ext_der, ext_len); Ssl::X509_EXTENSION_Pointer extAuthKeyId(X509_EXTENSION_create_by_NID(nullptr, NID_authority_key_identifier, 0, extOct.get())); if (!extAuthKeyId.get()) return false; @@ -471,7 +481,7 @@ mimicExtensions(Security::CertPointer & cert, Security::CertPointer const &mimic int nid; for (int i = 0; (nid = extensions[i]) != 0; ++i) { const int pos = X509_get_ext_by_NID(mimicCert.get(), nid, -1); - if (X509_EXTENSION *ext = X509_get_ext(mimicCert.get(), pos)) { + if (X509_EXTENSION *ext = const_cast(X509_get_ext(mimicCert.get(), pos))) { // Mimic extension exactly. if (X509_add_ext(cert.get(), ext, -1)) ++added; @@ -482,7 +492,7 @@ mimicExtensions(Security::CertPointer & cert, Security::CertPointer const &mimic // that the more stringent requirements are met. const int p = X509_get_ext_by_NID(cert.get(), NID_key_usage, -1); - if ((ext = X509_get_ext(cert.get(), p)) != nullptr) { + if ((ext = const_cast(X509_get_ext(cert.get(), p))) != nullptr) { ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ext); ASN1_BIT_STRING_set_bit(keyusage, KeyEncipherment, 1); @@ -495,8 +505,7 @@ mimicExtensions(Security::CertPointer & cert, Security::CertPointer const &mimic (const ASN1_ITEM *)ASN1_ITEM_ptr(method->it)); ASN1_OCTET_STRING *ext_oct = ASN1_OCTET_STRING_new(); - ext_oct->data = ext_der; - ext_oct->length = ext_len; + ASN1_STRING_set(ext_oct, ext_der, ext_len); X509_EXTENSION_set_data(ext, ext_oct); ASN1_OCTET_STRING_free(ext_oct); @@ -518,7 +527,7 @@ mimicExtensions(Security::CertPointer & cert, Security::CertPointer const &mimic SBuf Ssl::AsnToSBuf(const ASN1_STRING &buffer) { - return SBuf(reinterpret_cast(buffer.data), buffer.length); + return SBuf(reinterpret_cast(ASN1_STRING_get0_data(&buffer)), ASN1_STRING_length(&buffer)); } /// OpenSSL ASN1_STRING_to_UTF8() wrapper @@ -547,7 +556,7 @@ Ssl::ParseAsSimpleDomainNameOrIp(const SBuf &text) } std::optional -Ssl::ParseCommonNameAt(X509_NAME &name, const int cnIndex) +Ssl::ParseCommonNameAt(const X509_NAME &name, const int cnIndex) { const auto cn = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(&name, cnIndex)); if (!cn) { @@ -576,7 +585,7 @@ Ssl::ParseCommonNameAt(X509_NAME &name, const int cnIndex) static bool addAltNameWithSubjectCn(Security::CertPointer &cert) { - X509_NAME *name = X509_get_subject_name(cert.get()); + const X509_NAME *name = X509_get_subject_name(cert.get()); if (!name) return false; @@ -610,7 +619,7 @@ static bool buildCertificate(Security::CertPointer & cert, Ssl::CertificatePrope // returns a pointer to the existing subject name. Nothing to clean here. if (properties.mimicCert.get()) { // Leave subject empty if we cannot extract it from true cert. - if (X509_NAME *name = X509_get_subject_name(properties.mimicCert.get())) { + if (const X509_NAME *name = X509_get_subject_name(properties.mimicCert.get())) { // X509_set_subject_name will call X509_dup for name X509_set_subject_name(cert.get(), name); } @@ -656,7 +665,7 @@ static bool buildCertificate(Security::CertPointer & cert, Ssl::CertificatePrope bool useCommonNameAsAltName = true; // mimic the alias and possibly subjectAltName if (properties.mimicCert.get()) { - unsigned char *alStr; + const unsigned char *alStr; int alLen; alStr = X509_alias_get0(properties.mimicCert.get(), &alLen); if (alStr) { @@ -667,7 +676,7 @@ static bool buildCertificate(Security::CertPointer & cert, Ssl::CertificatePrope // certificates with CN unrelated to subjectAltNames. if (!properties.setCommonName) { int pos = X509_get_ext_by_NID(properties.mimicCert.get(), NID_subject_alt_name, -1); - X509_EXTENSION *ext=X509_get_ext(properties.mimicCert.get(), pos); + X509_EXTENSION *ext = const_cast(X509_get_ext(properties.mimicCert.get(), pos)); if (ext) { if (X509_add_ext(cert.get(), ext, -1)) ++addedExtensions; @@ -922,20 +931,23 @@ Ssl::WritePrivateKey(Ssl::BIO_Pointer &bio, const Security::PrivateKeyPointer &p } Ssl::UniqueCString -Ssl::OneLineSummary(X509_NAME &name) +Ssl::OneLineSummary(const X509_NAME &name) { return Ssl::UniqueCString(X509_NAME_oneline(&name, nullptr, 0)); } bool Ssl::sslDateIsInTheFuture(char const * date) { - ASN1_UTCTIME tm; - tm.flags = 0; - tm.type = 23; - tm.data = (unsigned char *)date; - tm.length = strlen(date); - - return (X509_cmp_current_time(&tm) > 0); + ASN1_UTCTIME *tm = ASN1_UTCTIME_new(); + if (!tm) + return false; + if (!ASN1_UTCTIME_set_string(tm, date)) { + ASN1_UTCTIME_free(tm); + return false; + } + int result = X509_cmp_current_time(tm); + ASN1_UTCTIME_free(tm); + return (result > 0); } /// Print the time represented by a ASN1_TIME struct to a string using GeneralizedTime format @@ -945,14 +957,18 @@ static bool asn1timeToGeneralizedTimeStr(ASN1_TIME *aTime, char *buf, int bufLen // UTCTime has the form YYMMDDHHMMSS[Z | [+|-]offset] // GeneralizedTime has the form YYYYMMDDHHMMSS[Z | [+|-] offset] + const unsigned char *data = ASN1_STRING_get0_data(aTime); + int length = ASN1_STRING_length(aTime); + int type = ASN1_STRING_type(aTime); + // length should have space for data plus 2 extra bytes for the two extra year fields // plus the '\0' char. - if ((aTime->length + 3) > bufLen) + if ((length + 3) > bufLen) return false; char *str; - if (aTime->type == V_ASN1_UTCTIME) { - if (aTime->data[0] > '5') { // RFC 2459, section 4.1.2.5.1 + if (type == V_ASN1_UTCTIME) { + if (data[0] > '5') { // RFC 2459, section 4.1.2.5.1 buf[0] = '1'; buf[1] = '9'; } else { @@ -960,11 +976,11 @@ static bool asn1timeToGeneralizedTimeStr(ASN1_TIME *aTime, char *buf, int bufLen buf[1] = '0'; } str = buf +2; - } else // if (aTime->type == V_ASN1_GENERALIZEDTIME) + } else // if (type == V_ASN1_GENERALIZEDTIME) str = buf; - memcpy(str, aTime->data, aTime->length); - str[aTime->length] = '\0'; + memcpy(str, data, length); + str[length] = '\0'; return true; } @@ -996,8 +1012,8 @@ bool Ssl::certificateMatchesProperties(X509 *cert, CertificateProperties const & return true; if (!properties.setCommonName) { - X509_NAME *cert1_name = X509_get_subject_name(cert); - X509_NAME *cert2_name = X509_get_subject_name(cert2); + const X509_NAME *cert1_name = X509_get_subject_name(cert); + const X509_NAME *cert2_name = X509_get_subject_name(cert2); if (X509_NAME_cmp(cert1_name, cert2_name) != 0) return false; } else if (properties.commonName != CommonHostName(cert)) diff --git a/src/ssl/gadgets.h b/src/ssl/gadgets.h index e0c60c3..4c48759 100644 --- a/src/ssl/gadgets.h +++ b/src/ssl/gadgets.h @@ -160,7 +160,7 @@ bool WriteX509Certificate(BIO_Pointer &bio, const Security::CertPointer & cert); bool WritePrivateKey(BIO_Pointer &bio, const Security::PrivateKeyPointer &pkey); /// a RAII wrapper for the memory-allocating flavor of X509_NAME_oneline() -UniqueCString OneLineSummary(X509_NAME &); +UniqueCString OneLineSummary(const X509_NAME &); /** \ingroup SslCrtdSslAPI @@ -285,7 +285,7 @@ const char *CommonHostName(X509 *x509); SBuf AsnToSBuf(const ASN1_STRING &); /// interprets X.509 Subject or Issuer name entry (at the given position) as CN -std::optional ParseCommonNameAt(X509_NAME &, int); +std::optional ParseCommonNameAt(const X509_NAME &, int); /// interprets the given buffer as either a textual representation of an IP /// address (if possible) or a domain name without wildcard support (otherwise) diff --git a/src/ssl/support.cc b/src/ssl/support.cc index e787203..09f268a 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -272,23 +272,23 @@ ParseSubjectAltName(const GENERAL_NAME &san) // RFC 5280 section 4.2.1.6 signals IPv4/IPv6 address family using data length - if (san.d.iPAddress->length == 4) { + if (ASN1_STRING_length(san.d.iPAddress) == 4) { struct in_addr addr; static_assert(sizeof(addr.s_addr) == 4); - memcpy(&addr.s_addr, san.d.iPAddress->data, sizeof(addr.s_addr)); + memcpy(&addr.s_addr, ASN1_STRING_get0_data(san.d.iPAddress), sizeof(addr.s_addr)); const Ip::Address ip(addr); return AnyP::Host::ParseIp(ip); } - if (san.d.iPAddress->length == 16) { + if (ASN1_STRING_length(san.d.iPAddress) == 16) { struct in6_addr addr; static_assert(sizeof(addr.s6_addr) == 16); - memcpy(&addr.s6_addr, san.d.iPAddress->data, sizeof(addr.s6_addr)); + memcpy(&addr.s6_addr, ASN1_STRING_get0_data(san.d.iPAddress), sizeof(addr.s6_addr)); const Ip::Address ip(addr); return AnyP::Host::ParseIp(ip); } - debugs(83, 3, "unexpected length of an IP address SAN: " << san.d.iPAddress->length); + debugs(83, 3, "unexpected length of an IP address SAN: " << ASN1_STRING_length(san.d.iPAddress)); return std::nullopt; } @@ -856,7 +856,7 @@ Ssl::InitClientContext(Security::ContextPointer &ctx, Security::PeerOptions &pee /// \ingroup ServerProtocolSSLInternal static const char * -ssl_get_attribute(X509_NAME * name, const char *attribute_name) +ssl_get_attribute(const X509_NAME * name, const char *attribute_name) { static char buffer[1024]; buffer[0] = '\0'; @@ -879,7 +879,7 @@ ssl_get_attribute(X509_NAME * name, const char *attribute_name) const char * Ssl::GetX509UserAttribute(X509 * cert, const char *attribute_name) { - X509_NAME *name; + const X509_NAME *name; const char *ret; if (!cert) @@ -933,7 +933,7 @@ const char * Ssl::GetX509CAAttribute(X509 * cert, const char *attribute_name) { - X509_NAME *name; + const X509_NAME *name; const char *ret; if (!cert) @@ -1484,7 +1484,7 @@ void Ssl::InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties if (certProperties.mimicCert) { if (auto *sig = Ssl::X509_get_signature(certProperties.mimicCert)) { origSignatureAsKey = true; - key.append((const char *)sig->data, sig->length); + key.append((const char *)ASN1_STRING_get0_data(sig), ASN1_STRING_length(sig)); } } -- 2.53.0