1 /* $OpenBSD: asn1time.c,v 1.8 2015/12/28 14:18:38 bcook Exp $ */
2 /*
3  * Copyright (c) 2015 Joel Sing <jsing@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 <openssl/asn1.h>
19 
20 #include <err.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 struct asn1_time_test {
25 	const char *str;
26 	const char *data;
27 	const unsigned char der[32];
28 	time_t time;
29 };
30 
31 struct asn1_time_test asn1_invtime_tests[] = {
32 	{
33 		.str = "",
34 	},
35 	{
36 		.str = "2015",
37 	},
38 	{
39 		.str = "201509",
40 	},
41 	{
42 		.str = "20150923",
43 	},
44 	{
45 		.str = "20150923032700",
46 	},
47 	{
48 		.str = "20150923032700.Z",
49 	},
50 	{
51 		.str = "20150923032700.123",
52 	},
53 	{
54 		.str = "20150923032700+1.09",
55 	},
56 	{
57 		.str = "20150923032700+1100Z",
58 	},
59 	{
60 		.str = "20150923032700-11001",
61 	},
62 	{
63 		/* UTC time cannot have fractional seconds. */
64 		.str = "150923032700.123Z",
65 	},
66 	{
67 		.str = "aaaaaaaaaaaaaaZ",
68 	},
69 };
70 
71 struct asn1_time_test asn1_gentime_tests[] = {
72 	{
73 		.str = "19700101000000Z",
74 		.data = "19700101000000Z",
75 		.time = 0,
76 		.der = {
77 			0x18, 0x0f, 0x31, 0x39, 0x37, 0x30, 0x30, 0x31,
78 			0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
79 			0x5a,
80 		},
81 	},
82 	{
83 		.str = "20150923032700Z",
84 		.data = "20150923032700Z",
85 		.time = 1442978820,
86 		.der = {
87 			0x18, 0x0f, 0x32, 0x30, 0x31, 0x35, 0x30, 0x39,
88 			0x32, 0x33, 0x30, 0x33, 0x32, 0x37, 0x30, 0x30,
89 			0x5a,
90 		},
91 	},
92 };
93 
94 struct asn1_time_test asn1_utctime_tests[] = {
95 	{
96 		.str = "700101000000Z",
97 		.data = "700101000000Z",
98 		.time = 0,
99 		.der = {
100 			0x17, 0x0d, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31,
101 			0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
102 		},
103 	},
104 	{
105 		.str = "150923032700Z",
106 		.data = "150923032700Z",
107 		.time = 1442978820,
108 		.der = {
109 			0x17, 0x0d, 0x31, 0x35, 0x30, 0x39, 0x32, 0x33,
110 			0x30, 0x33, 0x32, 0x37, 0x30, 0x30, 0x5a,
111 		},
112 	},
113 	{
114 		.str = "140524144512Z",
115 		.data = "140524144512Z",
116 		.time = 1400942712,
117 		.der = {
118 			0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x32, 0x34,
119 			0x31, 0x34, 0x34, 0x35, 0x31, 0x32, 0x5a,
120 		},
121 	},
122 	{
123 		.str = "240401144512Z",
124 		.data = "240401144512Z",
125 		.time = 1711982712,
126 		.der = {
127 			0x17, 0x0d, 0x32, 0x34, 0x30, 0x34, 0x30, 0x31,
128 			0x31, 0x34, 0x34, 0x35, 0x31, 0x32, 0x5a
129 		},
130 	},
131 };
132 
133 #define N_INVTIME_TESTS \
134     (sizeof(asn1_invtime_tests) / sizeof(*asn1_invtime_tests))
135 #define N_GENTIME_TESTS \
136     (sizeof(asn1_gentime_tests) / sizeof(*asn1_gentime_tests))
137 #define N_UTCTIME_TESTS \
138     (sizeof(asn1_utctime_tests) / sizeof(*asn1_utctime_tests))
139 
140 static void
hexdump(const unsigned char * buf,size_t len)141 hexdump(const unsigned char *buf, size_t len)
142 {
143 	size_t i;
144 
145 	for (i = 1; i <= len; i++)
146 		fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
147 
148 	fprintf(stderr, "\n");
149 }
150 
151 static int
asn1_compare_bytes(int test_no,const unsigned char * d1,const unsigned char * d2,int len1,int len2)152 asn1_compare_bytes(int test_no, const unsigned char *d1,
153     const unsigned char *d2, int len1, int len2)
154 {
155 	if (len1 != len2) {
156 		fprintf(stderr, "FAIL: test %i - byte lengths differ "
157 		    "(%i != %i)\n", test_no, len1, len2);
158 		return (1);
159 	}
160 	if (memcmp(d1, d2, len1) != 0) {
161 		fprintf(stderr, "FAIL: test %i - bytes differ\n", test_no);
162 		fprintf(stderr, "Got:\n");
163 		hexdump(d1, len1);
164 		fprintf(stderr, "Want:\n");
165 		hexdump(d2, len2);
166 	}
167 	return (0);
168 }
169 
170 static int
asn1_compare_str(int test_no,struct asn1_string_st * asn1str,const char * str)171 asn1_compare_str(int test_no, struct asn1_string_st *asn1str, const char *str)
172 {
173 	int length = strlen(str);
174 
175 	if (asn1str->length != length) {
176 		fprintf(stderr, "FAIL: test %i - string lengths differ "
177 		    "(%i != %i)\n", test_no, asn1str->length, length);
178 		return (1);
179 	}
180 	if (strncmp(asn1str->data, str, length) != 0) {
181 		fprintf(stderr, "FAIL: test %i - strings differ "
182 		    "('%s' != '%s')\n", test_no, asn1str->data, str);
183 		return (1);
184 	}
185 
186 	return (0);
187 }
188 
189 static int
asn1_invtime_test(int test_no,struct asn1_time_test * att)190 asn1_invtime_test(int test_no, struct asn1_time_test *att)
191 {
192 	ASN1_GENERALIZEDTIME *gt = NULL;
193 	ASN1_UTCTIME *ut = NULL;
194 	ASN1_TIME *t = NULL;
195 	int failure = 1;
196 
197 	if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
198 		goto done;
199 	if ((ut = ASN1_UTCTIME_new()) == NULL)
200 		goto done;
201 	if ((t = ASN1_TIME_new()) == NULL)
202 		goto done;
203 
204 	if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 0) {
205 		fprintf(stderr, "FAIL: test %i - successfully set "
206 		    "GENERALIZEDTIME string '%s'\n", test_no, att->str);
207 		goto done;
208 	}
209 	if (ASN1_UTCTIME_set_string(ut, att->str) != 0) {
210 		fprintf(stderr, "FAIL: test %i - successfully set UTCTIME "
211 		    "string '%s'\n", test_no, att->str);
212 		goto done;
213 	}
214 	if (ASN1_TIME_set_string(t, att->str) != 0) {
215 		fprintf(stderr, "FAIL: test %i - successfully set TIME "
216 		    "string '%s'\n", test_no, att->str);
217 		goto done;
218 	}
219 
220 	failure = 0;
221 
222  done:
223 	ASN1_GENERALIZEDTIME_free(gt);
224 	ASN1_UTCTIME_free(ut);
225 	ASN1_TIME_free(t);
226 
227 	return (failure);
228 }
229 
230 static int
asn1_gentime_test(int test_no,struct asn1_time_test * att)231 asn1_gentime_test(int test_no, struct asn1_time_test *att)
232 {
233 	const unsigned char *der;
234 	unsigned char *p = NULL;
235 	ASN1_GENERALIZEDTIME *gt = NULL;
236 	int failure = 1;
237 	int len;
238 
239 	if (ASN1_GENERALIZEDTIME_set_string(NULL, att->str) != 1) {
240 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
241 		    test_no, att->str);
242 		goto done;
243 	}
244 
245 	if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
246 		goto done;
247 
248 	if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) {
249 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
250 		    test_no, att->str);
251 		goto done;
252 	}
253 	if (asn1_compare_str(test_no, gt, att->str) != 0)
254 		goto done;
255 
256 	if ((len = i2d_ASN1_GENERALIZEDTIME(gt, &p)) <= 0) {
257 		fprintf(stderr, "FAIL: test %i - i2d_ASN1_GENERALIZEDTIME "
258 		    "failed\n", test_no);
259 		goto done;
260 	}
261 	der = att->der;
262 	if (asn1_compare_bytes(test_no, p, der, len, strlen(der)) != 0)
263 		goto done;
264 
265 	len = strlen(att->der);
266 	if (d2i_ASN1_GENERALIZEDTIME(&gt, &der, len) == NULL) {
267 		fprintf(stderr, "FAIL: test %i - d2i_ASN1_GENERALIZEDTIME "
268 		    "failed\n", test_no);
269 		goto done;
270 	}
271 	if (asn1_compare_str(test_no, gt, att->str) != 0)
272 		goto done;
273 
274 	ASN1_GENERALIZEDTIME_free(gt);
275 
276 	if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) {
277 		fprintf(stderr, "FAIL: test %i - failed to set time %lli\n",
278 		    test_no, (long long)att->time);
279 		goto done;
280 	}
281 	if (asn1_compare_str(test_no, gt, att->data) != 0)
282 		goto done;
283 
284 	failure = 0;
285 
286  done:
287 	ASN1_GENERALIZEDTIME_free(gt);
288 	free(p);
289 
290 	return (failure);
291 }
292 
293 static int
asn1_utctime_test(int test_no,struct asn1_time_test * att)294 asn1_utctime_test(int test_no, struct asn1_time_test *att)
295 {
296 	const unsigned char *der;
297 	unsigned char *p = NULL;
298 	ASN1_UTCTIME *ut = NULL;
299 	int failure = 1;
300 	int len;
301 
302 	if (ASN1_UTCTIME_set_string(NULL, att->str) != 1) {
303 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
304 		    test_no, att->str);
305 		goto done;
306 	}
307 
308 	if ((ut = ASN1_UTCTIME_new()) == NULL)
309 		goto done;
310 
311 	if (ASN1_UTCTIME_set_string(ut, att->str) != 1) {
312 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
313 		    test_no, att->str);
314 		goto done;
315 	}
316 	if (asn1_compare_str(test_no, ut, att->str) != 0)
317 		goto done;
318 
319 	if ((len = i2d_ASN1_UTCTIME(ut, &p)) <= 0) {
320 		fprintf(stderr, "FAIL: test %i - i2d_ASN1_UTCTIME failed\n",
321 		    test_no);
322 		goto done;
323 	}
324 	der = att->der;
325 	if (asn1_compare_bytes(test_no, p, der, len, strlen(der)) != 0)
326 		goto done;
327 
328 	len = strlen(att->der);
329 	if (d2i_ASN1_UTCTIME(&ut, &der, len) == NULL) {
330 		fprintf(stderr, "FAIL: test %i - d2i_ASN1_UTCTIME failed\n",
331 		    test_no);
332 		goto done;
333 	}
334 	if (asn1_compare_str(test_no, ut, att->str) != 0)
335 		goto done;
336 
337 	ASN1_UTCTIME_free(ut);
338 
339 	if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) {
340 		fprintf(stderr, "FAIL: test %i - failed to set time %lli\n",
341 		    test_no, (long long)att->time);
342 		goto done;
343 	}
344 	if (asn1_compare_str(test_no, ut, att->data) != 0)
345 		goto done;
346 
347 	failure = 0;
348 
349  done:
350 	ASN1_UTCTIME_free(ut);
351 	free(p);
352 
353 	return (failure);
354 }
355 
356 static int
asn1_time_test(int test_no,struct asn1_time_test * att,int type)357 asn1_time_test(int test_no, struct asn1_time_test *att, int type)
358 {
359 	ASN1_TIME *t = NULL;
360 	int failure = 1;
361 
362 	if (ASN1_TIME_set_string(NULL, att->str) != 1) {
363 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
364 		    test_no, att->str);
365 		goto done;
366 	}
367 
368 	if ((t = ASN1_TIME_new()) == NULL)
369 		goto done;
370 
371 	if (ASN1_TIME_set_string(t, att->str) != 1) {
372 		fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n",
373 		    test_no, att->str);
374 		goto done;
375 	}
376 
377 	if (t->type != type) {
378 		fprintf(stderr, "FAIL: test %i - got type %i, want %i\n",
379 		    test_no, t->type, type);
380 		goto done;
381 	}
382 
383 	failure = 0;
384 
385  done:
386 
387 	ASN1_TIME_free(t);
388 
389 	return (failure);
390 }
391 
392 int
main(int argc,char ** argv)393 main(int argc, char **argv)
394 {
395 	struct asn1_time_test *att;
396 	int failed = 0;
397 	size_t i;
398 
399 	fprintf(stderr, "Invalid time tests...\n");
400 	for (i = 0; i < N_INVTIME_TESTS; i++) {
401 		att = &asn1_invtime_tests[i];
402 		failed |= asn1_invtime_test(i, att);
403 	}
404 
405 	fprintf(stderr, "GENERALIZEDTIME tests...\n");
406 	for (i = 0; i < N_GENTIME_TESTS; i++) {
407 		att = &asn1_gentime_tests[i];
408 		failed |= asn1_gentime_test(i, att);
409 	}
410 
411 	fprintf(stderr, "UTCTIME tests...\n");
412 	for (i = 0; i < N_UTCTIME_TESTS; i++) {
413 		att = &asn1_utctime_tests[i];
414 		failed |= asn1_utctime_test(i, att);
415 	}
416 
417 	fprintf(stderr, "TIME tests...\n");
418 	for (i = 0; i < N_UTCTIME_TESTS; i++) {
419 		att = &asn1_utctime_tests[i];
420 		failed |= asn1_time_test(i, att, V_ASN1_UTCTIME);
421 	}
422 	for (i = 0; i < N_GENTIME_TESTS; i++) {
423 		att = &asn1_gentime_tests[i];
424 		failed |= asn1_time_test(i, att, V_ASN1_GENERALIZEDTIME);
425 	}
426 
427 	return (failed);
428 }
429