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(&ltm, 0, sizeof(ltm));
168 		lt = &ltm;
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