From: Otto Moerbeek Date: Wed, 4 Feb 2026 13:42:20 +0000 (+0100) Subject: Basic infra for client cert X-Git-Tag: rec-5.5.0-alpha0^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70852be053b5d719f08b48ed96206f8d71139c34;p=thirdparty%2Fpdns.git Basic infra for client cert Signed-off-by: Otto Moerbeek --- diff --git a/pdns/libssl.cc b/pdns/libssl.cc index 6058e82690..f8c6e2e636 100644 --- a/pdns/libssl.cc +++ b/pdns/libssl.cc @@ -1081,7 +1081,7 @@ static void mergeNewCertificateAndKey(pdns::libssl::ServerContext& serverContext } } -void libssl_setup_context_no_sni(std::unique_ptr& ctx, const TLSCertKeyPair& pair, std::vector& keyTypes) +void libssl_setup_context_no_sni(SSL_CTX* ctx, const TLSCertKeyPair& pair, std::vector& keyTypes) { if (!pair.d_key) { #if defined(HAVE_SSL_CTX_USE_CERT_AND_KEY) @@ -1126,7 +1126,7 @@ void libssl_setup_context_no_sni(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) { + if (SSL_CTX_use_cert_and_key(ctx, 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); } @@ -1134,17 +1134,17 @@ void libssl_setup_context_no_sni(std::unique_ptrc_str(), SSL_FILETYPE_PEM) != 1) { + if (SSL_CTX_use_PrivateKey_file(ctx, 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) { + if (SSL_CTX_check_private_key(ctx) != 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 + "'"); } @@ -1165,7 +1165,7 @@ std::pair, std::vector keyTypes; /* load certificate and private key */ for (const auto& pair : config.d_certKeyPairs) { - libssl_setup_context_no_sni(ctx, pair, keyTypes); + libssl_setup_context_no_sni(ctx.get(), pair, keyTypes); } #ifndef DISABLE_OCSP_STAPLING diff --git a/pdns/libssl.hh b/pdns/libssl.hh index f4a7bc0e12..3a0a3c0df8 100644 --- a/pdns/libssl.hh +++ b/pdns/libssl.hh @@ -167,7 +167,7 @@ public: } /* add a keypair to an SSL context */ -void libssl_setup_context_no_sni(std::unique_ptr& ctx, const TLSCertKeyPair& pair, std::vector& keyTypes); +void libssl_setup_context_no_sni(SSL_CTX* 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 */ diff --git a/pdns/recursordist/rec-rust-lib/rust-bridge-in.rs b/pdns/recursordist/rec-rust-lib/rust-bridge-in.rs index ed9e0e5cd4..b31b3316f3 100644 --- a/pdns/recursordist/rec-rust-lib/rust-bridge-in.rs +++ b/pdns/recursordist/rec-rust-lib/rust-bridge-in.rs @@ -348,6 +348,13 @@ struct OutgoingTLSConfiguration { ciphers: String, #[serde(default, skip_serializing_if = "crate::is_default")] ciphers_tls_13: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + // Fields below added in 5.5.0 + client_certificate: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + client_certificate_key: String, + #[serde(default, skip_serializing_if = "crate::is_default")] + client_certificate_password: String, } #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)] diff --git a/pdns/recursordist/rec-rust-lib/rust/src/bridge.rs b/pdns/recursordist/rec-rust-lib/rust/src/bridge.rs index 524b7a2c19..036aa93156 100644 --- a/pdns/recursordist/rec-rust-lib/rust/src/bridge.rs +++ b/pdns/recursordist/rec-rust-lib/rust/src/bridge.rs @@ -818,7 +818,12 @@ impl OutgoingTLSConfiguration { inserts(&mut map, "subject_name", &self.subject_name); inserts(&mut map, "subject_address", &self.subject_address); inserts(&mut map, "ciphers", &self.ciphers); - inserts(&mut map, "ciphers_tls", &self.ciphers_tls_13); + inserts(&mut map, "ciphers_tls_13", &self.ciphers_tls_13); + + inserts(&mut map, "client_certificate", &self.client_certificate); + inserts(&mut map, "client_certificate_key", &self.client_certificate_key); + inserts(&mut map, "client_certificate_password", &self.client_certificate_password); + serde_yaml::Value::Mapping(map) } diff --git a/pdns/recursordist/rec-tcpout.cc b/pdns/recursordist/rec-tcpout.cc index 762178478d..20bbd86279 100644 --- a/pdns/recursordist/rec-tcpout.cc +++ b/pdns/recursordist/rec-tcpout.cc @@ -142,6 +142,10 @@ std::shared_ptr TCPOutConnectionManager::getTLSContext(const std::string verboseLogging = config->verbose_logging; tlsParams.d_ciphers = std::string(config->ciphers); tlsParams.d_ciphers13 = std::string(config->ciphers_tls_13); + + tlsParams.d_client_certificate = std::string(config->client_certificate); + tlsParams.d_client_certificate_key = std::string(config->client_certificate_key); + tlsParams.d_client_certificate_password = std::string(config->client_certificate_password); } } return ::getTLSContext(tlsParams); diff --git a/pdns/tcpiohandler.cc b/pdns/tcpiohandler.cc index dfd770b83c..b9ef3ac65e 100644 --- a/pdns/tcpiohandler.cc +++ b/pdns/tcpiohandler.cc @@ -857,6 +857,20 @@ public: libssl_set_alpn_protos(d_tlsCtx.get(), getALPNVector(params.d_alpn, true)); + if (!params.d_client_certificate.empty()) { + std::optional key = std::nullopt; + if (!params.d_client_certificate_key.empty()) { + key = params.d_client_certificate_key; + } + std::optional password = std::nullopt; + if (!params.d_client_certificate_password.empty()) { + password = params.d_client_certificate_password; + } + TLSCertKeyPair pair{params.d_client_certificate, key, password}; + std::vector keyTypes; + libssl_setup_context_no_sni(d_tlsCtx.get(), pair, keyTypes); + } + #ifdef SSL_MODE_RELEASE_BUFFERS if (params.d_releaseBuffers) { SSL_CTX_set_mode(d_tlsCtx.get(), SSL_MODE_RELEASE_BUFFERS); diff --git a/pdns/tcpiohandler.hh b/pdns/tcpiohandler.hh index f031987a47..a3f7b52d0b 100644 --- a/pdns/tcpiohandler.hh +++ b/pdns/tcpiohandler.hh @@ -598,6 +598,9 @@ struct TLSContextParameters std::string d_ciphers13; std::string d_caStore; std::string d_keyLogFile; + std::string d_client_certificate; + std::string d_client_certificate_key; + std::string d_client_certificate_password; TLSFrontend::ALPN d_alpn{TLSFrontend::ALPN::Unset}; bool d_validateCertificates{true}; bool d_releaseBuffers{true};