Add Generate Key and Certificate Signing Request (CSR)

Generates Private key and CSR file, at present supporing
only RSA algorithm type.

-The generateCSR method defined in Create interface is implemented
by manager class to Create CSR and PrivateKey files.

-The cSR method defined in View interface is implemented by CSR
class to view CSR file.

- Generate CSR is time consuming operation and it might time-out
the D-Bus call. Forking process and performing CSR generation in
the child process, adding the process ID of the child process to the
SD Event loop so that callback is received when the chid process
is done with the CSR generation.

- As the GenerateCSR method returns immediately, caller need
to wait on InterfacesAdded signal that is generated after completion
of the CSR request. The caller then invokes cSR method of
CSR interface to read the CSR.

- For any failure in Generate CSR CSR object is created with error
status.

- CSR object raises exception if error is set else CSR data is
returned to the caller.

- To cater for failure cases caller need to start a timer, which
will be terminated after getting InterfaceAdded signal or upon timeout.

-Added Unit tests.
Tested:
1) Added unit tests to verify CSR generation
2) Tested with Redfish to generate and view CSR
curl -c cjar -b cjar -k -H "X-Auth-Token: $bmc_token" -X POST
https://${bmc}/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR/
-d @generate.jon

{
  "CSRString": "-----BEGIN CERTIFICATE REQUEST---7E=\n-----END CERTIFICATE
REQUEST-----\n",
  "CertificateCollection": {
    "@odata.id": "/redfish/v1/AccountService/LDAP/Certificates/"
  }
}
Change-Id: I1e3ae8df45f87bfd8903f552d93c4df1af7c569f
Signed-off-by: Marri Devender Rao <devenrao@in.ibm.com>
Signed-off-by: Nagaraju Goruganti <ngorugan@in.ibm.com>
diff --git a/certs_manager.hpp b/certs_manager.hpp
index 2e93975..0c8f4e6 100644
--- a/certs_manager.hpp
+++ b/certs_manager.hpp
@@ -1,6 +1,12 @@
 #pragma once
-#include "certificate.hpp"
+#include "config.h"
 
+#include "certificate.hpp"
+#include "csr.hpp"
+
+#include <sdeventplus/source/child.hpp>
+#include <sdeventplus/source/event.hpp>
+#include <xyz/openbmc_project/Certs/CSR/Create/server.hpp>
 #include <xyz/openbmc_project/Certs/Install/server.hpp>
 #include <xyz/openbmc_project/Object/Delete/server.hpp>
 
@@ -8,9 +14,13 @@
 {
 namespace certs
 {
-using Create = sdbusplus::xyz::openbmc_project::Certs::server::Install;
+using Install = 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 CSRCreate = sdbusplus::xyz::openbmc_project::Certs::CSR::server::Create;
+using Ifaces = sdbusplus::server::object::object<Install, CSRCreate, Delete>;
+
+using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
+using EVP_PKEY_Ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
 
 class Manager : public Ifaces
 {
@@ -34,14 +44,15 @@
 
     /** @brief Constructor to put object onto bus at a dbus path.
      *  @param[in] bus - Bus to attach to.
+     *  @param[in] event - sd event handler.
      *  @param[in] path - Path to attach at.
      *  @param[in] type - Type of the certificate.
      *  @param[in] unit - Unit consumed by this certificate.
      *  @param[in] installPath - Certificate installation path.
      */
-    Manager(sdbusplus::bus::bus& bus, const char* path,
-            const CertificateType& type, UnitsToRestart&& unit,
-            CertInstallPath&& installPath);
+    Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
+            const char* path, const CertificateType& type,
+            UnitsToRestart&& unit, CertInstallPath&& installPath);
 
     /** @brief Implementation for Install
      *  Replace the existing certificate key file with another
@@ -56,10 +67,135 @@
      */
     void delete_() override;
 
+    /** @brief Generate Private key and CSR file
+     *  Generates the Private key file and CSR file based on the input
+     *  parameters. Validation of the parameters is callers responsibility.
+     *  At present supports only RSA algorithm type
+     *
+     *  @param[in] alternativeNames - Additional hostnames of the component that
+     *      is being secured.
+     *  @param[in] challengePassword - The challenge password to be applied to
+     *      the certificate for revocation requests.
+     *  @param[in] city - The city or locality of the organization making the
+     *      request. For Example Austin
+     *  @param[in] commonName - The fully qualified domain name of the component
+     *      that is being secured.
+     *  @param[in] contactPerson - The name of the user making the request.
+     *  @param[in] country - The country of the organization making the request.
+     *  @param[in] email - The email address of the contact within the
+     *      organization making the request.
+     *  @param[in] givenName - The given name of the user making the request.
+     *  @param[in] initials - The initials of the user making the request.
+     *  @param[in] keyBitLength - The length of the key in bits, if needed based
+     *      on the value of the KeyPairAlgorithm parameter.
+     *  @param[in] keyCurveId - The curve ID to be used with the key, if needed
+     *      based on the value of the KeyPairAlgorithm parameter.
+     *  @param[in] keyPairAlgorithm - The type of key pair for use with signing
+     *      algorithms. Valid built-in algorithm names for private key
+     *      generation are: RSA, DSA, DH and EC.
+     *  @param[in] keyUsage - Key usage extensions define the purpose of the
+     *      public key contained in a certificate. Valid Key usage extensions
+     *      and its usage description.
+     *      - ClientAuthentication: The public key is used for TLS WWW client
+     *      authentication.
+     *      - CodeSigning: The public key is used for the signing of executable
+     *          code
+     *      - CRLSigning: The public key is used for verifying signatures on
+     *          certificate revocation lists (CLRs).
+     *      - DataEncipherment: The public key is used for directly enciphering
+     *          raw user data without the use of an intermediate symmetric
+     *          cipher.
+     *      - DecipherOnly: The public key could be used for deciphering data
+     *          while performing key agreement.
+     *      - DigitalSignature: The public key is used for verifying digital
+     *          signatures, other than signatures on certificatesand CRLs.
+     *      - EmailProtection: The public key is used for email protection.
+     *      - EncipherOnly: Thepublic key could be used for enciphering data
+     *          while performing key agreement.
+     *      - KeyCertSign: The public key is used for verifying signatures on
+     *          public key certificates.
+     *      - KeyEncipherment: The public key is used for enciphering private or
+     *          secret keys.
+     *      - NonRepudiation: The public key is used to verify digital
+     *          signatures, other than signatures on certificates and CRLs, and
+     *          used to provide a non-repudiation service that protects against
+     *          the signing entity falsely denying some action.
+     *      - OCSPSigning: The public key is used for signing OCSP responses.
+     *      - ServerAuthentication: The public key is used for TLS WWW server
+     *          authentication.
+     *      - Timestamping: The public key is used for binding the hash of an
+     *          object to a time.
+     *  @param[in] organization - The legal name of the organization. This
+     *      should not be abbreviated and should include suffixes such as Inc,
+     *      Corp, or LLC.For example, IBM Corp.
+     *  @param[in] organizationalUnit - The name of the unit or division of the
+     *      organization making the request.
+     *  @param[in] state - The state or province where the organization is
+     *      located. This should not be abbreviated. For example, Texas.
+     *  @param[in] surname - The surname of the user making the request.
+     *  @param[in] unstructuredName - The unstructured name of the subject.
+     *
+     *  @return path[std::string] - The object path of the D-Bus object
+     *      representing CSR string. Note: For new CSR request will overwrite
+     * the existing CSR in the system.
+     */
+    std::string generateCSR(
+        std::vector<std::string> alternativeNames,
+        std::string challengePassword, std::string city, std::string commonName,
+        std::string contactPerson, std::string country, std::string email,
+        std::string givenName, std::string initials, int64_t keyBitLength,
+        std::string keyCurveId, std::string keyPairAlgorithm,
+        std::vector<std::string> keyUsage, std::string organization,
+        std::string organizationalUnit, std::string state, std::string surname,
+        std::string unstructuredName) override;
+
   private:
+    void generateCSRHelper(std::vector<std::string> alternativeNames,
+                           std::string challengePassword, std::string city,
+                           std::string commonName, std::string contactPerson,
+                           std::string country, std::string email,
+                           std::string givenName, std::string initials,
+                           int64_t keyBitLength, std::string keyCurveId,
+                           std::string keyPairAlgorithm,
+                           std::vector<std::string> keyUsage,
+                           std::string organization,
+                           std::string organizationalUnit, std::string state,
+                           std::string surname, std::string unstructuredName);
+
+    /** @brief Write private key data to file
+     *
+     *  @param[in] keyBitLength - KeyBit length.
+     *  @param[in] x509Req - pointer to X509 request.
+     *  @return pointer to private key
+     */
+    EVP_PKEY_Ptr writePrivateKey(int64_t keyBitLength, X509_REQ_Ptr& x509Req);
+
+    /** @brief Add the specified CSR field with the data
+     *  @param[in] x509Name - Structure used in setting certificate properties
+     *  @param[in] field - field name
+     *  @param[in] bytes - field value in bytes
+     */
+    void addEntry(X509_NAME* x509Name, const char* field,
+                  const std::string& bytes);
+
+    /** @brief Create CSR D-Bus object by reading the data in the CSR file
+     *  @param[in] statis - SUCCESSS/FAILURE In CSR generation.
+     */
+    void createCSRObject(const Status& status);
+
+    /** @brief Write generated CSR data to file
+     *
+     *  @param[in] filePath - CSR file path.
+     *  @param[in] x509Req - OpenSSL Request Pointer.
+     */
+    void writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req);
+
     /** @brief sdbusplus handler */
     sdbusplus::bus::bus& bus;
 
+    // sdevent Event handle
+    sdeventplus::Event& event;
+
     /** @brief object path */
     std::string objectPath;
 
@@ -74,7 +210,12 @@
 
     /** @brief pointer to certificate */
     std::unique_ptr<Certificate> certificatePtr = nullptr;
-};
 
+    /** @brief pointer to CSR */
+    std::unique_ptr<CSR> csrPtr = nullptr;
+
+    /** @brief SDEventPlus child pointer added to event loop */
+    std::unique_ptr<sdeventplus::source::Child> childPtr;
+};
 } // namespace certs
 } // namespace phosphor