1 /* $OpenBSD: rfc5280time.c,v 1.4 2015/10/30 15:52:55 miod Exp $ */
2 /*
3  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4  * Copyright (c) 2015 Bob Beck <beck@opebsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <openssl/asn1.h>
20 #include <openssl/x509.h>
21 
22 #include <err.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 struct rfc5280_time_test {
27 	const char *str;
28 	const char *data;
29 	time_t time;
30 };
31 
32 struct rfc5280_time_test rfc5280_invtime_tests[] = {
33 	{
34 		.str = "",
35 	},
36 	{
37 		.str = "2015",
38 	},
39 	{
40 		.str = "201509",
41 	},
42 	{
43 		.str = "20150923",
44 	},
45 	{
46 		.str = "20150923032700",
47 	},
48 	{
49 		/* UTC time must have seconds */
50 		.str = "7001010000Z",
51 	},
52 	{
53 		.str = "201509230327Z",
54 	},
55 	{
56 		.str = "20150923032700.Z",
57 	},
58 	{
59 		.str = "20150923032700.123",
60 	},
61 	{
62 		.str = "20150923032700+1100Z",
63 	},
64 	{
65 		.str = "20150923032700-11001",
66 	},
67 	{
68 		/* UTC time cannot have fractional seconds. */
69 		.str = "150923032700.123Z",
70 	},
71 	{
72 		/* Gen time cannot have +- TZ. */
73 		.str = "20150923032712+1115",
74 	},
75 	{
76 		/* Gen time cannot have fractional seconds */
77 		.str = "20150923032712.123Z",
78 	},
79 	{
80 		.str = "aaaaaaaaaaaaaaZ",
81 	},
82 	{
83 		/* Must be a UTC time per RFC 5280 */
84 		.str = "19700101000000Z",
85 		.data = "19700101000000Z",
86 		.time = 0,
87 	},
88 	{
89 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
90 		.str = "20150923032700Z",
91 		.data = "20150923032700Z",
92 		.time = 1442978820,
93 	},
94 #if SIZEOF_TIME_T == 8
95 	{
96 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
97 		.str = "00000101000000Z",
98 		.data = "00000101000000Z",
99 		.time = -62167219200LL,
100 	},
101 	{
102 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
103 		.str = "20491231235959Z",
104 		.data = "20491231235959Z",
105 		.time = 2524607999LL,
106 	},
107 #endif
108 	{
109 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
110 		.str = "19500101000000Z",
111 		.data = "19500101000000Z",
112 		.time = -631152000LL,
113 	},
114 };
115 
116 struct rfc5280_time_test rfc5280_gentime_tests[] = {
117 #if SIZEOF_TIME_T == 8
118 	{
119 		/* Biggest RFC 5280 time */
120 		.str = "99991231235959Z",
121 		.data = "99991231235959Z",
122 		.time = 253402300799LL,
123 	},
124 	{
125 		.str = "21600218104000Z",
126 		.data = "21600218104000Z",
127 		.time = 6000000000LL,
128 	},
129 	{
130 		/* Smallest RFC 5280 gen time */
131 		.str = "20500101000000Z",
132 		.data = "20500101000000Z",
133 		.time =  2524608000LL,
134 	},
135 #endif
136 };
137 struct rfc5280_time_test rfc5280_utctime_tests[] = {
138 	{
139 		.str = "500101000000Z",
140 		.data = "500101000000Z",
141 		.time = -631152000,
142 	},
143 	{
144 		.str = "540226230640Z",
145 		.data = "540226230640Z",
146 		.time = -500000000,
147 	},
148 #if SIZEOF_TIME_T == 8
149 	{
150 		.str = "491231235959Z",
151 		.data = "491231235959Z",
152 		.time = 2524607999LL,
153 	},
154 #endif
155 	{
156 		.str = "700101000000Z",
157 		.data = "700101000000Z",
158 		.time = 0,
159 	},
160 	{
161 		.str = "150923032700Z",
162 		.data = "150923032700Z",
163 		.time = 1442978820,
164 	},
165 	{
166 		.str = "150923102700Z",
167 		.data = "150923102700Z",
168 		.time = 1443004020,
169 	},
170 	{
171 		.str = "150922162712Z",
172 		.data = "150922162712Z",
173 		.time = 1442939232,
174 	},
175 	{
176 		.str = "140524144512Z",
177 		.data = "140524144512Z",
178 		.time = 1400942712,
179 	},
180 	{
181 		.str = "240401144512Z",
182 		.data = "240401144512Z",
183 		.time = 1711982712,
184 	},
185 };
186 
187 #define N_INVTIME_TESTS \
188     (sizeof(rfc5280_invtime_tests) / sizeof(*rfc5280_invtime_tests))
189 #define N_GENTIME_TESTS \
190     (sizeof(rfc5280_gentime_tests) / sizeof(*rfc5280_gentime_tests))
191 #define N_UTCTIME_TESTS \
192     (sizeof(rfc5280_utctime_tests) / sizeof(*rfc5280_utctime_tests))
193 
194 static int
asn1_compare_str(int test_no,struct asn1_string_st * asn1str,const char * str)195 asn1_compare_str(int test_no, struct asn1_string_st *asn1str, const char *str)
196 {
197 	int length = strlen(str);
198 
199 	if (asn1str->length != length) {
200 		fprintf(stderr, "FAIL: test %i - string lengths differ "
201 		    "(%i != %i)\n", test_no, asn1str->length, length);
202 		return (1);
203 	}
204 	if (strncmp(asn1str->data, str, length) != 0) {
205 		fprintf(stderr, "FAIL: test %i - strings differ "
206 		    "('%s' != '%s')\n", test_no, asn1str->data, str);
207 		return (1);
208 	}
209 
210 	return (0);
211 }
212 
213 static int
rfc5280_invtime_test(int test_no,struct rfc5280_time_test * att)214 rfc5280_invtime_test(int test_no, struct rfc5280_time_test *att)
215 {
216 	ASN1_GENERALIZEDTIME *gt = NULL;
217 	ASN1_UTCTIME *ut = NULL;
218 	ASN1_TIME *t = NULL;
219 	int failure = 1;
220 	time_t now = time(NULL);
221 
222 	if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
223 		goto done;
224 	if ((ut = ASN1_UTCTIME_new()) == NULL)
225 		goto done;
226 	if ((t = ASN1_TIME_new()) == NULL)
227 		goto done;
228 
229 	if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 0) {
230 		if (X509_cmp_time(gt, &now) != 0) {
231 			fprintf(stderr, "FAIL: test %i - successfully parsed as GENTIME "
232 			    "string '%s'\n", test_no, att->str);
233 			goto done;
234 		}
235 	}
236 	if (ASN1_UTCTIME_set_string(ut, att->str) != 0) {
237 		if (X509_cmp_time(ut, &now) != 0) {
238 			fprintf(stderr, "FAIL: test %i - successfully parsed as UTCTIME "
239 			    "string '%s'\n", test_no, att->str);
240 			goto done;
241 		}
242 	}
243 	if (ASN1_TIME_set_string(t, att->str) != 0) {
244 		if (X509_cmp_time(t, &now) != 0) {
245 			fprintf(stderr, "FAIL: test %i - successfully parsed as UTCTIME "
246 			    "string '%s'\n", test_no, att->str);
247 			goto done;
248 		}
249 	}
250 
251 	failure = 0;
252 
253  done:
254 	ASN1_GENERALIZEDTIME_free(gt);
255 	ASN1_UTCTIME_free(ut);
256 	ASN1_TIME_free(t);
257 
258 	return (failure);
259 }
260 
261 static int
rfc5280_gentime_test(int test_no,struct rfc5280_time_test * att)262 rfc5280_gentime_test(int test_no, struct rfc5280_time_test *att)
263 {
264 	unsigned char *p = NULL;
265 	ASN1_GENERALIZEDTIME *gt;
266 	int failure = 1;
267 	int i;
268 
269 	if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
270 		goto done;
271 
272 	if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) {
273 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
274 		    test_no, att->str);
275 		goto done;
276 	}
277 	if (asn1_compare_str(test_no, gt, att->str) != 0)
278 		goto done;
279 
280 	if ((i = X509_cmp_time(gt, &att->time)) != -1) {
281 		fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n",
282 		    test_no, i, (long long)att->time);
283 		goto done;
284 	}
285 
286 	att->time--;
287 	if ((i = X509_cmp_time(gt, &att->time)) != 1) {
288 		fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n",
289 		    test_no, i, (long long)att->time);
290 		goto done;
291 	}
292 	att->time++;
293 
294 	ASN1_GENERALIZEDTIME_free(gt);
295 
296 	if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) {
297 		fprintf(stderr, "FAIL: test %i - failed to set time %lli\n",
298 		    test_no, (long long)att->time);
299 		goto done;
300 	}
301 	if (asn1_compare_str(test_no, gt, att->data) != 0)
302 		goto done;
303 
304 	failure = 0;
305 
306  done:
307 	ASN1_GENERALIZEDTIME_free(gt);
308 	free(p);
309 
310 	return (failure);
311 }
312 
313 static int
rfc5280_utctime_test(int test_no,struct rfc5280_time_test * att)314 rfc5280_utctime_test(int test_no, struct rfc5280_time_test *att)
315 {
316 	unsigned char *p = NULL;
317 	ASN1_UTCTIME *ut;
318 	int failure = 1;
319 	int i;
320 
321 	if ((ut = ASN1_UTCTIME_new()) == NULL)
322 		goto done;
323 
324 	if (ASN1_UTCTIME_set_string(ut, att->str) != 1) {
325 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
326 		    test_no, att->str);
327 		goto done;
328 	}
329 	if (asn1_compare_str(test_no, ut, att->str) != 0)
330 		goto done;
331 
332 	if ((i = X509_cmp_time(ut, &att->time)) != -1) {
333 		fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n",
334 		    test_no, i, (long long)att->time);
335 		goto done;
336 	}
337 
338 	att->time--;
339 	if ((i = X509_cmp_time(ut, &att->time)) != 1) {
340 		fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n",
341 		    test_no, i, (long long)att->time);
342 		goto done;
343 	}
344 	att->time++;
345 
346 	ASN1_UTCTIME_free(ut);
347 
348 	if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) {
349 		fprintf(stderr, "FAIL: test %i - failed to set time %lli\n",
350 		    test_no, (long long)att->time);
351 		goto done;
352 	}
353 	if (asn1_compare_str(test_no, ut, att->data) != 0)
354 		goto done;
355 
356 	failure = 0;
357 
358  done:
359 	ASN1_UTCTIME_free(ut);
360 	free(p);
361 
362 	return (failure);
363 }
364 
365 int
main(int argc,char ** argv)366 main(int argc, char **argv)
367 {
368 	struct rfc5280_time_test *att;
369 	int failed = 0;
370 	size_t i;
371 
372 	fprintf(stderr, "RFC5280 Invalid time tests...\n");
373 	for (i = 0; i < N_INVTIME_TESTS; i++) {
374 		att = &rfc5280_invtime_tests[i];
375 		failed |= rfc5280_invtime_test(i, att);
376 	}
377 
378 	fprintf(stderr, "RFC5280 GENERALIZEDTIME tests...\n");
379 	for (i = 0; i < N_GENTIME_TESTS; i++) {
380 		att = &rfc5280_gentime_tests[i];
381 		failed |= rfc5280_gentime_test(i, att);
382 	}
383 
384 	fprintf(stderr, "RFC5280 UTCTIME tests...\n");
385 	for (i = 0; i < N_UTCTIME_TESTS; i++) {
386 		att = &rfc5280_utctime_tests[i];
387 		failed |= rfc5280_utctime_test(i, att);
388 	}
389 	return (failed);
390 }
391