From 88d2da22f4fcfbf24cb2ee14232127a8f9f75361 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Tue, 29 Mar 2022 16:36:13 +0200 Subject: [PATCH] Introduce ApiListener#RenewCert() --- lib/remote/apilistener.cpp | 24 ++++++++++++++++++++++++ lib/remote/apilistener.hpp | 1 + lib/remote/jsonrpcconnection-pki.cpp | 22 ++++------------------ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp index d3c4d32cf..031c60cfa 100644 --- a/lib/remote/apilistener.cpp +++ b/lib/remote/apilistener.cpp @@ -179,6 +179,30 @@ void ApiListener::OnConfigLoaded() UpdateSSLContext(); } +std::shared_ptr ApiListener::RenewCert(const std::shared_ptr& cert) +{ + std::shared_ptr pubkey (X509_get_pubkey(cert.get()), EVP_PKEY_free); + auto subject (X509_get_subject_name(cert.get())); + auto cacert (GetX509Certificate(GetDefaultCaPath())); + auto newcert (CreateCertIcingaCA(pubkey.get(), subject)); + + /* verify that the new cert matches the CA we're using for the ApiListener; + * this ensures that the CA we have in /var/lib/icinga2/ca matches the one + * we're using for cluster connections (there's no point in sending a client + * a certificate it wouldn't be able to use to connect to us anyway) */ + try { + if (!VerifyCertificate(cacert, newcert, GetCrlPath())) { + Log(LogWarning, "ApiListener") + << "The CA in '" << GetDefaultCaPath() << "' does not match the CA which Icinga uses " + << "for its own cluster connections. This is most likely a configuration problem."; + + return nullptr; + } + } catch (const std::exception&) { } /* Swallow the exception on purpose, cacert will never be a non-CA certificate. */ + + return newcert; +} + void ApiListener::UpdateSSLContext() { m_SSLContext = SetupSslContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath(), GetCrlPath(), GetCipherList(), GetTlsProtocolmin(), GetDebugInfo()); diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp index 21c9eb9fb..e52a3ac5b 100644 --- a/lib/remote/apilistener.hpp +++ b/lib/remote/apilistener.hpp @@ -89,6 +89,7 @@ public: static String GetCaDir(); static String GetCertificateRequestsDir(); + std::shared_ptr RenewCert(const std::shared_ptr& cert); void UpdateSSLContext(); static ApiListener::Ptr GetInstance(); diff --git a/lib/remote/jsonrpcconnection-pki.cpp b/lib/remote/jsonrpcconnection-pki.cpp index c38c96d0b..7b7c63f3b 100644 --- a/lib/remote/jsonrpcconnection-pki.cpp +++ b/lib/remote/jsonrpcconnection-pki.cpp @@ -145,8 +145,6 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona } std::shared_ptr newcert; - std::shared_ptr pubkey; - X509_NAME *subject; Dictionary::Ptr message; String ticket; @@ -197,23 +195,11 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona } } - pubkey = std::shared_ptr(X509_get_pubkey(cert.get()), EVP_PKEY_free); - subject = X509_get_subject_name(cert.get()); + newcert = listener->RenewCert(cert); - newcert = CreateCertIcingaCA(pubkey.get(), subject); - - /* verify that the new cert matches the CA we're using for the ApiListener; - * this ensures that the CA we have in /var/lib/icinga2/ca matches the one - * we're using for cluster connections (there's no point in sending a client - * a certificate it wouldn't be able to use to connect to us anyway) */ - try { - if (!VerifyCertificate(cacert, newcert, listener->GetCrlPath())) { - Log(LogWarning, "JsonRpcConnection") - << "The CA in '" << listener->GetDefaultCaPath() << "' does not match the CA which Icinga uses " - << "for its own cluster connections. This is most likely a configuration problem."; - goto delayed_request; - } - } catch (const std::exception&) { } /* Swallow the exception on purpose, cacert will never be a non-CA certificate. */ + if (!newcert) { + goto delayed_request; + } /* Send the signed certificate update. */ Log(LogInformation, "JsonRpcConnection")