1 /* 2 * Copyright 1999-2021 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 /*- 11 * This is an implementation of the ASN1 Time structure which is: 12 * Time ::= CHOICE { 13 * utcTime UTCTime, 14 * generalTime GeneralizedTime } 15 */ 16 17 #include <stdio.h> 18 #include <time.h> 19 #include "crypto/asn1.h" 20 #include "crypto/ctype.h" 21 #include "internal/cryptlib.h" 22 #include <openssl/asn1t.h> 23 #include "asn1_local.h" 24 25 IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME) 26 27 IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME) 28 IMPLEMENT_ASN1_DUP_FUNCTION(ASN1_TIME) 29 30 static int is_utc(const int year) 31 { 32 if (50 <= year && year <= 149) 33 return 1; 34 return 0; 35 } 36 37 static int leap_year(const int year) 38 { 39 if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) 40 return 1; 41 return 0; 42 } 43 44 /* 45 * Compute the day of the week and the day of the year from the year, month 46 * and day. The day of the year is straightforward, the day of the week uses 47 * a form of Zeller's congruence. For this months start with March and are 48 * numbered 4 through 15. 49 */ 50 static void determine_days(struct tm *tm) 51 { 52 static const int ydays[12] = { 53 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 54 }; 55 int y = tm->tm_year + 1900; 56 int m = tm->tm_mon; 57 int d = tm->tm_mday; 58 int c; 59 60 tm->tm_yday = ydays[m] + d - 1; 61 if (m >= 2) { 62 /* March and onwards can be one day further into the year */ 63 tm->tm_yday += leap_year(y); 64 m += 2; 65 } else { 66 /* Treat January and February as part of the previous year */ 67 m += 14; 68 y--; 69 } 70 c = y / 100; 71 y %= 100; 72 /* Zeller's congruence */ 73 tm->tm_wday = (d + (13 * m) / 5 + y + y / 4 + c / 4 + 5 * c + 6) % 7; 74 } 75 76 int ossl_asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d) 77 { 78 static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 }; 79 static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 }; 80 static const int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 81 char *a; 82 int n, i, i2, l, o, min_l = 11, strict = 0, end = 6, btz = 5, md; 83 struct tm tmp; 84 #if defined(CHARSET_EBCDIC) 85 const char upper_z = 0x5A, num_zero = 0x30, period = 0x2E, minus = 0x2D, plus = 0x2B; 86 #else 87 const char upper_z = 'Z', num_zero = '0', period = '.', minus = '-', plus = '+'; 88 #endif 89 /* 90 * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280 91 * time string format, in which: 92 * 93 * 1. "seconds" is a 'MUST' 94 * 2. "Zulu" timezone is a 'MUST' 95 * 3. "+|-" is not allowed to indicate a time zone 96 */ 97 if (d->type == V_ASN1_UTCTIME) { 98 if (d->flags & ASN1_STRING_FLAG_X509_TIME) { 99 min_l = 13; 100 strict = 1; 101 } 102 } else if (d->type == V_ASN1_GENERALIZEDTIME) { 103 end = 7; 104 btz = 6; 105 if (d->flags & ASN1_STRING_FLAG_X509_TIME) { 106 min_l = 15; 107 strict = 1; 108 } else { 109 min_l = 13; 110 } 111 } else { 112 return 0; 113 } 114 115 l = d->length; 116 a = (char *)d->data; 117 o = 0; 118 memset(&tmp, 0, sizeof(tmp)); 119 120 /* 121 * GENERALIZEDTIME is similar to UTCTIME except the year is represented 122 * as YYYY. This stuff treats everything as a two digit field so make 123 * first two fields 00 to 99 124 */ 125 126 if (l < min_l) 127 goto err; 128 for (i = 0; i < end; i++) { 129 if (!strict && (i == btz) && ((a[o] == upper_z) || (a[o] == plus) || (a[o] == minus))) { 130 i++; 131 break; 132 } 133 if (!ossl_ascii_isdigit(a[o])) 134 goto err; 135 n = a[o] - num_zero; 136 /* incomplete 2-digital number */ 137 if (++o == l) 138 goto err; 139 140 if (!ossl_ascii_isdigit(a[o])) 141 goto err; 142 n = (n * 10) + a[o] - num_zero; 143 /* no more bytes to read, but we haven't seen time-zone yet */ 144 if (++o == l) 145 goto err; 146 147 i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i; 148 149 if ((n < min[i2]) || (n > max[i2])) 150 goto err; 151 switch (i2) { 152 case 0: 153 /* UTC will never be here */ 154 tmp.tm_year = n * 100 - 1900; 155 break; 156 case 1: 157 if (d->type == V_ASN1_UTCTIME) 158 tmp.tm_year = n < 50 ? n + 100 : n; 159 else 160 tmp.tm_year += n; 161 break; 162 case 2: 163 tmp.tm_mon = n - 1; 164 break; 165 case 3: 166 /* check if tm_mday is valid in tm_mon */ 167 if (tmp.tm_mon == 1) { 168 /* it's February */ 169 md = mdays[1] + leap_year(tmp.tm_year + 1900); 170 } else { 171 md = mdays[tmp.tm_mon]; 172 } 173 if (n > md) 174 goto err; 175 tmp.tm_mday = n; 176 determine_days(&tmp); 177 break; 178 case 4: 179 tmp.tm_hour = n; 180 break; 181 case 5: 182 tmp.tm_min = n; 183 break; 184 case 6: 185 tmp.tm_sec = n; 186 break; 187 } 188 } 189 190 /* 191 * Optional fractional seconds: decimal point followed by one or more 192 * digits. 193 */ 194 if (d->type == V_ASN1_GENERALIZEDTIME && a[o] == period) { 195 if (strict) 196 /* RFC 5280 forbids fractional seconds */ 197 goto err; 198 if (++o == l) 199 goto err; 200 i = o; 201 while ((o < l) && ossl_ascii_isdigit(a[o])) 202 o++; 203 /* Must have at least one digit after decimal point */ 204 if (i == o) 205 goto err; 206 /* no more bytes to read, but we haven't seen time-zone yet */ 207 if (o == l) 208 goto err; 209 } 210 211 /* 212 * 'o' will never point to '\0' at this point, the only chance 213 * 'o' can point to '\0' is either the subsequent if or the first 214 * else if is true. 215 */ 216 if (a[o] == upper_z) { 217 o++; 218 } else if (!strict && ((a[o] == plus) || (a[o] == minus))) { 219 int offsign = a[o] == minus ? 1 : -1; 220 int offset = 0; 221 222 o++; 223 /* 224 * if not equal, no need to do subsequent checks 225 * since the following for-loop will add 'o' by 4 226 * and the final return statement will check if 'l' 227 * and 'o' are equal. 228 */ 229 if (o + 4 != l) 230 goto err; 231 for (i = end; i < end + 2; i++) { 232 if (!ossl_ascii_isdigit(a[o])) 233 goto err; 234 n = a[o] - num_zero; 235 o++; 236 if (!ossl_ascii_isdigit(a[o])) 237 goto err; 238 n = (n * 10) + a[o] - num_zero; 239 i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i; 240 if ((n < min[i2]) || (n > max[i2])) 241 goto err; 242 /* if tm is NULL, no need to adjust */ 243 if (tm != NULL) { 244 if (i == end) 245 offset = n * 3600; 246 else if (i == end + 1) 247 offset += n * 60; 248 } 249 o++; 250 } 251 if (offset && !OPENSSL_gmtime_adj(&tmp, 0, offset * offsign)) 252 goto err; 253 } else { 254 /* not Z, or not +/- in non-strict mode */ 255 goto err; 256 } 257 if (o == l) { 258 /* success, check if tm should be filled */ 259 if (tm != NULL) 260 *tm = tmp; 261 return 1; 262 } 263 err: 264 return 0; 265 } 266 267 ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type) 268 { 269 char* p; 270 ASN1_TIME *tmps = NULL; 271 const size_t len = 20; 272 273 if (type == V_ASN1_UNDEF) { 274 if (is_utc(ts->tm_year)) 275 type = V_ASN1_UTCTIME; 276 else 277 type = V_ASN1_GENERALIZEDTIME; 278 } else if (type == V_ASN1_UTCTIME) { 279 if (!is_utc(ts->tm_year)) 280 goto err; 281 } else if (type != V_ASN1_GENERALIZEDTIME) { 282 goto err; 283 } 284 285 if (s == NULL) 286 tmps = ASN1_STRING_new(); 287 else 288 tmps = s; 289 if (tmps == NULL) 290 return NULL; 291 292 if (!ASN1_STRING_set(tmps, NULL, len)) 293 goto err; 294 295 tmps->type = type; 296 p = (char*)tmps->data; 297 298 if (type == V_ASN1_GENERALIZEDTIME) 299 tmps->length = BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", 300 ts->tm_year + 1900, ts->tm_mon + 1, 301 ts->tm_mday, ts->tm_hour, ts->tm_min, 302 ts->tm_sec); 303 else 304 tmps->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ", 305 ts->tm_year % 100, ts->tm_mon + 1, 306 ts->tm_mday, ts->tm_hour, ts->tm_min, 307 ts->tm_sec); 308 309 #ifdef CHARSET_EBCDIC 310 ebcdic2ascii(tmps->data, tmps->data, tmps->length); 311 #endif 312 return tmps; 313 err: 314 if (tmps != s) 315 ASN1_STRING_free(tmps); 316 return NULL; 317 } 318 319 ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t) 320 { 321 return ASN1_TIME_adj(s, t, 0, 0); 322 } 323 324 ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, 325 int offset_day, long offset_sec) 326 { 327 struct tm *ts; 328 struct tm data; 329 330 ts = OPENSSL_gmtime(&t, &data); 331 if (ts == NULL) { 332 ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME); 333 return NULL; 334 } 335 if (offset_day || offset_sec) { 336 if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) 337 return NULL; 338 } 339 return ossl_asn1_time_from_tm(s, ts, V_ASN1_UNDEF); 340 } 341 342 int ASN1_TIME_check(const ASN1_TIME *t) 343 { 344 if (t->type == V_ASN1_GENERALIZEDTIME) 345 return ASN1_GENERALIZEDTIME_check(t); 346 else if (t->type == V_ASN1_UTCTIME) 347 return ASN1_UTCTIME_check(t); 348 return 0; 349 } 350 351 /* Convert an ASN1_TIME structure to GeneralizedTime */ 352 ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t, 353 ASN1_GENERALIZEDTIME **out) 354 { 355 ASN1_GENERALIZEDTIME *ret = NULL; 356 struct tm tm; 357 358 if (!ASN1_TIME_to_tm(t, &tm)) 359 return NULL; 360 361 if (out != NULL) 362 ret = *out; 363 364 ret = ossl_asn1_time_from_tm(ret, &tm, V_ASN1_GENERALIZEDTIME); 365 366 if (out != NULL && ret != NULL) 367 *out = ret; 368 369 return ret; 370 } 371 372 int ASN1_TIME_set_string(ASN1_TIME *s, const char *str) 373 { 374 /* Try UTC, if that fails, try GENERALIZED */ 375 if (ASN1_UTCTIME_set_string(s, str)) 376 return 1; 377 return ASN1_GENERALIZEDTIME_set_string(s, str); 378 } 379 380 int ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str) 381 { 382 ASN1_TIME t; 383 struct tm tm; 384 int rv = 0; 385 386 t.length = strlen(str); 387 t.data = (unsigned char *)str; 388 t.flags = ASN1_STRING_FLAG_X509_TIME; 389 390 t.type = V_ASN1_UTCTIME; 391 392 if (!ASN1_TIME_check(&t)) { 393 t.type = V_ASN1_GENERALIZEDTIME; 394 if (!ASN1_TIME_check(&t)) 395 goto out; 396 } 397 398 /* 399 * Per RFC 5280 (section 4.1.2.5.), the valid input time 400 * strings should be encoded with the following rules: 401 * 402 * 1. UTC: YYMMDDHHMMSSZ, if YY < 50 (20YY) --> UTC: YYMMDDHHMMSSZ 403 * 2. UTC: YYMMDDHHMMSSZ, if YY >= 50 (19YY) --> UTC: YYMMDDHHMMSSZ 404 * 3. G'd: YYYYMMDDHHMMSSZ, if YYYY >= 2050 --> G'd: YYYYMMDDHHMMSSZ 405 * 4. G'd: YYYYMMDDHHMMSSZ, if YYYY < 2050 --> UTC: YYMMDDHHMMSSZ 406 * 407 * Only strings of the 4th rule should be reformatted, but since a 408 * UTC can only present [1950, 2050), so if the given time string 409 * is less than 1950 (e.g. 19230419000000Z), we do nothing... 410 */ 411 412 if (s != NULL && t.type == V_ASN1_GENERALIZEDTIME) { 413 if (!ossl_asn1_time_to_tm(&tm, &t)) 414 goto out; 415 if (is_utc(tm.tm_year)) { 416 t.length -= 2; 417 /* 418 * it's OK to let original t.data go since that's assigned 419 * to a piece of memory allocated outside of this function. 420 * new t.data would be freed after ASN1_STRING_copy is done. 421 */ 422 t.data = OPENSSL_zalloc(t.length + 1); 423 if (t.data == NULL) { 424 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 425 goto out; 426 } 427 memcpy(t.data, str + 2, t.length); 428 t.type = V_ASN1_UTCTIME; 429 } 430 } 431 432 if (s == NULL || ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t)) 433 rv = 1; 434 435 if (t.data != (unsigned char *)str) 436 OPENSSL_free(t.data); 437 out: 438 return rv; 439 } 440 441 int ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm) 442 { 443 if (s == NULL) { 444 time_t now_t; 445 446 time(&now_t); 447 memset(tm, 0, sizeof(*tm)); 448 if (OPENSSL_gmtime(&now_t, tm) != NULL) 449 return 1; 450 return 0; 451 } 452 453 return ossl_asn1_time_to_tm(tm, s); 454 } 455 456 int ASN1_TIME_diff(int *pday, int *psec, 457 const ASN1_TIME *from, const ASN1_TIME *to) 458 { 459 struct tm tm_from, tm_to; 460 461 if (!ASN1_TIME_to_tm(from, &tm_from)) 462 return 0; 463 if (!ASN1_TIME_to_tm(to, &tm_to)) 464 return 0; 465 return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to); 466 } 467 468 static const char _asn1_mon[12][4] = { 469 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 470 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 471 }; 472 473 /* prints the time with the default date format (RFC 822) */ 474 int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) 475 { 476 return ASN1_TIME_print_ex(bp, tm, ASN1_DTFLGS_RFC822); 477 } 478 479 /* returns 1 on success, 0 on BIO write error or parse failure */ 480 int ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags) 481 { 482 return ossl_asn1_time_print_ex(bp, tm, flags) > 0; 483 } 484 485 486 /* prints the time with the date format of ISO 8601 */ 487 /* returns 0 on BIO write error, else -1 in case of parse failure, else 1 */ 488 int ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags) 489 { 490 char *v; 491 int gmt = 0, l; 492 struct tm stm; 493 const char upper_z = 0x5A, period = 0x2E; 494 495 /* ossl_asn1_time_to_tm will check the time type */ 496 if (!ossl_asn1_time_to_tm(&stm, tm)) 497 return BIO_write(bp, "Bad time value", 14) ? -1 : 0; 498 499 l = tm->length; 500 v = (char *)tm->data; 501 if (v[l - 1] == upper_z) 502 gmt = 1; 503 504 if (tm->type == V_ASN1_GENERALIZEDTIME) { 505 char *f = NULL; 506 int f_len = 0; 507 508 /* 509 * Try to parse fractional seconds. '14' is the place of 510 * 'fraction point' in a GeneralizedTime string. 511 */ 512 if (tm->length > 15 && v[14] == period) { 513 f = &v[14]; 514 f_len = 1; 515 while (14 + f_len < l && ossl_ascii_isdigit(f[f_len])) 516 ++f_len; 517 } 518 519 if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) { 520 return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d%.*s%s", 521 stm.tm_year + 1900, stm.tm_mon + 1, 522 stm.tm_mday, stm.tm_hour, 523 stm.tm_min, stm.tm_sec, f_len, f, 524 (gmt ? "Z" : "")) > 0; 525 } 526 else { 527 return BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s", 528 _asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour, 529 stm.tm_min, stm.tm_sec, f_len, f, stm.tm_year + 1900, 530 (gmt ? " GMT" : "")) > 0; 531 } 532 } else { 533 if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) { 534 return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d%s", 535 stm.tm_year + 1900, stm.tm_mon + 1, 536 stm.tm_mday, stm.tm_hour, 537 stm.tm_min, stm.tm_sec, 538 (gmt ? "Z" : "")) > 0; 539 } 540 else { 541 return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", 542 _asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour, 543 stm.tm_min, stm.tm_sec, stm.tm_year + 1900, 544 (gmt ? " GMT" : "")) > 0; 545 } 546 } 547 } 548 549 int ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t) 550 { 551 struct tm stm, ttm; 552 int day, sec; 553 554 if (!ASN1_TIME_to_tm(s, &stm)) 555 return -2; 556 557 if (!OPENSSL_gmtime(&t, &ttm)) 558 return -2; 559 560 if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm)) 561 return -2; 562 563 if (day > 0 || sec > 0) 564 return 1; 565 if (day < 0 || sec < 0) 566 return -1; 567 return 0; 568 } 569 570 int ASN1_TIME_normalize(ASN1_TIME *t) 571 { 572 struct tm tm; 573 574 if (!ASN1_TIME_to_tm(t, &tm)) 575 return 0; 576 577 return ossl_asn1_time_from_tm(t, &tm, V_ASN1_UNDEF) != NULL; 578 } 579 580 int ASN1_TIME_compare(const ASN1_TIME *a, const ASN1_TIME *b) 581 { 582 int day, sec; 583 584 if (!ASN1_TIME_diff(&day, &sec, b, a)) 585 return -2; 586 if (day > 0 || sec > 0) 587 return 1; 588 if (day < 0 || sec < 0) 589 return -1; 590 return 0; 591 } 592