1 /* $OpenBSD: objectstest.c,v 1.8 2023/05/23 11:06:52 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
hexdump(const unsigned char * buf,size_t len)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
obj_compare_bytes(const char * label,const unsigned char * d1,int len1,const unsigned char * d2,int len2)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
obj_name_test(struct obj_test * ot)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
obj_name_tests(void)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
obj_nid_test(struct obj_test * ot)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
obj_nid_tests(void)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
obj_oid_test(struct obj_test * ot)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
obj_oid_tests(void)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
obj_txt_test(struct obj_test * ot)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
obj_txt_early_nul_test(void)400 obj_txt_early_nul_test(void)
401 {
402 ASN1_OBJECT *obj = NULL;
403 char buf[2];
404 int failed = 1;
405
406 buf[0] = 'x';
407 buf[1] = '\0';
408
409 if (OBJ_obj2txt(buf, sizeof(buf), NULL, 1) != 0) {
410 fprintf(stderr, "FAIL: OBJ_obj2txt(NULL) succeded\n");
411 goto failed;
412 }
413 if (buf[0] != '\0') {
414 fprintf(stderr, "FAIL: OBJ_obj2txt(NULL) did not NUL terminate\n");
415 goto failed;
416 }
417
418 if ((obj = ASN1_OBJECT_new()) == NULL)
419 errx(1, "ASN1_OBJECT_new");
420
421 buf[0] = 'x';
422 buf[1] = '\0';
423
424 if (OBJ_obj2txt(buf, sizeof(buf), obj, 1) != 0) {
425 fprintf(stderr, "FAIL: OBJ_obj2txt(obj) succeeded\n");
426 goto failed;
427 }
428 if (buf[0] != '\0') {
429 fprintf(stderr, "FAIL: OBJ_obj2txt(obj) did not NUL terminate\n");
430 goto failed;
431 }
432
433 failed = 0;
434
435 failed:
436 ASN1_OBJECT_free(obj);
437
438 return failed;
439 }
440
441 static int
obj_txt_tests(void)442 obj_txt_tests(void)
443 {
444 int failed = 0;
445 size_t i;
446
447 for (i = 0; i < N_OBJ_TESTS; i++)
448 failed |= obj_txt_test(&obj_tests[i]);
449
450 failed |= obj_txt_early_nul_test();
451
452 return failed;
453 }
454
455 /* OID 1.3.18446744073709551615 (64 bits). */
456 const uint8_t asn1_large_oid1[] = {
457 0x06, 0x0b,
458 0x2b, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
459 0xff, 0xff, 0x7f,
460 };
461
462 /* OID 1.3.18446744073709551616 (65 bits). */
463 const uint8_t asn1_large_oid2[] = {
464 0x06, 0x0b,
465 0x2b, 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
466 0x80, 0x80, 0x00,
467 };
468
469 /* OID 1.3.340282366920938463463374607431768211455 (128 bits). */
470 const uint8_t asn1_large_oid3[] = {
471 0x06, 0x14,
472 0x2b, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
473 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
474 0xff, 0xff, 0xff, 0x7f,
475 };
476
477 /* OID 1.3.115792089237316195423570985008687907853269984665640564039457584007913129639935 (256 bits). */
478 const uint8_t asn1_large_oid4[] = {
479 0x06, 0x26,
480 0x2b, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
481 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
482 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
483 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
484 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
485 };
486
487 struct oid_large_test {
488 const char *oid;
489 const uint8_t *asn1_der;
490 size_t asn1_der_len;
491 int obj2txt;
492 };
493
494 struct oid_large_test oid_large_tests[] = {
495 {
496 .oid = "1.3.18446744073709551615",
497 .asn1_der = asn1_large_oid1,
498 .asn1_der_len = sizeof(asn1_large_oid1),
499 .obj2txt = 1,
500 },
501 {
502 .oid = "1.3.18446744073709551616",
503 .asn1_der = asn1_large_oid2,
504 .asn1_der_len = sizeof(asn1_large_oid2),
505 .obj2txt = 0,
506 },
507 {
508 .oid = "1.3.340282366920938463463374607431768211455",
509 .asn1_der = asn1_large_oid3,
510 .asn1_der_len = sizeof(asn1_large_oid3),
511 .obj2txt = 0,
512 },
513 {
514 .oid = "1.3.115792089237316195423570985008687907853269984665640"
515 "564039457584007913129639935",
516 .asn1_der = asn1_large_oid4,
517 .asn1_der_len = sizeof(asn1_large_oid4),
518 .obj2txt = 0,
519 },
520 };
521
522 #define N_OID_LARGE_TESTS (sizeof(oid_large_tests) / sizeof(*oid_large_tests))
523
524 static int
obj_oid_large_test(size_t test_no,struct oid_large_test * olt)525 obj_oid_large_test(size_t test_no, struct oid_large_test *olt)
526 {
527 ASN1_OBJECT *obj = NULL;
528 const uint8_t *p;
529 char buf[1024];
530 int len;
531 int failed = 1;
532
533 p = olt->asn1_der;
534 if ((obj = d2i_ASN1_OBJECT(NULL, &p, olt->asn1_der_len)) == NULL) {
535 fprintf(stderr, "FAIL: d2i_ASN1_OBJECT() failed for large "
536 "oid %zu\n", test_no);
537 goto failed;
538 }
539 len = OBJ_obj2txt(buf, sizeof(buf), obj, 1);
540 if (len < 0 || (size_t)len >= sizeof(buf)) {
541 fprintf(stderr, "FAIL: OBJ_obj2txt() failed for large "
542 "oid %zu\n", test_no);
543 goto failed;
544 }
545 if ((len != 0) != olt->obj2txt) {
546 fprintf(stderr, "FAIL: OBJ_obj2txt() failed for large "
547 "oid %zu\n", test_no);
548 goto failed;
549 }
550 if (len != 0 && strcmp(buf, olt->oid) != 0) {
551 fprintf(stderr, "FAIL: OBJ_obj2txt() returned '%s', want '%s'\n",
552 buf, olt->oid);
553 goto failed;
554 }
555
556 failed = 0;
557
558 failed:
559 ASN1_OBJECT_free(obj);
560
561 return failed;
562 }
563
564 static int
obj_oid_large_tests(void)565 obj_oid_large_tests(void)
566 {
567 int failed = 0;
568 size_t i;
569
570 for (i = 0; i < N_OID_LARGE_TESTS; i++)
571 failed |= obj_oid_large_test(i, &oid_large_tests[i]);
572
573 return failed;
574 }
575
576 int
main(int argc,char ** argv)577 main(int argc, char **argv)
578 {
579 int failed = 0;
580
581 failed |= obj_name_tests();
582 failed |= obj_nid_tests();
583 failed |= obj_oid_tests();
584 failed |= obj_txt_tests();
585 failed |= obj_oid_large_tests();
586
587 return (failed);
588 }
589