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