1 /* $OpenBSD: a_time_tm.c,v 1.24 2022/07/04 14:39:43 tb Exp $ */ 2 /* 3 * Copyright (c) 2015 Bob Beck <beck@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 <ctype.h> 19 #include <limits.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <time.h> 23 24 #include <openssl/asn1t.h> 25 #include <openssl/err.h> 26 27 #include "bytestring.h" 28 #include "o_time.h" 29 30 #define RFC5280 0 31 #define GENTIME_LENGTH 15 32 #define UTCTIME_LENGTH 13 33 34 int 35 ASN1_time_tm_cmp(struct tm *tm1, struct tm *tm2) 36 { 37 if (tm1->tm_year < tm2->tm_year) 38 return (-1); 39 if (tm1->tm_year > tm2->tm_year) 40 return (1); 41 if (tm1->tm_mon < tm2->tm_mon) 42 return (-1); 43 if (tm1->tm_mon > tm2->tm_mon) 44 return (1); 45 if (tm1->tm_mday < tm2->tm_mday) 46 return (-1); 47 if (tm1->tm_mday > tm2->tm_mday) 48 return (1); 49 if (tm1->tm_hour < tm2->tm_hour) 50 return (-1); 51 if (tm1->tm_hour > tm2->tm_hour) 52 return (1); 53 if (tm1->tm_min < tm2->tm_min) 54 return (-1); 55 if (tm1->tm_min > tm2->tm_min) 56 return (1); 57 if (tm1->tm_sec < tm2->tm_sec) 58 return (-1); 59 if (tm1->tm_sec > tm2->tm_sec) 60 return (1); 61 return 0; 62 } 63 64 int 65 ASN1_time_tm_clamp_notafter(struct tm *tm) 66 { 67 #ifdef SMALL_TIME_T 68 struct tm broken_os_epoch_tm; 69 time_t broken_os_epoch_time = INT_MAX; 70 71 if (gmtime_r(&broken_os_epoch_time, &broken_os_epoch_tm) == NULL) 72 return 0; 73 74 if (ASN1_time_tm_cmp(tm, &broken_os_epoch_tm) == 1) 75 memcpy(tm, &broken_os_epoch_tm, sizeof(*tm)); 76 #endif 77 return 1; 78 } 79 80 /* Convert time to GeneralizedTime, X.690, 11.7. */ 81 ASN1_TIME * 82 tm_to_gentime(struct tm *tm, ASN1_TIME *atime) 83 { 84 char *time_str = NULL; 85 int year; 86 87 year = tm->tm_year + 1900; 88 if (year < 0 || year > 9999) { 89 ASN1error(ASN1_R_ILLEGAL_TIME_VALUE); 90 goto err; 91 } 92 93 if (asprintf(&time_str, "%04u%02u%02u%02u%02u%02uZ", year, 94 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, 95 tm->tm_sec) == -1) { 96 time_str = NULL; 97 ASN1error(ERR_R_MALLOC_FAILURE); 98 goto err; 99 } 100 101 if (atime == NULL) 102 atime = ASN1_TIME_new(); 103 if (atime == NULL) { 104 ASN1error(ERR_R_MALLOC_FAILURE); 105 goto err; 106 } 107 108 free(atime->data); 109 atime->data = time_str; 110 atime->length = GENTIME_LENGTH; 111 atime->type = V_ASN1_GENERALIZEDTIME; 112 113 return (atime); 114 115 err: 116 free(time_str); 117 118 return (NULL); 119 } 120 121 /* Convert time to UTCTime, X.690, 11.8. */ 122 ASN1_TIME * 123 tm_to_utctime(struct tm *tm, ASN1_TIME *atime) 124 { 125 char *time_str = NULL; 126 127 if (tm->tm_year >= 150 || tm->tm_year < 50) { 128 ASN1error(ASN1_R_ILLEGAL_TIME_VALUE); 129 goto err; 130 } 131 132 if (asprintf(&time_str, "%02u%02u%02u%02u%02u%02uZ", 133 tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, 134 tm->tm_hour, tm->tm_min, tm->tm_sec) == -1) { 135 time_str = NULL; 136 ASN1error(ERR_R_MALLOC_FAILURE); 137 goto err; 138 } 139 140 if (atime == NULL) 141 atime = ASN1_TIME_new(); 142 if (atime == NULL) { 143 ASN1error(ERR_R_MALLOC_FAILURE); 144 goto err; 145 } 146 147 free(atime->data); 148 atime->data = time_str; 149 atime->length = UTCTIME_LENGTH; 150 atime->type = V_ASN1_UTCTIME; 151 152 return (atime); 153 154 err: 155 free(time_str); 156 157 return (NULL); 158 } 159 160 ASN1_TIME * 161 tm_to_rfc5280_time(struct tm *tm, ASN1_TIME *atime) 162 { 163 int year; 164 165 year = tm->tm_year + 1900; 166 if (year < 1950 || year > 9999) { 167 ASN1error(ASN1_R_ILLEGAL_TIME_VALUE); 168 return (NULL); 169 } 170 171 if (year < 2050) 172 return (tm_to_utctime(tm, atime)); 173 174 return (tm_to_gentime(tm, atime)); 175 } 176 177 178 static int 179 cbs_get_two_digit_value(CBS *cbs, int *out) 180 { 181 uint8_t first_digit, second_digit; 182 183 if (!CBS_get_u8(cbs, &first_digit)) 184 return 0; 185 if (!isdigit(first_digit)) 186 return 0; 187 if (!CBS_get_u8(cbs, &second_digit)) 188 return 0; 189 if (!isdigit(second_digit)) 190 return 0; 191 192 *out = (first_digit - '0') * 10 + (second_digit - '0'); 193 194 return 1; 195 } 196 197 static int 198 is_valid_day(int year, int month, int day) 199 { 200 if (day < 1) 201 return 0; 202 switch (month) { 203 case 1: 204 case 3: 205 case 5: 206 case 7: 207 case 8: 208 case 10: 209 case 12: 210 return day <= 31; 211 case 4: 212 case 6: 213 case 9: 214 case 11: 215 return day <= 30; 216 case 2: 217 if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) 218 return day <= 29; 219 else 220 return day <= 28; 221 default: 222 return 0; 223 } 224 } 225 226 /* 227 * asn1_time_parse_cbs returns one if |cbs| is a valid DER-encoded, ASN.1 Time 228 * body within the limitations imposed by RFC 5280, or zero otherwise. The time 229 * is expected to parse as a Generalized Time if is_gentime is true, and as a 230 * UTC Time otherwise. If |out_tm| is non-NULL, |*out_tm| will be zeroed, and 231 * then set to the corresponding time in UTC. This function does not compute 232 * |out_tm->tm_wday| or |out_tm->tm_yday|. |cbs| is not consumed. 233 */ 234 int 235 asn1_time_parse_cbs(const CBS *cbs, int is_gentime, struct tm *out_tm) 236 { 237 int year, month, day, hour, min, sec, val; 238 CBS copy; 239 uint8_t tz; 240 241 CBS_dup(cbs, ©); 242 243 if (is_gentime) { 244 if (!cbs_get_two_digit_value(©, &val)) 245 return 0; 246 year = val * 100; 247 if (!cbs_get_two_digit_value(©, &val)) 248 return 0; 249 year += val; 250 } else { 251 year = 1900; 252 if (!cbs_get_two_digit_value(©, &val)) 253 return 0; 254 year += val; 255 if (year < 1950) 256 year += 100; 257 if (year >= 2050) 258 return 0; /* A Generalized time must be used. */ 259 } 260 261 if (!cbs_get_two_digit_value(©, &month)) 262 return 0; 263 if (month < 1 || month > 12) 264 return 0; /* Reject invalid months. */ 265 266 if (!cbs_get_two_digit_value(©, &day)) 267 return 0; 268 if (!is_valid_day(year, month, day)) 269 return 0; /* Reject invalid days. */ 270 271 if (!cbs_get_two_digit_value(©, &hour)) 272 return 0; 273 if (hour > 23) 274 return 0; /* Reject invalid hours. */ 275 276 if (!cbs_get_two_digit_value(©, &min)) 277 return 0; 278 if (min > 59) 279 return 0; /* Reject invalid minutes. */ 280 281 if (!cbs_get_two_digit_value(©, &sec)) 282 return 0; 283 if (sec > 59) 284 return 0; /* Reject invalid seconds. Leap seconds are invalid. */ 285 286 if (!CBS_get_u8(©, &tz)) 287 return 0; 288 if (tz != 'Z') 289 return 0; /* Reject anything but Z on the end. */ 290 291 if (CBS_len(©) != 0) 292 return 0; /* Reject invalid lengths. */ 293 294 if (out_tm != NULL) { 295 memset(out_tm, 0, sizeof(*out_tm)); 296 /* Fill in the tm fields corresponding to what we validated. */ 297 out_tm->tm_year = year - 1900; 298 out_tm->tm_mon = month - 1; 299 out_tm->tm_mday = day; 300 out_tm->tm_hour = hour; 301 out_tm->tm_min = min; 302 out_tm->tm_sec = sec; 303 } 304 305 return 1; 306 } 307 308 /* 309 * Parse an RFC 5280 format ASN.1 time string. 310 * 311 * mode must be: 312 * 0 if we expect to parse a time as specified in RFC 5280 for an X509 object. 313 * V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time. 314 * V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time. 315 * 316 * Returns: 317 * -1 if the string was invalid. 318 * V_ASN1_UTCTIME if the string validated as a UTC time string. 319 * V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string. 320 * 321 * Fills in *tm with the corresponding time if tm is non NULL. 322 */ 323 int 324 ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) 325 { 326 struct tm tml, *tmp = tm ? tm : &tml; 327 int type = 0; 328 CBS cbs; 329 330 if (bytes == NULL) 331 return (-1); 332 333 CBS_init(&cbs, bytes, len); 334 335 if (CBS_len(&cbs) == UTCTIME_LENGTH) 336 type = V_ASN1_UTCTIME; 337 if (CBS_len(&cbs) == GENTIME_LENGTH) 338 type = V_ASN1_GENERALIZEDTIME; 339 if (asn1_time_parse_cbs(&cbs, type == V_ASN1_GENERALIZEDTIME, tmp)) { 340 if (mode != 0 && mode != type) 341 return -1; 342 return type; 343 } 344 345 return -1; 346 } 347 348 /* 349 * ASN1_TIME generic functions. 350 */ 351 352 static int 353 ASN1_TIME_set_string_internal(ASN1_TIME *s, const char *str, int mode) 354 { 355 int type; 356 char *tmp; 357 358 if ((type = ASN1_time_parse(str, strlen(str), NULL, mode)) == -1) 359 return (0); 360 if (mode != 0 && mode != type) 361 return (0); 362 363 if (s == NULL) 364 return (1); 365 366 if ((tmp = strdup(str)) == NULL) 367 return (0); 368 free(s->data); 369 s->data = tmp; 370 s->length = strlen(tmp); 371 s->type = type; 372 373 return (1); 374 } 375 376 static ASN1_TIME * 377 ASN1_TIME_adj_internal(ASN1_TIME *s, time_t t, int offset_day, long offset_sec, 378 int mode) 379 { 380 struct tm tm; 381 382 if (gmtime_r(&t, &tm) == NULL) 383 return (NULL); 384 385 if (offset_day != 0 || offset_sec != 0) { 386 if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec)) 387 return (NULL); 388 } 389 390 switch (mode) { 391 case V_ASN1_UTCTIME: 392 return (tm_to_utctime(&tm, s)); 393 case V_ASN1_GENERALIZEDTIME: 394 return (tm_to_gentime(&tm, s)); 395 case RFC5280: 396 return (tm_to_rfc5280_time(&tm, s)); 397 default: 398 return (NULL); 399 } 400 } 401 402 ASN1_TIME * 403 ASN1_TIME_set(ASN1_TIME *s, time_t t) 404 { 405 return (ASN1_TIME_adj(s, t, 0, 0)); 406 } 407 408 ASN1_TIME * 409 ASN1_TIME_set_tm(ASN1_TIME *s, struct tm *tm) 410 { 411 time_t t; 412 413 if ((t = timegm(tm)) == -1) 414 return NULL; 415 return (ASN1_TIME_adj(s, t, 0, 0)); 416 } 417 418 ASN1_TIME * 419 ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec) 420 { 421 return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, RFC5280)); 422 } 423 424 int 425 ASN1_TIME_check(const ASN1_TIME *t) 426 { 427 if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) 428 return (0); 429 return (t->type == ASN1_time_parse(t->data, t->length, NULL, t->type)); 430 } 431 432 ASN1_GENERALIZEDTIME * 433 ASN1_TIME_to_generalizedtime(const ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) 434 { 435 ASN1_GENERALIZEDTIME *agt = NULL; 436 struct tm tm; 437 438 if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) 439 return (NULL); 440 441 if (t->type != ASN1_time_parse(t->data, t->length, &tm, t->type)) 442 return (NULL); 443 444 if (out != NULL) 445 agt = *out; 446 if ((agt = tm_to_gentime(&tm, agt)) == NULL) 447 return (NULL); 448 if (out != NULL) 449 *out = agt; 450 451 return (agt); 452 } 453 454 int 455 ASN1_TIME_set_string(ASN1_TIME *s, const char *str) 456 { 457 return (ASN1_TIME_set_string_internal(s, str, 0)); 458 } 459 460 static int 461 ASN1_TIME_cmp_time_t_internal(const ASN1_TIME *s, time_t t2, int mode) 462 { 463 struct tm tm1, tm2; 464 465 /* 466 * This function has never handled failure conditions properly 467 * The OpenSSL version used to simply follow NULL pointers on failure. 468 * BoringSSL and OpenSSL now make it return -2 on failure. 469 * 470 * The danger is that users of this function will not differentiate the 471 * -2 failure case from s < t2. Callers must be careful. Sadly this is 472 * one of those pervasive things from OpenSSL we must continue with. 473 */ 474 475 if (ASN1_time_parse(s->data, s->length, &tm1, mode) == -1) 476 return -2; 477 478 if (gmtime_r(&t2, &tm2) == NULL) 479 return -2; 480 481 return ASN1_time_tm_cmp(&tm1, &tm2); 482 } 483 484 int 485 ASN1_TIME_compare(const ASN1_TIME *t1, const ASN1_TIME *t2) 486 { 487 struct tm tm1, tm2; 488 489 if (t1->type != V_ASN1_UTCTIME && t1->type != V_ASN1_GENERALIZEDTIME) 490 return -2; 491 492 if (t2->type != V_ASN1_UTCTIME && t2->type != V_ASN1_GENERALIZEDTIME) 493 return -2; 494 495 if (ASN1_time_parse(t1->data, t1->length, &tm1, t1->type) == -1) 496 return -2; 497 498 if (ASN1_time_parse(t1->data, t2->length, &tm2, t2->type) == -1) 499 return -2; 500 501 return ASN1_time_tm_cmp(&tm1, &tm2); 502 } 503 504 int 505 ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t) 506 { 507 if (s->type == V_ASN1_UTCTIME) 508 return ASN1_TIME_cmp_time_t_internal(s, t, V_ASN1_UTCTIME); 509 if (s->type == V_ASN1_GENERALIZEDTIME) 510 return ASN1_TIME_cmp_time_t_internal(s, t, 511 V_ASN1_GENERALIZEDTIME); 512 return -2; 513 } 514 515 /* 516 * ASN1_UTCTIME wrappers 517 */ 518 519 int 520 ASN1_UTCTIME_check(const ASN1_UTCTIME *d) 521 { 522 if (d->type != V_ASN1_UTCTIME) 523 return (0); 524 return (d->type == ASN1_time_parse(d->data, d->length, NULL, d->type)); 525 } 526 527 int 528 ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) 529 { 530 if (s != NULL && s->type != V_ASN1_UTCTIME) 531 return (0); 532 return (ASN1_TIME_set_string_internal(s, str, V_ASN1_UTCTIME)); 533 } 534 535 ASN1_UTCTIME * 536 ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) 537 { 538 return (ASN1_UTCTIME_adj(s, t, 0, 0)); 539 } 540 541 ASN1_UTCTIME * 542 ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec) 543 { 544 return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, 545 V_ASN1_UTCTIME)); 546 } 547 548 int 549 ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t) 550 { 551 if (s->type == V_ASN1_UTCTIME) 552 return ASN1_TIME_cmp_time_t_internal(s, t, V_ASN1_UTCTIME); 553 return -2; 554 } 555 556 /* 557 * ASN1_GENERALIZEDTIME wrappers 558 */ 559 560 int 561 ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d) 562 { 563 if (d->type != V_ASN1_GENERALIZEDTIME) 564 return (0); 565 return (d->type == ASN1_time_parse(d->data, d->length, NULL, d->type)); 566 } 567 568 int 569 ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) 570 { 571 if (s != NULL && s->type != V_ASN1_GENERALIZEDTIME) 572 return (0); 573 return (ASN1_TIME_set_string_internal(s, str, V_ASN1_GENERALIZEDTIME)); 574 } 575 576 ASN1_GENERALIZEDTIME * 577 ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t) 578 { 579 return (ASN1_GENERALIZEDTIME_adj(s, t, 0, 0)); 580 } 581 582 ASN1_GENERALIZEDTIME * 583 ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, 584 long offset_sec) 585 { 586 return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, 587 V_ASN1_GENERALIZEDTIME)); 588 } 589 590 int 591 ASN1_TIME_normalize(ASN1_TIME *t) 592 { 593 struct tm tm; 594 595 if (!ASN1_TIME_to_tm(t, &tm)) 596 return 0; 597 return tm_to_rfc5280_time(&tm, t) != NULL; 598 } 599 600 int 601 ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str) 602 { 603 return ASN1_TIME_set_string_internal(s, str, RFC5280); 604 } 605