GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/asn1/a_time_tm.c Lines: 143 199 71.9 %
Date: 2017-11-13 Branches: 93 152 61.2 %

Line Branch Exec Source
1
/* $OpenBSD: a_time_tm.c,v 1.14 2017/08/28 17:42:47 jsing 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
20356
	if (tm1->tm_year < tm2->tm_year)
36
585
		return (-1);
37
9593
	if (tm1->tm_year > tm2->tm_year)
38
594
		return (1);
39
8999
	if (tm1->tm_mon < tm2->tm_mon)
40
		return (-1);
41
8999
	if (tm1->tm_mon > tm2->tm_mon)
42
		return (1);
43
8999
	if (tm1->tm_mday < tm2->tm_mday)
44
		return (-1);
45
8999
	if (tm1->tm_mday > tm2->tm_mday)
46
4466
		return (1);
47
4533
	if (tm1->tm_hour < tm2->tm_hour)
48
		return (-1);
49
4533
	if (tm1->tm_hour > tm2->tm_hour)
50
		return (1);
51
4533
	if (tm1->tm_min < tm2->tm_min)
52
1760
		return (-1);
53
2773
	if (tm1->tm_min > tm2->tm_min)
54
9
		return (1);
55
2764
	if (tm1->tm_sec < tm2->tm_sec)
56
2706
		return (-1);
57
58
	if (tm1->tm_sec > tm2->tm_sec)
58
18
		return (1);
59
40
	return 0;
60
10178
}
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
10126
	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
62
	char *ret = NULL;
83
	int year;
84
85
31
	year = tm->tm_year + 1900;
86
31
	if (year < 0 || year > 9999)
87
		return (NULL);
88
89
62
	if (asprintf(&ret, "%04u%02u%02u%02u%02u%02uZ", year,
90
31
	    tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
91
62
	    tm->tm_sec) == -1)
92
		ret = NULL;
93
94
31
	return (ret);
95
31
}
96
97
/* Format a time as an RFC 5280 format UTC time */
98
char *
99
utctime_string_from_tm(struct tm *tm)
100
{
101
206
	char *ret = NULL;
102
103

206
	if (tm->tm_year >= 150 || tm->tm_year < 50)
104
		return (NULL);
105
106
206
	if (asprintf(&ret, "%02u%02u%02u%02u%02u%02uZ",
107
103
	    tm->tm_year % 100,  tm->tm_mon + 1, tm->tm_mday,
108
206
	    tm->tm_hour, tm->tm_min, tm->tm_sec) == -1)
109
		ret = NULL;
110
111
103
	return (ret);
112
103
}
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
128
	year = tm->tm_year + 1900;
122
64
	if (year < 1950 || year > 9999)
123
		return (NULL);
124
125
64
	if (year < 2050)
126
64
		ret = utctime_string_from_tm(tm);
127
	else
128
		ret = gentime_string_from_tm(tm);
129
130
64
	return (ret);
131
64
}
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
21360
	struct tm ltm;
155
	struct tm *lt;
156
	const char *p;
157
158
10680
	if (bytes == NULL)
159
		return (-1);
160
161
	/* Constrain to valid lengths. */
162
10680
	if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH)
163
216
		return (-1);
164
165
	lt = tm;
166
10464
	if (lt == NULL) {
167
220
		memset(&ltm, 0, sizeof(ltm));
168
		lt = &ltm;
169
220
	}
170
171
	/* Timezone is required and must be GMT (Zulu). */
172
10464
	if (bytes[len - 1] != 'Z')
173
		return (-1);
174
175
	/* Make sure everything else is digits. */
176
272160
	for (i = 0; i < len - 1; i++) {
177
125634
		if (isdigit((unsigned char)bytes[i]))
178
			continue;
179
18
		return (-1);
180
	}
181
182
	/*
183
	 * Validate and convert the time
184
	 */
185
	p = bytes;
186
10563
	switch (len) {
187
	case GENTIME_LENGTH:
188
132
		if (mode == V_ASN1_UTCTIME)
189
15
			return (-1);
190
117
		lt->tm_year = (ATOI2(p) * 100) - 1900;	/* cc */
191
117
		type = V_ASN1_GENERALIZEDTIME;
192
		/* FALLTHROUGH */
193
	case UTCTIME_LENGTH:
194
10431
		if (type == 0) {
195
10314
			if (mode == V_ASN1_GENERALIZEDTIME)
196
3
				return (-1);
197
			type = V_ASN1_UTCTIME;
198
10311
		}
199
10428
		lt->tm_year += ATOI2(p);		/* yy */
200
10428
		if (type == V_ASN1_UTCTIME) {
201
10311
			if (lt->tm_year < 50)
202
10272
				lt->tm_year += 100;
203
		}
204
10428
		lt->tm_mon = ATOI2(p) - 1;		/* mm */
205

20856
		if (lt->tm_mon < 0 || lt->tm_mon > 11)
206
6
			return (-1);
207
10422
		lt->tm_mday = ATOI2(p);			/* dd */
208

20844
		if (lt->tm_mday < 1 || lt->tm_mday > 31)
209
			return (-1);
210
10422
		lt->tm_hour = ATOI2(p);			/* HH */
211

20844
		if (lt->tm_hour < 0 || lt->tm_hour > 23)
212
			return (-1);
213
10422
		lt->tm_min = ATOI2(p);			/* MM */
214

20844
		if (lt->tm_min < 0 || lt->tm_min > 59)
215
			return (-1);
216
10422
		lt->tm_sec = ATOI2(p);			/* SS */
217
		/* Leap second 60 is not accepted. Reconsider later? */
218

20844
		if (lt->tm_sec < 0 || lt->tm_sec > 59)
219
			return (-1);
220
		break;
221
	default:
222
		return (-1);
223
	}
224
225
10422
	return (type);
226
10680
}
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
872
	if ((type = ASN1_time_parse(str, strlen(str), NULL, mode)) == -1)
239
258
		return (0);
240

275
	if (mode != 0 && mode != type)
241
		return (0);
242
243
178
	if (s == NULL)
244
66
		return (1);
245
246
112
	if ((tmp = strdup(str)) == NULL)
247
		return (0);
248
112
	free(s->data);
249
112
	s->data = tmp;
250
112
	s->length = strlen(tmp);
251
112
	s->type = type;
252
253
112
	return (1);
254
436
}
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
122
	struct tm tm;
262
	size_t len;
263
	char * p;
264
265
122
 	if (gmtime_r(&t, &tm) == NULL)
266
 		return (NULL);
267
268
122
	if (offset_day || offset_sec) {
269
24
		if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec))
270
			return (NULL);
271
	}
272
273

122
	switch (mode) {
274
	case V_ASN1_UTCTIME:
275
39
		p = utctime_string_from_tm(&tm);
276
39
		break;
277
	case V_ASN1_GENERALIZEDTIME:
278
19
		p = gentime_string_from_tm(&tm);
279
19
		break;
280
	case RFC5280:
281
64
		p = rfc5280_string_from_tm(&tm);
282
64
		break;
283
	default:
284
		return (NULL);
285
	}
286
122
	if (p == NULL) {
287
		ASN1error(ASN1_R_ILLEGAL_TIME_VALUE);
288
		return (NULL);
289
	}
290
291
122
	if (s == NULL) {
292
70
		if ((s = ASN1_TIME_new()) == NULL)
293
			return (NULL);
294
		allocated = 1;
295
70
	}
296
297
122
	len = strlen(p);
298
122
	switch (len) {
299
	case GENTIME_LENGTH:
300
		s->type = V_ASN1_GENERALIZEDTIME;
301
19
		break;
302
 	case UTCTIME_LENGTH:
303
		s->type = V_ASN1_UTCTIME;
304
103
		break;
305
	default:
306
		if (allocated)
307
			ASN1_TIME_free(s);
308
		free(p);
309
		return (NULL);
310
	}
311
122
	free(s->data);
312
122
	s->data = p;
313
122
	s->length = len;
314
122
	return (s);
315
122
}
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
128
	return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, RFC5280));
337
}
338
339
int
340
ASN1_TIME_check(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(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out)
349
{
350
	ASN1_GENERALIZEDTIME *tmp = NULL;
351
24
	struct tm tm;
352
	char *str;
353
354

24
	if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME)
355
		return (NULL);
356
357
12
	memset(&tm, 0, sizeof(tm));
358
12
	if (t->type != ASN1_time_parse(t->data, t->length, &tm, t->type))
359
		return (NULL);
360
12
	if ((str = gentime_string_from_tm(&tm)) == NULL)
361
		return (NULL);
362
363
12
	if (out != NULL)
364
12
		tmp = *out;
365

12
	if (tmp == NULL && (tmp = ASN1_GENERALIZEDTIME_new()) == NULL) {
366
		free(str);
367
		return (NULL);
368
	}
369
12
	if (out != NULL)
370
12
		*out = tmp;
371
372
12
	free(tmp->data);
373
12
	tmp->data = str;
374
12
	tmp->length = strlen(str);
375
12
	return (tmp);
376
12
}
377
378
int
379
ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
380
{
381
324
	return (ASN1_TIME_set_string_internal(s, str, 0));
382
}
383
384
/*
385
 * ASN1_UTCTIME wrappers
386
 */
387
388
int
389
ASN1_UTCTIME_check(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

453
	if (s != NULL && s->type != V_ASN1_UTCTIME)
400
		return (0);
401
155
	return (ASN1_TIME_set_string_internal(s, str, V_ASN1_UTCTIME));
402
155
}
403
404
ASN1_UTCTIME *
405
ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
406
{
407
78
	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
78
	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(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

351
	if (s != NULL && s->type != V_ASN1_GENERALIZEDTIME)
456
		return (0);
457
119
	return (ASN1_TIME_set_string_internal(s, str, V_ASN1_GENERALIZEDTIME));
458
119
}
459
460
ASN1_GENERALIZEDTIME *
461
ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t)
462
{
463
38
	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
38
	return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec,
471
	    V_ASN1_GENERALIZEDTIME));
472
}