1 /* 2 * Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (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" 18 #include "internal/nelem.h" 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 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", 57 0, 58 1, 59 -1, 60 NULL, 61 }, 62 { 63 /* not leap year, check only */ 64 "20170229180105Z", 65 0, 66 0, 67 -1, 68 NULL, 69 }, 70 { 71 /* leap year, check only */ 72 "20160229180105Z", 73 0, 74 1, 75 -1, 76 NULL, 77 }, 78 { 79 /* SS is missing, check only */ 80 "201702171801Z", 81 0, 82 0, 83 -1, 84 NULL, 85 }, 86 { 87 /* fractional seconds, check only */ 88 "20170217180105.001Z", 89 0, 90 0, 91 -1, 92 NULL, 93 }, 94 { 95 /* timezone, check only */ 96 "20170217180105+0800", 97 0, 98 0, 99 -1, 100 NULL, 101 }, 102 { 103 /* SS is missing, set string */ 104 "201702171801Z", 105 1, 106 0, 107 -1, 108 NULL, 109 }, 110 { 111 /* fractional seconds, set string */ 112 "20170217180105.001Z", 113 1, 114 0, 115 -1, 116 NULL, 117 }, 118 { 119 /* timezone, set string */ 120 "20170217180105+0800", 121 1, 122 0, 123 -1, 124 NULL, 125 }, 126 { 127 /* good format, check returned 'turned' string */ 128 "20170217180154Z", 129 1, 130 1, 131 V_ASN1_UTCTIME, 132 "170217180154Z", 133 }, 134 { 135 /* good format, check returned string */ 136 "20510217180154Z", 137 1, 138 1, 139 V_ASN1_GENERALIZEDTIME, 140 "20510217180154Z", 141 }, 142 { 143 /* good format but out of UTC range, check returned string */ 144 "19230419180154Z", 145 1, 146 1, 147 V_ASN1_GENERALIZEDTIME, 148 "19230419180154Z", 149 }, 150 /* UTC */ 151 { 152 /* SS is missing, check only */ 153 "1702171801Z", 154 0, 155 0, 156 -1, 157 NULL, 158 }, 159 { 160 /* not leap year, check only */ 161 "050229180101Z", 162 0, 163 0, 164 -1, 165 NULL, 166 }, 167 { 168 /* leap year, check only */ 169 "040229180101Z", 170 0, 171 1, 172 -1, 173 NULL, 174 }, 175 { 176 /* timezone, check only */ 177 "170217180154+0800", 178 0, 179 0, 180 -1, 181 NULL, 182 }, 183 { 184 /* SS is missing, set string */ 185 "1702171801Z", 186 1, 187 0, 188 -1, 189 NULL, 190 }, 191 { 192 /* timezone, set string */ 193 "170217180154+0800", 194 1, 195 0, 196 -1, 197 NULL, 198 }, 199 { 200 /* 2017, good format, check returned string */ 201 "170217180154Z", 202 1, 203 1, 204 V_ASN1_UTCTIME, 205 "170217180154Z", 206 }, 207 { 208 /* 1998, good format, check returned string */ 209 "981223180154Z", 210 1, 211 1, 212 V_ASN1_UTCTIME, 213 "981223180154Z", 214 }, 215 }; 216 217 static TESTDATA x509_cmp_tests[] = { 218 { 219 "20170217180154Z", 220 V_ASN1_GENERALIZEDTIME, 221 /* The same in seconds since epoch. */ 222 1487354514, 223 -1, 224 }, 225 { 226 "20170217180154Z", 227 V_ASN1_GENERALIZEDTIME, 228 /* One second more. */ 229 1487354515, 230 -1, 231 }, 232 { 233 "20170217180154Z", 234 V_ASN1_GENERALIZEDTIME, 235 /* One second less. */ 236 1487354513, 237 1, 238 }, 239 /* Same as UTC time. */ 240 { 241 "170217180154Z", 242 V_ASN1_UTCTIME, 243 /* The same in seconds since epoch. */ 244 1487354514, 245 -1, 246 }, 247 { 248 "170217180154Z", 249 V_ASN1_UTCTIME, 250 /* One second more. */ 251 1487354515, 252 -1, 253 }, 254 { 255 "170217180154Z", 256 V_ASN1_UTCTIME, 257 /* One second less. */ 258 1487354513, 259 1, 260 }, 261 /* UTCTime from the 20th century. */ 262 { 263 "990217180154Z", 264 V_ASN1_UTCTIME, 265 /* The same in seconds since epoch. */ 266 919274514, 267 -1, 268 }, 269 { 270 "990217180154Z", 271 V_ASN1_UTCTIME, 272 /* One second more. */ 273 919274515, 274 -1, 275 }, 276 { 277 "990217180154Z", 278 V_ASN1_UTCTIME, 279 /* One second less. */ 280 919274513, 281 1, 282 }, 283 /* Various invalid formats. */ 284 { 285 /* No trailing Z. */ 286 "20170217180154", 287 V_ASN1_GENERALIZEDTIME, 288 0, 289 0, 290 }, 291 { 292 /* No trailing Z, UTCTime. */ 293 "170217180154", 294 V_ASN1_UTCTIME, 295 0, 296 0, 297 }, 298 { 299 /* No seconds. */ 300 "201702171801Z", 301 V_ASN1_GENERALIZEDTIME, 302 0, 303 0, 304 }, 305 { 306 /* No seconds, UTCTime. */ 307 "1702171801Z", 308 V_ASN1_UTCTIME, 309 0, 310 0, 311 }, 312 { 313 /* Fractional seconds. */ 314 "20170217180154.001Z", 315 V_ASN1_GENERALIZEDTIME, 316 0, 317 0, 318 }, 319 { 320 /* Fractional seconds, UTCTime. */ 321 "170217180154.001Z", 322 V_ASN1_UTCTIME, 323 0, 324 0, 325 }, 326 { 327 /* Timezone offset. */ 328 "20170217180154+0100", 329 V_ASN1_GENERALIZEDTIME, 330 0, 331 0, 332 }, 333 { 334 /* Timezone offset, UTCTime. */ 335 "170217180154+0100", 336 V_ASN1_UTCTIME, 337 0, 338 0, 339 }, 340 { 341 /* Extra digits. */ 342 "2017021718015400Z", 343 V_ASN1_GENERALIZEDTIME, 344 0, 345 0, 346 }, 347 { 348 /* Extra digits, UTCTime. */ 349 "17021718015400Z", 350 V_ASN1_UTCTIME, 351 0, 352 0, 353 }, 354 { 355 /* Non-digits. */ 356 "2017021718015aZ", 357 V_ASN1_GENERALIZEDTIME, 358 0, 359 0, 360 }, 361 { 362 /* Non-digits, UTCTime. */ 363 "17021718015aZ", 364 V_ASN1_UTCTIME, 365 0, 366 0, 367 }, 368 { 369 /* Trailing garbage. */ 370 "20170217180154Zlongtrailinggarbage", 371 V_ASN1_GENERALIZEDTIME, 372 0, 373 0, 374 }, 375 { 376 /* Trailing garbage, UTCTime. */ 377 "170217180154Zlongtrailinggarbage", 378 V_ASN1_UTCTIME, 379 0, 380 0, 381 }, 382 { 383 /* Swapped type. */ 384 "20170217180154Z", 385 V_ASN1_UTCTIME, 386 0, 387 0, 388 }, 389 { 390 /* Swapped type. */ 391 "170217180154Z", 392 V_ASN1_GENERALIZEDTIME, 393 0, 394 0, 395 }, 396 { 397 /* Bad type. */ 398 "20170217180154Z", 399 V_ASN1_OCTET_STRING, 400 0, 401 0, 402 }, 403 }; 404 405 static int test_x509_cmp_time(int idx) 406 { 407 ASN1_TIME t; 408 int result; 409 410 memset(&t, 0, sizeof(t)); 411 t.type = x509_cmp_tests[idx].type; 412 t.data = (unsigned char *)(x509_cmp_tests[idx].data); 413 t.length = strlen(x509_cmp_tests[idx].data); 414 t.flags = 0; 415 416 result = X509_cmp_time(&t, &x509_cmp_tests[idx].cmp_time); 417 if (!TEST_int_eq(result, x509_cmp_tests[idx].expected)) { 418 TEST_info("test_x509_cmp_time(%d) failed: expected %d, got %d\n", 419 idx, x509_cmp_tests[idx].expected, result); 420 return 0; 421 } 422 return 1; 423 } 424 425 static int test_x509_cmp_time_current(void) 426 { 427 time_t now = time(NULL); 428 /* Pick a day earlier and later, relative to any system clock. */ 429 ASN1_TIME *asn1_before = NULL, *asn1_after = NULL; 430 int cmp_result, failed = 0; 431 432 asn1_before = ASN1_TIME_adj(NULL, now, -1, 0); 433 asn1_after = ASN1_TIME_adj(NULL, now, 1, 0); 434 435 cmp_result = X509_cmp_time(asn1_before, NULL); 436 if (!TEST_int_eq(cmp_result, -1)) 437 failed = 1; 438 439 cmp_result = X509_cmp_time(asn1_after, NULL); 440 if (!TEST_int_eq(cmp_result, 1)) 441 failed = 1; 442 443 ASN1_TIME_free(asn1_before); 444 ASN1_TIME_free(asn1_after); 445 446 return failed == 0; 447 } 448 449 static int test_X509_cmp_timeframe_vpm(const X509_VERIFY_PARAM *vpm, 450 ASN1_TIME *asn1_before, 451 ASN1_TIME *asn1_mid, 452 ASN1_TIME *asn1_after) 453 { 454 int always_0 = vpm != NULL 455 && (X509_VERIFY_PARAM_get_flags(vpm) & X509_V_FLAG_USE_CHECK_TIME) == 0 456 && (X509_VERIFY_PARAM_get_flags(vpm) & X509_V_FLAG_NO_CHECK_TIME) != 0; 457 458 return asn1_before != NULL && asn1_mid != NULL && asn1_after != NULL 459 && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_before, asn1_after), 0) 460 && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_before, NULL), 0) 461 && TEST_int_eq(X509_cmp_timeframe(vpm, NULL, asn1_after), 0) 462 && TEST_int_eq(X509_cmp_timeframe(vpm, NULL, NULL), 0) 463 && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_after, asn1_after), 464 always_0 ? 0 : -1) 465 && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_before, asn1_before), 466 always_0 ? 0 : 1) 467 && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_after, asn1_before), 468 always_0 ? 0 : 1); 469 } 470 471 static int test_X509_cmp_timeframe(void) 472 { 473 time_t now = time(NULL); 474 ASN1_TIME *asn1_mid = ASN1_TIME_adj(NULL, now, 0, 0); 475 /* Pick a day earlier and later, relative to any system clock. */ 476 ASN1_TIME *asn1_before = ASN1_TIME_adj(NULL, now, -1, 0); 477 ASN1_TIME *asn1_after = ASN1_TIME_adj(NULL, now, 1, 0); 478 X509_VERIFY_PARAM *vpm = X509_VERIFY_PARAM_new(); 479 int res = 0; 480 481 if (vpm == NULL) 482 goto finish; 483 res = test_X509_cmp_timeframe_vpm(NULL, asn1_before, asn1_mid, asn1_after) 484 && test_X509_cmp_timeframe_vpm(vpm, asn1_before, asn1_mid, asn1_after); 485 486 X509_VERIFY_PARAM_set_time(vpm, now); 487 res = res 488 && test_X509_cmp_timeframe_vpm(vpm, asn1_before, asn1_mid, asn1_after) 489 && X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME) 490 && test_X509_cmp_timeframe_vpm(vpm, asn1_before, asn1_mid, asn1_after); 491 492 X509_VERIFY_PARAM_free(vpm); 493 finish: 494 ASN1_TIME_free(asn1_mid); 495 ASN1_TIME_free(asn1_before); 496 ASN1_TIME_free(asn1_after); 497 498 return res; 499 } 500 501 static int test_x509_time(int idx) 502 { 503 ASN1_TIME *t = NULL; 504 int result, rv = 0; 505 506 if (x509_format_tests[idx].set_string) { 507 /* set-string mode */ 508 t = ASN1_TIME_new(); 509 if (t == NULL) { 510 TEST_info("test_x509_time(%d) failed: internal error\n", idx); 511 return 0; 512 } 513 } 514 515 result = ASN1_TIME_set_string_X509(t, x509_format_tests[idx].data); 516 /* time string parsing result is always checked against what's expected */ 517 if (!TEST_int_eq(result, x509_format_tests[idx].expected)) { 518 TEST_info("test_x509_time(%d) failed: expected %d, got %d\n", 519 idx, x509_format_tests[idx].expected, result); 520 goto out; 521 } 522 523 /* if t is not NULL but expected_type is ignored(-1), it is an 'OK' case */ 524 if (t != NULL && x509_format_tests[idx].expected_type != -1) { 525 if (!TEST_int_eq(t->type, x509_format_tests[idx].expected_type)) { 526 TEST_info("test_x509_time(%d) failed: expected_type %d, got %d\n", 527 idx, x509_format_tests[idx].expected_type, t->type); 528 goto out; 529 } 530 } 531 532 /* if t is not NULL but expected_string is NULL, it is an 'OK' case too */ 533 if (t != NULL && x509_format_tests[idx].expected_string) { 534 if (!TEST_mem_eq((const char *)t->data, t->length, 535 x509_format_tests[idx].expected_string, 536 strlen(x509_format_tests[idx].expected_string))) { 537 TEST_info("test_x509_time(%d) failed: expected_string %s, got %.*s\n", 538 idx, x509_format_tests[idx].expected_string, t->length, 539 t->data); 540 goto out; 541 } 542 } 543 544 rv = 1; 545 out: 546 if (t != NULL) 547 ASN1_TIME_free(t); 548 return rv; 549 } 550 551 static const struct { 552 int y, m, d; 553 int yd, wd; 554 } day_of_week_tests[] = { 555 /*YYYY MM DD DoY DoW */ 556 { 1900, 1, 1, 0, 1 }, 557 { 1900, 2, 28, 58, 3 }, 558 { 1900, 3, 1, 59, 4 }, 559 { 1900, 12, 31, 364, 1 }, 560 { 1901, 1, 1, 0, 2 }, 561 { 1970, 1, 1, 0, 4 }, 562 { 1999, 1, 10, 9, 0 }, 563 { 1999, 12, 31, 364, 5 }, 564 { 2000, 1, 1, 0, 6 }, 565 { 2000, 2, 28, 58, 1 }, 566 { 2000, 2, 29, 59, 2 }, 567 { 2000, 3, 1, 60, 3 }, 568 { 2000, 12, 31, 365, 0 }, 569 { 2001, 1, 1, 0, 1 }, 570 { 2008, 1, 1, 0, 2 }, 571 { 2008, 2, 28, 58, 4 }, 572 { 2008, 2, 29, 59, 5 }, 573 { 2008, 3, 1, 60, 6 }, 574 { 2008, 12, 31, 365, 3 }, 575 { 2009, 1, 1, 0, 4 }, 576 { 2011, 1, 1, 0, 6 }, 577 { 2011, 2, 28, 58, 1 }, 578 { 2011, 3, 1, 59, 2 }, 579 { 2011, 12, 31, 364, 6 }, 580 { 2012, 1, 1, 0, 0 }, 581 { 2019, 1, 2, 1, 3 }, 582 { 2019, 2, 2, 32, 6 }, 583 { 2019, 3, 2, 60, 6 }, 584 { 2019, 4, 2, 91, 2 }, 585 { 2019, 5, 2, 121, 4 }, 586 { 2019, 6, 2, 152, 0 }, 587 { 2019, 7, 2, 182, 2 }, 588 { 2019, 8, 2, 213, 5 }, 589 { 2019, 9, 2, 244, 1 }, 590 { 2019, 10, 2, 274, 3 }, 591 { 2019, 11, 2, 305, 6 }, 592 { 2019, 12, 2, 335, 1 }, 593 { 2020, 1, 2, 1, 4 }, 594 { 2020, 2, 2, 32, 0 }, 595 { 2020, 3, 2, 61, 1 }, 596 { 2020, 4, 2, 92, 4 }, 597 { 2020, 5, 2, 122, 6 }, 598 { 2020, 6, 2, 153, 2 }, 599 { 2020, 7, 2, 183, 4 }, 600 { 2020, 8, 2, 214, 0 }, 601 { 2020, 9, 2, 245, 3 }, 602 { 2020, 10, 2, 275, 5 }, 603 { 2020, 11, 2, 306, 1 }, 604 { 2020, 12, 2, 336, 3 } 605 }; 606 607 static int test_days(int n) 608 { 609 char d[16]; 610 ASN1_TIME *a = NULL; 611 struct tm t; 612 int r; 613 614 BIO_snprintf(d, sizeof(d), "%04d%02d%02d050505Z", 615 day_of_week_tests[n].y, day_of_week_tests[n].m, 616 day_of_week_tests[n].d); 617 618 if (!TEST_ptr(a = ASN1_TIME_new())) 619 return 0; 620 621 r = TEST_true(ASN1_TIME_set_string(a, d)) 622 && TEST_true(ASN1_TIME_to_tm(a, &t)) 623 && TEST_int_eq(t.tm_yday, day_of_week_tests[n].yd) 624 && TEST_int_eq(t.tm_wday, day_of_week_tests[n].wd); 625 626 ASN1_TIME_free(a); 627 return r; 628 } 629 630 #define construct_asn1_time(s, t, e) \ 631 { { sizeof(s) - 1, t, (unsigned char *)s, 0 }, e } 632 633 static const struct { 634 ASN1_TIME asn1; 635 const char *readable; 636 } x509_print_tests_rfc_822[] = { 637 /* Generalized Time */ 638 construct_asn1_time("20170731222050Z", V_ASN1_GENERALIZEDTIME, 639 "Jul 31 22:20:50 2017 GMT"), 640 /* Generalized Time, no seconds */ 641 construct_asn1_time("201707312220Z", V_ASN1_GENERALIZEDTIME, 642 "Bad time value"), 643 /* Generalized Time, fractional seconds (3 digits) */ 644 construct_asn1_time("20170731222050.123Z", V_ASN1_GENERALIZEDTIME, 645 "Jul 31 22:20:50.123 2017 GMT"), 646 /* Generalized Time, fractional seconds (1 digit) */ 647 construct_asn1_time("20170731222050.1Z", V_ASN1_GENERALIZEDTIME, 648 "Jul 31 22:20:50.1 2017 GMT"), 649 /* Generalized Time, fractional seconds (0 digit) */ 650 construct_asn1_time("20170731222050.Z", V_ASN1_GENERALIZEDTIME, 651 "Bad time value"), 652 /* UTC Time */ 653 construct_asn1_time("170731222050Z", V_ASN1_UTCTIME, 654 "Jul 31 22:20:50 2017 GMT"), 655 /* UTC Time, no seconds */ 656 construct_asn1_time("1707312220Z", V_ASN1_UTCTIME, 657 "Bad time value"), 658 }; 659 660 static const struct { 661 ASN1_TIME asn1; 662 const char *readable; 663 } x509_print_tests_iso_8601[] = { 664 /* Generalized Time */ 665 construct_asn1_time("20170731222050Z", V_ASN1_GENERALIZEDTIME, 666 "2017-07-31 22:20:50Z"), 667 /* Generalized Time, no seconds */ 668 construct_asn1_time("201707312220Z", V_ASN1_GENERALIZEDTIME, 669 "Bad time value"), 670 /* Generalized Time, fractional seconds (3 digits) */ 671 construct_asn1_time("20170731222050.123Z", V_ASN1_GENERALIZEDTIME, 672 "2017-07-31 22:20:50.123Z"), 673 /* Generalized Time, fractional seconds (1 digit) */ 674 construct_asn1_time("20170731222050.1Z", V_ASN1_GENERALIZEDTIME, 675 "2017-07-31 22:20:50.1Z"), 676 /* Generalized Time, fractional seconds (0 digit) */ 677 construct_asn1_time("20170731222050.Z", V_ASN1_GENERALIZEDTIME, 678 "Bad time value"), 679 /* UTC Time */ 680 construct_asn1_time("170731222050Z", V_ASN1_UTCTIME, 681 "2017-07-31 22:20:50Z"), 682 /* UTC Time, no seconds */ 683 construct_asn1_time("1707312220Z", V_ASN1_UTCTIME, 684 "Bad time value"), 685 }; 686 687 static int test_x509_time_print_rfc_822(int idx) 688 { 689 BIO *m; 690 int ret = 0, rv; 691 char *pp; 692 const char *readable; 693 694 if (!TEST_ptr(m = BIO_new(BIO_s_mem()))) 695 goto err; 696 697 rv = ASN1_TIME_print_ex(m, &x509_print_tests_rfc_822[idx].asn1, ASN1_DTFLGS_RFC822); 698 readable = x509_print_tests_rfc_822[idx].readable; 699 700 if (rv == 0 && !TEST_str_eq(readable, "Bad time value")) { 701 /* only if the test case intends to fail... */ 702 goto err; 703 } 704 if (!TEST_int_ne(rv = BIO_get_mem_data(m, &pp), 0) 705 || !TEST_int_eq(rv, (int)strlen(readable)) 706 || !TEST_strn_eq(pp, readable, rv)) 707 goto err; 708 709 ret = 1; 710 err: 711 BIO_free(m); 712 return ret; 713 } 714 715 static int test_x509_time_print_iso_8601(int idx) 716 { 717 BIO *m; 718 int ret = 0, rv; 719 char *pp; 720 const char *readable; 721 722 if (!TEST_ptr(m = BIO_new(BIO_s_mem()))) 723 goto err; 724 725 rv = ASN1_TIME_print_ex(m, &x509_print_tests_iso_8601[idx].asn1, ASN1_DTFLGS_ISO8601); 726 readable = x509_print_tests_iso_8601[idx].readable; 727 728 if (rv == 0 && !TEST_str_eq(readable, "Bad time value")) { 729 /* only if the test case intends to fail... */ 730 goto err; 731 } 732 if (!TEST_int_ne(rv = BIO_get_mem_data(m, &pp), 0) 733 || !TEST_int_eq(rv, (int)strlen(readable)) 734 || !TEST_strn_eq(pp, readable, rv)) 735 goto err; 736 737 ret = 1; 738 err: 739 BIO_free(m); 740 return ret; 741 } 742 743 int setup_tests(void) 744 { 745 ADD_TEST(test_x509_cmp_time_current); 746 ADD_TEST(test_X509_cmp_timeframe); 747 ADD_ALL_TESTS(test_x509_cmp_time, OSSL_NELEM(x509_cmp_tests)); 748 ADD_ALL_TESTS(test_x509_time, OSSL_NELEM(x509_format_tests)); 749 ADD_ALL_TESTS(test_days, OSSL_NELEM(day_of_week_tests)); 750 ADD_ALL_TESTS(test_x509_time_print_rfc_822, OSSL_NELEM(x509_print_tests_rfc_822)); 751 ADD_ALL_TESTS(test_x509_time_print_iso_8601, OSSL_NELEM(x509_print_tests_iso_8601)); 752 return 1; 753 } 754