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