1 /* $OpenBSD: rfc5280time.c,v 1.8 2024/04/08 19:57:40 beck Exp $ */
2 /*
3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2015 Bob Beck <beck@opebsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <openssl/asn1.h>
20 #include <openssl/x509.h>
21
22 #include <err.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 struct rfc5280_time_test {
27 const char *str;
28 const char *data;
29 time_t time;
30 };
31
32 struct rfc5280_time_test rfc5280_invtime_tests[] = {
33 {
34 .str = "",
35 },
36 {
37 .str = "2015",
38 },
39 {
40 .str = "201509",
41 },
42 {
43 .str = "20150923",
44 },
45 {
46 .str = "20150923032700",
47 },
48 {
49 /* UTC time must have seconds */
50 .str = "7001010000Z",
51 },
52 {
53 .str = "201509230327Z",
54 },
55 {
56 .str = "20150923032700.Z",
57 },
58 {
59 .str = "20150923032700.123",
60 },
61 {
62 .str = "20150923032700+1100Z",
63 },
64 {
65 .str = "20150923032700-11001",
66 },
67 {
68 /* UTC time cannot have fractional seconds. */
69 .str = "150923032700.123Z",
70 },
71 {
72 /* Gen time cannot have +- TZ. */
73 .str = "20150923032712+1115",
74 },
75 {
76 /* Gen time cannot have fractional seconds */
77 .str = "20150923032712.123Z",
78 },
79 {
80 .str = "aaaaaaaaaaaaaaZ",
81 },
82 {
83 /* Must be a UTC time per RFC 5280 */
84 .str = "19700101000000Z",
85 .data = "19700101000000Z",
86 .time = 0,
87 },
88 {
89 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
90 .str = "20150923032700Z",
91 .data = "20150923032700Z",
92 .time = 1442978820,
93 },
94 {
95 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
96 .str = "00000101000000Z",
97 .data = "00000101000000Z",
98 .time = -62167219200LL,
99 },
100 {
101 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
102 .str = "20491231235959Z",
103 .data = "20491231235959Z",
104 .time = 2524607999LL,
105 },
106 {
107 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
108 .str = "19500101000000Z",
109 .data = "19500101000000Z",
110 .time = -631152000LL,
111 },
112 };
113
114 struct rfc5280_time_test rfc5280_gentime_tests[] = {
115 {
116 /* Biggest RFC 5280 time */
117 .str = "99991231235959Z",
118 .data = "99991231235959Z",
119 .time = 253402300799LL,
120 },
121 {
122 .str = "21600218104000Z",
123 .data = "21600218104000Z",
124 .time = 6000000000LL,
125 },
126 {
127 /* Smallest RFC 5280 gen time */
128 .str = "20500101000000Z",
129 .data = "20500101000000Z",
130 .time = 2524608000LL,
131 },
132 };
133 struct rfc5280_time_test rfc5280_utctime_tests[] = {
134 {
135 .str = "500101000000Z",
136 .data = "500101000000Z",
137 .time = -631152000,
138 },
139 {
140 .str = "540226230640Z",
141 .data = "540226230640Z",
142 .time = -500000000,
143 },
144 {
145 .str = "491231235959Z",
146 .data = "491231235959Z",
147 .time = 2524607999LL,
148 },
149 {
150 .str = "700101000000Z",
151 .data = "700101000000Z",
152 .time = 0,
153 },
154 {
155 .str = "150923032700Z",
156 .data = "150923032700Z",
157 .time = 1442978820,
158 },
159 {
160 .str = "150923102700Z",
161 .data = "150923102700Z",
162 .time = 1443004020,
163 },
164 {
165 .str = "150922162712Z",
166 .data = "150922162712Z",
167 .time = 1442939232,
168 },
169 {
170 .str = "140524144512Z",
171 .data = "140524144512Z",
172 .time = 1400942712,
173 },
174 {
175 .str = "240401144512Z",
176 .data = "240401144512Z",
177 .time = 1711982712,
178 },
179 };
180
181 #define N_INVTIME_TESTS \
182 (sizeof(rfc5280_invtime_tests) / sizeof(*rfc5280_invtime_tests))
183 #define N_GENTIME_TESTS \
184 (sizeof(rfc5280_gentime_tests) / sizeof(*rfc5280_gentime_tests))
185 #define N_UTCTIME_TESTS \
186 (sizeof(rfc5280_utctime_tests) / sizeof(*rfc5280_utctime_tests))
187
188 static int
asn1_compare_str(int test_no,struct asn1_string_st * asn1str,const char * str)189 asn1_compare_str(int test_no, struct asn1_string_st *asn1str, const char *str)
190 {
191 int length = strlen(str);
192
193 if (asn1str->length != length) {
194 fprintf(stderr, "FAIL: test %d - string lengths differ "
195 "(%d != %d)\n", test_no, asn1str->length, length);
196 return (1);
197 }
198 if (strncmp(asn1str->data, str, length) != 0) {
199 fprintf(stderr, "FAIL: test %d - strings differ "
200 "('%s' != '%s')\n", test_no, asn1str->data, str);
201 return (1);
202 }
203
204 return (0);
205 }
206
207 static int
rfc5280_invtime_test(int test_no,struct rfc5280_time_test * att)208 rfc5280_invtime_test(int test_no, struct rfc5280_time_test *att)
209 {
210 ASN1_GENERALIZEDTIME *gt = NULL;
211 ASN1_UTCTIME *ut = NULL;
212 ASN1_TIME *t = NULL;
213 int failure = 1;
214 time_t now = time(NULL);
215
216 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
217 goto done;
218 if ((ut = ASN1_UTCTIME_new()) == NULL)
219 goto done;
220 if ((t = ASN1_TIME_new()) == NULL)
221 goto done;
222
223 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 0) {
224 if (X509_cmp_time(gt, &now) != 0) {
225 fprintf(stderr, "FAIL: test %d - successfully parsed as GENTIME "
226 "string '%s'\n", test_no, att->str);
227 goto done;
228 }
229 }
230 if (ASN1_UTCTIME_set_string(ut, att->str) != 0) {
231 if (X509_cmp_time(ut, &now) != 0) {
232 fprintf(stderr, "FAIL: test %d - successfully parsed as UTCTIME "
233 "string '%s'\n", test_no, att->str);
234 goto done;
235 }
236 }
237
238 failure = 0;
239
240 done:
241 ASN1_GENERALIZEDTIME_free(gt);
242 ASN1_UTCTIME_free(ut);
243 ASN1_TIME_free(t);
244
245 return (failure);
246 }
247
248 static int
rfc5280_gentime_test(int test_no,struct rfc5280_time_test * att)249 rfc5280_gentime_test(int test_no, struct rfc5280_time_test *att)
250 {
251 unsigned char *p = NULL;
252 ASN1_GENERALIZEDTIME *gt;
253 int failure = 1;
254 int i;
255
256 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
257 goto done;
258
259 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) {
260 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n",
261 test_no, att->str);
262 goto done;
263 }
264 if (asn1_compare_str(test_no, gt, att->str) != 0)
265 goto done;
266
267 if ((i = X509_cmp_time(gt, &att->time)) != -1) {
268 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
269 test_no, i, (long long)att->time);
270 goto done;
271 }
272
273 att->time--;
274 if ((i = X509_cmp_time(gt, &att->time)) != 1) {
275 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
276 test_no, i, (long long)att->time);
277 goto done;
278 }
279 att->time++;
280
281 ASN1_GENERALIZEDTIME_free(gt);
282
283 if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) {
284 fprintf(stderr, "FAIL: test %d - failed to set time %lld\n",
285 test_no, (long long)att->time);
286 goto done;
287 }
288 if (asn1_compare_str(test_no, gt, att->data) != 0)
289 goto done;
290
291 failure = 0;
292
293 done:
294 ASN1_GENERALIZEDTIME_free(gt);
295 free(p);
296
297 return (failure);
298 }
299
300 static int
rfc5280_utctime_test(int test_no,struct rfc5280_time_test * att)301 rfc5280_utctime_test(int test_no, struct rfc5280_time_test *att)
302 {
303 unsigned char *p = NULL;
304 ASN1_UTCTIME *ut;
305 int failure = 1;
306 int i;
307
308 if ((ut = ASN1_UTCTIME_new()) == NULL)
309 goto done;
310
311 if (ASN1_UTCTIME_set_string(ut, att->str) != 1) {
312 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n",
313 test_no, att->str);
314 goto done;
315 }
316 if (asn1_compare_str(test_no, ut, att->str) != 0)
317 goto done;
318
319 if ((i = X509_cmp_time(ut, &att->time)) != -1) {
320 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
321 test_no, i, (long long)att->time);
322 goto done;
323 }
324
325 att->time--;
326 if ((i = X509_cmp_time(ut, &att->time)) != 1) {
327 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
328 test_no, i, (long long)att->time);
329 goto done;
330 }
331 att->time++;
332
333 ASN1_UTCTIME_free(ut);
334
335 if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) {
336 fprintf(stderr, "FAIL: test %d - failed to set time %lld\n",
337 test_no, (long long)att->time);
338 goto done;
339 }
340 if (asn1_compare_str(test_no, ut, att->data) != 0)
341 goto done;
342
343 failure = 0;
344
345 done:
346 ASN1_UTCTIME_free(ut);
347 free(p);
348
349 return (failure);
350 }
351
352 int
main(int argc,char ** argv)353 main(int argc, char **argv)
354 {
355 struct rfc5280_time_test *att;
356 int failed = 0;
357 size_t i;
358
359 fprintf(stderr, "RFC5280 Invalid time tests...\n");
360 for (i = 0; i < N_INVTIME_TESTS; i++) {
361 att = &rfc5280_invtime_tests[i];
362 failed |= rfc5280_invtime_test(i, att);
363 }
364
365 fprintf(stderr, "RFC5280 GENERALIZEDTIME tests...\n");
366 for (i = 0; i < N_GENTIME_TESTS; i++) {
367 att = &rfc5280_gentime_tests[i];
368 failed |= rfc5280_gentime_test(i, att);
369 }
370
371 fprintf(stderr, "RFC5280 UTCTIME tests...\n");
372 for (i = 0; i < N_UTCTIME_TESTS; i++) {
373 att = &rfc5280_utctime_tests[i];
374 failed |= rfc5280_utctime_test(i, att);
375 }
376 return (failed);
377 }
378