]>
Commit | Line | Data |
---|---|---|
80770da3 EK |
1 | /* |
2 | * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the OpenSSL license (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | /* Tests for X509 time functions */ | |
11 | ||
12 | #include <string.h> | |
13 | #include <time.h> | |
14 | ||
15 | #include <openssl/asn1.h> | |
16 | #include <openssl/x509.h> | |
17 | #include "testutil.h" | |
176db6dc | 18 | #include "internal/nelem.h" |
80770da3 EK |
19 | |
20 | typedef struct { | |
21 | const char *data; | |
22 | int type; | |
23 | time_t cmp_time; | |
24 | /* -1 if asn1_time <= cmp_time, 1 if asn1_time > cmp_time, 0 if error. */ | |
25 | int expected; | |
26 | } TESTDATA; | |
27 | ||
04e62715 RS |
28 | typedef struct { |
29 | const char *data; | |
30 | /* 0 for check-only mode, 1 for set-string mode */ | |
31 | int set_string; | |
32 | /* 0 for error, 1 if succeed */ | |
33 | int expected; | |
34 | /* | |
35 | * The following 2 fields are ignored if set_string field is set to '0' | |
36 | * (in check only mode). | |
37 | * | |
38 | * But they can still be ignored explicitly in set-string mode by: | |
39 | * setting -1 to expected_type and setting NULL to expected_string. | |
40 | * | |
41 | * It's useful in a case of set-string mode but the expected result | |
42 | * is a 'parsing error'. | |
43 | */ | |
44 | int expected_type; | |
45 | const char *expected_string; | |
46 | } TESTDATA_FORMAT; | |
47 | ||
48 | /* | |
49 | * Actually, the "loose" mode has been tested in | |
50 | * those time-compare-cases, so we may not test it again. | |
51 | */ | |
52 | static TESTDATA_FORMAT x509_format_tests[] = { | |
53 | /* GeneralizedTime */ | |
54 | { | |
55 | /* good format, check only */ | |
56 | "20170217180105Z", 0, 1, -1, NULL, | |
57 | }, | |
3d0f1cb9 PY |
58 | { |
59 | /* not leap year, check only */ | |
60 | "20170229180105Z", 0, 0, -1, NULL, | |
61 | }, | |
62 | { | |
63 | /* leap year, check only */ | |
64 | "20160229180105Z", 0, 1, -1, NULL, | |
65 | }, | |
04e62715 RS |
66 | { |
67 | /* SS is missing, check only */ | |
68 | "201702171801Z", 0, 0, -1, NULL, | |
69 | }, | |
70 | { | |
71 | /* fractional seconds, check only */ | |
72 | "20170217180105.001Z", 0, 0, -1, NULL, | |
73 | }, | |
74 | { | |
75 | /* time zone, check only */ | |
76 | "20170217180105+0800", 0, 0, -1, NULL, | |
77 | }, | |
78 | { | |
79 | /* SS is missing, set string */ | |
80 | "201702171801Z", 1, 0, -1, NULL, | |
81 | }, | |
82 | { | |
83 | /* fractional seconds, set string */ | |
84 | "20170217180105.001Z", 1, 0, -1, NULL, | |
85 | }, | |
86 | { | |
87 | /* time zone, set string */ | |
88 | "20170217180105+0800", 1, 0, -1, NULL, | |
89 | }, | |
90 | { | |
91 | /* good format, check returned 'turned' string */ | |
92 | "20170217180154Z", 1, 1, V_ASN1_UTCTIME, "170217180154Z", | |
93 | }, | |
94 | { | |
95 | /* good format, check returned string */ | |
96 | "20510217180154Z", 1, 1, V_ASN1_GENERALIZEDTIME, "20510217180154Z", | |
97 | }, | |
98 | { | |
99 | /* good format but out of UTC range, check returned string */ | |
100 | "19230419180154Z", 1, 1, V_ASN1_GENERALIZEDTIME, "19230419180154Z", | |
101 | }, | |
102 | /* UTC */ | |
103 | { | |
104 | /* SS is missing, check only */ | |
105 | "1702171801Z", 0, 0, -1, NULL, | |
106 | }, | |
3d0f1cb9 PY |
107 | { |
108 | /* not leap year, check only */ | |
109 | "050229180101Z", 0, 0, -1, NULL, | |
110 | }, | |
111 | { | |
112 | /* leap year, check only */ | |
113 | "040229180101Z", 0, 1, -1, NULL, | |
114 | }, | |
04e62715 RS |
115 | { |
116 | /* time zone, check only */ | |
117 | "170217180154+0800", 0, 0, -1, NULL, | |
118 | }, | |
119 | { | |
120 | /* SS is missing, set string */ | |
121 | "1702171801Z", 1, 0, -1, NULL, | |
122 | }, | |
123 | { | |
124 | /* time zone, set string */ | |
125 | "170217180154+0800", 1, 0, -1, NULL, | |
126 | }, | |
127 | { | |
128 | /* 2017, good format, check returned string */ | |
129 | "170217180154Z", 1, 1, V_ASN1_UTCTIME, "170217180154Z", | |
130 | }, | |
131 | { | |
132 | /* 1998, good format, check returned string */ | |
133 | "981223180154Z", 1, 1, V_ASN1_UTCTIME, "981223180154Z", | |
134 | }, | |
135 | }; | |
136 | ||
80770da3 EK |
137 | static TESTDATA x509_cmp_tests[] = { |
138 | { | |
139 | "20170217180154Z", V_ASN1_GENERALIZEDTIME, | |
140 | /* The same in seconds since epoch. */ | |
141 | 1487354514, -1, | |
142 | }, | |
143 | { | |
144 | "20170217180154Z", V_ASN1_GENERALIZEDTIME, | |
145 | /* One second more. */ | |
146 | 1487354515, -1, | |
147 | }, | |
148 | { | |
149 | "20170217180154Z", V_ASN1_GENERALIZEDTIME, | |
150 | /* One second less. */ | |
151 | 1487354513, 1, | |
152 | }, | |
153 | /* Same as UTC time. */ | |
154 | { | |
155 | "170217180154Z", V_ASN1_UTCTIME, | |
156 | /* The same in seconds since epoch. */ | |
157 | 1487354514, -1, | |
158 | }, | |
159 | { | |
160 | "170217180154Z", V_ASN1_UTCTIME, | |
161 | /* One second more. */ | |
162 | 1487354515, -1, | |
163 | }, | |
164 | { | |
165 | "170217180154Z", V_ASN1_UTCTIME, | |
166 | /* One second less. */ | |
167 | 1487354513, 1, | |
168 | }, | |
169 | /* UTCTime from the 20th century. */ | |
170 | { | |
171 | "990217180154Z", V_ASN1_UTCTIME, | |
172 | /* The same in seconds since epoch. */ | |
173 | 919274514, -1, | |
174 | }, | |
175 | { | |
176 | "990217180154Z", V_ASN1_UTCTIME, | |
177 | /* One second more. */ | |
178 | 919274515, -1, | |
179 | }, | |
180 | { | |
181 | "990217180154Z", V_ASN1_UTCTIME, | |
182 | /* One second less. */ | |
183 | 919274513, 1, | |
184 | }, | |
185 | /* Various invalid formats. */ | |
186 | { | |
187 | /* No trailing Z. */ | |
188 | "20170217180154", V_ASN1_GENERALIZEDTIME, 0, 0, | |
189 | }, | |
190 | { | |
191 | /* No trailing Z, UTCTime. */ | |
192 | "170217180154", V_ASN1_UTCTIME, 0, 0, | |
193 | }, | |
194 | { | |
195 | /* No seconds. */ | |
196 | "201702171801Z", V_ASN1_GENERALIZEDTIME, 0, 0, | |
197 | }, | |
198 | { | |
199 | /* No seconds, UTCTime. */ | |
200 | "1702171801Z", V_ASN1_UTCTIME, 0, 0, | |
201 | }, | |
202 | { | |
203 | /* Fractional seconds. */ | |
204 | "20170217180154.001Z", V_ASN1_GENERALIZEDTIME, 0, 0, | |
205 | }, | |
206 | { | |
207 | /* Fractional seconds, UTCTime. */ | |
208 | "170217180154.001Z", V_ASN1_UTCTIME, 0, 0, | |
209 | }, | |
210 | { | |
211 | /* Timezone offset. */ | |
212 | "20170217180154+0100", V_ASN1_GENERALIZEDTIME, 0, 0, | |
213 | }, | |
214 | { | |
215 | /* Timezone offset, UTCTime. */ | |
216 | "170217180154+0100", V_ASN1_UTCTIME, 0, 0, | |
217 | }, | |
218 | { | |
219 | /* Extra digits. */ | |
220 | "2017021718015400Z", V_ASN1_GENERALIZEDTIME, 0, 0, | |
221 | }, | |
222 | { | |
223 | /* Extra digits, UTCTime. */ | |
224 | "17021718015400Z", V_ASN1_UTCTIME, 0, 0, | |
225 | }, | |
226 | { | |
227 | /* Non-digits. */ | |
228 | "2017021718015aZ", V_ASN1_GENERALIZEDTIME, 0, 0, | |
229 | }, | |
230 | { | |
231 | /* Non-digits, UTCTime. */ | |
232 | "17021718015aZ", V_ASN1_UTCTIME, 0, 0, | |
233 | }, | |
234 | { | |
235 | /* Trailing garbage. */ | |
236 | "20170217180154Zlongtrailinggarbage", V_ASN1_GENERALIZEDTIME, 0, 0, | |
237 | }, | |
238 | { | |
239 | /* Trailing garbage, UTCTime. */ | |
240 | "170217180154Zlongtrailinggarbage", V_ASN1_UTCTIME, 0, 0, | |
241 | }, | |
242 | { | |
243 | /* Swapped type. */ | |
244 | "20170217180154Z", V_ASN1_UTCTIME, 0, 0, | |
245 | }, | |
246 | { | |
247 | /* Swapped type. */ | |
248 | "170217180154Z", V_ASN1_GENERALIZEDTIME, 0, 0, | |
249 | }, | |
250 | { | |
251 | /* Bad type. */ | |
252 | "20170217180154Z", V_ASN1_OCTET_STRING, 0, 0, | |
253 | }, | |
254 | }; | |
255 | ||
256 | static int test_x509_cmp_time(int idx) | |
257 | { | |
258 | ASN1_TIME t; | |
259 | int result; | |
260 | ||
261 | memset(&t, 0, sizeof(t)); | |
262 | t.type = x509_cmp_tests[idx].type; | |
263 | t.data = (unsigned char*)(x509_cmp_tests[idx].data); | |
264 | t.length = strlen(x509_cmp_tests[idx].data); | |
04e62715 | 265 | t.flags = 0; |
80770da3 EK |
266 | |
267 | result = X509_cmp_time(&t, &x509_cmp_tests[idx].cmp_time); | |
2fae041d P |
268 | if (!TEST_int_eq(result, x509_cmp_tests[idx].expected)) { |
269 | TEST_info("test_x509_cmp_time(%d) failed: expected %d, got %d\n", | |
80770da3 EK |
270 | idx, x509_cmp_tests[idx].expected, result); |
271 | return 0; | |
272 | } | |
273 | return 1; | |
274 | } | |
275 | ||
31a80694 | 276 | static int test_x509_cmp_time_current(void) |
80770da3 EK |
277 | { |
278 | time_t now = time(NULL); | |
279 | /* Pick a day earlier and later, relative to any system clock. */ | |
280 | ASN1_TIME *asn1_before = NULL, *asn1_after = NULL; | |
281 | int cmp_result, failed = 0; | |
282 | ||
283 | asn1_before = ASN1_TIME_adj(NULL, now, -1, 0); | |
284 | asn1_after = ASN1_TIME_adj(NULL, now, 1, 0); | |
285 | ||
286 | cmp_result = X509_cmp_time(asn1_before, NULL); | |
2fae041d | 287 | if (!TEST_int_eq(cmp_result, -1)) |
80770da3 | 288 | failed = 1; |
80770da3 EK |
289 | |
290 | cmp_result = X509_cmp_time(asn1_after, NULL); | |
2fae041d | 291 | if (!TEST_int_eq(cmp_result, 1)) |
80770da3 | 292 | failed = 1; |
80770da3 EK |
293 | |
294 | ASN1_TIME_free(asn1_before); | |
295 | ASN1_TIME_free(asn1_after); | |
296 | ||
297 | return failed == 0; | |
298 | } | |
299 | ||
04e62715 RS |
300 | static int test_x509_time(int idx) |
301 | { | |
302 | ASN1_TIME *t = NULL; | |
303 | int result, rv = 0; | |
304 | ||
305 | if (x509_format_tests[idx].set_string) { | |
306 | /* set-string mode */ | |
307 | t = ASN1_TIME_new(); | |
308 | if (t == NULL) { | |
309 | TEST_info("test_x509_time(%d) failed: internal error\n", idx); | |
310 | return 0; | |
311 | } | |
312 | } | |
313 | ||
314 | result = ASN1_TIME_set_string_X509(t, x509_format_tests[idx].data); | |
315 | /* time string parsing result is always checked against what's expected */ | |
316 | if (!TEST_int_eq(result, x509_format_tests[idx].expected)) { | |
317 | TEST_info("test_x509_time(%d) failed: expected %d, got %d\n", | |
318 | idx, x509_format_tests[idx].expected, result); | |
319 | goto out; | |
320 | } | |
321 | ||
322 | /* if t is not NULL but expected_type is ignored(-1), it is an 'OK' case */ | |
323 | if (t != NULL && x509_format_tests[idx].expected_type != -1) { | |
324 | if (!TEST_int_eq(t->type, x509_format_tests[idx].expected_type)) { | |
325 | TEST_info("test_x509_time(%d) failed: expected_type %d, got %d\n", | |
326 | idx, x509_format_tests[idx].expected_type, t->type); | |
327 | goto out; | |
328 | } | |
329 | } | |
330 | ||
331 | /* if t is not NULL but expected_string is NULL, it is an 'OK' case too */ | |
332 | if (t != NULL && x509_format_tests[idx].expected_string) { | |
333 | if (!TEST_str_eq((const char *)t->data, | |
334 | x509_format_tests[idx].expected_string)) { | |
335 | TEST_info("test_x509_time(%d) failed: expected_string %s, got %s\n", | |
336 | idx, x509_format_tests[idx].expected_string, t->data); | |
337 | goto out; | |
338 | } | |
339 | } | |
340 | ||
341 | rv = 1; | |
342 | out: | |
343 | if (t != NULL) | |
344 | ASN1_TIME_free(t); | |
345 | return rv; | |
346 | } | |
347 | ||
1a68e5b0 P |
348 | static const struct { |
349 | int y, m, d; | |
350 | int yd, wd; | |
351 | } day_of_week_tests[] = { | |
352 | /*YYYY MM DD DoY DoW */ | |
353 | { 1900, 1, 1, 0, 1 }, | |
354 | { 1900, 2, 28, 58, 3 }, | |
355 | { 1900, 3, 1, 59, 4 }, | |
356 | { 1900, 12, 31, 364, 1 }, | |
357 | { 1901, 1, 1, 0, 2 }, | |
358 | { 1970, 1, 1, 0, 4 }, | |
359 | { 1999, 1, 10, 9, 0 }, | |
360 | { 1999, 12, 31, 364, 5 }, | |
361 | { 2000, 1, 1, 0, 6 }, | |
362 | { 2000, 2, 28, 58, 1 }, | |
363 | { 2000, 2, 29, 59, 2 }, | |
364 | { 2000, 3, 1, 60, 3 }, | |
365 | { 2000, 12, 31, 365, 0 }, | |
366 | { 2001, 1, 1, 0, 1 }, | |
367 | { 2008, 1, 1, 0, 2 }, | |
368 | { 2008, 2, 28, 58, 4 }, | |
369 | { 2008, 2, 29, 59, 5 }, | |
370 | { 2008, 3, 1, 60, 6 }, | |
371 | { 2008, 12, 31, 365, 3 }, | |
372 | { 2009, 1, 1, 0, 4 }, | |
373 | { 2011, 1, 1, 0, 6 }, | |
374 | { 2011, 2, 28, 58, 1 }, | |
375 | { 2011, 3, 1, 59, 2 }, | |
376 | { 2011, 12, 31, 364, 6 }, | |
377 | { 2012, 1, 1, 0, 0 }, | |
378 | { 2019, 1, 2, 1, 3 }, | |
379 | { 2019, 2, 2, 32, 6 }, | |
380 | { 2019, 3, 2, 60, 6 }, | |
381 | { 2019, 4, 2, 91, 2 }, | |
382 | { 2019, 5, 2, 121, 4 }, | |
383 | { 2019, 6, 2, 152, 0 }, | |
384 | { 2019, 7, 2, 182, 2 }, | |
385 | { 2019, 8, 2, 213, 5 }, | |
386 | { 2019, 9, 2, 244, 1 }, | |
387 | { 2019, 10, 2, 274, 3 }, | |
388 | { 2019, 11, 2, 305, 6 }, | |
389 | { 2019, 12, 2, 335, 1 }, | |
390 | { 2020, 1, 2, 1, 4 }, | |
391 | { 2020, 2, 2, 32, 0 }, | |
392 | { 2020, 3, 2, 61, 1 }, | |
393 | { 2020, 4, 2, 92, 4 }, | |
394 | { 2020, 5, 2, 122, 6 }, | |
395 | { 2020, 6, 2, 153, 2 }, | |
396 | { 2020, 7, 2, 183, 4 }, | |
397 | { 2020, 8, 2, 214, 0 }, | |
398 | { 2020, 9, 2, 245, 3 }, | |
399 | { 2020, 10, 2, 275, 5 }, | |
400 | { 2020, 11, 2, 306, 1 }, | |
401 | { 2020, 12, 2, 336, 3 } | |
402 | }; | |
403 | ||
404 | static int test_days(int n) | |
405 | { | |
406 | char d[16]; | |
407 | ASN1_TIME *a = NULL; | |
408 | struct tm t; | |
409 | int r; | |
410 | ||
411 | BIO_snprintf(d, sizeof(d), "%04d%02d%02d050505Z", | |
412 | day_of_week_tests[n].y, day_of_week_tests[n].m, | |
413 | day_of_week_tests[n].d); | |
414 | ||
415 | if (!TEST_ptr(a = ASN1_TIME_new())) | |
416 | return 0; | |
417 | ||
418 | r = TEST_true(ASN1_TIME_set_string(a, d)) | |
419 | && TEST_true(ASN1_TIME_to_tm(a, &t)) | |
420 | && TEST_int_eq(t.tm_yday, day_of_week_tests[n].yd) | |
421 | && TEST_int_eq(t.tm_wday, day_of_week_tests[n].wd); | |
422 | ||
423 | ASN1_TIME_free(a); | |
424 | return r; | |
425 | } | |
426 | ||
a9dee230 PY |
427 | #define construct_asn1_time(s, t, e) \ |
428 | { { sizeof(s) - 1, t, (unsigned char*)s, 0 }, e } | |
429 | ||
430 | static const struct { | |
431 | ASN1_TIME asn1; | |
432 | const char *readable; | |
433 | } x509_print_tests [] = { | |
434 | /* Generalized Time */ | |
435 | construct_asn1_time("20170731222050Z", V_ASN1_GENERALIZEDTIME, | |
436 | "Jul 31 22:20:50 2017 GMT"), | |
437 | /* Generalized Time, no seconds */ | |
438 | construct_asn1_time("201707312220Z", V_ASN1_GENERALIZEDTIME, | |
439 | "Jul 31 22:20:00 2017 GMT"), | |
440 | /* Generalized Time, fractional seconds (3 digits) */ | |
441 | construct_asn1_time("20170731222050.123Z", V_ASN1_GENERALIZEDTIME, | |
442 | "Jul 31 22:20:50.123 2017 GMT"), | |
443 | /* Generalized Time, fractional seconds (1 digit) */ | |
444 | construct_asn1_time("20170731222050.1Z", V_ASN1_GENERALIZEDTIME, | |
445 | "Jul 31 22:20:50.1 2017 GMT"), | |
446 | /* Generalized Time, fractional seconds (0 digit) */ | |
447 | construct_asn1_time("20170731222050.Z", V_ASN1_GENERALIZEDTIME, | |
448 | "Bad time value"), | |
449 | /* UTC Time */ | |
450 | construct_asn1_time("170731222050Z", V_ASN1_UTCTIME, | |
451 | "Jul 31 22:20:50 2017 GMT"), | |
452 | /* UTC Time, no seconds */ | |
453 | construct_asn1_time("1707312220Z", V_ASN1_UTCTIME, | |
454 | "Jul 31 22:20:00 2017 GMT"), | |
455 | }; | |
456 | ||
457 | static int test_x509_time_print(int idx) | |
458 | { | |
459 | BIO *m; | |
460 | int ret = 0, rv; | |
461 | char *pp; | |
462 | const char *readable; | |
463 | ||
464 | if (!TEST_ptr(m = BIO_new(BIO_s_mem()))) | |
465 | goto err; | |
466 | ||
467 | rv = ASN1_TIME_print(m, &x509_print_tests[idx].asn1); | |
468 | readable = x509_print_tests[idx].readable; | |
469 | ||
470 | if (rv == 0 && !TEST_str_eq(readable, "Bad time value")) { | |
471 | /* only if the test case intends to fail... */ | |
472 | goto err; | |
473 | } | |
474 | if (!TEST_int_ne(rv = BIO_get_mem_data(m, &pp), 0) | |
475 | || !TEST_int_eq(rv, (int)strlen(readable)) | |
476 | || !TEST_strn_eq(pp, readable, rv)) | |
477 | goto err; | |
478 | ||
479 | ret = 1; | |
480 | err: | |
481 | BIO_free(m); | |
482 | return ret; | |
483 | } | |
484 | ||
ad887416 | 485 | int setup_tests() |
80770da3 EK |
486 | { |
487 | ADD_TEST(test_x509_cmp_time_current); | |
488 | ADD_ALL_TESTS(test_x509_cmp_time, OSSL_NELEM(x509_cmp_tests)); | |
04e62715 | 489 | ADD_ALL_TESTS(test_x509_time, OSSL_NELEM(x509_format_tests)); |
1a68e5b0 | 490 | ADD_ALL_TESTS(test_days, OSSL_NELEM(day_of_week_tests)); |
a9dee230 | 491 | ADD_ALL_TESTS(test_x509_time_print, OSSL_NELEM(x509_print_tests)); |
ad887416 | 492 | return 1; |
80770da3 | 493 | } |