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