From: Alexander A. Klimov Date: Mon, 25 Feb 2019 17:58:04 +0000 (+0100) Subject: Use new I/O engine in PkiUtility::FetchCert() and PkiUtility::RequestCertificate() X-Git-Tag: v2.11.0-rc1~141^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=refs%2Fpull%2F7133%2Fhead;p=icinga2 Use new I/O engine in PkiUtility::FetchCert() and PkiUtility::RequestCertificate() --- diff --git a/lib/remote/pkiutility.cpp b/lib/remote/pkiutility.cpp index e1e785288..c08989dd8 100644 --- a/lib/remote/pkiutility.cpp +++ b/lib/remote/pkiutility.cpp @@ -2,8 +2,11 @@ #include "remote/pkiutility.hpp" #include "remote/apilistener.hpp" +#include "base/defer.hpp" +#include "base/io-engine.hpp" #include "base/logger.hpp" #include "base/application.hpp" +#include "base/tcpsocket.hpp" #include "base/tlsutility.hpp" #include "base/console.hpp" #include "base/tlsstream.hpp" @@ -14,6 +17,7 @@ #include "remote/jsonrpc.hpp" #include #include +#include using namespace icinga; @@ -76,41 +80,43 @@ int PkiUtility::SignCsr(const String& csrfile, const String& certfile) std::shared_ptr PkiUtility::FetchCert(const String& host, const String& port) { - TcpSocket::Ptr client = new TcpSocket(); + std::shared_ptr sslContext; try { - client->Connect(host, port); + sslContext = MakeAsioSslContext(); } catch (const std::exception& ex) { Log(LogCritical, "pki") - << "Cannot connect to host '" << host << "' on port '" << port << "'"; + << "Cannot make SSL context."; Log(LogDebug, "pki") - << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex); + << "Cannot make SSL context:\n" << DiagnosticInformation(ex); return std::shared_ptr(); } - std::shared_ptr sslContext; + auto stream (std::make_shared(IoEngine::Get().GetIoService(), *sslContext, host)); try { - sslContext = MakeSSLContext(); + Connect(stream->lowest_layer(), host, port); } catch (const std::exception& ex) { Log(LogCritical, "pki") - << "Cannot make SSL context."; + << "Cannot connect to host '" << host << "' on port '" << port << "'"; Log(LogDebug, "pki") - << "Cannot make SSL context:\n" << DiagnosticInformation(ex); + << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex); return std::shared_ptr(); } - TlsStream::Ptr stream = new TlsStream(client, host, RoleClient, sslContext); + auto& sslConn (stream->next_layer()); try { - stream->Handshake(); + sslConn.handshake(sslConn.client); } catch (const std::exception& ex) { Log(LogCritical, "pki") << "Client TLS handshake failed. (" << ex.what() << ")"; return std::shared_ptr(); } - return stream->GetPeerCertificate(); + Defer shutdown ([&sslConn]() { sslConn.shutdown(); }); + + return sslConn.GetPeerCertificate(); } int PkiUtility::WriteCert(const std::shared_ptr& cert, const String& trustedfile) @@ -142,41 +148,43 @@ int PkiUtility::GenTicket(const String& cn, const String& salt, std::ostream& ti int PkiUtility::RequestCertificate(const String& host, const String& port, const String& keyfile, const String& certfile, const String& cafile, const std::shared_ptr& trustedCert, const String& ticket) { - TcpSocket::Ptr client = new TcpSocket(); + std::shared_ptr sslContext; try { - client->Connect(host, port); + sslContext = MakeAsioSslContext(certfile, keyfile); } catch (const std::exception& ex) { Log(LogCritical, "cli") - << "Cannot connect to host '" << host << "' on port '" << port << "'"; + << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "'."; Log(LogDebug, "cli") - << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex); + << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "':\n" << DiagnosticInformation(ex); return 1; } - std::shared_ptr sslContext; + auto stream (std::make_shared(IoEngine::Get().GetIoService(), *sslContext, host)); try { - sslContext = MakeSSLContext(certfile, keyfile); + Connect(stream->lowest_layer(), host, port); } catch (const std::exception& ex) { Log(LogCritical, "cli") - << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "'."; + << "Cannot connect to host '" << host << "' on port '" << port << "'"; Log(LogDebug, "cli") - << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "' ca path: '" << cafile << "':\n" << DiagnosticInformation(ex); + << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex); return 1; } - TlsStream::Ptr stream = new TlsStream(client, host, RoleClient, sslContext); + auto& sslConn (stream->next_layer()); try { - stream->Handshake(); + sslConn.handshake(sslConn.client); } catch (const std::exception& ex) { Log(LogCritical, "cli") << "Client TLS handshake failed: " << DiagnosticInformation(ex, false); return 1; } - std::shared_ptr peerCert = stream->GetPeerCertificate(); + Defer shutdown ([&sslConn]() { sslConn.shutdown(); }); + + auto peerCert (sslConn.GetPeerCertificate()); if (X509_cmp(peerCert.get(), trustedCert.get())) { Log(LogCritical, "cli", "Peer certificate does not match trusted certificate."); @@ -196,36 +204,32 @@ int PkiUtility::RequestCertificate(const String& host, const String& port, const { "params", params } }); - JsonRpc::SendMessage(stream, request); - - String jsonString; Dictionary::Ptr response; - StreamReadContext src; - - for (;;) { - StreamReadStatus srs = JsonRpc::ReadMessage(stream, &jsonString, src); - - if (srs == StatusEof) - break; - if (srs != StatusNewItem) - continue; + try { + JsonRpc::SendMessage(stream, request); + stream->flush(); - response = JsonRpc::DecodeMessage(jsonString); + for (;;) { + response = JsonRpc::DecodeMessage(JsonRpc::ReadMessage(stream)); - if (response && response->Contains("error")) { - Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log (notice or debug)."); + if (response && response->Contains("error")) { + Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log (notice or debug)."); #ifdef I2_DEBUG - /* we shouldn't expose master errors to the user in production environments */ - Log(LogCritical, "cli", response->Get("error")); + /* we shouldn't expose master errors to the user in production environments */ + Log(LogCritical, "cli", response->Get("error")); #endif /* I2_DEBUG */ - return 1; - } + return 1; + } - if (response && (response->Get("id") != msgid)) - continue; + if (response && (response->Get("id") != msgid)) + continue; - break; + break; + } + } catch (...) { + Log(LogCritical, "cli", "Could not fetch valid response. Please check the master log."); + return 1; } if (!response) {