Add Public/Private key compare function

Comparing private key against certificate public key
from input .pem file

Change-Id: I6abac7f6f33182a41d7bac3562c126c91164de82
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
diff --git a/certs_manager.cpp b/certs_manager.cpp
index 7ecefa2..4017ff7 100644
--- a/certs_manager.cpp
+++ b/certs_manager.cpp
@@ -25,6 +25,7 @@
     std::unique_ptr<X509_STORE_CTX, decltype(&::X509_STORE_CTX_free)>;
 using X509_LOOKUP_Ptr =
     std::unique_ptr<X509_LOOKUP, decltype(&::X509_LOOKUP_free)>;
+using EVP_PKEY_Ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
 
 namespace fs = std::experimental::filesystem;
 using namespace phosphor::logging;
@@ -47,6 +48,14 @@
         // Loging general error here.
         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);
 
@@ -252,5 +261,68 @@
     return errCode;
 }
 
+bool Manager::compareKeys(const std::string& filePath)
+{
+    X509_Ptr cert(X509_new(), ::X509_free);
+    if (!cert)
+    {
+        log<level::ERR>("Error occured during X509_new call",
+                        entry("FILE=%s", filePath.c_str()),
+                        entry("ERRCODE=%lu", ERR_get_error()));
+        elog<InternalFailure>();
+    }
+
+    BIO_MEM_Ptr bioCert(BIO_new_file(filePath.c_str(), "rb"), ::BIO_free);
+    if (!bioCert)
+    {
+        log<level::ERR>("Error occured during BIO_new_file call",
+                        entry("FILE=%s", filePath.c_str()));
+        elog<InternalFailure>();
+    }
+
+    X509* x509 = cert.get();
+    PEM_read_bio_X509(bioCert.get(), &x509, nullptr, nullptr);
+
+    EVP_PKEY_Ptr pubKey(X509_get_pubkey(cert.get()), ::EVP_PKEY_free);
+    if (!pubKey)
+    {
+        log<level::ERR>("Error occurred during X509_get_pubkey",
+                        entry("FILE=%s", filePath.c_str()),
+                        entry("ERRCODE=%lu", ERR_get_error()));
+        elog<InvalidCertificate>(Reason("Failed to get public key info"));
+    }
+
+    BIO_MEM_Ptr keyBio(BIO_new(BIO_s_file()), ::BIO_free);
+    if (!keyBio)
+    {
+        log<level::ERR>("Error occured during BIO_s_file call",
+                        entry("FILE=%s", filePath.c_str()));
+        elog<InternalFailure>();
+    }
+    BIO_read_filename(keyBio.get(), filePath.c_str());
+
+    EVP_PKEY_Ptr priKey(
+        PEM_read_bio_PrivateKey(keyBio.get(), nullptr, nullptr, nullptr),
+        ::EVP_PKEY_free);
+
+    if (!priKey)
+    {
+        log<level::ERR>("Error occurred during PEM_read_bio_PrivateKey",
+                        entry("FILE=%s", filePath.c_str()),
+                        entry("ERRCODE=%lu", ERR_get_error()));
+        elog<InvalidCertificate>(Reason("Failed to get private key info"));
+    }
+
+    int32_t rc = EVP_PKEY_cmp(priKey.get(), pubKey.get());
+    if (rc != 1)
+    {
+        log<level::ERR>("Private key is not matching with Certificate",
+                        entry("FILE=%s", filePath.c_str()),
+                        entry("ERRCODE=%d", rc));
+        return false;
+    }
+
+    return true;
+}
 } // namespace certs
 } // namespace phosphor