GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/asn1/a_time_tm.c Lines: 132 201 65.7 %
Date: 2016-12-06 Branches: 73 132 55.3 %

Line Branch Exec Source
1
/* $OpenBSD: a_time_tm.c,v 1.9 2015/12/12 21:02:59 beck 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
60
asn1_tm_cmp(struct tm *tm1, struct tm *tm2) {
34
60
	if (tm1->tm_year < tm2->tm_year)
35
12
		return (-1);
36
48
	if (tm1->tm_year > tm2->tm_year)
37
21
		return (1);
38
27
	if (tm1->tm_mon < tm2->tm_mon)
39
6
		return (-1);
40
21
	if (tm1->tm_mon > tm2->tm_mon)
41
		return (1);
42
21
	if (tm1->tm_mday < tm2->tm_mday)
43
		return (-1);
44
21
	if (tm1->tm_mday > tm2->tm_mday)
45
		return (1);
46
21
	if (tm1->tm_hour < tm2->tm_hour)
47
		return (-1);
48
21
	if (tm1->tm_hour > tm2->tm_hour)
49
		return (1);
50
21
	if (tm1->tm_min < tm2->tm_min)
51
		return (-1);
52
21
	if (tm1->tm_min > tm2->tm_min)
53
3
		return (1);
54
18
	if (tm1->tm_sec < tm2->tm_sec)
55
		return (-1);
56
18
	if (tm1->tm_sec > tm2->tm_sec)
57
6
		return (1);
58
12
	return 0;
59
}
60
61
/* Format a time as an RFC 5280 format Generalized time */
62
char *
63
gentime_string_from_tm(struct tm *tm)
64
5
{
65
5
	char *ret = NULL;
66
	int year;
67
68
5
	year = tm->tm_year + 1900;
69
5
	if (year < 0 || year > 9999)
70
		return (NULL);
71
72
5
	if (asprintf(&ret, "%04u%02u%02u%02u%02u%02uZ", year,
73
	    tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
74
	    tm->tm_sec) == -1)
75
		ret = NULL;
76
77
5
	return (ret);
78
}
79
80
/* Format a time as an RFC 5280 format UTC time */
81
char *
82
utctime_string_from_tm(struct tm *tm)
83
15
{
84
15
	char *ret = NULL;
85
86
15
	if (tm->tm_year >= 150 || tm->tm_year < 50)
87
		return (NULL);
88
89
15
	if (asprintf(&ret, "%02u%02u%02u%02u%02u%02uZ",
90
	    tm->tm_year % 100,  tm->tm_mon + 1, tm->tm_mday,
91
	    tm->tm_hour, tm->tm_min, tm->tm_sec) == -1)
92
		ret = NULL;
93
94
15
	return (ret);
95
}
96
97
/* Format a time correctly for an X509 object as per RFC 5280 */
98
char *
99
rfc5280_string_from_tm(struct tm *tm)
100
2
{
101
2
	char *ret = NULL;
102
	int year;
103
104
2
	year = tm->tm_year + 1900;
105
2
	if (year < 1950 || year > 9999)
106
		return (NULL);
107
108
2
	if (year < 2050)
109
2
		ret = utctime_string_from_tm(tm);
110
	else
111
		ret = gentime_string_from_tm(tm);
112
113
2
	return (ret);
114
}
115
116
/*
117
 * Parse an RFC 5280 format ASN.1 time string.
118
 *
119
 * mode must be:
120
 * 0 if we expect to parse a time as specified in RFC 5280 from an X509 object.
121
 * V_ASN1_UTCTIME if we wish to parse on RFC5280 format UTC time.
122
 * V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
123
 *
124
 * Returns:
125
 * -1 if the string was invalid.
126
 * V_ASN1_UTCTIME if the string validated as a UTC time string.
127
 * V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
128
 *
129
 * Fills in *tm with the corresponding time if tm is non NULL.
130
 */
131
#define	ATOI2(ar)	((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0'))
132
int
133
asn1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode)
134
202
{
135
	size_t i;
136
202
	int type = 0;
137
	struct tm ltm;
138
	struct tm *lt;
139
	const char *p;
140
141
202
	if (bytes == NULL)
142
		return (-1);
143
144
	/* Constrain to valid lengths. */
145
202
	if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH)
146
72
		return (-1);
147
148
130
	lt = tm;
149
130
	if (lt == NULL) {
150
60
		memset(&ltm, 0, sizeof(ltm));
151
60
		lt = &ltm;
152
	}
153
154
	/* Timezone is required and must be GMT (Zulu). */
155
130
	if (bytes[len - 1] != 'Z')
156
		return (-1);
157
158
	/* Make sure everything else is digits. */
159
1702
	for (i = 0; i < len - 1; i++) {
160
1578
		if (isdigit((unsigned char)bytes[i]))
161
1572
			continue;
162
6
		return (-1);
163
	}
164
165
	/*
166
	 * Validate and convert the time
167
	 */
168
124
	p = bytes;
169
124
	switch (len) {
170
	case GENTIME_LENGTH:
171
42
		if (mode == V_ASN1_UTCTIME)
172
5
			return (-1);
173
37
		lt->tm_year = (ATOI2(p) * 100) - 1900;	/* cc */
174
37
		type = V_ASN1_GENERALIZEDTIME;
175
		/* FALLTHROUGH */
176
	case UTCTIME_LENGTH:
177
119
		if (type == 0) {
178
82
			if (mode == V_ASN1_GENERALIZEDTIME)
179
1
				return (-1);
180
81
			type = V_ASN1_UTCTIME;
181
		}
182
118
		lt->tm_year += ATOI2(p);		/* yy */
183
118
		if (type == V_ASN1_UTCTIME) {
184
81
			if (lt->tm_year < 50)
185
68
				lt->tm_year += 100;
186
		}
187
118
		lt->tm_mon = ATOI2(p) - 1;		/* mm */
188
118
		if (lt->tm_mon < 0 || lt->tm_mon > 11)
189
2
			return (-1);
190
116
		lt->tm_mday = ATOI2(p);			/* dd */
191
116
		if (lt->tm_mday < 1 || lt->tm_mday > 31)
192
			return (-1);
193
116
		lt->tm_hour = ATOI2(p);			/* HH */
194
116
		if (lt->tm_hour < 0 || lt->tm_hour > 23)
195
			return (-1);
196
116
		lt->tm_min = ATOI2(p);			/* MM */
197
116
		if (lt->tm_min < 0 || lt->tm_min > 59)
198
			return (-1);
199
116
		lt->tm_sec = ATOI2(p);			/* SS */
200
		/* Leap second 60 is not accepted. Reconsider later? */
201
116
		if (lt->tm_sec < 0 || lt->tm_sec > 59)
202
			return (-1);
203
		break;
204
	default:
205
		return (-1);
206
	}
207
208
116
	return (type);
209
}
210
211
/*
212
 * ASN1_TIME generic functions.
213
 */
214
215
static int
216
ASN1_TIME_set_string_internal(ASN1_TIME *s, const char *str, int mode)
217
132
{
218
	int type;
219
	char *tmp;
220
221
132
	if ((type = asn1_time_parse(str, strlen(str), NULL, mode)) == -1)
222
86
		return (0);
223
46
	if (mode != 0 && mode != type)
224
		return (0);
225
226
46
	if (s == NULL)
227
12
		return (1);
228
229
34
	if ((tmp = strdup(str)) == NULL)
230
		return (0);
231
34
	free(s->data);
232
34
	s->data = tmp;
233
34
	s->length = strlen(tmp);
234
34
	s->type = type;
235
236
34
	return (1);
237
}
238
239
static ASN1_TIME *
240
ASN1_TIME_adj_internal(ASN1_TIME *s, time_t t, int offset_day, long offset_sec,
241
    int mode)
242
20
{
243
20
	int allocated = 0;
244
	struct tm tm;
245
	size_t len;
246
	char * p;
247
248
20
 	if (gmtime_r(&t, &tm) == NULL)
249
 		return (NULL);
250
251
20
	if (offset_day || offset_sec) {
252
		if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec))
253
			return (NULL);
254
	}
255
256

20
	switch (mode) {
257
	case V_ASN1_UTCTIME:
258
13
		p = utctime_string_from_tm(&tm);
259
13
		break;
260
	case V_ASN1_GENERALIZEDTIME:
261
5
		p = gentime_string_from_tm(&tm);
262
5
		break;
263
	case RFC5280:
264
2
		p = rfc5280_string_from_tm(&tm);
265
2
		break;
266
	default:
267
		return (NULL);
268
	}
269
20
	if (p == NULL) {
270
		ASN1err(ASN1_F_ASN1_GENERALIZEDTIME_ADJ,
271
		    ASN1_R_ILLEGAL_TIME_VALUE);
272
		return (NULL);
273
	}
274
275
20
	if (s == NULL) {
276
20
		if ((s = ASN1_TIME_new()) == NULL)
277
			return (NULL);
278
20
		allocated = 1;
279
	}
280
281
20
	len = strlen(p);
282
20
	switch (len) {
283
	case GENTIME_LENGTH:
284
5
		s->type = V_ASN1_GENERALIZEDTIME;
285
5
		break;
286
 	case UTCTIME_LENGTH:
287
15
		s->type = V_ASN1_UTCTIME;
288
15
		break;
289
	default:
290
		if (allocated)
291
			ASN1_TIME_free(s);
292
		free(p);
293
		return (NULL);
294
	}
295
20
	free(s->data);
296
20
	s->data = p;
297
20
	s->length = len;
298
20
	return (s);
299
}
300
301
ASN1_TIME *
302
ASN1_TIME_set(ASN1_TIME *s, time_t t)
303
{
304
	return (ASN1_TIME_adj(s, t, 0, 0));
305
}
306
307
ASN1_TIME *
308
ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec)
309
2
{
310
2
	return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, RFC5280));
311
}
312
313
int
314
ASN1_TIME_check(ASN1_TIME *t)
315
{
316
	if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME)
317
		return (0);
318
	return (t->type == asn1_time_parse(t->data, t->length, NULL, t->type));
319
}
320
321
ASN1_GENERALIZEDTIME *
322
ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out)
323
{
324
	ASN1_GENERALIZEDTIME *tmp = NULL;
325
	struct tm tm;
326
	char *str;
327
328
	if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME)
329
		return (NULL);
330
331
	memset(&tm, 0, sizeof(tm));
332
	if (t->type != asn1_time_parse(t->data, t->length, &tm, t->type))
333
		return (NULL);
334
	if ((str = gentime_string_from_tm(&tm)) == NULL)
335
		return (NULL);
336
337
	if (out != NULL)
338
		tmp = *out;
339
	if (tmp == NULL && (tmp = ASN1_GENERALIZEDTIME_new()) == NULL) {
340
		free(str);
341
		return (NULL);
342
	}
343
	if (out != NULL)
344
		*out = tmp;
345
346
	free(tmp->data);
347
	tmp->data = str;
348
	tmp->length = strlen(str);
349
	return (tmp);
350
}
351
352
int
353
ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
354
44
{
355
44
	return (ASN1_TIME_set_string_internal(s, str, 0));
356
}
357
358
/*
359
 * ASN1_UTCTIME wrappers
360
 */
361
362
int
363
ASN1_UTCTIME_check(ASN1_UTCTIME *d)
364
{
365
	if (d->type != V_ASN1_UTCTIME)
366
		return (0);
367
	return (d->type == asn1_time_parse(d->data, d->length, NULL, d->type));
368
}
369
370
int
371
ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
372
49
{
373

49
	if (s != NULL && s->type != V_ASN1_UTCTIME)
374
		return (0);
375
49
	return (ASN1_TIME_set_string_internal(s, str, V_ASN1_UTCTIME));
376
}
377
378
ASN1_UTCTIME *
379
ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
380
13
{
381
13
	return (ASN1_UTCTIME_adj(s, t, 0, 0));
382
}
383
384
ASN1_UTCTIME *
385
ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec)
386
13
{
387
13
	return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec,
388
	    V_ASN1_UTCTIME));
389
}
390
391
int
392
ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t2)
393
{
394
	struct tm tm1, tm2;
395
396
	/*
397
	 * This function has never handled failure conditions properly
398
	 * and should be deprecated. The OpenSSL version used to
399
	 * simply follow NULL pointers on failure. BoringSSL and
400
	 * OpenSSL now make it return -2 on failure.
401
	 *
402
	 * The danger is that users of this function will not
403
	 * differentiate the -2 failure case from t1 < t2.
404
	 */
405
	if (asn1_time_parse(s->data, s->length, &tm1, V_ASN1_UTCTIME) == -1)
406
		return (-2); /* XXX */
407
408
	if (gmtime_r(&t2, &tm2) == NULL)
409
		return (-2); /* XXX */
410
411
	return asn1_tm_cmp(&tm1, &tm2);
412
}
413
414
/*
415
 * ASN1_GENERALIZEDTIME wrappers
416
 */
417
418
int
419
ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *d)
420
{
421
	if (d->type != V_ASN1_GENERALIZEDTIME)
422
		return (0);
423
	return (d->type == asn1_time_parse(d->data, d->length, NULL, d->type));
424
}
425
426
int
427
ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str)
428
39
{
429

39
	if (s != NULL && s->type != V_ASN1_GENERALIZEDTIME)
430
		return (0);
431
39
	return (ASN1_TIME_set_string_internal(s, str, V_ASN1_GENERALIZEDTIME));
432
}
433
434
ASN1_GENERALIZEDTIME *
435
ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t)
436
5
{
437
5
	return (ASN1_GENERALIZEDTIME_adj(s, t, 0, 0));
438
}
439
440
ASN1_GENERALIZEDTIME *
441
ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day,
442
    long offset_sec)
443
5
{
444
5
	return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec,
445
	    V_ASN1_GENERALIZEDTIME));
446
}