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 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_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 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 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 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 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