Introduce ApiListener#RenewCert()

This commit is contained in:
Alexander A. Klimov 2022-03-29 16:36:13 +02:00
parent 83911d0e05
commit 88d2da22f4
3 changed files with 29 additions and 18 deletions

View File

@ -179,6 +179,30 @@ void ApiListener::OnConfigLoaded()
UpdateSSLContext(); UpdateSSLContext();
} }
std::shared_ptr<X509> ApiListener::RenewCert(const std::shared_ptr<X509>& cert)
{
std::shared_ptr<EVP_PKEY> 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() void ApiListener::UpdateSSLContext()
{ {
m_SSLContext = SetupSslContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath(), GetCrlPath(), GetCipherList(), GetTlsProtocolmin(), GetDebugInfo()); m_SSLContext = SetupSslContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath(), GetCrlPath(), GetCipherList(), GetTlsProtocolmin(), GetDebugInfo());

View File

@ -89,6 +89,7 @@ public:
static String GetCaDir(); static String GetCaDir();
static String GetCertificateRequestsDir(); static String GetCertificateRequestsDir();
std::shared_ptr<X509> RenewCert(const std::shared_ptr<X509>& cert);
void UpdateSSLContext(); void UpdateSSLContext();
static ApiListener::Ptr GetInstance(); static ApiListener::Ptr GetInstance();

View File

@ -145,8 +145,6 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
} }
std::shared_ptr<X509> newcert; std::shared_ptr<X509> newcert;
std::shared_ptr<EVP_PKEY> pubkey;
X509_NAME *subject;
Dictionary::Ptr message; Dictionary::Ptr message;
String ticket; String ticket;
@ -197,23 +195,11 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
} }
} }
pubkey = std::shared_ptr<EVP_PKEY>(X509_get_pubkey(cert.get()), EVP_PKEY_free); newcert = listener->RenewCert(cert);
subject = X509_get_subject_name(cert.get());
newcert = CreateCertIcingaCA(pubkey.get(), subject); if (!newcert) {
goto delayed_request;
/* 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. */
/* Send the signed certificate update. */ /* Send the signed certificate update. */
Log(LogInformation, "JsonRpcConnection") Log(LogInformation, "JsonRpcConnection")