xref: /openbsd-src/regress/lib/libcrypto/objects/objectstest.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /* $OpenBSD: objectstest.c,v 1.6 2022/09/05 21:06:31 tb Exp $ */
2 /*
3  * Copyright (c) 2017, 2022 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/objects.h>
19 
20 #include <err.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 static void
25 hexdump(const unsigned char *buf, size_t len)
26 {
27 	size_t i;
28 
29 	for (i = 1; i <= len; i++)
30 		fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
31 
32 	fprintf(stderr, "\n");
33 }
34 
35 static int
36 obj_compare_bytes(const char *label, const unsigned char *d1, int len1,
37     const unsigned char *d2, int len2)
38 {
39 	if (len1 != len2) {
40 		fprintf(stderr, "FAIL: %s - byte lengths differ "
41 		    "(%d != %d)\n", label, len1, len2);
42 		fprintf(stderr, "Got:\n");
43 		hexdump(d1, len1);
44 		fprintf(stderr, "Want:\n");
45 		hexdump(d2, len2);
46 		return 0;
47 	}
48 	if (memcmp(d1, d2, len1) != 0) {
49 		fprintf(stderr, "FAIL: %s - bytes differ\n", label);
50 		fprintf(stderr, "Got:\n");
51 		hexdump(d1, len1);
52 		fprintf(stderr, "Want:\n");
53 		hexdump(d2, len2);
54 		return 0;
55 	}
56 	return 1;
57 }
58 
59 struct obj_test {
60 	const char *oid;
61 	const char *sn;
62 	const char *ln;
63 	int nid;
64 	uint8_t data[255];
65 	size_t data_len;
66 };
67 
68 struct obj_test obj_tests[] = {
69 	{
70 		.oid = NULL,
71 		.sn = "UNDEF",
72 		.ln = "undefined",
73 		.nid = NID_undef,
74 	},
75 	{
76 		.oid = "2.5.4.10",
77 		.sn = "O",
78 		.ln = "organizationName",
79 		.nid = NID_organizationName,
80 		.data = {
81 			0x55, 0x04, 0x0a,
82 		},
83 		.data_len = 3,
84 	},
85 	{
86 		.oid = "2.5.4.8",
87 		.sn = "ST",
88 		.ln = "stateOrProvinceName",
89 		.nid = NID_stateOrProvinceName,
90 		.data = {
91 			0x55, 0x04, 0x08,
92 		},
93 		.data_len = 3,
94 	},
95 	{
96 		.oid = "2.23.43.1",
97 		.sn = "wap-wsg",
98 		.nid = NID_wap_wsg,
99 		.data = {
100 			0x67, 0x2b, 0x01,
101 		},
102 		.data_len = 3,
103 	},
104 	{
105 		.oid = "1.3.6.1.4.1.11129.2.4.5",
106 		.sn = "ct_cert_scts",
107 		.ln = "CT Certificate SCTs",
108 		.nid = NID_ct_cert_scts,
109 		.data = {
110 			0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02,
111 			0x04, 0x05,
112 		},
113 		.data_len = 10,
114 	},
115 	{
116 		.oid = "1.3.6.1.4.1",
117 		.sn = "enterprises",
118 		.ln = "Enterprises",
119 		.nid = NID_Enterprises,
120 		.data = {
121 			0x2b, 0x06, 0x01, 0x04, 0x01,
122 		},
123 		.data_len = 5,
124 	},
125 	{
126 		.oid = "1.3.6.1.4.1.5454.1.70.6.11.2",
127 		.nid = NID_undef,
128 		.data = {
129 			0x2b, 0x06, 0x01, 0x04, 0x01, 0xaa, 0x4e, 0x01,
130 			0x46, 0x06, 0x0b, 0x02,
131 		},
132 		.data_len = 12,
133 	},
134 	{
135 		.oid = "1.3.6.1.4.1.890.1.5.8.60.102.2",
136 		.nid = NID_undef,
137 		.data = {
138 			0x2b, 0x06, 0x01, 0x04, 0x01, 0x86, 0x7a, 0x01,
139 			0x05, 0x08, 0x3c, 0x66, 0x02,
140 		},
141 		.data_len = 13,
142 	},
143 	{
144 		.oid = "1.3.6.1.4.1.173.7.3.4.1.1.26",
145 		.nid = NID_undef,
146 		.data = {
147 			0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x2d, 0x07,
148 			0x03, 0x04, 0x01, 0x01, 0x1a,
149 		},
150 		.data_len = 13,
151 	},
152 };
153 
154 #define N_OBJ_TESTS (sizeof(obj_tests) / sizeof(*obj_tests))
155 
156 static int
157 obj_name_test(struct obj_test *ot)
158 {
159 	const char *ln, *sn;
160 	int nid;
161 	int failed = 1;
162 
163 	if (ot->ln != NULL) {
164 		if ((nid = OBJ_ln2nid(ot->ln)) != ot->nid) {
165 			fprintf(stderr, "FAIL: OBJ_ln2nid() for '%s' = %d, "
166 			    "want %d\n", ot->ln, nid, ot->nid);
167 			goto failed;
168 		}
169 		if ((ln = OBJ_nid2ln(ot->nid)) == NULL) {
170 			fprintf(stderr, "FAIL: OBJ_nid2ln() for '%s' returned "
171 			    "NULL\n", ot->oid);
172 			goto failed;
173 		}
174 		if (strcmp(ln, ot->ln) != 0) {
175 			fprintf(stderr, "FAIL: OBJ_nid2ln() for '%s' = '%s', "
176 			    "want '%s'\n", ot->oid, ln, ot->ln);
177 			goto failed;
178 		}
179 	}
180 	if (ot->sn != NULL) {
181 		if ((nid = OBJ_sn2nid(ot->sn)) != ot->nid) {
182 			fprintf(stderr, "FAIL: OBJ_sn2nid() for '%s' = %d, "
183 			    "want %d\n", ot->sn, nid, ot->nid);
184 			goto failed;
185 		}
186 		if ((sn = OBJ_nid2sn(ot->nid)) == NULL) {
187 			fprintf(stderr, "FAIL: OBJ_nid2sn() for '%s' returned "
188 			    "NULL\n", ot->oid);
189 			goto failed;
190 		}
191 		if (strcmp(sn, ot->sn) != 0) {
192 			fprintf(stderr, "FAIL: OBJ_nid2sn() for '%s' = '%s', "
193 			    "want '%s'\n", ot->oid, sn, ot->sn);
194 			goto failed;
195 		}
196 	}
197 
198 	failed = 0;
199 
200  failed:
201 	return failed;
202 }
203 
204 static int
205 obj_name_tests(void)
206 {
207 	int failed = 0;
208 	size_t i;
209 
210 	for (i = 0; i < N_OBJ_TESTS; i++)
211 		failed |= obj_name_test(&obj_tests[i]);
212 
213 	return failed;
214 }
215 
216 static int
217 obj_nid_test(struct obj_test *ot)
218 {
219 	ASN1_OBJECT *obj = NULL;
220 	int nid;
221 	int failed = 1;
222 
223 	if (ot->nid == NID_undef && ot->oid != NULL)
224 		return 0;
225 
226 	if ((obj = OBJ_nid2obj(ot->nid)) == NULL) {
227 		fprintf(stderr, "FAIL: OBJ_nid2obj() failed for '%s' (NID %d)\n",
228 		    ot->oid, ot->nid);
229 		goto failed;
230 	}
231 	if ((nid = OBJ_obj2nid(obj)) != ot->nid) {
232 		fprintf(stderr, "FAIL: OBJ_obj2nid() failed for '%s' - got %d, "
233 		    "want %d\n", ot->oid ? ot->oid : "undef", nid, ot->nid);
234 		goto failed;
235 	}
236 
237 	failed = 0;
238 
239  failed:
240 	ASN1_OBJECT_free(obj);
241 
242 	return failed;
243 }
244 
245 static int
246 obj_nid_tests(void)
247 {
248 	int failed = 0;
249 	size_t i;
250 
251 	for (i = 0; i < N_OBJ_TESTS; i++)
252 		failed |= obj_nid_test(&obj_tests[i]);
253 
254 	return failed;
255 }
256 
257 static int
258 obj_oid_test(struct obj_test *ot)
259 {
260 	ASN1_OBJECT *obj = NULL;
261 	char buf[1024];
262 	int len, nid;
263 	int failed = 1;
264 
265 	if (ot->oid == NULL)
266 		return 0;
267 
268 	if ((obj = OBJ_txt2obj(ot->oid, 0)) == NULL) {
269 		fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s'\n", ot->oid);
270 		goto failed;
271 	}
272 	if ((nid = OBJ_txt2nid(ot->oid)) != ot->nid) {
273 		fprintf(stderr, "FAIL: OBJ_txt2nid() failed for '%s', got %d "
274 		    "want %d\n", ot->oid, nid, ot->nid);
275 		goto failed;
276 	}
277 
278 	if (!obj_compare_bytes("object data", OBJ_get0_data(obj), OBJ_length(obj),
279 	    ot->data, ot->data_len))
280 		goto failed;
281 
282 	len = OBJ_obj2txt(buf, sizeof(buf), obj, 1);
283 	if (len <= 0 || (size_t)len >= sizeof(buf)) {
284 		fprintf(stderr, "FAIL: OBJ_obj2txt() failed for '%s'\n", ot->oid);
285 		goto failed;
286 	}
287 	if (strcmp(buf, ot->oid) != 0) {
288 		fprintf(stderr, "FAIL: OBJ_obj2txt() returned '%s', want '%s'\n",
289 		    buf, ot->oid);
290 		goto failed;
291 	}
292 
293 	if ((OBJ_obj2txt(NULL, 0, obj, 1) != len)) {
294 		fprintf(stderr, "FAIL: OBJ_obj2txt() with NULL buffer != %d\n",
295 		    len);
296 		goto failed;
297 	}
298 	if ((OBJ_obj2txt(buf, 3, obj, 1) != len)) {
299 		fprintf(stderr, "FAIL: OBJ_obj2txt() with short buffer != %d\n",
300 		    len);
301 		goto failed;
302 	}
303 
304 	failed = 0;
305 
306  failed:
307 	ASN1_OBJECT_free(obj);
308 
309 	return failed;
310 }
311 
312 static int
313 obj_oid_tests(void)
314 {
315 	int failed = 0;
316 	size_t i;
317 
318 	for (i = 0; i < N_OBJ_TESTS; i++)
319 		failed |= obj_oid_test(&obj_tests[i]);
320 
321 	return failed;
322 }
323 
324 static int
325 obj_txt_test(struct obj_test *ot)
326 {
327 	ASN1_OBJECT *obj = NULL;
328 	const char *want;
329 	char buf[1024];
330 	int len, nid;
331 	int failed = 1;
332 
333 	if (ot->oid == NULL)
334 		return 0;
335 
336 	if (ot->sn != NULL) {
337 		if ((obj = OBJ_txt2obj(ot->sn, 0)) == NULL) {
338 			fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s'\n",
339 			    ot->sn);
340 			goto failed;
341 		}
342 		if ((nid = OBJ_obj2nid(obj)) != ot->nid) {
343 			fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s', "
344 			    "got nid %d want %d\n", ot->sn, nid, ot->nid);
345 			goto failed;
346 		}
347 		ASN1_OBJECT_free(obj);
348 		obj = NULL;
349 	}
350 	if (ot->ln != NULL) {
351 		if ((obj = OBJ_txt2obj(ot->ln, 0)) == NULL) {
352 			fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s'\n",
353 			    ot->ln);
354 			goto failed;
355 		}
356 		if ((nid = OBJ_obj2nid(obj)) != ot->nid) {
357 			fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s', "
358 			    "got nid %d want %d\n", ot->ln, nid, ot->nid);
359 			goto failed;
360 		}
361 		ASN1_OBJECT_free(obj);
362 		obj = NULL;
363 	}
364 
365 	if ((obj = OBJ_txt2obj(ot->oid, 0)) == NULL) {
366 		fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s'\n", ot->oid);
367 		goto failed;
368 	}
369 	if ((nid = OBJ_obj2nid(obj)) != ot->nid) {
370 		fprintf(stderr, "FAIL: OBJ_txt2obj() failed for '%s', "
371 		    "got nid %d want %d\n", ot->oid, nid, ot->nid);
372 		goto failed;
373 	}
374 
375 	len = OBJ_obj2txt(buf, sizeof(buf), obj, 0);
376 	if (len <= 0 || (size_t)len >= sizeof(buf)) {
377 		fprintf(stderr, "FAIL: OBJ_obj2txt() failed for '%s'\n", ot->oid);
378 		goto failed;
379 	}
380 	want = ot->ln;
381 	if (want == NULL)
382 		want = ot->sn;
383 	if (want == NULL)
384 		want = ot->oid;
385 	if (strcmp(buf, want) != 0) {
386 		fprintf(stderr, "FAIL: OBJ_obj2txt() returned '%s', want '%s'\n",
387 		    buf, want);
388 		goto failed;
389 	}
390 
391 	failed = 0;
392 
393  failed:
394 	ASN1_OBJECT_free(obj);
395 
396 	return failed;
397 }
398 
399 static int
400 obj_txt_tests(void)
401 {
402 	int failed = 0;
403 	size_t i;
404 
405 	for (i = 0; i < N_OBJ_TESTS; i++)
406 		failed |= obj_txt_test(&obj_tests[i]);
407 
408 	return failed;
409 }
410 
411 /* OID 1.3.18446744073709551615 (64 bits). */
412 const uint8_t asn1_large_oid1[] = {
413 	0x06, 0x0b,
414 	0x2b, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
415 	0xff, 0xff, 0x7f,
416 };
417 
418 /* OID 1.3.18446744073709551616 (65 bits). */
419 const uint8_t asn1_large_oid2[] = {
420 	0x06, 0x0b,
421 	0x2b, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
422 	0x80, 0x80, 0x00,
423 };
424 
425 /* OID 1.3.340282366920938463463374607431768211455 (128 bits). */
426 const uint8_t asn1_large_oid3[] = {
427 	0x06, 0x14,
428 	0x2b, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
429 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
430 	0xff, 0xff, 0xff, 0x7f,
431 };
432 
433 /* OID 1.3.115792089237316195423570985008687907853269984665640564039457584007913129639935 (256 bits). */
434 const uint8_t asn1_large_oid4[] = {
435 	0x06, 0x26,
436 	0x2b, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
437 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
438 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
439 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
440 	0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
441 };
442 
443 struct oid_large_test {
444 	const char *oid;
445 	const uint8_t *asn1_der;
446 	size_t asn1_der_len;
447 	int obj2txt;
448 };
449 
450 struct oid_large_test oid_large_tests[] = {
451 	{
452 		.oid = "1.3.18446744073709551615",
453 		.asn1_der = asn1_large_oid1,
454 		.asn1_der_len = sizeof(asn1_large_oid1),
455 		.obj2txt = 1,
456 	},
457 	{
458 		.oid = "1.3.18446744073709551616",
459 		.asn1_der = asn1_large_oid2,
460 		.asn1_der_len = sizeof(asn1_large_oid2),
461 		.obj2txt = 0,
462 	},
463 	{
464 		.oid = "1.3.340282366920938463463374607431768211455",
465 		.asn1_der = asn1_large_oid3,
466 		.asn1_der_len = sizeof(asn1_large_oid3),
467 		.obj2txt = 0,
468 	},
469 	{
470 		.oid = "1.3.115792089237316195423570985008687907853269984665640"
471 		    "564039457584007913129639935",
472 		.asn1_der = asn1_large_oid4,
473 		.asn1_der_len = sizeof(asn1_large_oid4),
474 		.obj2txt = 0,
475 	},
476 };
477 
478 #define N_OID_LARGE_TESTS (sizeof(oid_large_tests) / sizeof(*oid_large_tests))
479 
480 static int
481 obj_oid_large_test(size_t test_no, struct oid_large_test *olt)
482 {
483 	ASN1_OBJECT *obj = NULL;
484 	const uint8_t *p;
485 	char buf[1024];
486 	int len;
487 	int failed = 1;
488 
489 	p = olt->asn1_der;
490 	if ((obj = d2i_ASN1_OBJECT(NULL, &p, olt->asn1_der_len)) == NULL) {
491 		fprintf(stderr, "FAIL: d2i_ASN1_OBJECT() failed for large "
492 		    "oid %zu\n", test_no);
493 		goto failed;
494 	}
495 	len = OBJ_obj2txt(buf, sizeof(buf), obj, 1);
496 	if (len < 0 || (size_t)len >= sizeof(buf)) {
497 		fprintf(stderr, "FAIL: OBJ_obj2txt() failed for large "
498 		    "oid %zu\n", test_no);
499 		goto failed;
500 	}
501 	if ((len != 0) != olt->obj2txt) {
502 		fprintf(stderr, "FAIL: OBJ_obj2txt() failed for large "
503 		    "oid %zu\n", test_no);
504 		goto failed;
505 	}
506 	if (len != 0 && strcmp(buf, olt->oid) != 0) {
507 		fprintf(stderr, "FAIL: OBJ_obj2txt() returned '%s', want '%s'\n",
508 		    buf, olt->oid);
509 		goto failed;
510 	}
511 
512 	failed = 0;
513 
514  failed:
515 	ASN1_OBJECT_free(obj);
516 
517 	return failed;
518 }
519 
520 static int
521 obj_oid_large_tests(void)
522 {
523 	int failed = 0;
524 	size_t i;
525 
526 	for (i = 0; i < N_OID_LARGE_TESTS; i++)
527 		failed |= obj_oid_large_test(i, &oid_large_tests[i]);
528 
529 	return failed;
530 }
531 
532 int
533 main(int argc, char **argv)
534 {
535 	int failed = 0;
536 
537 	failed |= obj_name_tests();
538 	failed |= obj_nid_tests();
539 	failed |= obj_oid_tests();
540 	failed |= obj_txt_tests();
541 	failed |= obj_oid_large_tests();
542 
543 	return (failed);
544 }
545