x509_time_test.c 14 KB

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