Cleanup: use dcp::LocalTime for certificate validity times.
authorCarl Hetherington <cth@carlh.net>
Sat, 12 Feb 2022 20:15:03 +0000 (21:15 +0100)
committerCarl Hetherington <cth@carlh.net>
Sat, 12 Feb 2022 22:13:49 +0000 (23:13 +0100)
Before we were using struct tm but not filling it all in, which
seems quite unpleasant.

src/certificate.cc
src/certificate.h
src/decrypted_kdm.cc
src/local_time.cc
src/local_time.h
test/certificates_test.cc
test/local_time_test.cc
tools/dcpkdm.cc

index 93f271ef29ff0adab23a9b81ebb2233cda089424..1e7714a321e61991c2a7a2a284c9d30004ebef76 100644 (file)
@@ -329,29 +329,24 @@ Certificate::subject_organizational_unit_name () const
 
 
 static
-struct tm
+LocalTime
 convert_time (ASN1_TIME const * time)
 {
-       struct tm t;
+       LocalTime t;
        char const * s = (char const *) time->data;
 
        if (time->type == V_ASN1_UTCTIME) {
-               sscanf(s, "%2d%2d%2d%2d%2d%2d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
-               if (t.tm_year < 70) {
-                       t.tm_year += 100;
-               }
+               return LocalTime::from_asn1_utc_time (s);
        } else if (time->type == V_ASN1_GENERALIZEDTIME) {
-               sscanf(s, "%4d%2d%2d%2d%2d%2d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
-               t.tm_year -= 1900;
+               return LocalTime::from_asn1_generalized_time (s);
        }
 
-       t.tm_mon--;
-
-       return t;
+       DCP_ASSERT (false);
+       return {};
 }
 
 
-struct tm
+LocalTime
 Certificate::not_before () const
 {
        DCP_ASSERT (_certificate);
@@ -363,7 +358,7 @@ Certificate::not_before () const
 }
 
 
-struct tm
+LocalTime
 Certificate::not_after () const
 {
        DCP_ASSERT (_certificate);
index 1b8188c7c77283a74a2275fd339c78cbc73ba513..49fca02cdab55aa38df5dc45a03660cfb13624c9 100644 (file)
@@ -41,6 +41,7 @@
 #define LIBDCP_CERTIFICATE_H
 
 
+#include "local_time.h"
 #undef X509_NAME
 #include <openssl/x509.h>
 #include <boost/filesystem.hpp>
@@ -106,8 +107,9 @@ public:
        std::string subject_common_name () const;
        std::string subject_organization_name () const;
        std::string subject_organizational_unit_name () const;
-       struct tm not_before () const;
-       struct tm not_after () const;
+
+       LocalTime not_before () const;
+       LocalTime not_after () const;
 
        X509* x509 () const {
                return _certificate;
index b2d8e61839cdeb4bfc6fa24700c91858a27f6f28..592ab71738218bfba64d664fdb8e2c6e199e5194 100644 (file)
@@ -327,9 +327,9 @@ DecryptedKDM::encrypt (
        DCP_ASSERT (!_keys.empty ());
 
        for (auto i: signer->leaf_to_root()) {
-               if (day_greater_than_or_equal(dcp::LocalTime(i.not_before()), _not_valid_before)) {
+               if (day_greater_than_or_equal(i.not_before(), _not_valid_before)) {
                        throw BadKDMDateError (true);
-               } else if (day_less_than_or_equal(dcp::LocalTime(i.not_after()), _not_valid_after)) {
+               } else if (day_less_than_or_equal(i.not_after(), _not_valid_after)) {
                        throw BadKDMDateError (false);
                }
        }
index 892ffba4c248aaf07c49c46bc32473102c72ea6d..ad2291f995b988f1b5f2f0b132bf69e9bfea75a0 100644 (file)
@@ -307,3 +307,34 @@ dcp::operator<< (ostream& s, LocalTime const & t)
        s << t.as_string ();
        return s;
 }
+
+
+LocalTime
+LocalTime::from_asn1_utc_time (string time)
+{
+       LocalTime t;
+       sscanf(time.c_str(), "%2d%2d%2d%2d%2d%2d", &t._year, &t._month, &t._day, &t._hour, &t._minute, &t._second);
+
+       if (t._year < 70) {
+               t._year += 100;
+       }
+       t._year += 1900;
+
+       t._tz_hour = t._tz_minute = t._millisecond = 0;
+
+       return t;
+}
+
+
+LocalTime
+LocalTime::from_asn1_generalized_time (string time)
+{
+       LocalTime t;
+       sscanf(time.c_str(), "%4d%2d%2d%2d%2d%2d", &t._year, &t._month, &t._day, &t._hour, &t._minute, &t._second);
+
+       t._tz_hour = t._tz_minute = t._millisecond = 0;
+
+       return t;
+}
+
+
index a5a479cd4f80b69d0b6123923e8492df8fdf8abd..b84e3098d0f0dab99ebec9950f0db279323ccdc4 100644 (file)
@@ -103,6 +103,18 @@ public:
                return _year;
        }
 
+       int hour () const {
+               return _hour;
+       }
+
+       int minute () const {
+               return _minute;
+       }
+
+       int second () const {
+               return _second;
+       }
+
        void set_year (int y) {
                _year = y;
        }
@@ -111,6 +123,9 @@ public:
        void add_months (int a);
        void add_minutes (int a);
 
+       static LocalTime from_asn1_utc_time (std::string time);
+       static LocalTime from_asn1_generalized_time (std::string time);
+
        bool operator== (LocalTime const & other) const;
        bool operator!= (LocalTime const & other) const;
        bool operator< (LocalTime const & other) const;
index 1dc1193221f12c3342faa65281c442131c18caef..927bddafafa8f720843cc825cd693d46f6ecc83c 100644 (file)
@@ -263,18 +263,18 @@ BOOST_AUTO_TEST_CASE (certificate_chain_from_string)
 BOOST_AUTO_TEST_CASE (certificate_not_before_after)
 {
        dcp::Certificate c (dcp::file_to_string("test/ref/crypt/ca.self-signed.pem"));
-       struct tm not_before = c.not_before();
-       BOOST_CHECK_EQUAL (not_before.tm_sec, 8);
-       BOOST_CHECK_EQUAL (not_before.tm_min, 20);
-       BOOST_CHECK_EQUAL (not_before.tm_hour, 13);
-       BOOST_CHECK_EQUAL (not_before.tm_mday, 5);
-       BOOST_CHECK_EQUAL (not_before.tm_mon, 5);
-       BOOST_CHECK_EQUAL (not_before.tm_year, 115);
-       struct tm not_after = c.not_after();
-       BOOST_CHECK_EQUAL (not_after.tm_sec, 8);
-       BOOST_CHECK_EQUAL (not_after.tm_min, 20);
-       BOOST_CHECK_EQUAL (not_after.tm_hour, 13);
-       BOOST_CHECK_EQUAL (not_after.tm_mday, 2);
-       BOOST_CHECK_EQUAL (not_after.tm_mon, 5);
-       BOOST_CHECK_EQUAL (not_after.tm_year, 125);
+       auto not_before = c.not_before();
+       BOOST_CHECK_EQUAL (not_before.second(), 8);
+       BOOST_CHECK_EQUAL (not_before.minute(), 20);
+       BOOST_CHECK_EQUAL (not_before.hour(), 13);
+       BOOST_CHECK_EQUAL (not_before.day(), 5);
+       BOOST_CHECK_EQUAL (not_before.month(), 6);
+       BOOST_CHECK_EQUAL (not_before.year(), 2015);
+       auto not_after = c.not_after();
+       BOOST_CHECK_EQUAL (not_after.second(), 8);
+       BOOST_CHECK_EQUAL (not_after.minute(), 20);
+       BOOST_CHECK_EQUAL (not_after.hour(), 13);
+       BOOST_CHECK_EQUAL (not_after.day(), 2);
+       BOOST_CHECK_EQUAL (not_after.month(), 6);
+       BOOST_CHECK_EQUAL (not_after.year(), 2025);
 }
index e80a863d91fdc59b7be4a75e9464dfa18206b36e..769826cfc40a2b962588b27be67f07c70cc54d3f 100644 (file)
@@ -214,3 +214,18 @@ BOOST_AUTO_TEST_CASE (local_time_add_months_test)
                BOOST_CHECK_EQUAL (t.as_string(), "2018-02-28T11:00:00+01:00");
        }
 }
+
+
+BOOST_AUTO_TEST_CASE (local_time_from_asn1_utctime_test)
+{
+       BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_utc_time("991231235952").as_string(), "1999-12-31T23:59:52+00:00");
+       BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_utc_time("210215165952").as_string(), "2021-02-15T16:59:52+00:00");
+}
+
+
+BOOST_AUTO_TEST_CASE (local_time_from_asn1_generalized_time_test)
+{
+       BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_generalized_time("19991231235952").as_string(), "1999-12-31T23:59:52+00:00");
+       BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_generalized_time("20210215165952").as_string(), "2021-02-15T16:59:52+00:00");
+}
+
index 20b07ebca513b1476fe2872fccd87b514c91cb0e..d8a10fa35eae8058684b41cffee29787c629d7c4 100644 (file)
@@ -55,15 +55,6 @@ help (string n)
 }
 
 
-static string
-tm_to_string (struct tm t)
-{
-       char buffer[64];
-       snprintf (buffer, 64, "%02d/%02d/%02d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
-       return buffer;
-}
-
-
 int
 main (int argc, char* argv[])
 try
@@ -122,8 +113,8 @@ try
                cout << "\t\tSubject common name: " << i.subject_common_name() << "\n";
                cout << "\t\tSubject organization name: " << i.subject_organization_name() << "\n";
                cout << "\t\tSubject organizational unit name: " << i.subject_organizational_unit_name() << "\n";
-               cout << "\t\tNot before: " << tm_to_string(i.not_before()) << "\n";
-               cout << "\t\tNot after:  " << tm_to_string(i.not_after()) << "\n";
+               cout << "\t\tNot before: " << i.not_before().as_string() << "\n";
+               cout << "\t\tNot after:  " << i.not_after().as_string() << "\n";
                if (i.has_utf8_strings()) {
                        cout << "\t\tUSES INCORRECT (UTF8) STRING ENCODING\n";
                }