1 /* $OpenBSD: a_time_tm.c,v 1.15 2018/04/25 11:48:21 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 #include <ctype.h> 18 #include <limits.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <time.h> 22 23 #include <openssl/asn1t.h> 24 #include <openssl/err.h> 25 26 #include "o_time.h" 27 28 #define RFC5280 0 29 #define GENTIME_LENGTH 15 30 #define UTCTIME_LENGTH 13 31 32 int 33 ASN1_time_tm_cmp(struct tm *tm1, struct tm *tm2) 34 { 35 if (tm1->tm_year < tm2->tm_year) 36 return (-1); 37 if (tm1->tm_year > tm2->tm_year) 38 return (1); 39 if (tm1->tm_mon < tm2->tm_mon) 40 return (-1); 41 if (tm1->tm_mon > tm2->tm_mon) 42 return (1); 43 if (tm1->tm_mday < tm2->tm_mday) 44 return (-1); 45 if (tm1->tm_mday > tm2->tm_mday) 46 return (1); 47 if (tm1->tm_hour < tm2->tm_hour) 48 return (-1); 49 if (tm1->tm_hour > tm2->tm_hour) 50 return (1); 51 if (tm1->tm_min < tm2->tm_min) 52 return (-1); 53 if (tm1->tm_min > tm2->tm_min) 54 return (1); 55 if (tm1->tm_sec < tm2->tm_sec) 56 return (-1); 57 if (tm1->tm_sec > tm2->tm_sec) 58 return (1); 59 return 0; 60 } 61 62 int 63 ASN1_time_tm_clamp_notafter(struct tm *tm) 64 { 65 #ifdef SMALL_TIME_T 66 struct tm broken_os_epoch_tm; 67 time_t broken_os_epoch_time = INT_MAX; 68 69 if (gmtime_r(&broken_os_epoch_time, &broken_os_epoch_tm) == NULL) 70 return 0; 71 72 if (ASN1_time_tm_cmp(tm, &broken_os_epoch_tm) == 1) 73 memcpy(tm, &broken_os_epoch_tm, sizeof(*tm)); 74 #endif 75 return 1; 76 } 77 78 /* Format a time as an RFC 5280 format Generalized time */ 79 char * 80 gentime_string_from_tm(struct tm *tm) 81 { 82 char *ret = NULL; 83 int year; 84 85 year = tm->tm_year + 1900; 86 if (year < 0 || year > 9999) 87 return (NULL); 88 89 if (asprintf(&ret, "%04u%02u%02u%02u%02u%02uZ", year, 90 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, 91 tm->tm_sec) == -1) 92 ret = NULL; 93 94 return (ret); 95 } 96 97 /* Format a time as an RFC 5280 format UTC time */ 98 char * 99 utctime_string_from_tm(struct tm *tm) 100 { 101 char *ret = NULL; 102 103 if (tm->tm_year >= 150 || tm->tm_year < 50) 104 return (NULL); 105 106 if (asprintf(&ret, "%02u%02u%02u%02u%02u%02uZ", 107 tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, 108 tm->tm_hour, tm->tm_min, tm->tm_sec) == -1) 109 ret = NULL; 110 111 return (ret); 112 } 113 114 /* Format a time correctly for an X509 object as per RFC 5280 */ 115 char * 116 rfc5280_string_from_tm(struct tm *tm) 117 { 118 char *ret = NULL; 119 int year; 120 121 year = tm->tm_year + 1900; 122 if (year < 1950 || year > 9999) 123 return (NULL); 124 125 if (year < 2050) 126 ret = utctime_string_from_tm(tm); 127 else 128 ret = gentime_string_from_tm(tm); 129 130 return (ret); 131 } 132 133 /* 134 * Parse an RFC 5280 format ASN.1 time string. 135 * 136 * mode must be: 137 * 0 if we expect to parse a time as specified in RFC 5280 for an X509 object. 138 * V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time. 139 * V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time. 140 * 141 * Returns: 142 * -1 if the string was invalid. 143 * V_ASN1_UTCTIME if the string validated as a UTC time string. 144 * V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string. 145 * 146 * Fills in *tm with the corresponding time if tm is non NULL. 147 */ 148 #define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) 149 int 150 ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) 151 { 152 size_t i; 153 int type = 0; 154 struct tm ltm; 155 struct tm *lt; 156 const char *p; 157 158 if (bytes == NULL) 159 return (-1); 160 161 /* Constrain to valid lengths. */ 162 if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH) 163 return (-1); 164 165 lt = tm; 166 if (lt == NULL) { 167 memset(<m, 0, sizeof(ltm)); 168 lt = <m; 169 } 170 171 /* Timezone is required and must be GMT (Zulu). */ 172 if (bytes[len - 1] != 'Z') 173 return (-1); 174 175 /* Make sure everything else is digits. */ 176 for (i = 0; i < len - 1; i++) { 177 if (isdigit((unsigned char)bytes[i])) 178 continue; 179 return (-1); 180 } 181 182 /* 183 * Validate and convert the time 184 */ 185 p = bytes; 186 switch (len) { 187 case GENTIME_LENGTH: 188 if (mode == V_ASN1_UTCTIME) 189 return (-1); 190 lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */ 191 type = V_ASN1_GENERALIZEDTIME; 192 /* FALLTHROUGH */ 193 case UTCTIME_LENGTH: 194 if (type == 0) { 195 if (mode == V_ASN1_GENERALIZEDTIME) 196 return (-1); 197 type = V_ASN1_UTCTIME; 198 } 199 lt->tm_year += ATOI2(p); /* yy */ 200 if (type == V_ASN1_UTCTIME) { 201 if (lt->tm_year < 50) 202 lt->tm_year += 100; 203 } 204 lt->tm_mon = ATOI2(p) - 1; /* mm */ 205 if (lt->tm_mon < 0 || lt->tm_mon > 11) 206 return (-1); 207 lt->tm_mday = ATOI2(p); /* dd */ 208 if (lt->tm_mday < 1 || lt->tm_mday > 31) 209 return (-1); 210 lt->tm_hour = ATOI2(p); /* HH */ 211 if (lt->tm_hour < 0 || lt->tm_hour > 23) 212 return (-1); 213 lt->tm_min = ATOI2(p); /* MM */ 214 if (lt->tm_min < 0 || lt->tm_min > 59) 215 return (-1); 216 lt->tm_sec = ATOI2(p); /* SS */ 217 /* Leap second 60 is not accepted. Reconsider later? */ 218 if (lt->tm_sec < 0 || lt->tm_sec > 59) 219 return (-1); 220 break; 221 default: 222 return (-1); 223 } 224 225 return (type); 226 } 227 228 /* 229 * ASN1_TIME generic functions. 230 */ 231 232 static int 233 ASN1_TIME_set_string_internal(ASN1_TIME *s, const char *str, int mode) 234 { 235 int type; 236 char *tmp; 237 238 if ((type = ASN1_time_parse(str, strlen(str), NULL, mode)) == -1) 239 return (0); 240 if (mode != 0 && mode != type) 241 return (0); 242 243 if (s == NULL) 244 return (1); 245 246 if ((tmp = strdup(str)) == NULL) 247 return (0); 248 free(s->data); 249 s->data = tmp; 250 s->length = strlen(tmp); 251 s->type = type; 252 253 return (1); 254 } 255 256 static ASN1_TIME * 257 ASN1_TIME_adj_internal(ASN1_TIME *s, time_t t, int offset_day, long offset_sec, 258 int mode) 259 { 260 int allocated = 0; 261 struct tm tm; 262 size_t len; 263 char * p; 264 265 if (gmtime_r(&t, &tm) == NULL) 266 return (NULL); 267 268 if (offset_day || offset_sec) { 269 if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec)) 270 return (NULL); 271 } 272 273 switch (mode) { 274 case V_ASN1_UTCTIME: 275 p = utctime_string_from_tm(&tm); 276 break; 277 case V_ASN1_GENERALIZEDTIME: 278 p = gentime_string_from_tm(&tm); 279 break; 280 case RFC5280: 281 p = rfc5280_string_from_tm(&tm); 282 break; 283 default: 284 return (NULL); 285 } 286 if (p == NULL) { 287 ASN1error(ASN1_R_ILLEGAL_TIME_VALUE); 288 return (NULL); 289 } 290 291 if (s == NULL) { 292 if ((s = ASN1_TIME_new()) == NULL) 293 return (NULL); 294 allocated = 1; 295 } 296 297 len = strlen(p); 298 switch (len) { 299 case GENTIME_LENGTH: 300 s->type = V_ASN1_GENERALIZEDTIME; 301 break; 302 case UTCTIME_LENGTH: 303 s->type = V_ASN1_UTCTIME; 304 break; 305 default: 306 if (allocated) 307 ASN1_TIME_free(s); 308 free(p); 309 return (NULL); 310 } 311 free(s->data); 312 s->data = p; 313 s->length = len; 314 return (s); 315 } 316 317 ASN1_TIME * 318 ASN1_TIME_set(ASN1_TIME *s, time_t t) 319 { 320 return (ASN1_TIME_adj(s, t, 0, 0)); 321 } 322 323 ASN1_TIME * 324 ASN1_TIME_set_tm(ASN1_TIME *s, struct tm *tm) 325 { 326 time_t t; 327 328 if ((t = timegm(tm)) == -1) 329 return NULL; 330 return (ASN1_TIME_adj(s, t, 0, 0)); 331 } 332 333 ASN1_TIME * 334 ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec) 335 { 336 return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, RFC5280)); 337 } 338 339 int 340 ASN1_TIME_check(const ASN1_TIME *t) 341 { 342 if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) 343 return (0); 344 return (t->type == ASN1_time_parse(t->data, t->length, NULL, t->type)); 345 } 346 347 ASN1_GENERALIZEDTIME * 348 ASN1_TIME_to_generalizedtime(const ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) 349 { 350 ASN1_GENERALIZEDTIME *tmp = NULL; 351 struct tm tm; 352 char *str; 353 354 if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) 355 return (NULL); 356 357 memset(&tm, 0, sizeof(tm)); 358 if (t->type != ASN1_time_parse(t->data, t->length, &tm, t->type)) 359 return (NULL); 360 if ((str = gentime_string_from_tm(&tm)) == NULL) 361 return (NULL); 362 363 if (out != NULL) 364 tmp = *out; 365 if (tmp == NULL && (tmp = ASN1_GENERALIZEDTIME_new()) == NULL) { 366 free(str); 367 return (NULL); 368 } 369 if (out != NULL) 370 *out = tmp; 371 372 free(tmp->data); 373 tmp->data = str; 374 tmp->length = strlen(str); 375 return (tmp); 376 } 377 378 int 379 ASN1_TIME_set_string(ASN1_TIME *s, const char *str) 380 { 381 return (ASN1_TIME_set_string_internal(s, str, 0)); 382 } 383 384 /* 385 * ASN1_UTCTIME wrappers 386 */ 387 388 int 389 ASN1_UTCTIME_check(const ASN1_UTCTIME *d) 390 { 391 if (d->type != V_ASN1_UTCTIME) 392 return (0); 393 return (d->type == ASN1_time_parse(d->data, d->length, NULL, d->type)); 394 } 395 396 int 397 ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) 398 { 399 if (s != NULL && s->type != V_ASN1_UTCTIME) 400 return (0); 401 return (ASN1_TIME_set_string_internal(s, str, V_ASN1_UTCTIME)); 402 } 403 404 ASN1_UTCTIME * 405 ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) 406 { 407 return (ASN1_UTCTIME_adj(s, t, 0, 0)); 408 } 409 410 ASN1_UTCTIME * 411 ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec) 412 { 413 return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, 414 V_ASN1_UTCTIME)); 415 } 416 417 int 418 ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t2) 419 { 420 struct tm tm1, tm2; 421 422 /* 423 * This function has never handled failure conditions properly 424 * and should be deprecated. The OpenSSL version used to 425 * simply follow NULL pointers on failure. BoringSSL and 426 * OpenSSL now make it return -2 on failure. 427 * 428 * The danger is that users of this function will not 429 * differentiate the -2 failure case from t1 < t2. 430 */ 431 if (ASN1_time_parse(s->data, s->length, &tm1, V_ASN1_UTCTIME) == -1) 432 return (-2); /* XXX */ 433 434 if (gmtime_r(&t2, &tm2) == NULL) 435 return (-2); /* XXX */ 436 437 return ASN1_time_tm_cmp(&tm1, &tm2); 438 } 439 440 /* 441 * ASN1_GENERALIZEDTIME wrappers 442 */ 443 444 int 445 ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d) 446 { 447 if (d->type != V_ASN1_GENERALIZEDTIME) 448 return (0); 449 return (d->type == ASN1_time_parse(d->data, d->length, NULL, d->type)); 450 } 451 452 int 453 ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) 454 { 455 if (s != NULL && s->type != V_ASN1_GENERALIZEDTIME) 456 return (0); 457 return (ASN1_TIME_set_string_internal(s, str, V_ASN1_GENERALIZEDTIME)); 458 } 459 460 ASN1_GENERALIZEDTIME * 461 ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t) 462 { 463 return (ASN1_GENERALIZEDTIME_adj(s, t, 0, 0)); 464 } 465 466 ASN1_GENERALIZEDTIME * 467 ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, 468 long offset_sec) 469 { 470 return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, 471 V_ASN1_GENERALIZEDTIME)); 472 } 473