CCF
Loading...
Searching...
No Matches
x509_time_fmt.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
5#define FMT_HEADER_ONLY
6#include <chrono>
7#include <fmt/chrono.h>
8#include <fmt/format.h>
9#include <iomanip>
10#include <sstream>
11#include <time.h>
12#include <vector>
13
14namespace ccf::ds
15{
16 static inline std::string to_x509_time_string(const std::tm& time)
17 {
18 // Returns ASN1 time string (YYYYMMDDHHMMSSZ) from time_t, as per
19 // https://www.openssl.org/docs/man1.1.1/man3/ASN1_UTCTIME_set.html
20 return fmt::format("{:%Y%m%d%H%M%SZ}", time);
21 }
22
23 static inline std::string to_x509_time_string(
24 const std::chrono::system_clock::time_point& time)
25 {
26 return to_x509_time_string(fmt::gmtime(time));
27 }
28
29 static inline std::chrono::system_clock::time_point time_point_from_string(
30 const std::string& time)
31 {
32 const char* ts = time.c_str();
33
34 auto accepted_formats = {
35 "%y%m%d%H%M%SZ", // ASN.1
36 "%Y%m%d%H%M%SZ", // Generalized ASN.1
37 "%Y-%m-%d %H:%M:%S"};
38
39 for (auto afmt : accepted_formats)
40 {
41 // Sadly %y in std::get_time seems to be broken, so strptime it is.
42 struct tm t = {};
43 auto sres = strptime(ts, afmt, &t);
44 if (sres != NULL && *sres == '\0')
45 {
46 auto r = std::chrono::system_clock::from_time_t(timegm(&t));
47 r -= std::chrono::seconds(t.tm_gmtoff);
48 return r;
49 }
50 }
51
52 // Then there are formats that strptime doesn't support...
53 std::vector<std::pair<const char*, int>> more_formats = {
54 // Note: longest format to match first
55 {"%04u-%02u-%02u %02u:%02u:%f %d:%02u", 8},
56 {"%04u-%02u-%02uT%02u:%02u:%f %d:%02u", 8},
57 {"%04u-%02u-%02u %02u:%02u:%f %03d %02u", 8},
58 {"%02u%02u%02u%02u%02u%02f%03d%02u", 8},
59 {"%04u%02u%02u%02u%02u%02f%03d%02u", 8},
60 {"%04u-%02u-%02uT%02u:%02u:%f", 6},
61 {"%04u-%02u-%02u %02u:%02u:%f", 6}};
62
63 for (auto [fmt, n] : more_formats)
64 {
65 unsigned y = 0, m = 0, d = 0, h = 0, mn = 0, om = 0;
66 int oh = 0;
67 float s = 0.0;
68
69 int rs = sscanf(ts, fmt, &y, &m, &d, &h, &mn, &s, &oh, &om);
70 if (rs >= 1 && rs == n)
71 {
72 using namespace std::chrono;
73
74 if (strncmp(fmt, "%02u", 4) == 0)
75 {
76 // ASN.1 two-digit year range
77 y += y >= 50 ? 1900 : 2000;
78 }
79
80 if (rs >= 3)
81 {
82 auto date = year_month_day(year(y), month(m), day(d));
83
84 if (
85 !date.ok() || (rs >= 6 && (h > 24 || mn > 60 || s < 0.0)) ||
86 (rs >= 8 && (s > 60.0 || oh < -23 || oh > 23 || om > 60)))
87 {
88 continue;
89 }
90
91 system_clock::time_point r = (sys_days)date;
92 if (rs >= 6)
93 r += hours(h) + minutes(mn) + microseconds((long)(s * 1e6));
94 if (rs >= 8)
95 r -= hours(oh) + minutes(om);
96 return r;
97 }
98 }
99 }
100
101 throw std::runtime_error(
102 fmt::format("'{}' does not match any accepted time format", time));
103 }
104
105 static inline std::string to_x509_time_string(const std::string& time)
106 {
107 return to_x509_time_string(time_point_from_string(time));
108 }
109}
Definition contiguous_set.h:12