Add method to update certificate properities.
Read a certificate file and update properties to the D-Bus object
Change-Id: I108909a044dd678000142ea68cc019ab3d13f97b
Signed-off-by: Dhruvaraj Subhashchandran <dhruvaraj@in.ibm.com>
diff --git a/certificate.cpp b/certificate.cpp
index afd15ce..413ad54 100644
--- a/certificate.cpp
+++ b/certificate.cpp
@@ -21,6 +21,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 ASN1_TIME_ptr = std::unique_ptr<ASN1_TIME, decltype(&ASN1_STRING_free)>;
using EVP_PKEY_Ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
using BUF_MEM_Ptr = std::unique_ptr<BUF_MEM, decltype(&::BUF_MEM_free)>;
using InternalFailure =
@@ -37,6 +38,34 @@
(errnum == X509_V_ERR_CERT_UNTRUSTED) || \
(errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
+// Refer to schema 2018.3
+// http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for
+// supported KeyUsage types in redfish
+// Refer to
+// https://github.com/openssl/openssl/blob/master/include/openssl/x509v3.h for
+// key usage bit fields
+std::map<uint8_t, std::string> keyUsageToRfStr = {
+ {KU_DIGITAL_SIGNATURE, "DigitalSignature"},
+ {KU_NON_REPUDIATION, "NonRepudiation"},
+ {KU_KEY_ENCIPHERMENT, "KeyEncipherment"},
+ {KU_DATA_ENCIPHERMENT, "DataEncipherment"},
+ {KU_KEY_AGREEMENT, "KeyAgreement"},
+ {KU_KEY_CERT_SIGN, "KeyCertSign"},
+ {KU_CRL_SIGN, "CRLSigning"},
+ {KU_ENCIPHER_ONLY, "EncipherOnly"},
+ {KU_DECIPHER_ONLY, "DecipherOnly"}};
+
+// Refer to schema 2018.3
+// http://redfish.dmtf.org/schemas/v1/Certificate.json#/definitions/KeyUsage for
+// supported Extended KeyUsage types in redfish
+std::map<uint8_t, std::string> extendedKeyUsageToRfStr = {
+ {NID_server_auth, "ServerAuthentication"},
+ {NID_client_auth, "ClientAuthentication"},
+ {NID_email_protect, "EmailProtection"},
+ {NID_OCSP_sign, "OCSPSigning"},
+ {NID_ad_timeStamping, "Timestamping"},
+ {NID_code_sign, "CodeSigning"}};
+
Certificate::Certificate(sdbusplus::bus::bus& bus, const std::string& objPath,
const CertificateType& type,
const UnitsToRestart& unit,
@@ -228,6 +257,86 @@
{
reloadOrReset(unitToRestart);
}
+
+ // Parse the certificate file and populate properties
+ populateProperties();
+}
+
+void Certificate::populateProperties()
+{
+ X509_Ptr cert = std::move(loadCert(certInstallPath));
+ // Update properties if no error thrown
+ BIO_MEM_Ptr certBio(BIO_new(BIO_s_mem()), BIO_free);
+ PEM_write_bio_X509(certBio.get(), cert.get());
+ BUF_MEM_Ptr certBuf(BUF_MEM_new(), BUF_MEM_free);
+ BUF_MEM* buf = certBuf.get();
+ BIO_get_mem_ptr(certBio.get(), &buf);
+ std::string certStr(buf->data, buf->length);
+ CertificateIface::certificateString(certStr);
+
+ static const int maxKeySize = 4096;
+ char subBuffer[maxKeySize] = {0};
+ // This pointer cannot be freed independantly.
+ X509_NAME* sub = X509_get_subject_name(cert.get());
+ X509_NAME_print_ex(certBio.get(), sub, 0, 0);
+ BIO_read(certBio.get(), subBuffer, maxKeySize);
+ CertificateIface::subject(subBuffer);
+
+ // This pointer cannot be freed independantly.
+ char issuerBuffer[maxKeySize] = {0};
+ X509_NAME* issuer_name = X509_get_issuer_name(cert.get());
+ X509_NAME_print_ex(certBio.get(), issuer_name, 0, 0);
+ BIO_read(certBio.get(), issuerBuffer, maxKeySize);
+ CertificateIface::issuer(issuerBuffer);
+
+ std::vector<std::string> keyUsageList;
+ ASN1_BIT_STRING* usage;
+
+ // Go through each usage in the bit string and convert to
+ // corresponding string value
+ if ((usage = static_cast<ASN1_BIT_STRING*>(
+ X509_get_ext_d2i(cert.get(), NID_key_usage, NULL, NULL))))
+ {
+ for (auto i = 0; i < usage->length; ++i)
+ {
+ for (auto& x : keyUsageToRfStr)
+ {
+ if (x.first & usage->data[i])
+ {
+ keyUsageList.push_back(x.second);
+ break;
+ }
+ }
+ }
+ }
+
+ EXTENDED_KEY_USAGE* extUsage;
+ if ((extUsage = static_cast<EXTENDED_KEY_USAGE*>(
+ X509_get_ext_d2i(cert.get(), NID_ext_key_usage, NULL, NULL))))
+ {
+ for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++)
+ {
+ keyUsageList.push_back(extendedKeyUsageToRfStr[OBJ_obj2nid(
+ sk_ASN1_OBJECT_value(extUsage, i))]);
+ }
+ }
+ CertificateIface::keyUsage(keyUsageList);
+
+ int days = 0;
+ int secs = 0;
+
+ ASN1_TIME_ptr epoch(ASN1_TIME_new(), ASN1_STRING_free);
+ // Set time to 12:00am GMT, Jan 1 1970
+ ASN1_TIME_set_string(epoch.get(), "700101120000Z");
+
+ static const int dayToSeconds = 24 * 60 * 60;
+ ASN1_TIME* notAfter = X509_get_notAfter(cert.get());
+ ASN1_TIME_diff(&days, &secs, epoch.get(), notAfter);
+ CertificateIface::validNotAfter((days * dayToSeconds) + secs);
+
+ ASN1_TIME* notBefore = X509_get_notBefore(cert.get());
+ ASN1_TIME_diff(&days, &secs, epoch.get(), notBefore);
+ CertificateIface::validNotBefore((days * dayToSeconds) + secs);
}
X509_Ptr Certificate::loadCert(const std::string& filePath)
diff --git a/certificate.hpp b/certificate.hpp
index fc48f03..878ae71 100644
--- a/certificate.hpp
+++ b/certificate.hpp
@@ -81,6 +81,11 @@
*/
X509_Ptr loadCert(const std::string& filePath);
+ /** @brief Populate certificate properties by parsing certificate file
+ * @return void
+ */
+ void populateProperties();
+
/** @brief Public/Private key compare function.
* Comparing private key against certificate public key
* from input .pem file.