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