From: Otto Moerbeek Date: Wed, 4 Feb 2026 08:43:49 +0000 (+0100) Subject: Refactor key setup so it isn's tied to server-only code X-Git-Tag: rec-5.5.0-alpha0^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=55e93dbd692f86309cdf77ade7edddb186ab51a9;p=thirdparty%2Fpdns.git Refactor key setup so it isn's tied to server-only code Signed-off-by: Otto Moerbeek --- diff --git a/pdns/libssl.cc b/pdns/libssl.cc index 684b35bbbf..6058e82690 100644 --- a/pdns/libssl.cc +++ b/pdns/libssl.cc @@ -1081,87 +1081,92 @@ static void mergeNewCertificateAndKey(pdns::libssl::ServerContext& serverContext } } -std::pair, std::vector> libssl_init_server_context_no_sni(const TLSConfig& config, - [[maybe_unused]] std::map& ocspResponses) +void libssl_setup_context_no_sni(std::unique_ptr& ctx, const TLSCertKeyPair& pair, std::vector& keyTypes) { - std::vector warnings; - auto ctx = getNewServerContext(config, warnings); - - std::vector keyTypes; - /* load certificate and private key */ - for (const auto& pair : config.d_certKeyPairs) { - if (!pair.d_key) { + if (!pair.d_key) { #if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY) - // If no separate key is given, treat it as a pkcs12 file - auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r")); - if (!filePtr) { - throw std::runtime_error("Unable to open file " + pair.d_cert); - } - auto p12 = std::unique_ptr(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free); - if (!p12) { - throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert); - } - EVP_PKEY *keyptr = nullptr; - X509 *certptr = nullptr; - STACK_OF(X509) *captr = nullptr; - if (!PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) { + // If no separate key is given, treat it as a pkcs12 file + auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r")); + if (!filePtr) { + throw std::runtime_error("Unable to open file " + pair.d_cert); + } + auto p12 = std::unique_ptr(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free); + if (!p12) { + throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert); + } + EVP_PKEY *keyptr = nullptr; + X509 *certptr = nullptr; + STACK_OF(X509) *captr = nullptr; + if (!PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) { #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 - bool failed = true; - /* we might be opening a PKCS12 file that uses RC2 CBC or 3DES CBC which, since OpenSSL 3.0.0, requires loading the legacy provider */ - auto libCtx = OSSL_LIB_CTX_get0_global_default(); - /* check whether the legacy provider is already loaded */ - if (!OSSL_PROVIDER_available(libCtx, "legacy")) { - /* it's not */ - auto provider = OSSL_PROVIDER_load(libCtx, "legacy"); - if (provider != nullptr) { - if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) { - failed = false; - } - /* we do not want to keep that provider around after that */ - OSSL_PROVIDER_unload(provider); + bool failed = true; + /* we might be opening a PKCS12 file that uses RC2 CBC or 3DES CBC which, since OpenSSL 3.0.0, requires loading the legacy provider */ + auto libCtx = OSSL_LIB_CTX_get0_global_default(); + /* check whether the legacy provider is already loaded */ + if (!OSSL_PROVIDER_available(libCtx, "legacy")) { + /* it's not */ + auto provider = OSSL_PROVIDER_load(libCtx, "legacy"); + if (provider != nullptr) { + if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr)) { + failed = false; } + /* we do not want to keep that provider around after that */ + OSSL_PROVIDER_unload(provider); } - if (failed) { + } + if (failed) { #endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert); + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert); #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 - } -#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ } - auto key = std::unique_ptr(keyptr, EVP_PKEY_free); - auto cert = std::unique_ptr(certptr, X509_free); - auto ca = std::unique_ptr(captr, [](STACK_OF(X509)* st){ sk_X509_free(st); }); +#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ + } + auto key = std::unique_ptr(keyptr, EVP_PKEY_free); + auto cert = std::unique_ptr(certptr, X509_free); + auto ca = std::unique_ptr(captr, [](STACK_OF(X509)* st){ sk_X509_free(st); }); - if (SSL_CTX_use_cert_and_key(ctx.get(), cert.get(), key.get(), ca.get(), 1) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert); - } + if (SSL_CTX_use_cert_and_key(ctx.get(), cert.get(), key.get(), ca.get(), 1) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert); + } #else - throw std::runtime_error("PKCS12 files are not supported by your openssl version"); + throw std::runtime_error("PKCS12 files are not supported by your openssl version"); #endif /* HAVE_SSL_CTX_USE_CERT_AND_KEY */ - } else { - if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.d_cert.c_str()) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert); - } - if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value()); - } - } - - if (SSL_CTX_check_private_key(ctx.get()) != 1) { + } else { + if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.d_cert.c_str()) != 1) { ERR_print_errors_fp(stderr); - throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'"); + throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert); } - /* store the type of the new key, we might need it later to select the right OCSP stapling response */ - auto keyType = libssl_get_last_key_type(*ctx); - if (keyType < 0) { - throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type"); + if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value()); } - keyTypes.push_back(keyType); - } + } + + if (SSL_CTX_check_private_key(ctx.get()) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'"); + } + /* store the type of the new key, we might need it later to select the right OCSP stapling response */ + auto keyType = libssl_get_last_key_type(*ctx); + if (keyType < 0) { + throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type"); + } + keyTypes.push_back(keyType); +} + +std::pair, std::vector> libssl_init_server_context_no_sni(const TLSConfig& config, + [[maybe_unused]] std::map& ocspResponses) +{ + std::vector warnings; + auto ctx = getNewServerContext(config, warnings); + + std::vector keyTypes; + /* load certificate and private key */ + for (const auto& pair : config.d_certKeyPairs) { + libssl_setup_context_no_sni(ctx, pair, keyTypes); + } #ifndef DISABLE_OCSP_STAPLING if (!config.d_ocspFiles.empty()) { @@ -1187,110 +1192,116 @@ std::pair, std::vector> libssl_init_server_context(const TLSConfig& config) -{ - std::vector warnings; - pdns::libssl::ServerContext serverContext; - std::vector keyTypes; - /* load certificate and private key */ - for (const auto& pair : config.d_certKeyPairs) { - auto uniqueCtx = getNewServerContext(config, warnings); - auto ctx = std::shared_ptr(uniqueCtx.release(), SSL_CTX_free); - if (!pair.d_key) { +static void libssl_setup_context(const TLSConfig& config, const TLSCertKeyPair& pair, std::vector& warnings, pdns::libssl::ServerContext& serverContext, std::vector& keyTypes) +{ + auto uniqueCtx = getNewServerContext(config, warnings); + auto ctx = std::shared_ptr(uniqueCtx.release(), SSL_CTX_free); + if (!pair.d_key) { #if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY) - // If no separate key is given, treat it as a pkcs12 file - auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r")); - if (!filePtr) { - throw std::runtime_error("Unable to open file " + pair.d_cert); - } - auto p12 = std::unique_ptr(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free); - if (!p12) { - throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert); - } - EVP_PKEY *keyptr = nullptr; - X509 *certptr = nullptr; - STACK_OF(X509) *captr = nullptr; - if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) != 1) { + // If no separate key is given, treat it as a pkcs12 file + auto filePtr = pdns::UniqueFilePtr(fopen(pair.d_cert.c_str(), "r")); + if (!filePtr) { + throw std::runtime_error("Unable to open file " + pair.d_cert); + } + auto p12 = std::unique_ptr(d2i_PKCS12_fp(filePtr.get(), nullptr), PKCS12_free); + if (!p12) { + throw std::runtime_error("Unable to open PKCS12 file " + pair.d_cert); + } + EVP_PKEY *keyptr = nullptr; + X509 *certptr = nullptr; + STACK_OF(X509) *captr = nullptr; + if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) != 1) { #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 - bool failed = true; - /* we might be opening a PKCS12 file that uses RC2 CBC or 3DES CBC which, since OpenSSL 3.0.0, requires loading the legacy provider */ - auto* libCtx = OSSL_LIB_CTX_get0_global_default(); - /* check whether the legacy provider is already loaded */ - if (OSSL_PROVIDER_available(libCtx, "legacy") == 0) { - /* it's not */ - auto* provider = OSSL_PROVIDER_load(libCtx, "legacy"); - if (provider != nullptr) { - if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) == 1) { - failed = false; - } - /* we do not want to keep that provider around after that */ - OSSL_PROVIDER_unload(provider); + bool failed = true; + /* we might be opening a PKCS12 file that uses RC2 CBC or 3DES CBC which, since OpenSSL 3.0.0, requires loading the legacy provider */ + auto* libCtx = OSSL_LIB_CTX_get0_global_default(); + /* check whether the legacy provider is already loaded */ + if (OSSL_PROVIDER_available(libCtx, "legacy") == 0) { + /* it's not */ + auto* provider = OSSL_PROVIDER_load(libCtx, "legacy"); + if (provider != nullptr) { + if (PKCS12_parse(p12.get(), (pair.d_password ? pair.d_password->c_str() : nullptr), &keyptr, &certptr, &captr) == 1) { + failed = false; } + /* we do not want to keep that provider around after that */ + OSSL_PROVIDER_unload(provider); } - if (failed) { + } + if (failed) { #endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert); + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while parsing PKCS12 file " + pair.d_cert); #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 - } -#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ } - auto key = std::unique_ptr(keyptr, EVP_PKEY_free); - auto cert = std::unique_ptr(certptr, X509_free); - auto caList = std::unique_ptr(captr, [](STACK_OF(X509)* stack){ sk_X509_free(stack); }); - - auto addCertificateAndKey = [&pair, &key, &cert, &caList](std::shared_ptr& tlsContext) { - if (SSL_CTX_use_cert_and_key(tlsContext.get(), cert.get(), key.get(), caList.get(), 1) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert); - } - }; +#endif /* defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3 */ + } + auto key = std::unique_ptr(keyptr, EVP_PKEY_free); + auto cert = std::unique_ptr(certptr, X509_free); + auto caList = std::unique_ptr(captr, [](STACK_OF(X509)* stack){ sk_X509_free(stack); }); - addCertificateAndKey(ctx); - auto names = get_names_from_last_certificate(*ctx); - if (!names.empty()) { - mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey); - } - else if (!serverContext.d_defaultContext) { - serverContext.d_defaultContext = ctx; + auto addCertificateAndKey = [&pair, &key, &cert, &caList](std::shared_ptr& tlsContext) { + if (SSL_CTX_use_cert_and_key(tlsContext.get(), cert.get(), key.get(), caList.get(), 1) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS certificate and key from PKCS12 file " + pair.d_cert); } + }; + + addCertificateAndKey(ctx); + auto names = get_names_from_last_certificate(*ctx); + if (!names.empty()) { + mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey); + } + else if (!serverContext.d_defaultContext) { + serverContext.d_defaultContext = ctx; + } #else - throw std::runtime_error("PKCS12 files are not supported by your openssl version"); + throw std::runtime_error("PKCS12 files are not supported by your openssl version"); #endif /* HAVE_SSL_CTX_USE_CERT_AND_KEY */ - } else { - auto addCertificateAndKey = [&pair](std::shared_ptr& tlsContext) { - if (SSL_CTX_use_certificate_chain_file(tlsContext.get(), pair.d_cert.c_str()) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert); - } - if (SSL_CTX_use_PrivateKey_file(tlsContext.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value()); - } - }; - - addCertificateAndKey(ctx); - auto names = get_names_from_last_certificate(*ctx); - if (!names.empty()) { - mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey); + } else { + auto addCertificateAndKey = [&pair](std::shared_ptr& tlsContext) { + if (SSL_CTX_use_certificate_chain_file(tlsContext.get(), pair.d_cert.c_str()) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.d_cert); } - else if (!serverContext.d_defaultContext) { - serverContext.d_defaultContext = ctx; + if (SSL_CTX_use_PrivateKey_file(tlsContext.get(), pair.d_key->c_str(), SSL_FILETYPE_PEM) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.d_key.value()); } - } + }; - if (SSL_CTX_check_private_key(ctx.get()) != 1) { - ERR_print_errors_fp(stderr); - throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'"); + addCertificateAndKey(ctx); + auto names = get_names_from_last_certificate(*ctx); + if (!names.empty()) { + mergeNewCertificateAndKey(serverContext, ctx, names, addCertificateAndKey); } - /* store the type of the new key, we might need it later to select the right OCSP stapling response */ - auto keyType = libssl_get_last_key_type(*ctx); - if (keyType < 0) { - throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type"); + else if (!serverContext.d_defaultContext) { + serverContext.d_defaultContext = ctx; } - keyTypes.push_back(keyType); - } + } + + if (SSL_CTX_check_private_key(ctx.get()) != 1) { + ERR_print_errors_fp(stderr); + throw std::runtime_error("The key from '" + pair.d_key.value() + "' does not match the certificate from '" + pair.d_cert + "'"); + } + /* store the type of the new key, we might need it later to select the right OCSP stapling response */ + auto keyType = libssl_get_last_key_type(*ctx); + if (keyType < 0) { + throw std::runtime_error("The key from '" + pair.d_key.value() + "' has an unknown type"); + } + keyTypes.push_back(keyType); +} + +std::pair> libssl_init_server_context(const TLSConfig& config) +{ + std::vector warnings; + pdns::libssl::ServerContext serverContext; + + std::vector keyTypes; + /* load certificate and private key */ + for (const auto& pair : config.d_certKeyPairs) { + libssl_setup_context(config, pair, warnings, serverContext, keyTypes); + } #ifndef DISABLE_OCSP_STAPLING if (!config.d_ocspFiles.empty()) { diff --git a/pdns/libssl.hh b/pdns/libssl.hh index da784b26df..f4a7bc0e12 100644 --- a/pdns/libssl.hh +++ b/pdns/libssl.hh @@ -166,6 +166,9 @@ public: }; } +/* add a keypair to an SSL context */ +void libssl_setup_context_no_sni(std::unique_ptr& ctx, const TLSCertKeyPair& pair, std::vector& keyTypes); + /* return the created context, and a list of warning messages for issues not severe enough to trigger raising an exception, like failing to load an OCSP response file */ std::pair, std::vector> libssl_init_server_context_no_sni(const TLSConfig& config,