@@ -190,7 +190,7 @@ ccf::crypto::Pem generate_self_signed_cert(
190190 constexpr size_t certificate_validity_period_days = 365 ;
191191 using namespace std ::literals;
192192 auto valid_from =
193- ccf::ds::to_x509_time_string (std::chrono::system_clock ::now () - 24h);
193+ ccf::ds::to_x509_time_string (ccf::nonstd::SystemClock ::now () - 24h);
194194
195195 return ccf::crypto::create_self_signed_cert (
196196 kp, name, {}, valid_from, certificate_validity_period_days);
@@ -793,6 +793,11 @@ TEST_CASE("Non-ASN.1 timepoint formats")
793793 conv = ccf::ds::to_x509_time_string (tp);
794794 REQUIRE (conv == " 20220405215327Z" );
795795
796+ time_str = " 2026-02-09 05:00:00 -03:30" ;
797+ tp = ccf::ds::time_point_from_string (time_str);
798+ conv = ccf::ds::to_x509_time_string (tp);
799+ REQUIRE (conv == " 20260209083000Z" );
800+
796801 time_str = " 2022-04-07T10:37:49.567612" ;
797802 tp = ccf::ds::time_point_from_string (time_str);
798803 conv = ccf::ds::to_x509_time_string (tp);
@@ -824,6 +829,91 @@ TEST_CASE("Non-ASN.1 timepoint formats")
824829 REQUIRE (conv == " 20220425195619Z" );
825830}
826831
832+ TEST_CASE (" Timepoint bounds" )
833+ {
834+ // Can handle values beyond bounds of system_clock::time_point
835+ {
836+ INFO (" Beyond system_clock::time_point min" );
837+ auto time_str = " 1677-09-21 00:12:44" ;
838+ auto tp = ccf::ds::time_point_from_string (time_str);
839+ auto conv = ccf::ds::to_x509_time_string (tp);
840+ REQUIRE (conv == " 16770921001244Z" );
841+
842+ time_str = " 1677-09-21 00:12:43" ;
843+ tp = ccf::ds::time_point_from_string (time_str);
844+ conv = ccf::ds::to_x509_time_string (tp);
845+ REQUIRE (conv == " 16770921001243Z" );
846+ }
847+
848+ {
849+ INFO (" Beyond system_clock::time_point max" );
850+ auto time_str = " 2262-04-11 23:47:16" ;
851+ auto tp = ccf::ds::time_point_from_string (time_str);
852+ auto conv = ccf::ds::to_x509_time_string (tp);
853+ REQUIRE (conv == " 22620411234716Z" );
854+
855+ time_str = " 2262-04-11 23:47:17" ;
856+ tp = ccf::ds::time_point_from_string (time_str);
857+ conv = ccf::ds::to_x509_time_string (tp);
858+ CHECK (conv == " 22620411234717Z" );
859+ }
860+
861+ {
862+ INFO (" Approx ASN.1 format bounds" );
863+ auto time_str = " 9999-12-31 23:59:59" ;
864+ auto tp = ccf::ds::time_point_from_string (time_str);
865+ auto conv = ccf::ds::to_x509_time_string (tp);
866+ REQUIRE (conv == " 99991231235959Z" );
867+
868+ INFO (" sscanf variants of near-min value" );
869+ for (auto time_str : {
870+ " 0001-02-03 04:05:06" ,
871+ " 0001-02-03 04:05:06.700000 +0:00" ,
872+ " 0001-02-03 12:14:06.700000 +8:09" ,
873+ " 0001-02-02 19:56:06.700000 -8:09" ,
874+
875+ " 0001-02-03T04:05:06.700000 +0:00" ,
876+ " 0001-02-03T12:14:06.700000 +8:09" ,
877+ " 0001-02-02T19:56:06.700000 -8:09" ,
878+
879+ " 0001-02-03 04:05:06.700000 +00 00" ,
880+ " 0001-02-03 12:14:06.700000 +08:09" ,
881+ " 0001-02-02 19:56:06.700000 -08:09" ,
882+
883+ " 00010203040506.700000+0000" ,
884+ " 00010203121406.700000+0809" ,
885+ " 00010202195606.700000-0809" ,
886+
887+ " 0001-02-03T04:05:06.700000" ,
888+ " 0001-02-03 04:05:06.700000" ,
889+ })
890+ {
891+ tp = ccf::ds::time_point_from_string (time_str);
892+ conv = ccf::ds::to_x509_time_string (tp);
893+ CHECK (conv == " 00010203040506Z" );
894+ }
895+ }
896+ }
897+
898+ TEST_CASE (" Invalid times" )
899+ {
900+ REQUIRE_THROWS_WITH (
901+ ccf::ds::time_point_from_string (" hello" ),
902+ " 'hello' does not match any accepted time format" );
903+
904+ REQUIRE_THROWS_WITH (
905+ ccf::ds::time_point_from_string (" Monday" ),
906+ " 'Monday' does not match any accepted time format" );
907+
908+ REQUIRE_THROWS_WITH (
909+ ccf::ds::time_point_from_string (" April 1st, 1984" ),
910+ " 'April 1st, 1984' does not match any accepted time format" );
911+
912+ REQUIRE_THROWS_WITH (
913+ ccf::ds::time_point_from_string (" 1111-1111" ),
914+ " '1111-1111' does not match any accepted time format" );
915+ }
916+
827917TEST_CASE (" Create sign and verify certificates" )
828918{
829919 bool corrupt_csr = false ;
@@ -928,7 +1018,7 @@ TEST_CASE("AES-GCM convenience functions")
9281018
9291019TEST_CASE (" x509 time" )
9301020{
931- auto time = std::chrono::system_clock ::now ();
1021+ auto time = ccf::nonstd::SystemClock ::now ();
9321022
9331023 auto next_minute_time = time + 1min;
9341024 auto next_day_time = time + 24h;
@@ -940,8 +1030,8 @@ TEST_CASE("x509 time")
9401030 {
9411031 struct Input
9421032 {
943- std::chrono::system_clock ::time_point from;
944- std::chrono::system_clock ::time_point to;
1033+ ccf::nonstd::SystemClock ::time_point from;
1034+ ccf::nonstd::SystemClock ::time_point to;
9451035 std::optional<uint32_t > maximum_validity_period_days = std::nullopt ;
9461036 };
9471037 Input input;
@@ -976,7 +1066,7 @@ TEST_CASE("x509 time")
9761066
9771067 INFO (" Adjust time" );
9781068 {
979- std::vector<std::chrono::system_clock ::time_point> times = {
1069+ std::vector<ccf::nonstd::SystemClock ::time_point> times = {
9801070 time, next_day_time, next_day_time};
9811071 size_t days_offset = 100 ;
9821072
0 commit comments