]> granicus.if.org Git - icinga2/commitdiff
Update node wizard
authorJean Flach <jean-marcel.flach@netways.de>
Tue, 24 Nov 2015 16:01:46 +0000 (17:01 +0100)
committerMichael Friedrich <michael.friedrich@netways.de>
Thu, 26 Nov 2015 09:29:43 +0000 (10:29 +0100)
The wizard now displays basic information on the to-be-imported master
certificate and asks the user for confirmation.

fixes #10632

lib/cli/nodesetupcommand.cpp
lib/cli/nodewizardcommand.cpp
lib/cli/pkirequestcommand.cpp
lib/cli/pkisavecertcommand.cpp
lib/cli/pkiutility.cpp
lib/cli/pkiutility.hpp

index 20579a7b7f23e079763c41b7aa00201b9e994177..110b29794a4da436fd77724c72357ff40f52a136 100644 (file)
@@ -292,7 +292,7 @@ int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm,
                return 1;
        }
 
-       String trustedcert = vm["trustedcert"].as<std::string>();
+       boost::shared_ptr<X509> trustedcert = GetX509Certificate(vm["trustedcert"].as<std::string>());
 
        Log(LogInformation, "cli")
            << "Verifying trusted certificate from file '" << trustedcert << "'.";
index 4e4e3c76894ce8124e1966fff623c2ff704f6b84..a143682763ddc293b72d5b75374e4c37f3cbc895 100644 (file)
@@ -67,14 +67,16 @@ int NodeWizardCommand::GetMaxArguments(void) const
  *
  * @returns An exit status.
  */
-int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
+int NodeWizardCommand::Run(const boost::program_options::variables_map& vm,
+    const std::vector<std::string>& ap) const
 {
        /*
         * The wizard will get all information from the user,
         * and then call all required functions.
         */
 
-       std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundBlue) << "Welcome to the Icinga 2 Setup Wizard!\n"
+       std::cout << ConsoleColorTag(Console_Bold | Console_ForegroundBlue)
+           << "Welcome to the Icinga 2 Setup Wizard!\n"
            << "\n"
            << "We'll guide you through all required configuration details.\n"
            << "\n"
@@ -101,8 +103,10 @@ int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, cons
        bool is_node_setup = true;
 
        /* master or node setup */
-       std::cout << ConsoleColorTag(Console_Bold) << "Please specify if this is a satellite setup "
-           << "('n' installs a master setup)" << ConsoleColorTag(Console_Normal) << " [Y/n]: ";
+       std::cout << ConsoleColorTag(Console_Bold)
+           << "Please specify if this is a satellite setup "
+           << "('n' installs a master setup)" << ConsoleColorTag(Console_Normal)
+           << " [Y/n]: ";
        std::getline (std::cin, answer);
 
        boost::algorithm::to_lower(answer);
@@ -117,7 +121,10 @@ int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, cons
                std::cout << "Starting the Node setup routine...\n";
 
                /* CN */
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specifiy the common name (CN)" << ConsoleColorTag(Console_Normal) << " [" << Utility::GetFQDN() << "]: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specifiy the common name (CN)"
+                   << ConsoleColorTag(Console_Normal)
+                   << " [" << Utility::GetFQDN() << "]: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -128,7 +135,9 @@ int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, cons
                String cn = answer;
                cn = cn.Trim();
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specifiy the local zone name" << ConsoleColorTag(Console_Normal) << " [" << cn << "]: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specifiy the local zone name"
+                   << ConsoleColorTag(Console_Normal) << " [" << cn << "]: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -143,12 +152,16 @@ int NodeWizardCommand::Run(const boost::program_options::variables_map& vm, cons
 
                String endpoint_buffer;
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specify the master endpoint(s) this node should connect to:" << ConsoleColorTag(Console_Normal) << "\n";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specify the master endpoint(s) this node should connect to:"
+                   << ConsoleColorTag(Console_Normal) << "\n";
                String master_endpoint_name;
 
 wizard_endpoint_loop_start:
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Master Common Name" << ConsoleColorTag(Console_Normal) << " (CN from your master setup): ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Master Common Name" << ConsoleColorTag(Console_Normal)
+                   << " (CN from your master setup): ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -161,7 +174,9 @@ wizard_endpoint_loop_start:
                endpoint_buffer = answer;
                endpoint_buffer = endpoint_buffer.Trim();
 
-               std::cout << "Do you want to establish a connection to the master " << ConsoleColorTag(Console_Bold) << "from this node?" << ConsoleColorTag(Console_Normal) << " [Y/n]: ";
+               std::cout << "Do you want to establish a connection to the master "
+                   << ConsoleColorTag(Console_Bold) << "from this node?"
+                   << ConsoleColorTag(Console_Normal) << " [Y/n]: ";
 
                std::getline (std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -171,8 +186,11 @@ wizard_endpoint_loop_start:
                        Log(LogWarning, "cli", "Node to master connection setup skipped");
                        std::cout << "Connection setup skipped. Please configure your master to connect to this node.\n";
                } else  {
-                       std::cout << ConsoleColorTag(Console_Bold) << "Please fill out the master connection information:" << ConsoleColorTag(Console_Normal) << "\n";
-                       std::cout << ConsoleColorTag(Console_Bold) << "Master endpoint host" << ConsoleColorTag(Console_Normal) << " (Your master's IP address or FQDN): ";
+                       std::cout << ConsoleColorTag(Console_Bold)
+                           << "Please fill out the master connection information:"
+                           << ConsoleColorTag(Console_Normal) << "\n"
+                           << ConsoleColorTag(Console_Bold) << "Master endpoint host"
+                           << ConsoleColorTag(Console_Normal) << " (Your master's IP address or FQDN): ";
 
                        std::getline(std::cin, answer);
                        boost::algorithm::to_lower(answer);
@@ -188,7 +206,9 @@ wizard_endpoint_loop_start:
                        endpoint_buffer += "," + tmp;
                        master_endpoint_name = tmp; //store the endpoint name for later
 
-                       std::cout << ConsoleColorTag(Console_Bold) << "Master endpoint port" << ConsoleColorTag(Console_Normal) << " [5665]: ";
+                       std::cout << ConsoleColorTag(Console_Bold)
+                            << "Master endpoint port" << ConsoleColorTag(Console_Normal)
+                            << " [5665]: ";
 
                        std::getline(std::cin, answer);
                        boost::algorithm::to_lower(answer);
@@ -203,7 +223,8 @@ wizard_endpoint_loop_start:
 
                endpoints.push_back(endpoint_buffer);
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Add more master endpoints?" << ConsoleColorTag(Console_Normal) << " [y/N]: ";
+               std::cout << ConsoleColorTag(Console_Bold) << "Add more master endpoints?"
+                   << ConsoleColorTag(Console_Normal) << " [y/N]: ";
                std::getline (std::cin, answer);
 
                boost::algorithm::to_lower(answer);
@@ -213,10 +234,13 @@ wizard_endpoint_loop_start:
                if (choice.Contains("y"))
                        goto wizard_endpoint_loop_start;
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specify the master connection for CSR auto-signing" << ConsoleColorTag(Console_Normal) << " (defaults to master endpoint host):\n";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specify the master connection for CSR auto-signing"
+                   << ConsoleColorTag(Console_Normal) << " (defaults to master endpoint host):\n";
 
 wizard_master_host:
-               std::cout << ConsoleColorTag(Console_Bold) << "Host" << ConsoleColorTag(Console_Normal) << " [" << master_endpoint_name << "]: ";
+               std::cout << ConsoleColorTag(Console_Bold) << "Host"
+                   << ConsoleColorTag(Console_Normal) << " [" << master_endpoint_name << "]: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -230,7 +254,8 @@ wizard_master_host:
                String master_host = answer;
                master_host = master_host.Trim();
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Port" << ConsoleColorTag(Console_Normal) << " [5665]: ";
+               std::cout << ConsoleColorTag(Console_Bold) << "Port"
+                   << ConsoleColorTag(Console_Normal) << " [5665]: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -250,7 +275,9 @@ wizard_master_host:
 
                if (!Utility::SetFileOwnership(pki_path, user, group)) {
                        Log(LogWarning, "cli")
-                           << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << pki_path << "'. Verify it yourself!";
+                           << "Cannot set ownership for user '" << user
+                           << "' group '" << group
+                           << "' on file '" << pki_path << "'. Verify it yourself!";
                }
 
                String node_cert = pki_path + "/" + cn + ".crt";
@@ -263,40 +290,48 @@ wizard_master_host:
 
                if (PkiUtility::NewCert(cn, node_key, Empty, node_cert) > 0) {
                        Log(LogCritical, "cli")
-                           << "Failed to create new self-signed certificate for CN '" << cn << "'. Please try again.";
+                           << "Failed to create new self-signed certificate for CN '"
+                           << cn << "'. Please try again.";
                        return 1;
                }
 
                /* fix permissions: root -> icinga daemon user */
                if (!Utility::SetFileOwnership(node_key, user, group)) {
                        Log(LogWarning, "cli")
-                           << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << node_key << "'. Verify it yourself!";
+                           << "Cannot set ownership for user '" << user
+                           << "' group '" << group
+                           << "' on file '" << node_key << "'. Verify it yourself!";
                }
 
                //save-cert and store the master certificate somewhere
-
-               Log(LogInformation, "cli", "Generating self-signed certificate:");
-
                Log(LogInformation, "cli")
                    << "Fetching public certificate from master ("
                    << master_host << ", " << master_port << "):\n";
 
-               String trusted_cert = PkiUtility::GetPkiPath() + "/trusted-master.crt";
+               boost::shared_ptr<X509> trustedcert = PkiUtility::FetchCert(master_host, master_port);
+               if (!trustedcert) {
+                       Log(LogCritical, "cli", "Peer did not present a valid certificate.");
+                       return 1;
+               }
 
-               if (Utility::PathExists(trusted_cert))
-                       NodeUtility::CreateBackupFile(trusted_cert);
+               std::cout << ConsoleColorTag(Console_Bold) << "Certificate information:\n"
+                   << ConsoleColorTag(Console_Normal) << PkiUtility::GetCertificateInformation(trustedcert)
+                   << ConsoleColorTag(Console_Bold) << "\nIs this information correct?"
+                   << ConsoleColorTag(Console_Normal) << " [y/N]: ";
 
-               if (PkiUtility::SaveCert(master_host, master_port, node_key, node_cert, trusted_cert) > 0) {
-                       Log(LogCritical, "cli")
-                           << "Failed to fetch trusted master certificate. Please try again.";
+               std::getline (std::cin, answer);
+               boost::algorithm::to_lower(answer);
+               if (answer != "y") {
+                       Log(LogWarning, "cli", "Process aborted.");
                        return 1;
                }
 
-               Log(LogInformation, "cli")
-                   << "Stored trusted master certificate in '" << trusted_cert << "'.\n";
+               Log(LogInformation, "cli", "Received trusted master certificate.\n");
 
 wizard_ticket:
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specify the request ticket generated on your Icinga 2 master." << ConsoleColorTag(Console_Normal) << "\n"
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specify the request ticket generated on your Icinga 2 master."
+                   << ConsoleColorTag(Console_Normal) << "\n"
                    << " (Hint: # icinga2 pki ticket --cn '" << cn << "'): ";
 
                std::getline(std::cin, answer);
@@ -309,7 +344,7 @@ wizard_ticket:
                ticket = ticket.Trim();
 
                Log(LogInformation, "cli")
-                   << "Processing self-signed certificate request. Ticket '" << ticket << "'.\n";
+                   << "Requesting certificate with ticket '" << ticket << "'.\n";
 
                String target_ca = pki_path + "/ca.crt";
 
@@ -318,9 +353,11 @@ wizard_ticket:
                if (Utility::PathExists(node_cert))
                        NodeUtility::CreateBackupFile(node_cert);
 
-               if (PkiUtility::RequestCertificate(master_host, master_port, node_key, node_cert, target_ca, trusted_cert, ticket) > 0) {
+               if (PkiUtility::RequestCertificate(master_host, master_port, node_key,
+                   node_cert, target_ca, trustedcert, ticket) > 0) {
                        Log(LogCritical, "cli")
-                           << "Failed to fetch signed certificate from master '" << master_host << ", "
+                           << "Failed to fetch signed certificate from master '"
+                           << master_host << ", "
                            << master_port <<"'. Please try again.";
                        goto wizard_ticket;
                }
@@ -328,12 +365,17 @@ wizard_ticket:
                /* fix permissions (again) when updating the signed certificate */
                if (!Utility::SetFileOwnership(node_cert, user, group)) {
                        Log(LogWarning, "cli")
-                           << "Cannot set ownership for user '" << user << "' group '" << group << "' on file '" << node_cert << "'. Verify it yourself!";
+                           << "Cannot set ownership for user '" << user
+                           << "' group '" << group << "' on file '"
+                           << node_cert << "'. Verify it yourself!";
                }
 
                /* apilistener config */
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specify the API bind host/port" << ConsoleColorTag(Console_Normal) << " (optional):\n";
-               std::cout << ConsoleColorTag(Console_Bold) << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specify the API bind host/port"
+                   << ConsoleColorTag(Console_Normal) << " (optional):\n"
+                   << ConsoleColorTag(Console_Bold) << "Bind Host"
+                   << ConsoleColorTag(Console_Normal) << " []: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -349,14 +391,18 @@ wizard_ticket:
                String bind_port = answer;
                bind_port = bind_port.Trim();
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Accept config from master?" << ConsoleColorTag(Console_Normal) << " [y/N]: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Accept config from master?" << ConsoleColorTag(Console_Normal)
+                   << " [y/N]: ";
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
                choice = answer;
 
                String accept_config = choice.Contains("y") ? "true" : "false";
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Accept commands from master?" << ConsoleColorTag(Console_Normal) << " [y/N]: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Accept commands from master?" << ConsoleColorTag(Console_Normal)
+                   << " [y/N]: ";
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
                choice = answer;
@@ -424,7 +470,8 @@ wizard_ticket:
 
                if (cn != Utility::GetFQDN()) {
                        Log(LogWarning, "cli")
-                           << "CN '" << cn << "' does not match the default FQDN '" << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!";
+                           << "CN '" << cn << "' does not match the default FQDN '"
+                           << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!";
                }
 
                Log(LogInformation, "cli", "Updating constants.conf.");
@@ -440,7 +487,9 @@ wizard_ticket:
                std::cout << ConsoleColorTag(Console_Bold) << "Starting the Master setup routine...\n";
 
                /* CN */
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specifiy the common name" << ConsoleColorTag(Console_Normal) << " (CN) [" << Utility::GetFQDN() << "]: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specifiy the common name" << ConsoleColorTag(Console_Normal)
+                   << " (CN) [" << Utility::GetFQDN() << "]: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -454,16 +503,20 @@ wizard_ticket:
                /* check whether the user wants to generate a new certificate or not */
                String existing_path = PkiUtility::GetPkiPath() + "/" + cn + ".crt";
 
-               std::cout << ConsoleColorTag(Console_Normal) << "Checking for existing certificates for common name '" << cn << "'...\n";
+               std::cout << ConsoleColorTag(Console_Normal)
+                   << "Checking for existing certificates for common name '" << cn << "'...\n";
 
                if (Utility::PathExists(existing_path)) {
-                       std::cout << "Certificate '" << existing_path << "' for CN '" << cn << "' already existing. Skipping certificate generation.\n";
+                       std::cout << "Certificate '" << existing_path << "' for CN '"
+                           << cn << "' already existing. Skipping certificate generation.\n";
                } else {
                        std::cout << "Certificates not yet generated. Running 'api setup' now.\n";
                        ApiSetupUtility::SetupMasterCertificates(cn);
                }
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Generating master configuration for Icinga 2.\n" << ConsoleColorTag(Console_Normal);
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Generating master configuration for Icinga 2.\n"
+                   << ConsoleColorTag(Console_Normal);
                ApiSetupUtility::SetupMasterApiUser();
 
                if (!FeatureUtility::CheckFeatureEnabled("api"))
@@ -474,8 +527,10 @@ wizard_ticket:
                NodeUtility::GenerateNodeMasterIcingaConfig();
 
                /* apilistener config */
-               std::cout << ConsoleColorTag(Console_Bold) << "Please specify the API bind host/port (optional):\n";
-               std::cout << ConsoleColorTag(Console_Bold) << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Please specify the API bind host/port (optional):\n";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Bind Host" << ConsoleColorTag(Console_Normal) << " []: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -483,7 +538,8 @@ wizard_ticket:
                String bind_host = answer;
                bind_host = bind_host.Trim();
 
-               std::cout << ConsoleColorTag(Console_Bold) << "Bind Port" << ConsoleColorTag(Console_Normal) << " []: ";
+               std::cout << ConsoleColorTag(Console_Bold)
+                   << "Bind Port" << ConsoleColorTag(Console_Normal) << " []: ";
 
                std::getline(std::cin, answer);
                boost::algorithm::to_lower(answer);
@@ -533,7 +589,8 @@ wizard_ticket:
                /* update constants.conf with NodeName = CN + TicketSalt = random value */
                if (cn != Utility::GetFQDN()) {
                        Log(LogWarning, "cli")
-                               << "CN '" << cn << "' does not match the default FQDN '" << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!";
+                           << "CN '" << cn << "' does not match the default FQDN '"
+                           << Utility::GetFQDN() << "'. Requires update for NodeName constant in constants.conf!";
                }
 
                Log(LogInformation, "cli", "Updating constants.conf.");
index cbb842e35cee8087ecb78164325f7899f596982b..8b7c32547ab0229d6d2d9d48f6f66c5c77b58582 100644 (file)
@@ -20,6 +20,7 @@
 #include "cli/pkirequestcommand.hpp"
 #include "cli/pkiutility.hpp"
 #include "base/logger.hpp"
+#include "base/tlsutility.hpp"
 #include <iostream>
 
 using namespace icinga;
@@ -105,6 +106,6 @@ int PKIRequestCommand::Run(const boost::program_options::variables_map& vm, cons
                port = vm["port"].as<std::string>();
 
        return PkiUtility::RequestCertificate(vm["host"].as<std::string>(), port, vm["key"].as<std::string>(),
-           vm["cert"].as<std::string>(), vm["ca"].as<std::string>(), vm["trustedcert"].as<std::string>(),
+           vm["cert"].as<std::string>(), vm["ca"].as<std::string>(), GetX509Certificate(vm["trustedcert"].as<std::string>()),
            vm["ticket"].as<std::string>());
 }
index e50a7bc92c6d82156d97abc569bf8318e7707f7a..96a8115456bcf194470b164c8b3160caa4c281d3 100644 (file)
@@ -20,6 +20,7 @@
 #include "cli/pkisavecertcommand.hpp"
 #include "cli/pkiutility.hpp"
 #include "base/logger.hpp"
+#include "base/tlsutility.hpp"
 
 using namespace icinga;
 namespace po = boost::program_options;
@@ -40,11 +41,11 @@ void PKISaveCertCommand::InitParameters(boost::program_options::options_descript
     boost::program_options::options_description& hiddenDesc) const
 {
        visibleDesc.add_options()
-           ("key", po::value<std::string>(), "Key file path (input)")
-           ("cert", po::value<std::string>(), "Certificate file path (input)")
+           ("key", po::value<std::string>(), "Key file path (input), obsolete")
+           ("cert", po::value<std::string>(), "Certificate file path (input), obsolete")
            ("trustedcert", po::value<std::string>(), "Trusted certificate file path (output)")
            ("host", po::value<std::string>(), "Icinga 2 host")
-           ("port", po::value<std::string>(), "Icinga 2 port");
+           ("port", po::value<std::string>()->default_value("5665"), "Icinga 2 port");
 }
 
 std::vector<String> PKISaveCertCommand::GetArgumentSuggestions(const String& argument, const String& word) const
@@ -71,25 +72,18 @@ int PKISaveCertCommand::Run(const boost::program_options::variables_map& vm, con
                return 1;
        }
 
-       if (!vm.count("key")) {
-               Log(LogCritical, "cli", "Key input file path (--key) must be specified.");
-               return 1;
-       }
-
-       if (!vm.count("cert")) {
-               Log(LogCritical, "cli", "Certificate input file path (--cert) must be specified.");
-               return 1;
-       }
-
        if (!vm.count("trustedcert")) {
                Log(LogCritical, "cli", "Trusted certificate output file path (--trustedcert) must be specified.");
                return 1;
        }
 
-       String port = "5665";
+       boost::shared_ptr<X509> cert =
+           PkiUtility::FetchCert(vm["host"].as<std::string>(), vm["port"].as<std::string>());
 
-       if (vm.count("port"))
-               port = vm["port"].as<std::string>();
+       if (!cert) {
+               Log(LogCritical, "cli", "Failed to fetch certificate from host");
+               return 1;
+       }
 
-       return PkiUtility::SaveCert(vm["host"].as<std::string>(), port, vm["key"].as<std::string>(), vm["cert"].as<std::string>(), vm["trustedcert"].as<std::string>());
+       return PkiUtility::WriteCert(cert, vm["trustedcert"].as<std::string>());
 }
index 6f0faab8054a8beeba914433857e218d34693997..b1003665df32c7afd886727a8bf0f0e0f68f2480 100644 (file)
@@ -22,6 +22,7 @@
 #include "base/logger.hpp"
 #include "base/application.hpp"
 #include "base/tlsutility.hpp"
+#include "base/console.hpp"
 #include "base/tlsstream.hpp"
 #include "base/tcpsocket.hpp"
 #include "base/json.hpp"
@@ -110,30 +111,30 @@ int PkiUtility::SignCsr(const String& csrfile, const String& certfile)
        return 0;
 }
 
-int PkiUtility::SaveCert(const String& host, const String& port, const String& keyfile, const String& certfile, const String& trustedfile)
+boost::shared_ptr<X509> PkiUtility::FetchCert(const String& host, const String& port)
 {
        TcpSocket::Ptr client = new TcpSocket();
 
        try {
                client->Connect(host, port);
        } catch (const std::exception& ex) {
-               Log(LogCritical, "cli")
+               Log(LogCritical, "pki")
                    << "Cannot connect to host '" << host << "' on port '" << port << "'";
-               Log(LogDebug, "cli")
+               Log(LogDebug, "pki")
                    << "Cannot connect to host '" << host << "' on port '" << port << "':\n" << DiagnosticInformation(ex);
-               return 1;
+               return NULL;
        }
 
        boost::shared_ptr<SSL_CTX> sslContext;
 
        try {
-               sslContext = MakeSSLContext(certfile, keyfile);
+               sslContext = MakeSSLContext();
        } catch (const std::exception& ex) {
-               Log(LogCritical, "cli")
-                   << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "'.";
-               Log(LogDebug, "cli")
-                   << "Cannot make SSL context for cert path: '" << certfile << "' key path: '" << keyfile << "':\n"  << DiagnosticInformation(ex);
-               return 1;
+               Log(LogCritical, "pki")
+                   << "Cannot make SSL context.";
+               Log(LogDebug, "pki")
+                   << "Cannot make SSL context:\n"  << DiagnosticInformation(ex);
+               return NULL;
        }
 
        TlsStream::Ptr stream = new TlsStream(client, String(), RoleClient, sslContext);
@@ -144,25 +145,23 @@ int PkiUtility::SaveCert(const String& host, const String& port, const String& k
 
        }
 
-       boost::shared_ptr<X509> cert = stream->GetPeerCertificate();
-
-       if (!cert) {
-               Log(LogCritical, "cli", "Peer did not present a valid certificate.");
-               return 1;
-       }
+       return stream->GetPeerCertificate();
+}
 
+int PkiUtility::WriteCert(const boost::shared_ptr<X509>& cert, const String& trustedfile)
+{
        std::ofstream fpcert;
        fpcert.open(trustedfile.CStr());
        fpcert << CertificateToString(cert);
        fpcert.close();
 
        if (fpcert.fail()) {
-               Log(LogCritical, "cli")
+               Log(LogCritical, "pki")
                    << "Could not write certificate to file '" << trustedfile << "'.";
                return 1;
        }
 
-       Log(LogInformation, "cli")
+       Log(LogInformation, "pki")
            << "Writing trusted certificate to file '" << trustedfile << "'.";
 
        return 0;
@@ -176,7 +175,7 @@ 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 String& trustedfile, const String& ticket)
+    const String& certfile, const String& cafile, const boost::shared_ptr<X509>& trustedCert, const String& ticket)
 {
        TcpSocket::Ptr client = new TcpSocket();
 
@@ -213,17 +212,7 @@ int PkiUtility::RequestCertificate(const String& host, const String& port, const
 
        boost::shared_ptr<X509> peerCert = stream->GetPeerCertificate();
 
-       boost::shared_ptr<X509> trustedCert;
-
-       try {
-               trustedCert = GetX509Certificate(trustedfile);
-       } catch (const std::exception&) {
-               Log(LogCritical, "cli")
-                   << "Cannot get trusted from cert path: '" << trustedfile << "'.";
-               return 1;
-       }
-
-       if (CertificateToString(peerCert) != CertificateToString(trustedCert)) {
+       if (X509_cmp(peerCert.get(), trustedCert.get())) {
                Log(LogCritical, "cli", "Peer certificate does not match trusted certificate.");
                return 1;
        }
@@ -312,3 +301,43 @@ int PkiUtility::RequestCertificate(const String& host, const String& port, const
 
        return 0;
 }
+
+String PkiUtility::GetCertificateInformation(const boost::shared_ptr<X509>& cert) {
+       BIO *out = BIO_new(BIO_s_mem());
+       String pre;
+
+       pre = "\n Subject:     ";
+       BIO_write(out, pre.CStr(), pre.GetLength());
+       X509_NAME_print_ex(out, X509_get_subject_name(cert.get()), 0, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB);
+
+       pre = "\n Issuer:      ";
+       BIO_write(out, pre.CStr(), pre.GetLength());
+       X509_NAME_print_ex(out, X509_get_issuer_name(cert.get()), 0, XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB);
+
+       pre = "\n Valid From:  ";
+       BIO_write(out, pre.CStr(), pre.GetLength());
+       ASN1_TIME_print(out, X509_get_notBefore(cert));
+
+       pre = "\n Valid Until: ";
+       BIO_write(out, pre.CStr(), pre.GetLength());
+       ASN1_TIME_print(out, X509_get_notAfter(cert));
+
+       pre = "\n Fingerprint: ";
+       BIO_write(out, pre.CStr(), pre.GetLength());
+       unsigned char md[EVP_MAX_MD_SIZE];
+       unsigned int diglen;
+       X509_digest(cert.get(), EVP_sha1(), md, &diglen);
+
+       char *data;
+       long length = BIO_get_mem_data(out, &data);
+
+       std::stringstream info;
+       info << String(data, data + length);
+       for (unsigned int i = 0; i < diglen; i++) {
+               info << std::setfill('0') << std::setw(2) << std::uppercase
+                   << std::hex << static_cast<int>(md[i]) << ' ';
+       }
+       info << '\n';
+
+       return info.str();
+}
index cfa2230e8e5cd9a8b2920770e96fdd0dea3f5327..323066bce5150738ca8bd68f038d49e5147e2a23 100644 (file)
@@ -24,6 +24,7 @@
 #include "cli/i2-cli.hpp"
 #include "base/dictionary.hpp"
 #include "base/string.hpp"
+#include <openssl/x509v3.h>
 
 namespace icinga
 {
@@ -40,15 +41,17 @@ public:
        static int NewCa(void);
        static int NewCert(const String& cn, const String& keyfile, const String& csrfile, const String& certfile);
        static int SignCsr(const String& csrfile, const String& certfile);
-       static int SaveCert(const String& host, const String& port, const String& keyfile, const String& certfile, const String& trustedfile);
+       static boost::shared_ptr<X509> FetchCert(const String& host, const String& port);
+       static int WriteCert(const boost::shared_ptr<X509>& cert, const String& trustedfile);
        static int GenTicket(const String& cn, const String& salt, std::ostream& ticketfp);
        static int RequestCertificate(const String& host, const String& port, const String& keyfile,
-           const String& certfile, const String& cafile, const String& trustedfile, const String& ticket);
+           const String& certfile, const String& cafile, const boost::shared_ptr<X509>& trustedcert,
+           const String& ticket);
+       static String GetCertificateInformation(const boost::shared_ptr<X509>& certificate);
 
 private:
        PkiUtility(void);
 
-
 };
 
 }