Return error if certificate expiry date is beyond year 2038
Any certificate which is uploaded with expiry year greater than 2038
causes the exipry date to be set to time before 1970.
time_t is used in calculation of expirty date based on seconds from
epoch. As time_t is defined as int32 any time beyond 2038 causes
integer overflow and generates a negtive number. When the negative
number is used in time calculation it generates year before 1970.
Modified to return error if the seconds computed for expiry date
is beyond INT_MAX.
This change is required till kernel changes time_t to use 64 bit value.
Tested:
Mar 12 11:14:38 xx phosphor-certificate-manager[520]: Certificate install
Mar 12 11:14:38 xx phosphor-certificate-manager[520]: Certificate expiry date is
beyond year 2038
Mar 12 11:14:38 xx phosphor-certificate-manager[520]: Invalid certificate file.
"MESSAGE" : "Certificate expiry date is beyond year 2038",
"PRIORITY" : "3",
"SECONDS" : "2366947077",
Signed-off-by: Marri Devender Rao <devenrao@in.ibm.com>
Change-Id: Icb926fe6eebb2ce896ccde2527b7494896653f58
diff --git a/certificate.cpp b/certificate.cpp
index 076fbd6..6bfd4af 100644
--- a/certificate.cpp
+++ b/certificate.cpp
@@ -339,12 +339,18 @@
{
if (errCode == X509_V_ERR_CERT_HAS_EXPIRED)
{
+ log<level::ERR>("Expired certificate ");
elog<InvalidCertificate>(Reason("Expired Certificate"));
}
// Loging general error here.
+ log<level::ERR>(
+ "Certificate validation failed", entry("ERRCODE=%d", errCode),
+ entry("ERROR_STR=%s", X509_verify_cert_error_string(errCode)));
elog<InvalidCertificate>(Reason("Certificate validation failed"));
}
+ validateCertificateExpiryDate(cert);
+
// Invoke type specific append private key function.
auto appendIter = appendKeyMap.find(certType);
if (appendIter == appendKeyMap.end())
@@ -410,6 +416,31 @@
}
}
+void Certificate::validateCertificateExpiryDate(const X509_Ptr& cert)
+{
+ 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");
+
+ ASN1_TIME* notAfter = X509_get_notAfter(cert.get());
+ ASN1_TIME_diff(&days, &secs, epoch.get(), notAfter);
+
+ static const int dayToSeconds = 24 * 60 * 60;
+
+ // TODO #issue15 - allow only upto year 2038 which time_t supports for now
+ // time_t is defined as int32 so any expiry date greater than 2038 will
+ // cause the time_t variable overflow resulting in -ve number.
+ if (days > (INT_MAX - secs) / dayToSeconds)
+ {
+ log<level::ERR>("Certificate expiry date is beyond year 2038",
+ entry("DAYS=%d", days));
+ elog<InvalidCertificate>(Reason("Expiry date should be below 2038"));
+ }
+}
+
void Certificate::populateProperties()
{
populateProperties(certInstallPath);
@@ -522,7 +553,7 @@
// Set time to 12:00am GMT, Jan 1 1970
ASN1_TIME_set_string(epoch.get(), "700101120000Z");
- static const int dayToSeconds = 24 * 60 * 60;
+ static const uint32_t 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);
diff --git a/certificate.hpp b/certificate.hpp
index feffecc..9a0c917 100644
--- a/certificate.hpp
+++ b/certificate.hpp
@@ -120,6 +120,18 @@
private:
/**
+ * @brief Return error if ceritificate expiry date is gt 2038
+ *
+ * Parse the certificate and return error if certificate expiry date
+ * is gt 2038.
+ *
+ * @param[in] cert Reference to certificate object uploaded
+ *
+ * @return void
+ */
+ void validateCertificateExpiryDate(const X509_Ptr& cert);
+
+ /**
* @brief Populate certificate properties by parsing given certificate file
*
* @param[in] certPath Path to certificate that should be parsed