1 /* $OpenBSD: asn1time.c,v 1.21 2023/10/05 07:59:41 tb Exp $ */ 2 /* 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <openssl/asn1.h> 19 20 #include <err.h> 21 #include <stdio.h> 22 #include <string.h> 23 24 int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t); 25 26 struct asn1_time_test { 27 const char *str; 28 const char *data; 29 const unsigned char der[32]; 30 time_t time; 31 }; 32 33 static const struct asn1_time_test asn1_invtime_tests[] = { 34 { 35 .str = "", 36 }, 37 { 38 .str = "2015", 39 }, 40 { 41 .str = "201509", 42 }, 43 { 44 .str = "20150923", 45 }, 46 { 47 .str = "20150923032700", 48 }, 49 { 50 .str = "20150923032700.Z", 51 }, 52 { 53 .str = "20150923032700.123", 54 }, 55 { 56 .str = "20150923032700+1.09", 57 }, 58 { 59 .str = "20150923032700+1100Z", 60 }, 61 { 62 .str = "20150923032700-11001", 63 }, 64 { 65 /* UTC time cannot have fractional seconds. */ 66 .str = "150923032700.123Z", 67 }, 68 { 69 .str = "aaaaaaaaaaaaaaZ", 70 }, 71 /* utc time with omitted seconds, should fail */ 72 { 73 .str = "1609082343Z", 74 }, 75 }; 76 77 static const struct asn1_time_test asn1_invgentime_tests[] = { 78 /* Generalized time with omitted seconds, should fail */ 79 { 80 .str = "201612081934Z", 81 }, 82 /* Valid UTC time, should fail as a generalized time */ 83 { 84 .str = "160908234300Z", 85 }, 86 }; 87 88 static const struct asn1_time_test asn1_gentime_tests[] = { 89 { 90 .str = "20161208193400Z", 91 .data = "20161208193400Z", 92 .time = 1481225640, 93 .der = { 94 0x18, 0x0f, 0x32, 0x30, 0x31, 0x36, 0x31, 0x32, 95 0x30, 0x38, 0x31, 0x39, 0x33, 0x34, 0x30, 0x30, 96 0x5a, 97 }, 98 }, 99 { 100 .str = "19700101000000Z", 101 .data = "19700101000000Z", 102 .time = 0, 103 .der = { 104 0x18, 0x0f, 0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 105 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 106 0x5a, 107 }, 108 }, 109 { 110 .str = "20150923032700Z", 111 .data = "20150923032700Z", 112 .time = 1442978820, 113 .der = { 114 0x18, 0x0f, 0x32, 0x30, 0x31, 0x35, 0x30, 0x39, 115 0x32, 0x33, 0x30, 0x33, 0x32, 0x37, 0x30, 0x30, 116 0x5a, 117 }, 118 }, 119 }; 120 121 static const struct asn1_time_test asn1_utctime_tests[] = { 122 { 123 .str = "700101000000Z", 124 .data = "700101000000Z", 125 .time = 0, 126 .der = { 127 0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, 128 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 129 }, 130 }, 131 { 132 .str = "150923032700Z", 133 .data = "150923032700Z", 134 .time = 1442978820, 135 .der = { 136 0x17, 0x0d, 0x31, 0x35, 0x30, 0x39, 0x32, 0x33, 137 0x30, 0x33, 0x32, 0x37, 0x30, 0x30, 0x5a, 138 }, 139 }, 140 { 141 .str = "140524144512Z", 142 .data = "140524144512Z", 143 .time = 1400942712, 144 .der = { 145 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x32, 0x34, 146 0x31, 0x34, 0x34, 0x35, 0x31, 0x32, 0x5a, 147 }, 148 }, 149 { 150 .str = "240401144512Z", 151 .data = "240401144512Z", 152 .time = 1711982712, 153 .der = { 154 0x17, 0x0d, 0x32, 0x34, 0x30, 0x34, 0x30, 0x31, 155 0x31, 0x34, 0x34, 0x35, 0x31, 0x32, 0x5a 156 }, 157 }, 158 }; 159 160 #define N_INVTIME_TESTS \ 161 (sizeof(asn1_invtime_tests) / sizeof(*asn1_invtime_tests)) 162 #define N_INVGENTIME_TESTS \ 163 (sizeof(asn1_invgentime_tests) / sizeof(*asn1_invgentime_tests)) 164 #define N_GENTIME_TESTS \ 165 (sizeof(asn1_gentime_tests) / sizeof(*asn1_gentime_tests)) 166 #define N_UTCTIME_TESTS \ 167 (sizeof(asn1_utctime_tests) / sizeof(*asn1_utctime_tests)) 168 169 static void 170 hexdump(const unsigned char *buf, size_t len) 171 { 172 size_t i; 173 174 for (i = 1; i <= len; i++) 175 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 176 177 fprintf(stderr, "\n"); 178 } 179 180 static int 181 asn1_compare_bytes(int test_no, const unsigned char *d1, 182 const unsigned char *d2, int len1, int len2) 183 { 184 if (len1 != len2) { 185 fprintf(stderr, "FAIL: test %d - byte lengths differ " 186 "(%d != %d)\n", test_no, len1, len2); 187 return (1); 188 } 189 if (memcmp(d1, d2, len1) != 0) { 190 fprintf(stderr, "FAIL: test %d - bytes differ\n", test_no); 191 fprintf(stderr, "Got:\n"); 192 hexdump(d1, len1); 193 fprintf(stderr, "Want:\n"); 194 hexdump(d2, len2); 195 return (1); 196 } 197 return (0); 198 } 199 200 static int 201 asn1_compare_str(int test_no, const struct asn1_string_st *asn1str, 202 const char *str) 203 { 204 int length = strlen(str); 205 206 if (asn1str->length != length) { 207 fprintf(stderr, "FAIL: test %d - string lengths differ " 208 "(%d != %d)\n", test_no, asn1str->length, length); 209 return (1); 210 } 211 if (strncmp(asn1str->data, str, length) != 0) { 212 fprintf(stderr, "FAIL: test %d - strings differ " 213 "('%s' != '%s')\n", test_no, asn1str->data, str); 214 return (1); 215 } 216 217 return (0); 218 } 219 220 static int 221 asn1_invtime_test(int test_no, const struct asn1_time_test *att, int gen) 222 { 223 ASN1_GENERALIZEDTIME *gt = NULL; 224 ASN1_UTCTIME *ut = NULL; 225 ASN1_TIME *t = NULL; 226 int failure = 1; 227 228 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL) 229 goto done; 230 if ((ut = ASN1_UTCTIME_new()) == NULL) 231 goto done; 232 if ((t = ASN1_TIME_new()) == NULL) 233 goto done; 234 235 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 0) { 236 fprintf(stderr, "FAIL: test %d - successfully set " 237 "GENERALIZEDTIME string '%s'\n", test_no, att->str); 238 goto done; 239 } 240 241 if (gen) { 242 failure = 0; 243 goto done; 244 } 245 246 if (ASN1_UTCTIME_set_string(ut, att->str) != 0) { 247 fprintf(stderr, "FAIL: test %d - successfully set UTCTIME " 248 "string '%s'\n", test_no, att->str); 249 goto done; 250 } 251 if (ASN1_TIME_set_string(t, att->str) != 0) { 252 fprintf(stderr, "FAIL: test %d - successfully set TIME " 253 "string '%s'\n", test_no, att->str); 254 goto done; 255 } 256 if (ASN1_TIME_set_string_X509(t, att->str) != 0) { 257 fprintf(stderr, "FAIL: test %d - successfully set x509 TIME " 258 "string '%s'\n", test_no, att->str); 259 goto done; 260 } 261 262 failure = 0; 263 264 done: 265 ASN1_GENERALIZEDTIME_free(gt); 266 ASN1_UTCTIME_free(ut); 267 ASN1_TIME_free(t); 268 269 return (failure); 270 } 271 272 static int 273 asn1_gentime_test(int test_no, const struct asn1_time_test *att) 274 { 275 const unsigned char *der; 276 unsigned char *p = NULL; 277 ASN1_GENERALIZEDTIME *gt = NULL; 278 int failure = 1; 279 int len; 280 struct tm tm; 281 282 if (ASN1_GENERALIZEDTIME_set_string(NULL, att->str) != 1) { 283 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 284 test_no, att->str); 285 goto done; 286 } 287 288 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL) 289 goto done; 290 291 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) { 292 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 293 test_no, att->str); 294 goto done; 295 } 296 if (asn1_compare_str(test_no, gt, att->str) != 0) 297 goto done; 298 299 if (ASN1_TIME_to_tm(gt, &tm) == 0) { 300 fprintf(stderr, "FAIL: test %d - ASN1_time_to_tm failed '%s'\n", 301 test_no, att->str); 302 goto done; 303 } 304 305 if (timegm(&tm) != att->time) { 306 /* things with crappy time_t should die in fire */ 307 int64_t a = timegm(&tm); 308 int64_t b = att->time; 309 fprintf(stderr, "FAIL: test %d - times don't match, expected %lld got %lld\n", 310 test_no, (long long)b, (long long)a); 311 goto done; 312 } 313 314 if ((len = i2d_ASN1_GENERALIZEDTIME(gt, &p)) <= 0) { 315 fprintf(stderr, "FAIL: test %d - i2d_ASN1_GENERALIZEDTIME " 316 "failed\n", test_no); 317 goto done; 318 } 319 der = att->der; 320 if (asn1_compare_bytes(test_no, p, der, len, strlen(der)) != 0) 321 goto done; 322 323 len = strlen(att->der); 324 if (d2i_ASN1_GENERALIZEDTIME(>, &der, len) == NULL) { 325 fprintf(stderr, "FAIL: test %d - d2i_ASN1_GENERALIZEDTIME " 326 "failed\n", test_no); 327 goto done; 328 } 329 if (asn1_compare_str(test_no, gt, att->str) != 0) 330 goto done; 331 332 ASN1_GENERALIZEDTIME_free(gt); 333 334 if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) { 335 fprintf(stderr, "FAIL: test %d - failed to set time %lld\n", 336 test_no, (long long)att->time); 337 goto done; 338 } 339 if (asn1_compare_str(test_no, gt, att->data) != 0) 340 goto done; 341 342 failure = 0; 343 344 done: 345 ASN1_GENERALIZEDTIME_free(gt); 346 free(p); 347 348 return (failure); 349 } 350 351 static int 352 asn1_utctime_test(int test_no, const struct asn1_time_test *att) 353 { 354 const unsigned char *der; 355 unsigned char *p = NULL; 356 ASN1_UTCTIME *ut = NULL; 357 int failure = 1; 358 int len; 359 360 if (ASN1_UTCTIME_set_string(NULL, att->str) != 1) { 361 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 362 test_no, att->str); 363 goto done; 364 } 365 366 if ((ut = ASN1_UTCTIME_new()) == NULL) 367 goto done; 368 369 if (ASN1_UTCTIME_set_string(ut, att->str) != 1) { 370 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 371 test_no, att->str); 372 goto done; 373 } 374 if (asn1_compare_str(test_no, ut, att->str) != 0) 375 goto done; 376 377 if ((len = i2d_ASN1_UTCTIME(ut, &p)) <= 0) { 378 fprintf(stderr, "FAIL: test %d - i2d_ASN1_UTCTIME failed\n", 379 test_no); 380 goto done; 381 } 382 der = att->der; 383 if (asn1_compare_bytes(test_no, p, der, len, strlen(der)) != 0) 384 goto done; 385 386 len = strlen(att->der); 387 if (d2i_ASN1_UTCTIME(&ut, &der, len) == NULL) { 388 fprintf(stderr, "FAIL: test %d - d2i_ASN1_UTCTIME failed\n", 389 test_no); 390 goto done; 391 } 392 if (asn1_compare_str(test_no, ut, att->str) != 0) 393 goto done; 394 395 ASN1_UTCTIME_free(ut); 396 397 if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) { 398 fprintf(stderr, "FAIL: test %d - failed to set time %lld\n", 399 test_no, (long long)att->time); 400 goto done; 401 } 402 if (asn1_compare_str(test_no, ut, att->data) != 0) 403 goto done; 404 405 failure = 0; 406 407 done: 408 ASN1_UTCTIME_free(ut); 409 free(p); 410 411 return (failure); 412 } 413 414 static int 415 asn1_time_test(int test_no, const struct asn1_time_test *att, int type) 416 { 417 ASN1_TIME *t = NULL, *tx509 = NULL; 418 int failure = 1; 419 420 if (ASN1_TIME_set_string(NULL, att->str) != 1) { 421 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 422 test_no, att->str); 423 goto done; 424 } 425 426 if ((t = ASN1_TIME_new()) == NULL) 427 goto done; 428 429 if ((tx509 = ASN1_TIME_new()) == NULL) 430 goto done; 431 432 if (ASN1_TIME_set_string(t, att->str) != 1) { 433 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 434 test_no, att->str); 435 goto done; 436 } 437 438 if (t->type != type) { 439 fprintf(stderr, "FAIL: test %d - got type %d, want %d\n", 440 test_no, t->type, type); 441 goto done; 442 } 443 444 if (ASN1_TIME_normalize(t) != 1) { 445 fprintf(stderr, "FAIL: test %d - failed to set normalize '%s'\n", 446 test_no, att->str); 447 goto done; 448 } 449 450 if (ASN1_TIME_set_string_X509(tx509, t->data) != 1) { 451 fprintf(stderr, "FAIL: test %d - failed to set string X509 '%s'\n", 452 test_no, t->data); 453 goto done; 454 } 455 456 if (t->type != tx509->type) { 457 fprintf(stderr, "FAIL: test %d - type %d, different from %d\n", 458 test_no, t->type, tx509->type); 459 goto done; 460 } 461 462 if (ASN1_TIME_compare(t, tx509) != 0) { 463 fprintf(stderr, "FAIL: ASN1_TIME values differ!\n"); 464 goto done; 465 } 466 467 468 failure = 0; 469 470 done: 471 472 ASN1_TIME_free(t); 473 ASN1_TIME_free(tx509); 474 475 return (failure); 476 } 477 478 static int 479 time_t_cmp(time_t t1, time_t t2) 480 { 481 if (t1 < t2) 482 return -1; 483 if (t2 < t1) 484 return 1; 485 return 0; 486 } 487 488 static int 489 asn1_time_compare_families(const struct asn1_time_test *fam1, size_t fam1_size, 490 const struct asn1_time_test *fam2, size_t fam2_size) 491 { 492 const struct asn1_time_test *att1, *att2; 493 ASN1_TIME *t1 = NULL, *t2 = NULL; 494 size_t i, j; 495 int asn1_cmp, time_cmp; 496 int comparison_failure = 0; 497 int failure = 1; 498 499 if ((t1 = ASN1_TIME_new()) == NULL) 500 goto done; 501 if ((t2 = ASN1_TIME_new()) == NULL) 502 goto done; 503 504 for (i = 0; i < fam1_size; i++) { 505 att1 = &fam1[i]; 506 507 if (!ASN1_TIME_set_string(t1, att1->str)) 508 goto done; 509 for (j = 0; j < fam2_size; j++) { 510 att2 = &fam2[j]; 511 512 if (!ASN1_TIME_set_string(t2, att2->str)) 513 goto done; 514 515 time_cmp = time_t_cmp(att1->time, att2->time); 516 asn1_cmp = ASN1_TIME_compare(t1, t2); 517 518 if (time_cmp != asn1_cmp) { 519 fprintf(stderr, "%s vs. %s: want %d, got %d\n", 520 att1->str, att2->str, time_cmp, asn1_cmp); 521 comparison_failure |= 1; 522 } 523 524 time_cmp = ASN1_TIME_cmp_time_t(t1, att2->time); 525 if (time_cmp != asn1_cmp) { 526 fprintf(stderr, "%s vs. %lld: want %d, got %d\n", 527 att1->str, (long long)att2->time, 528 asn1_cmp, time_cmp); 529 comparison_failure |= 1; 530 } 531 532 time_cmp = ASN1_UTCTIME_cmp_time_t(t1, att2->time); 533 if (t1->type != V_ASN1_UTCTIME) 534 asn1_cmp = -2; 535 if (time_cmp != asn1_cmp) { 536 fprintf(stderr, "%s vs. %lld: want %d, got %d\n", 537 att1->str, (long long)att2->time, 538 asn1_cmp, time_cmp); 539 comparison_failure |= 1; 540 } 541 } 542 } 543 544 failure = comparison_failure; 545 546 done: 547 ASN1_TIME_free(t1); 548 ASN1_TIME_free(t2); 549 550 return failure; 551 } 552 553 static int 554 asn1_time_compare_test(void) 555 { 556 const struct asn1_time_test *gen = asn1_gentime_tests; 557 size_t gen_size = N_GENTIME_TESTS; 558 const struct asn1_time_test *utc = asn1_utctime_tests; 559 size_t utc_size = N_UTCTIME_TESTS; 560 int failed = 0; 561 562 failed |= asn1_time_compare_families(gen, gen_size, gen, gen_size); 563 failed |= asn1_time_compare_families(gen, gen_size, utc, utc_size); 564 failed |= asn1_time_compare_families(utc, utc_size, gen, gen_size); 565 failed |= asn1_time_compare_families(utc, utc_size, utc, utc_size); 566 567 return failed; 568 } 569 570 int 571 main(int argc, char **argv) 572 { 573 const struct asn1_time_test *att; 574 int failed = 0; 575 size_t i; 576 577 fprintf(stderr, "Invalid time tests...\n"); 578 for (i = 0; i < N_INVTIME_TESTS; i++) { 579 att = &asn1_invtime_tests[i]; 580 failed |= asn1_invtime_test(i, att, 0); 581 } 582 583 fprintf(stderr, "Invalid generalized time tests...\n"); 584 for (i = 0; i < N_INVGENTIME_TESTS; i++) { 585 att = &asn1_invgentime_tests[i]; 586 failed |= asn1_invtime_test(i, att, 1); 587 } 588 589 fprintf(stderr, "GENERALIZEDTIME tests...\n"); 590 for (i = 0; i < N_GENTIME_TESTS; i++) { 591 att = &asn1_gentime_tests[i]; 592 failed |= asn1_gentime_test(i, att); 593 } 594 595 fprintf(stderr, "UTCTIME tests...\n"); 596 for (i = 0; i < N_UTCTIME_TESTS; i++) { 597 att = &asn1_utctime_tests[i]; 598 failed |= asn1_utctime_test(i, att); 599 } 600 601 fprintf(stderr, "TIME tests...\n"); 602 for (i = 0; i < N_UTCTIME_TESTS; i++) { 603 att = &asn1_utctime_tests[i]; 604 failed |= asn1_time_test(i, att, V_ASN1_UTCTIME); 605 } 606 for (i = 0; i < N_GENTIME_TESTS; i++) { 607 att = &asn1_gentime_tests[i]; 608 failed |= asn1_time_test(i, att, V_ASN1_GENERALIZEDTIME); 609 } 610 611 fprintf(stderr, "ASN1_TIME_compare tests...\n"); 612 failed |= asn1_time_compare_test(); 613 614 /* Check for a leak in ASN1_TIME_normalize(). */ 615 failed |= ASN1_TIME_normalize(NULL) != 0; 616 617 return (failed); 618 } 619