Add support to upload CA certificate

Added support to upload CA certificates in
/etc/ssl/certs path. Curently scope is limited to one
certificate and any new upload is going to override the
existing  CA certificate.

Change-Id: I9cc60accf6aae4d8123e5f86d618effe33d68d53
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
diff --git a/argument.cpp b/argument.cpp
index a5402e6..38d3978 100644
--- a/argument.cpp
+++ b/argument.cpp
@@ -69,7 +69,7 @@
     std::cerr << "Options:\n";
     std::cerr << "    --help            Print this menu\n";
     std::cerr << "    --type            certificate type\n";
-    std::cerr << "                      Valid types: Client,Server\n";
+    std::cerr << "                      Valid types: client,server,authority\n";
     std::cerr << "    --endpoint        d-bus endpoint\n";
     std::cerr << "    --path            certificate file path\n";
     std::cerr << "    --unit=<name>     Optional systemd unit need to reload\n";
diff --git a/certs_manager.cpp b/certs_manager.cpp
index d8c6263..8f36782 100644
--- a/certs_manager.cpp
+++ b/certs_manager.cpp
@@ -59,16 +59,6 @@
         elog<InvalidCertificate>(Reason("Certificate validation failed"));
     }
 
-    // Compare the Keys
-    if (!compareKeys(path))
-    {
-        elog<InvalidCertificate>(
-            Reason("Private key is not matching with Certificate"));
-    }
-
-    // Copy the certificate file
-    copy(path, certPath);
-
     // Invoke type specific install function.
     auto iter = typeFuncMap.find(type);
     if (iter == typeFuncMap.end())
@@ -76,25 +66,40 @@
         log<level::ERR>("Unsupported Type", entry("TYPE=%s", type.c_str()));
         elog<InternalFailure>();
     }
-    iter->second();
-}
+    iter->second(path);
 
-void Manager::serverInstall()
-{
+    // Copy the certificate file
+    copy(path, certPath);
+
     if (!unit.empty())
     {
         reloadOrReset(unit);
     }
 }
 
-void Manager::clientInstall()
+void Manager::serverInstallHelper(const std::string& filePath)
 {
-    if (!unit.empty())
+    if (!compareKeys(filePath))
     {
-        reloadOrReset(unit);
+        elog<InvalidCertificate>(
+            Reason("Private key does not match the Certificate"));
     }
 }
 
+void Manager::clientInstallHelper(const std::string& filePath)
+{
+    if (!compareKeys(filePath))
+    {
+        elog<InvalidCertificate>(
+            Reason("Private key does not match the Certificate"));
+    }
+}
+
+void Manager::authorityInstallHelper(const std::string& filePath)
+{
+    // No additional steps required now.
+}
+
 void Manager::reloadOrReset(const std::string& unit)
 {
     constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
diff --git a/certs_manager.hpp b/certs_manager.hpp
index 8601c64..1ca4f1a 100644
--- a/certs_manager.hpp
+++ b/certs_manager.hpp
@@ -18,13 +18,17 @@
 // Supported Types.
 static constexpr auto SERVER = "server";
 static constexpr auto CLIENT = "client";
+static constexpr auto AUTHORITY = "authority";
 
 using Create = sdbusplus::xyz::openbmc_project::Certs::server::Install;
 using Delete = sdbusplus::xyz::openbmc_project::Object::server::Delete;
 using Ifaces = sdbusplus::server::object::object<Create, Delete>;
-using InstallFunc = std::function<void()>;
+using InstallFunc = std::function<void(const std::string&)>;
 using InputType = std::string;
 
+// for placeholders
+using namespace std::placeholders;
+
 class Manager : public Ifaces
 {
   public:
@@ -59,9 +63,11 @@
         certPath(std::move(certPath))
     {
         typeFuncMap[SERVER] =
-            std::bind(&phosphor::certs::Manager::serverInstall, this);
+            std::bind(&phosphor::certs::Manager::serverInstallHelper, this, _1);
         typeFuncMap[CLIENT] =
-            std::bind(&phosphor::certs::Manager::clientInstall, this);
+            std::bind(&phosphor::certs::Manager::clientInstallHelper, this, _1);
+        typeFuncMap[AUTHORITY] = std::bind(
+            &phosphor::certs::Manager::authorityInstallHelper, this, _1);
     }
 
     /** @brief Implementation for Install
@@ -78,11 +84,20 @@
     void delete_() override;
 
   private:
-    /** @brief Client certificate Installation helper function **/
-    virtual void clientInstall();
+    /** @brief Client certificate Installation helper function
+     *  @param[in] path - Certificate key file path.
+     */
+    virtual void clientInstallHelper(const std::string& filePath);
 
-    /** @brief Server certificate Installation helper function **/
-    virtual void serverInstall();
+    /** @brief Server certificate Installation helper function
+     *  @param[in] path - Certificate key file path.
+     */
+    virtual void serverInstallHelper(const std::string& filePath);
+
+    /** @brief Authority certificate Installation helper function
+     *  @param[in] path - Certificate key file path.
+     */
+    virtual void authorityInstallHelper(const std::string& filePath);
 
     /** @brief systemd unit reload or reset helper function
      *  Reload if the unit supports it and use a restart otherwise.
diff --git a/mainapp.cpp b/mainapp.cpp
index 5b0f29f..3f97025 100644
--- a/mainapp.cpp
+++ b/mainapp.cpp
@@ -45,7 +45,8 @@
     auto type = std::move((options)["type"]);
     if ((type == phosphor::certs::util::ArgumentParser::empty_string) ||
         !((type == phosphor::certs::SERVER) ||
-          (type == phosphor::certs::CLIENT)))
+          (type == phosphor::certs::CLIENT) ||
+          (type == phosphor::certs::AUTHORITY)))
     {
         ExitWithError("type not specified or invalid.", argv);
     }
diff --git a/test/certs_manager_test.cpp b/test/certs_manager_test.cpp
index f1a7587..c381cec 100644
--- a/test/certs_manager_test.cpp
+++ b/test/certs_manager_test.cpp
@@ -117,8 +117,7 @@
     {
     }
 
-    MOCK_METHOD0(clientInstall, void());
-    MOCK_METHOD0(serverInstall, void());
+    MOCK_METHOD1(reloadOrReset, void(const std::string& unit));
 };
 
 /** @brief Check if server install routine is invoked for server setup
@@ -130,10 +129,11 @@
     std::string type("server");
     std::string path(certDir + "/" + certificateFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, serverInstall()).Times(1);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
 
     MainApp mainApp(&manager);
     EXPECT_NO_THROW({ mainApp.install(certificateFile); });
@@ -149,10 +149,31 @@
     std::string type("client");
     std::string path(certDir + "/" + certificateFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(1);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
+    MainApp mainApp(&manager);
+    EXPECT_NO_THROW({ mainApp.install(certificateFile); });
+    EXPECT_TRUE(fs::exists(verifyPath));
+}
+
+/** @brief Check if authority install routine is invoked for authority setup
+ */
+TEST_F(TestCertsManager, InvokeAuthorityInstall)
+{
+    std::string endpoint("ldap");
+    std::string unit("nslcd.service");
+    std::string type("authority");
+    std::string path(certDir + "/" + certificateFile);
+    std::string verifyPath(path);
+    std::string verifyUnit(unit);
+    auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
+    MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
+                            std::move(path));
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
+
     MainApp mainApp(&manager);
     EXPECT_NO_THROW({ mainApp.install(certificateFile); });
     EXPECT_TRUE(fs::exists(verifyPath));
@@ -167,10 +188,11 @@
     std::string type("client");
     std::string path(certDir + "/" + certificateFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(1);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(1);
     MainApp mainApp(&manager);
     EXPECT_NO_THROW({ mainApp.install(certificateFile); });
     EXPECT_TRUE(fs::exists(verifyPath));
@@ -186,10 +208,11 @@
     std::string type("client");
     std::string path(certDir + "/" + certificateFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(0);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
     MainApp mainApp(&manager);
     std::string certpath = "nofile.pem";
     EXPECT_THROW(
@@ -222,10 +245,11 @@
 
     std::string path(certDir + "/" + emptyFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(0);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
     MainApp mainApp(&manager);
     EXPECT_THROW(
         {
@@ -260,10 +284,11 @@
 
     std::string path(certDir + "/" + certificateFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(0);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
     MainApp mainApp(&manager);
     EXPECT_THROW(
         {
@@ -280,24 +305,6 @@
     EXPECT_FALSE(fs::exists(verifyPath));
 }
 
-/** @brief Test deletion of installed certificate file
- */
-class MockReloadReset : public phosphor::certs::Manager
-{
-  public:
-    MockReloadReset(sdbusplus::bus::bus& bus, const char* path,
-                    std::string& type, std::string&& unit,
-                    std::string&& certPath) :
-        Manager(bus, path, type, std::forward<std::string>(unit),
-                std::forward<std::string>(certPath))
-    {
-    }
-    virtual ~MockReloadReset()
-    {
-    }
-
-    MOCK_METHOD1(reloadOrReset, void(const std::string& unit));
-};
 TEST_F(TestCertsManager, TestDeleteCertificate)
 {
     std::string endpoint("ldap");
@@ -307,7 +314,7 @@
     std::string verifyPath(path);
     std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
-    MockReloadReset manager(bus, objPath.c_str(), type, std::move(unit),
+    MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
     EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(2);
     MainApp mainApp(&manager);
@@ -374,11 +381,11 @@
     std::string type("client");
     std::string path(certDir + "/" + certificateFile);
     std::string verifyPath(path);
-
+    std::string verifyUnit(unit);
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(0);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
     MainApp mainApp(&manager);
     EXPECT_THROW(
         {
@@ -404,11 +411,12 @@
     std::string type("client");
     std::string path(certDir + "/" + keyFile);
     std::string verifyPath(path);
+    std::string verifyUnit(unit);
 
     auto objPath = std::string(OBJPATH) + '/' + type + '/' + endpoint;
     MockCertManager manager(bus, objPath.c_str(), type, std::move(unit),
                             std::move(path));
-    EXPECT_CALL(manager, clientInstall()).Times(0);
+    EXPECT_CALL(manager, reloadOrReset(verifyUnit)).Times(0);
     MainApp mainApp(&manager);
     EXPECT_THROW(
         {