xref: /openbsd/lib/libcrypto/asn1/a_time_tm.c (revision c604ab84)
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, &copy);
206 
207 	if (is_gentime) {
208 		if (!cbs_get_two_digit_value(&copy, &val))
209 			return 0;
210 		year = val * 100;
211 		if (!cbs_get_two_digit_value(&copy, &val))
212 			return 0;
213 		year += val;
214 	} else {
215 		year = 1900;
216 		if (!cbs_get_two_digit_value(&copy, &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(&copy, &month))
226 		return 0;
227 	if (month < 1 || month > 12)
228 		return 0; /* Reject invalid months. */
229 
230 	if (!cbs_get_two_digit_value(&copy, &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(&copy, &hour))
236 		return 0;
237 	if (hour > 23)
238 		return 0; /* Reject invalid hours. */
239 
240 	if (!cbs_get_two_digit_value(&copy, &min))
241 		return 0;
242 	if (min > 59)
243 		return 0; /* Reject invalid minutes. */
244 
245 	if (!cbs_get_two_digit_value(&copy, &sec))
246 		return 0;
247 	if (sec > 59)
248 		return 0; /* Reject invalid seconds. Leap seconds are invalid. */
249 
250 	if (!CBS_get_u8(&copy, &tz))
251 		return 0;
252 	if (tz != 'Z')
253 		return 0; /* Reject anything but Z on the end. */
254 
255 	if (CBS_len(&copy) != 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