1*c604ab84Stb /* $OpenBSD: a_time_tm.c,v 1.42 2024/05/03 18:33:27 tb Exp $ */
2e385ad8fSbeck /*
3e385ad8fSbeck * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
4e385ad8fSbeck *
5e385ad8fSbeck * Permission to use, copy, modify, and distribute this software for any
6e385ad8fSbeck * purpose with or without fee is hereby granted, provided that the above
7e385ad8fSbeck * copyright notice and this permission notice appear in all copies.
8e385ad8fSbeck *
9e385ad8fSbeck * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10e385ad8fSbeck * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11e385ad8fSbeck * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12e385ad8fSbeck * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13e385ad8fSbeck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14e385ad8fSbeck * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15e385ad8fSbeck * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16e385ad8fSbeck */
175fff88f8Stb
1824ddf590Sbcook #include <ctype.h>
1924ddf590Sbcook #include <limits.h>
20e385ad8fSbeck #include <stdio.h>
21e385ad8fSbeck #include <string.h>
22e385ad8fSbeck #include <time.h>
23e385ad8fSbeck
24e385ad8fSbeck #include <openssl/asn1t.h>
25e385ad8fSbeck #include <openssl/err.h>
26e385ad8fSbeck
2702ba34f9Sbeck #include "bytestring.h"
28c9675a23Stb #include "asn1_local.h"
29e385ad8fSbeck
300b62c50aSbeck #define RFC5280 0
310b62c50aSbeck #define GENTIME_LENGTH 15
320b62c50aSbeck #define UTCTIME_LENGTH 13
330b62c50aSbeck
340b62c50aSbeck int
ASN1_time_tm_cmp(struct tm * tm1,struct tm * tm2)35568923c1Sjsing ASN1_time_tm_cmp(struct tm *tm1, struct tm *tm2)
36568923c1Sjsing {
370b62c50aSbeck if (tm1->tm_year < tm2->tm_year)
38123b2274Stb return -1;
390b62c50aSbeck if (tm1->tm_year > tm2->tm_year)
40123b2274Stb return 1;
410b62c50aSbeck if (tm1->tm_mon < tm2->tm_mon)
42123b2274Stb return -1;
430b62c50aSbeck if (tm1->tm_mon > tm2->tm_mon)
44123b2274Stb return 1;
450b62c50aSbeck if (tm1->tm_mday < tm2->tm_mday)
46123b2274Stb return -1;
470b62c50aSbeck if (tm1->tm_mday > tm2->tm_mday)
48123b2274Stb return 1;
490b62c50aSbeck if (tm1->tm_hour < tm2->tm_hour)
50123b2274Stb return -1;
510b62c50aSbeck if (tm1->tm_hour > tm2->tm_hour)
52123b2274Stb return 1;
530b62c50aSbeck if (tm1->tm_min < tm2->tm_min)
54123b2274Stb return -1;
550b62c50aSbeck if (tm1->tm_min > tm2->tm_min)
56123b2274Stb return 1;
570b62c50aSbeck if (tm1->tm_sec < tm2->tm_sec)
58123b2274Stb return -1;
590b62c50aSbeck if (tm1->tm_sec > tm2->tm_sec)
60123b2274Stb return 1;
610b62c50aSbeck return 0;
620b62c50aSbeck }
630b62c50aSbeck
64b943944fSbeck int
ASN1_time_tm_clamp_notafter(struct tm * tm)65b943944fSbeck ASN1_time_tm_clamp_notafter(struct tm *tm)
66b943944fSbeck {
67b943944fSbeck #ifdef SMALL_TIME_T
68b943944fSbeck struct tm broken_os_epoch_tm;
69b943944fSbeck time_t broken_os_epoch_time = INT_MAX;
70b943944fSbeck
711f3c80ceStb if (!asn1_time_time_t_to_tm(&broken_os_epoch_time, &broken_os_epoch_tm))
72b943944fSbeck return 0;
73b943944fSbeck
74b943944fSbeck if (ASN1_time_tm_cmp(tm, &broken_os_epoch_tm) == 1)
75b943944fSbeck memcpy(tm, &broken_os_epoch_tm, sizeof(*tm));
76b943944fSbeck #endif
77b943944fSbeck return 1;
78b943944fSbeck }
79b943944fSbeck
805fff88f8Stb /* Convert time to GeneralizedTime, X.690, 11.7. */
81f93ff421Stb static int
tm_to_gentime(struct tm * tm,ASN1_TIME * atime)825fff88f8Stb tm_to_gentime(struct tm *tm, ASN1_TIME *atime)
83e385ad8fSbeck {
845fff88f8Stb char *time_str = NULL;
85d69e9be1Sjsing
86f93ff421Stb if (tm->tm_year < -1900 || tm->tm_year > 9999 - 1900) {
875fff88f8Stb ASN1error(ASN1_R_ILLEGAL_TIME_VALUE);
88f93ff421Stb return 0;
89e385ad8fSbeck }
90e385ad8fSbeck
91f93ff421Stb if (asprintf(&time_str, "%04u%02u%02u%02u%02u%02uZ", tm->tm_year + 1900,
92f93ff421Stb tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
93f93ff421Stb tm->tm_sec) == -1) {
945fff88f8Stb ASN1error(ERR_R_MALLOC_FAILURE);
95f93ff421Stb return 0;
965fff88f8Stb }
97d69e9be1Sjsing
985fff88f8Stb free(atime->data);
995fff88f8Stb atime->data = time_str;
1005fff88f8Stb atime->length = GENTIME_LENGTH;
1015fff88f8Stb atime->type = V_ASN1_GENERALIZEDTIME;
1025fff88f8Stb
103f93ff421Stb return 1;
104e385ad8fSbeck }
105e385ad8fSbeck
1065fff88f8Stb /* Convert time to UTCTime, X.690, 11.8. */
107f93ff421Stb static int
tm_to_utctime(struct tm * tm,ASN1_TIME * atime)1085fff88f8Stb tm_to_utctime(struct tm *tm, ASN1_TIME *atime)
1090b62c50aSbeck {
1105fff88f8Stb char *time_str = NULL;
1115fff88f8Stb
1125fff88f8Stb if (tm->tm_year >= 150 || tm->tm_year < 50) {
1135fff88f8Stb ASN1error(ASN1_R_ILLEGAL_TIME_VALUE);
114f93ff421Stb return 0;
1155fff88f8Stb }
1165fff88f8Stb
1175fff88f8Stb if (asprintf(&time_str, "%02u%02u%02u%02u%02u%02uZ",
1185fff88f8Stb tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
1195fff88f8Stb tm->tm_hour, tm->tm_min, tm->tm_sec) == -1) {
1205fff88f8Stb ASN1error(ERR_R_MALLOC_FAILURE);
121f93ff421Stb return 0;
1225fff88f8Stb }
1235fff88f8Stb
1245fff88f8Stb free(atime->data);
1255fff88f8Stb atime->data = time_str;
1265fff88f8Stb atime->length = UTCTIME_LENGTH;
1275fff88f8Stb atime->type = V_ASN1_UTCTIME;
1285fff88f8Stb
129f93ff421Stb return 1;
1305fff88f8Stb }
1315fff88f8Stb
132f93ff421Stb static int
tm_to_rfc5280_time(struct tm * tm,ASN1_TIME * atime)1335fff88f8Stb tm_to_rfc5280_time(struct tm *tm, ASN1_TIME *atime)
1345fff88f8Stb {
13572c7c57aSbeck if (tm->tm_year >= 50 && tm->tm_year < 150)
136123b2274Stb return tm_to_utctime(tm, atime);
1370b62c50aSbeck
138123b2274Stb return tm_to_gentime(tm, atime);
1390b62c50aSbeck }
1400b62c50aSbeck
14102ba34f9Sbeck
14202ba34f9Sbeck static int
cbs_get_two_digit_value(CBS * cbs,int * out)14302ba34f9Sbeck cbs_get_two_digit_value(CBS *cbs, int *out)
14402ba34f9Sbeck {
14502ba34f9Sbeck uint8_t first_digit, second_digit;
14602ba34f9Sbeck
14702ba34f9Sbeck if (!CBS_get_u8(cbs, &first_digit))
14802ba34f9Sbeck return 0;
14902ba34f9Sbeck if (!isdigit(first_digit))
15002ba34f9Sbeck return 0;
15102ba34f9Sbeck if (!CBS_get_u8(cbs, &second_digit))
15202ba34f9Sbeck return 0;
15302ba34f9Sbeck if (!isdigit(second_digit))
15402ba34f9Sbeck return 0;
15502ba34f9Sbeck
15602ba34f9Sbeck *out = (first_digit - '0') * 10 + (second_digit - '0');
15702ba34f9Sbeck
15802ba34f9Sbeck return 1;
15902ba34f9Sbeck }
16002ba34f9Sbeck
16102ba34f9Sbeck static int
is_valid_day(int year,int month,int day)16202ba34f9Sbeck is_valid_day(int year, int month, int day)
16302ba34f9Sbeck {
16402ba34f9Sbeck if (day < 1)
16502ba34f9Sbeck return 0;
16602ba34f9Sbeck switch (month) {
16702ba34f9Sbeck case 1:
16802ba34f9Sbeck case 3:
16902ba34f9Sbeck case 5:
17002ba34f9Sbeck case 7:
17102ba34f9Sbeck case 8:
17202ba34f9Sbeck case 10:
17302ba34f9Sbeck case 12:
17402ba34f9Sbeck return day <= 31;
17502ba34f9Sbeck case 4:
17602ba34f9Sbeck case 6:
17702ba34f9Sbeck case 9:
17802ba34f9Sbeck case 11:
17902ba34f9Sbeck return day <= 30;
18002ba34f9Sbeck case 2:
18102ba34f9Sbeck if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
18202ba34f9Sbeck return day <= 29;
18302ba34f9Sbeck else
18402ba34f9Sbeck return day <= 28;
18502ba34f9Sbeck default:
18602ba34f9Sbeck return 0;
18702ba34f9Sbeck }
18802ba34f9Sbeck }
18902ba34f9Sbeck
19002ba34f9Sbeck /*
19102ba34f9Sbeck * asn1_time_parse_cbs returns one if |cbs| is a valid DER-encoded, ASN.1 Time
19202ba34f9Sbeck * body within the limitations imposed by RFC 5280, or zero otherwise. The time
19302ba34f9Sbeck * is expected to parse as a Generalized Time if is_gentime is true, and as a
19402ba34f9Sbeck * UTC Time otherwise. If |out_tm| is non-NULL, |*out_tm| will be zeroed, and
19502ba34f9Sbeck * then set to the corresponding time in UTC. This function does not compute
19602ba34f9Sbeck * |out_tm->tm_wday| or |out_tm->tm_yday|. |cbs| is not consumed.
19702ba34f9Sbeck */
19802ba34f9Sbeck int
asn1_time_parse_cbs(const CBS * cbs,int is_gentime,struct tm * out_tm)19902ba34f9Sbeck asn1_time_parse_cbs(const CBS *cbs, int is_gentime, struct tm *out_tm)
20002ba34f9Sbeck {
20102ba34f9Sbeck int year, month, day, hour, min, sec, val;
20202ba34f9Sbeck CBS copy;
20302ba34f9Sbeck uint8_t tz;
20402ba34f9Sbeck
20502ba34f9Sbeck CBS_dup(cbs, ©);
20602ba34f9Sbeck
20702ba34f9Sbeck if (is_gentime) {
20802ba34f9Sbeck if (!cbs_get_two_digit_value(©, &val))
20902ba34f9Sbeck return 0;
21002ba34f9Sbeck year = val * 100;
21102ba34f9Sbeck if (!cbs_get_two_digit_value(©, &val))
21202ba34f9Sbeck return 0;
21302ba34f9Sbeck year += val;
21402ba34f9Sbeck } else {
21502ba34f9Sbeck year = 1900;
21602ba34f9Sbeck if (!cbs_get_two_digit_value(©, &val))
21702ba34f9Sbeck return 0;
21802ba34f9Sbeck year += val;
21902ba34f9Sbeck if (year < 1950)
22002ba34f9Sbeck year += 100;
22102ba34f9Sbeck if (year >= 2050)
22202ba34f9Sbeck return 0; /* A Generalized time must be used. */
22302ba34f9Sbeck }
22402ba34f9Sbeck
22502ba34f9Sbeck if (!cbs_get_two_digit_value(©, &month))
22602ba34f9Sbeck return 0;
22702ba34f9Sbeck if (month < 1 || month > 12)
22802ba34f9Sbeck return 0; /* Reject invalid months. */
22902ba34f9Sbeck
23002ba34f9Sbeck if (!cbs_get_two_digit_value(©, &day))
23102ba34f9Sbeck return 0;
23202ba34f9Sbeck if (!is_valid_day(year, month, day))
23302ba34f9Sbeck return 0; /* Reject invalid days. */
23402ba34f9Sbeck
23502ba34f9Sbeck if (!cbs_get_two_digit_value(©, &hour))
23602ba34f9Sbeck return 0;
23702ba34f9Sbeck if (hour > 23)
23802ba34f9Sbeck return 0; /* Reject invalid hours. */
23902ba34f9Sbeck
24002ba34f9Sbeck if (!cbs_get_two_digit_value(©, &min))
24102ba34f9Sbeck return 0;
24202ba34f9Sbeck if (min > 59)
24302ba34f9Sbeck return 0; /* Reject invalid minutes. */
24402ba34f9Sbeck
24502ba34f9Sbeck if (!cbs_get_two_digit_value(©, &sec))
24602ba34f9Sbeck return 0;
24702ba34f9Sbeck if (sec > 59)
24802ba34f9Sbeck return 0; /* Reject invalid seconds. Leap seconds are invalid. */
24902ba34f9Sbeck
25002ba34f9Sbeck if (!CBS_get_u8(©, &tz))
25102ba34f9Sbeck return 0;
25202ba34f9Sbeck if (tz != 'Z')
25302ba34f9Sbeck return 0; /* Reject anything but Z on the end. */
25402ba34f9Sbeck
25502ba34f9Sbeck if (CBS_len(©) != 0)
25602ba34f9Sbeck return 0; /* Reject invalid lengths. */
25702ba34f9Sbeck
25802ba34f9Sbeck if (out_tm != NULL) {
25902ba34f9Sbeck memset(out_tm, 0, sizeof(*out_tm));
26002ba34f9Sbeck /* Fill in the tm fields corresponding to what we validated. */
26102ba34f9Sbeck out_tm->tm_year = year - 1900;
26202ba34f9Sbeck out_tm->tm_mon = month - 1;
26302ba34f9Sbeck out_tm->tm_mday = day;
26402ba34f9Sbeck out_tm->tm_hour = hour;
26502ba34f9Sbeck out_tm->tm_min = min;
26602ba34f9Sbeck out_tm->tm_sec = sec;
26702ba34f9Sbeck }
26802ba34f9Sbeck
26902ba34f9Sbeck return 1;
27002ba34f9Sbeck }
27102ba34f9Sbeck
272e385ad8fSbeck /*
2730b62c50aSbeck * Parse an RFC 5280 format ASN.1 time string.
274e385ad8fSbeck *
275e385ad8fSbeck * mode must be:
276e07eb418Sbeck * 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
277e07eb418Sbeck * V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
2780b62c50aSbeck * V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
279e385ad8fSbeck *
280e385ad8fSbeck * Returns:
281e385ad8fSbeck * -1 if the string was invalid.
282e385ad8fSbeck * V_ASN1_UTCTIME if the string validated as a UTC time string.
283e385ad8fSbeck * V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
284e385ad8fSbeck *
285e385ad8fSbeck * Fills in *tm with the corresponding time if tm is non NULL.
286e385ad8fSbeck */
287d69e9be1Sjsing int
ASN1_time_parse(const char * bytes,size_t len,struct tm * tm,int mode)288e07eb418Sbeck ASN1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode)
289e385ad8fSbeck {
290e9d68136Sbeck int type = 0;
29102ba34f9Sbeck CBS cbs;
292e385ad8fSbeck
293e385ad8fSbeck if (bytes == NULL)
294123b2274Stb return -1;
295e385ad8fSbeck
29602ba34f9Sbeck CBS_init(&cbs, bytes, len);
297d69e9be1Sjsing
29802ba34f9Sbeck if (CBS_len(&cbs) == UTCTIME_LENGTH)
299e385ad8fSbeck type = V_ASN1_UTCTIME;
30002ba34f9Sbeck if (CBS_len(&cbs) == GENTIME_LENGTH)
30102ba34f9Sbeck type = V_ASN1_GENERALIZEDTIME;
3024b23cd33Stb if (asn1_time_parse_cbs(&cbs, type == V_ASN1_GENERALIZEDTIME, tm)) {
30302ba34f9Sbeck if (mode != 0 && mode != type)
30402ba34f9Sbeck return -1;
30502ba34f9Sbeck return type;
306e385ad8fSbeck }
307e385ad8fSbeck
30802ba34f9Sbeck return -1;
309d69e9be1Sjsing }
310e385ad8fSbeck
3110b62c50aSbeck /*
3120b62c50aSbeck * ASN1_TIME generic functions.
3130b62c50aSbeck */
314e385ad8fSbeck
3150b62c50aSbeck static int
ASN1_TIME_set_string_internal(ASN1_TIME * s,const char * str,int mode)3160b62c50aSbeck ASN1_TIME_set_string_internal(ASN1_TIME *s, const char *str, int mode)
3170b62c50aSbeck {
31872c7c57aSbeck struct tm tm;
319d69e9be1Sjsing
32059caaba4Stb if (ASN1_time_parse(str, strlen(str), &tm, mode) == -1)
321123b2274Stb return 0;
32240a2c71eStb
32340a2c71eStb /* Only check str's format, as documented. */
32440a2c71eStb if (s == NULL)
32540a2c71eStb return 1;
32640a2c71eStb
32772c7c57aSbeck switch (mode) {
32872c7c57aSbeck case V_ASN1_UTCTIME:
32959caaba4Stb return tm_to_utctime(&tm, s);
33072c7c57aSbeck case V_ASN1_GENERALIZEDTIME:
33159caaba4Stb return tm_to_gentime(&tm, s);
33272c7c57aSbeck case RFC5280:
333123b2274Stb return tm_to_rfc5280_time(&tm, s);
33472c7c57aSbeck default:
335123b2274Stb return 0;
33672c7c57aSbeck }
337e385ad8fSbeck }
3380b62c50aSbeck
3390b62c50aSbeck static ASN1_TIME *
ASN1_TIME_adj_internal(ASN1_TIME * s,time_t t,int offset_day,long offset_sec,int mode)3400b62c50aSbeck ASN1_TIME_adj_internal(ASN1_TIME *s, time_t t, int offset_day, long offset_sec,
3410b62c50aSbeck int mode)
3420b62c50aSbeck {
343f93ff421Stb ASN1_TIME *atime = s;
3440b62c50aSbeck struct tm tm;
3450b62c50aSbeck
3469b176146Sbeck if (!asn1_time_time_t_to_tm(&t, &tm))
347f93ff421Stb goto err;
3480b62c50aSbeck
3495fff88f8Stb if (offset_day != 0 || offset_sec != 0) {
3500b62c50aSbeck if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec))
351f93ff421Stb goto err;
3520b62c50aSbeck }
3530b62c50aSbeck
354f93ff421Stb if (atime == NULL)
355f93ff421Stb atime = ASN1_TIME_new();
356f93ff421Stb if (atime == NULL)
357f93ff421Stb goto err;
358f93ff421Stb
3590b62c50aSbeck switch (mode) {
3600b62c50aSbeck case V_ASN1_UTCTIME:
361f93ff421Stb if (!tm_to_utctime(&tm, atime))
362f93ff421Stb goto err;
363f93ff421Stb break;
3640b62c50aSbeck case V_ASN1_GENERALIZEDTIME:
365f93ff421Stb if (!tm_to_gentime(&tm, atime))
366f93ff421Stb goto err;
367f93ff421Stb break;
3680b62c50aSbeck case RFC5280:
369f93ff421Stb if (!tm_to_rfc5280_time(&tm, atime))
370f93ff421Stb goto err;
371f93ff421Stb break;
3720b62c50aSbeck default:
373f93ff421Stb goto err;
3740b62c50aSbeck }
375f93ff421Stb
376f93ff421Stb return atime;
377f93ff421Stb
378f93ff421Stb err:
379f93ff421Stb if (atime != s)
380f93ff421Stb ASN1_TIME_free(atime);
381f93ff421Stb
382f93ff421Stb return NULL;
3830b62c50aSbeck }
3840b62c50aSbeck
3850b62c50aSbeck ASN1_TIME *
ASN1_TIME_set(ASN1_TIME * s,time_t t)3860b62c50aSbeck ASN1_TIME_set(ASN1_TIME *s, time_t t)
3870b62c50aSbeck {
388123b2274Stb return ASN1_TIME_adj(s, t, 0, 0);
3890b62c50aSbeck }
390acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_set);
3910b62c50aSbeck
3920b62c50aSbeck ASN1_TIME *
ASN1_TIME_adj(ASN1_TIME * s,time_t t,int offset_day,long offset_sec)3930b62c50aSbeck ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec)
3940b62c50aSbeck {
395123b2274Stb return ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, RFC5280);
3960b62c50aSbeck }
397acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_adj);
3980b62c50aSbeck
3990b62c50aSbeck int
ASN1_TIME_check(const ASN1_TIME * t)4009b3891c7Stb ASN1_TIME_check(const ASN1_TIME *t)
4010b62c50aSbeck {
4020b62c50aSbeck if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME)
403123b2274Stb return 0;
404123b2274Stb return t->type == ASN1_time_parse(t->data, t->length, NULL, t->type);
4050b62c50aSbeck }
406acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_check);
4070b62c50aSbeck
4080b62c50aSbeck ASN1_GENERALIZEDTIME *
ASN1_TIME_to_generalizedtime(const ASN1_TIME * t,ASN1_GENERALIZEDTIME ** out)4099b3891c7Stb ASN1_TIME_to_generalizedtime(const ASN1_TIME *t, ASN1_GENERALIZEDTIME **out)
4100b62c50aSbeck {
4115fff88f8Stb ASN1_GENERALIZEDTIME *agt = NULL;
4120b62c50aSbeck struct tm tm;
4130b62c50aSbeck
4140b62c50aSbeck if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME)
415f93ff421Stb goto err;
4160b62c50aSbeck
417e07eb418Sbeck if (t->type != ASN1_time_parse(t->data, t->length, &tm, t->type))
418f93ff421Stb goto err;
4190b62c50aSbeck
420f93ff421Stb if (out == NULL || (agt = *out) == NULL)
421f93ff421Stb agt = ASN1_TIME_new();
422f93ff421Stb if (agt == NULL)
423f93ff421Stb goto err;
424f93ff421Stb
425f93ff421Stb if (!tm_to_gentime(&tm, agt))
426f93ff421Stb goto err;
427f93ff421Stb
4280b62c50aSbeck if (out != NULL)
4295fff88f8Stb *out = agt;
4300b62c50aSbeck
431f93ff421Stb return agt;
432f93ff421Stb
433f93ff421Stb err:
434f93ff421Stb if (out == NULL || *out != agt)
435f93ff421Stb ASN1_TIME_free(agt);
436f93ff421Stb
437f93ff421Stb return NULL;
4380b62c50aSbeck }
439acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_to_generalizedtime);
4400b62c50aSbeck
4410b62c50aSbeck int
ASN1_TIME_set_string(ASN1_TIME * s,const char * str)4420b62c50aSbeck ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
4430b62c50aSbeck {
444123b2274Stb return ASN1_TIME_set_string_internal(s, str, RFC5280);
4450b62c50aSbeck }
446acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_set_string);
4470b62c50aSbeck
448b680683fSbeck static int
ASN1_TIME_cmp_time_t_internal(const ASN1_TIME * s,time_t t2,int mode)449b680683fSbeck ASN1_TIME_cmp_time_t_internal(const ASN1_TIME *s, time_t t2, int mode)
450b680683fSbeck {
451b680683fSbeck struct tm tm1, tm2;
452b680683fSbeck
453b680683fSbeck /*
454b680683fSbeck * This function has never handled failure conditions properly
455b680683fSbeck * The OpenSSL version used to simply follow NULL pointers on failure.
456b680683fSbeck * BoringSSL and OpenSSL now make it return -2 on failure.
457b680683fSbeck *
458b680683fSbeck * The danger is that users of this function will not differentiate the
459b680683fSbeck * -2 failure case from s < t2. Callers must be careful. Sadly this is
460b680683fSbeck * one of those pervasive things from OpenSSL we must continue with.
461b680683fSbeck */
462b680683fSbeck
463b680683fSbeck if (ASN1_time_parse(s->data, s->length, &tm1, mode) == -1)
464b680683fSbeck return -2;
465b680683fSbeck
4669b176146Sbeck if (!asn1_time_time_t_to_tm(&t2, &tm2))
467b680683fSbeck return -2;
468b680683fSbeck
469b680683fSbeck return ASN1_time_tm_cmp(&tm1, &tm2);
470b680683fSbeck }
471b680683fSbeck
472b680683fSbeck int
ASN1_TIME_compare(const ASN1_TIME * t1,const ASN1_TIME * t2)473b680683fSbeck ASN1_TIME_compare(const ASN1_TIME *t1, const ASN1_TIME *t2)
474b680683fSbeck {
475b680683fSbeck struct tm tm1, tm2;
476b680683fSbeck
477b680683fSbeck if (t1->type != V_ASN1_UTCTIME && t1->type != V_ASN1_GENERALIZEDTIME)
478b680683fSbeck return -2;
479b680683fSbeck
480b680683fSbeck if (t2->type != V_ASN1_UTCTIME && t2->type != V_ASN1_GENERALIZEDTIME)
481b680683fSbeck return -2;
482b680683fSbeck
483b680683fSbeck if (ASN1_time_parse(t1->data, t1->length, &tm1, t1->type) == -1)
484b680683fSbeck return -2;
485b680683fSbeck
486d30837c1Stb if (ASN1_time_parse(t2->data, t2->length, &tm2, t2->type) == -1)
487b680683fSbeck return -2;
488b680683fSbeck
489b680683fSbeck return ASN1_time_tm_cmp(&tm1, &tm2);
490b680683fSbeck }
491acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_compare);
492b680683fSbeck
493b680683fSbeck int
ASN1_TIME_cmp_time_t(const ASN1_TIME * s,time_t t)494b680683fSbeck ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t)
495b680683fSbeck {
496b680683fSbeck if (s->type == V_ASN1_UTCTIME)
497b680683fSbeck return ASN1_TIME_cmp_time_t_internal(s, t, V_ASN1_UTCTIME);
498b680683fSbeck if (s->type == V_ASN1_GENERALIZEDTIME)
499b680683fSbeck return ASN1_TIME_cmp_time_t_internal(s, t,
500b680683fSbeck V_ASN1_GENERALIZEDTIME);
501b680683fSbeck return -2;
502b680683fSbeck }
503acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_cmp_time_t);
504b680683fSbeck
5050b62c50aSbeck /*
5060b62c50aSbeck * ASN1_UTCTIME wrappers
5070b62c50aSbeck */
5080b62c50aSbeck
5090b62c50aSbeck int
ASN1_UTCTIME_check(const ASN1_UTCTIME * d)5109b3891c7Stb ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
5110b62c50aSbeck {
5120b62c50aSbeck if (d->type != V_ASN1_UTCTIME)
513123b2274Stb return 0;
514123b2274Stb return d->type == ASN1_time_parse(d->data, d->length, NULL, d->type);
5150b62c50aSbeck }
516acf64401Sbeck LCRYPTO_ALIAS(ASN1_UTCTIME_check);
5170b62c50aSbeck
5180b62c50aSbeck int
ASN1_UTCTIME_set_string(ASN1_UTCTIME * s,const char * str)5190b62c50aSbeck ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
5200b62c50aSbeck {
521c1736878Sjsing if (s != NULL && s->type != V_ASN1_UTCTIME)
522123b2274Stb return 0;
523123b2274Stb return ASN1_TIME_set_string_internal(s, str, V_ASN1_UTCTIME);
5240b62c50aSbeck }
525acf64401Sbeck LCRYPTO_ALIAS(ASN1_UTCTIME_set_string);
5260b62c50aSbeck
5270b62c50aSbeck ASN1_UTCTIME *
ASN1_UTCTIME_set(ASN1_UTCTIME * s,time_t t)5280b62c50aSbeck ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
5290b62c50aSbeck {
530123b2274Stb return ASN1_UTCTIME_adj(s, t, 0, 0);
5310b62c50aSbeck }
532acf64401Sbeck LCRYPTO_ALIAS(ASN1_UTCTIME_set);
5330b62c50aSbeck
5340b62c50aSbeck ASN1_UTCTIME *
ASN1_UTCTIME_adj(ASN1_UTCTIME * s,time_t t,int offset_day,long offset_sec)5350b62c50aSbeck ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec)
5360b62c50aSbeck {
537123b2274Stb return ASN1_TIME_adj_internal(s, t, offset_day, offset_sec,
538123b2274Stb V_ASN1_UTCTIME);
5390b62c50aSbeck }
540acf64401Sbeck LCRYPTO_ALIAS(ASN1_UTCTIME_adj);
5410b62c50aSbeck
5420b62c50aSbeck int
ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME * s,time_t t)543b680683fSbeck ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
5440b62c50aSbeck {
545b680683fSbeck if (s->type == V_ASN1_UTCTIME)
546b680683fSbeck return ASN1_TIME_cmp_time_t_internal(s, t, V_ASN1_UTCTIME);
547b680683fSbeck return -2;
5480b62c50aSbeck }
549b4712960Sbeck LCRYPTO_ALIAS(ASN1_UTCTIME_cmp_time_t);
5500b62c50aSbeck
5510b62c50aSbeck /*
5520b62c50aSbeck * ASN1_GENERALIZEDTIME wrappers
5530b62c50aSbeck */
5540b62c50aSbeck
5550b62c50aSbeck int
ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME * d)5569b3891c7Stb ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d)
5570b62c50aSbeck {
5580b62c50aSbeck if (d->type != V_ASN1_GENERALIZEDTIME)
559123b2274Stb return 0;
560123b2274Stb return d->type == ASN1_time_parse(d->data, d->length, NULL, d->type);
5610b62c50aSbeck }
562acf64401Sbeck LCRYPTO_ALIAS(ASN1_GENERALIZEDTIME_check);
5630b62c50aSbeck
5640b62c50aSbeck int
ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME * s,const char * str)5650b62c50aSbeck ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str)
5660b62c50aSbeck {
567c1736878Sjsing if (s != NULL && s->type != V_ASN1_GENERALIZEDTIME)
568123b2274Stb return 0;
569123b2274Stb return ASN1_TIME_set_string_internal(s, str, V_ASN1_GENERALIZEDTIME);
5700b62c50aSbeck }
571acf64401Sbeck LCRYPTO_ALIAS(ASN1_GENERALIZEDTIME_set_string);
5720b62c50aSbeck
5730b62c50aSbeck ASN1_GENERALIZEDTIME *
ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME * s,time_t t)5740b62c50aSbeck ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t)
5750b62c50aSbeck {
576123b2274Stb return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0);
5770b62c50aSbeck }
578acf64401Sbeck LCRYPTO_ALIAS(ASN1_GENERALIZEDTIME_set);
5790b62c50aSbeck
5800b62c50aSbeck ASN1_GENERALIZEDTIME *
ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME * s,time_t t,int offset_day,long offset_sec)5810b62c50aSbeck ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day,
5820b62c50aSbeck long offset_sec)
5830b62c50aSbeck {
584123b2274Stb return ASN1_TIME_adj_internal(s, t, offset_day, offset_sec,
585123b2274Stb V_ASN1_GENERALIZEDTIME);
5860b62c50aSbeck }
587acf64401Sbeck LCRYPTO_ALIAS(ASN1_GENERALIZEDTIME_adj);
588b680683fSbeck
589b680683fSbeck int
ASN1_TIME_normalize(ASN1_TIME * t)590b680683fSbeck ASN1_TIME_normalize(ASN1_TIME *t)
591b680683fSbeck {
592b680683fSbeck struct tm tm;
593b680683fSbeck
5944ee6c374Sjob if (t == NULL)
5954ee6c374Sjob return 0;
596b680683fSbeck if (!ASN1_TIME_to_tm(t, &tm))
597b680683fSbeck return 0;
598f93ff421Stb return tm_to_rfc5280_time(&tm, t);
599b680683fSbeck }
600acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_normalize);
601b680683fSbeck
602b680683fSbeck int
ASN1_TIME_set_string_X509(ASN1_TIME * s,const char * str)6035c2a185eStb ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str)
604b680683fSbeck {
605b680683fSbeck return ASN1_TIME_set_string_internal(s, str, RFC5280);
606b680683fSbeck }
607acf64401Sbeck LCRYPTO_ALIAS(ASN1_TIME_set_string_X509);
608