1 /* $OpenBSD: ber_test.c,v 1.20 2019/10/24 12:39:26 tb Exp $ 2 */ 3 /* 4 * Copyright (c) Rob Pierce <rob@openbsd.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 <sys/types.h> 20 21 #include <ber.h> 22 #include <errno.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 #define SUCCEED 0 27 #define FAIL 1 28 29 struct test_vector { 30 int fail; /* 1 means test is expected to fail */ 31 int memcheck; /* 1 when short forms used */ 32 char title[128]; 33 size_t length; 34 unsigned char input[1024]; 35 }; 36 37 struct test_vector test_vectors[] = { 38 { 39 SUCCEED, 40 1, 41 "boolean", 42 3, 43 { 44 0x01, 0x01, 0xff 45 }, 46 }, 47 { 48 FAIL, 49 0, 50 "boolean (constructed - expected failure)", 51 3, 52 { 53 0x21, 0x01, 0xff 54 }, 55 }, 56 { 57 FAIL, 58 0, 59 "boolean (more than 1 content octet - expected failure)", 60 4, 61 { 62 0x01, 0x02, 0x00, 0xff 63 }, 64 }, 65 { 66 SUCCEED, 67 1, 68 "enum", 69 3, 70 { 71 0x0a, 0x01, 0x00 72 }, 73 }, 74 { 75 FAIL, 76 0, 77 "enum (constructed - expected failure)", 78 3, 79 { 80 0x2a, 0x01, 0x00 81 }, 82 }, 83 { 84 FAIL, 85 0, 86 "enum minimal contents octets (expected failure)", 87 4, 88 { 89 0x0a, 0x02, 0x00, 0x01 90 }, 91 }, 92 { 93 SUCCEED, 94 1, 95 "integer (zero)", 96 3, 97 { 98 0x02, 0x01, 0x00 99 }, 100 }, 101 { 102 FAIL, 103 0, 104 "integer (constructed - expected failure)", 105 3, 106 { 107 0x22, 0x01, 0x01 108 }, 109 }, 110 { 111 SUCCEED, 112 1, 113 "positive integer", 114 3, 115 { 116 0x02, 0x01, 0x63 117 }, 118 }, 119 { 120 SUCCEED, 121 1, 122 "large positive integer", 123 5, 124 { 125 0x02, 0x03, 0x01, 0x00, 0x00 126 }, 127 }, 128 { 129 SUCCEED, 130 1, 131 "negative integer", 132 4, 133 { 134 0x02, 0x02, 0xff, 0x7f 135 }, 136 }, 137 { 138 FAIL, 139 0, 140 "integer minimal contents octets (expected failure)", 141 4, 142 { 143 0x02, 0x02, 0x00, 0x01 144 }, 145 }, 146 { 147 SUCCEED, 148 1, 149 "bit string", 150 6, 151 { 152 0x03, 0x04, 0xde, 0xad, 0xbe, 0xef 153 }, 154 }, 155 { 156 SUCCEED, 157 1, 158 "octet string", 159 10, 160 { 161 0x04, 0x08, 0x01, 0x23, 0x45, 162 0x67, 0x89, 0xab, 0xcd, 0xef 163 }, 164 }, 165 { 166 SUCCEED, 167 1, 168 "null", 169 2, 170 { 171 0x05, 0x00 172 }, 173 }, 174 { 175 FAIL, 176 0, 177 "null (constructed - expected failure)", 178 2, 179 { 180 0x25, 0x00 181 }, 182 }, 183 { 184 SUCCEED, 185 1, 186 "object identifier", 187 8, 188 { 189 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d 190 } 191 }, 192 { 193 SUCCEED, 194 1, 195 "sequence", /* ldap */ 196 14, 197 { 198 0x30, 0x0c, 0x02, 0x01, 0x01, 0x60, 0x07, 0x02, 199 0x01, 0x03, 0x04, 0x00, 0x80, 0x00 200 } 201 }, 202 { 203 SUCCEED, 204 1, 205 "ldap bind", 206 30, 207 { 208 0x30, 0x1c, 0x02, 0x01, 0x01, 0x60, 0x17, 0x02, 209 0x01, 0x03, 0x04, 0x08, 0x63, 0x6e, 0x3d, 0x61, 210 0x64, 0x6d, 0x69, 0x6e, 0x80, 0x08, 0x70, 0x61, 211 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64 212 } 213 }, 214 { 215 SUCCEED, 216 1, 217 "ldap search", 218 37, 219 { 220 0x30, 0x23, 0x02, 0x01, 0x01, 0x60, 0x1e, 0x04, 221 0x09, 0x6f, 0x75, 0x3d, 0x70, 0x65, 0x6f, 0x70, 222 0x6c, 0x65, 0x0a, 0x01, 0x00, 0x0a, 0x01, 0x00, 223 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x01, 0x01, 224 0x00, 0x04, 0x02, 0x63, 0x6e 225 } 226 }, 227 { 228 SUCCEED, 229 1, 230 "snmpd encode", 231 15, 232 { 233 0x30, 0x0d, 0x02, 0x01, 0x01, 0x02, 0x02, 0x20, 234 0x00, 0x04, 0x01, 0x01, 0x02, 0x01, 0x03 235 } 236 }, 237 { 238 SUCCEED, 239 1, 240 "set with integer and boolean", 241 8, 242 { 243 0x31, 0x06, 0x02, 0x01, 0x04, 0x01, 0x01, 0xff 244 } 245 }, 246 { 247 FAIL, 248 0, 249 "indefinite encoding (expected failure)", 250 4, 251 { 252 0x30, 0x80, 0x00, 0x00 253 } 254 }, 255 { 256 FAIL, 257 0, 258 "reserved for future use (expected failure)", 259 4, 260 { 261 0x30, 0xff, 0x01, 0x01 262 } 263 }, 264 { 265 FAIL, 266 0, 267 "long form tagging prohibited (expected failure)", 268 5, 269 { 270 0x1f, 0x80, 0x02, 0x01, 0x01 271 }, 272 }, 273 { 274 SUCCEED, 275 0, 276 "max long form length octets (i.e. 4 bytes)", 277 7, 278 { 279 0x02, 0x84, 0x00, 0x00, 0x00, 0x01, 0x01 280 }, 281 }, 282 { 283 FAIL, 284 0, 285 "overflow long form length octets (expected failure)", 286 8, 287 { 288 0x02, 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01 289 }, 290 }, 291 { 292 FAIL, 293 0, 294 "incorrect length - not enough data (expected failure)", 295 3, 296 { 297 0x02, 0x02, 0x01 298 } 299 } 300 }; 301 302 static void 303 hexdump(const unsigned char *buf, size_t len) 304 { 305 size_t i; 306 307 for (i = 1; i < len; i++) 308 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "": "\n"); 309 310 fprintf(stderr, " 0x%02hhx", buf[i - 1]); 311 fprintf(stderr, "\n"); 312 } 313 314 unsigned int 315 ldap_application(struct ber_element *elm) 316 { 317 return BER_TYPE_OCTETSTRING; 318 } 319 320 static int 321 test(int i) 322 { 323 int pos, b; 324 char *string; 325 void *p = NULL; 326 ssize_t len = 0; 327 struct ber_element *elm = NULL, *ptr = NULL; 328 struct ber ber; 329 long long val; 330 void *bstring = NULL; 331 struct ber_oid oid; 332 struct ber_octetstring ostring; 333 334 bzero(&ber, sizeof(ber)); 335 ober_set_readbuf(&ber, test_vectors[i].input, test_vectors[i].length); 336 ober_set_application(&ber, ldap_application); 337 338 elm = ober_read_elements(&ber, elm); 339 if (elm == NULL && test_vectors[i].fail && 340 (errno == EINVAL || errno == ERANGE || errno == ECANCELED)) 341 return 0; 342 else if (elm != NULL && test_vectors[i].fail) { 343 printf("expected failure of ober_read_elements did not occur\n"); 344 return 1; 345 } else if (elm == NULL) { 346 printf("unexpectedly failed ober_read_elements\n"); 347 return 1; 348 } 349 350 /* 351 * short form tagged elements start at the 3rd octet (i.e. position 2). 352 */ 353 if (test_vectors[i].memcheck) { 354 pos = ober_getpos(elm); 355 if (pos != 2) { 356 printf("unexpected element position within " 357 "byte stream\n"); 358 return 1; 359 } 360 } 361 362 switch (elm->be_encoding) { 363 case BER_TYPE_EOC: 364 if (ober_get_eoc(elm) == -1) { 365 printf("failed (eoc) encoding check\n"); 366 return 1; 367 } 368 if (ober_scanf_elements(elm, ".", &val) == -1) { 369 printf("failed (eoc) ober_scanf_elements\n"); 370 return 1; 371 } 372 break; 373 case BER_TYPE_BOOLEAN: 374 if (ober_get_boolean(elm, &b) == -1) { 375 printf("failed (boolean) encoding check\n"); 376 return 1; 377 } 378 if (ober_scanf_elements(elm, "b", &b) == -1) { 379 printf("failed (boolean) ober_scanf_elements\n"); 380 return 1; 381 } 382 break; 383 case BER_TYPE_INTEGER: 384 if (ober_get_integer(elm, &val) == -1) { 385 printf("failed (int) encoding check\n"); 386 return 1; 387 } 388 if (ober_scanf_elements(elm, "i", &val) == -1) { 389 printf("failed (int) ober_scanf_elements (i)\n"); 390 return 1; 391 } 392 if (ober_scanf_elements(elm, "d", &val) == -1) { 393 printf("failed (int) ober_scanf_elements (d)\n"); 394 return 1; 395 } 396 break; 397 case BER_TYPE_ENUMERATED: 398 if (ober_get_enumerated(elm, &val) == -1) { 399 printf("failed (enum) encoding check\n"); 400 return 1; 401 } 402 if (ober_scanf_elements(elm, "E", &val) == -1) { 403 printf("failed (enum) ober_scanf_elements (E)\n"); 404 return 1; 405 } 406 break; 407 case BER_TYPE_BITSTRING: 408 if (ober_get_bitstring(elm, &bstring, &len) == -1) { 409 printf("failed (bit string) encoding check\n"); 410 return 1; 411 } 412 break; 413 case BER_TYPE_OCTETSTRING: 414 if (ober_get_ostring(elm, &ostring) == -1) { 415 printf("failed (octet string) encoding check\n"); 416 return 1; 417 } 418 if (ober_scanf_elements(elm, "s", &string) == -1) { 419 printf("failed (octet string) ober_scanf_elements\n"); 420 return 1; 421 } 422 break; 423 case BER_TYPE_NULL: 424 if (ober_get_null(elm) == -1) { 425 printf("failed (null) encoding check\n"); 426 return 1; 427 } 428 if (ober_scanf_elements(elm, "0", &val) == -1) { 429 printf("failed (null) ober_scanf_elements\n"); 430 return 1; 431 } 432 break; 433 case BER_TYPE_OBJECT: /* OID */ 434 if (ober_get_oid(elm, &oid) == -1) { 435 printf("failed (oid) encoding check\n"); 436 return 1; 437 } 438 if (ober_scanf_elements(elm, "o", &oid) == -1) { 439 printf("failed (oid) ober_scanf_elements\n"); 440 return 1; 441 } 442 break; 443 case BER_TYPE_SET: 444 case BER_TYPE_SEQUENCE: 445 if (elm->be_sub != NULL) { 446 ptr = elm->be_sub; 447 if (ober_getpos(ptr) <= pos) { 448 printf("unexpected element position within " 449 "byte stream\n"); 450 return 1; 451 } 452 } else { 453 printf("expected sub element was not present\n"); 454 return 1; 455 } 456 break; 457 default: 458 printf("failed with unknown encoding (%ud)\n", 459 elm->be_encoding); 460 return 1; 461 } 462 463 /* 464 * additional testing on short form encoding 465 */ 466 if (test_vectors[i].memcheck) { 467 len = ober_calc_len(elm); 468 if (len != test_vectors[i].length) { 469 printf("failed to calculate length\n"); 470 return 1; 471 } 472 473 ber.br_wbuf = NULL; 474 len = ober_write_elements(&ber, elm); 475 if (len != test_vectors[i].length) { 476 printf("failed length check (was %zd want " 477 "%zd)\n", len, test_vectors[i].length); 478 return 1; 479 } 480 481 if (memcmp(ber.br_wbuf, test_vectors[i].input, 482 test_vectors[i].length) != 0) { 483 printf("failed byte stream compare\n"); 484 printf("Got:\n"); 485 hexdump(ber.br_wbuf, len); 486 printf("Expected:\n"); 487 hexdump(test_vectors[i].input, test_vectors[i].length); 488 return 1; 489 } 490 ober_free(&ber); 491 492 } 493 ober_free_elements(elm); 494 495 return 0; 496 } 497 498 int 499 test_ber_printf_elements_integer(void) { 500 int val = 1, len = 0; 501 struct ber_element *elm = NULL; 502 struct ber ber; 503 504 unsigned char exp[3] = { 0x02, 0x01, 0x01 }; 505 506 elm = ober_printf_elements(elm, "d", val); 507 if (elm == NULL) { 508 printf("failed ober_printf_elements\n"); 509 return 1; 510 } 511 512 bzero(&ber, sizeof(ber)); 513 ber.br_wbuf = NULL; 514 len = ober_write_elements(&ber, elm); 515 if (len != sizeof(exp)) { 516 printf("failed length check (was %d want %zd)\n", len, 517 sizeof(exp)); 518 return 1; 519 } 520 521 if (memcmp(ber.br_wbuf, exp, len) != 0) { 522 printf("failed (int) byte stream compare\n"); 523 return 1; 524 } 525 526 ober_free_elements(elm); 527 ober_free(&ber); 528 return 0; 529 } 530 531 #define LDAP_REQ_BIND 0 532 #define LDAP_REQ_SEARCH 0 533 #define VERSION 3 534 #define LDAP_AUTH_SIMPLE 0 535 536 int 537 test_ber_printf_elements_ldap_bind(void) { 538 int len = 0, msgid = 1; 539 char *binddn = "cn=admin"; 540 char *bindcred = "password"; 541 struct ber_element *root = NULL, *elm = NULL; 542 struct ber ber; 543 544 unsigned char exp[] = { 545 0x30, 0x1c, 546 0x02, 0x01, 0x01, 547 0x60, 0x17, 548 0x02, 0x01, 0x03, 549 0x04, 0x08, 0x63, 0x6e, 0x3d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 550 0x80, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64 551 }; 552 553 if ((root = ober_add_sequence(NULL)) == NULL) 554 return 1; 555 556 elm = ober_printf_elements(root, "d{tdsst", msgid, 557 BER_CLASS_APP, LDAP_REQ_BIND, 558 VERSION, 559 binddn, bindcred, 560 BER_CLASS_CONTEXT, LDAP_AUTH_SIMPLE); 561 562 if (elm == NULL) { 563 printf("failed ober_printf_elements\n"); 564 return 1; 565 } 566 567 bzero(&ber, sizeof(ber)); 568 ber.br_wbuf = NULL; 569 ober_set_application(&ber, ldap_application); 570 len = ober_write_elements(&ber, root); 571 if (len != sizeof(exp)) { 572 printf("failed length check (was %d want %zd)\n", len, 573 sizeof(exp)); 574 return 1; 575 } 576 577 if (memcmp(ber.br_wbuf, exp, len) != 0) { 578 printf("failed (ldap bind) byte stream compare\n"); 579 hexdump(ber.br_wbuf, len); 580 return 1; 581 } 582 583 ober_free_elements(elm); 584 ober_free(&ber); 585 return 0; 586 } 587 588 int 589 test_ber_printf_elements_ldap_search(void) { 590 int len = 0, msgid = 1; 591 int sizelimit = 0, timelimit = 0; 592 int typesonly = 0; 593 long long scope = 0, deref = 0; 594 char *basedn = "ou=people"; 595 char *filter = "cn"; 596 struct ber_element *root = NULL, *elm = NULL, *felm = NULL; 597 struct ber ber; 598 599 unsigned char exp[] = { 600 0x30, 0x23, 0x02, 0x01, 0x01, 0x60, 0x1e, 0x04, 601 0x09, 0x6f, 0x75, 0x3d, 0x70, 0x65, 0x6f, 0x70, 602 0x6c, 0x65, 0x0a, 0x01, 0x00, 0x0a, 0x01, 0x00, 603 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x01, 0x01, 604 0x00, 0x04, 0x02, 0x63, 0x6e 605 }; 606 607 if ((root = ober_add_sequence(NULL)) == NULL) 608 return 1; 609 610 elm = ober_printf_elements(root, "d{tsEEddbs", 611 msgid, BER_CLASS_APP, LDAP_REQ_SEARCH, 612 basedn, scope, deref, sizelimit, timelimit, typesonly, filter); 613 if (elm == NULL) { 614 printf("failed ober_printf_elements\n"); 615 return 1; 616 } 617 618 bzero(&ber, sizeof(ber)); 619 ber.br_wbuf = NULL; 620 ober_set_application(&ber, ldap_application); 621 len = ober_write_elements(&ber, root); 622 if (len != sizeof(exp)) { 623 printf("failed length check (was %d want %zd)\n", len, 624 sizeof(exp)); 625 return 1; 626 } 627 628 if (memcmp(ber.br_wbuf, exp, len) != 0) { 629 printf("failed (ldap search) byte stream compare\n"); 630 hexdump(ber.br_wbuf, len); 631 return 1; 632 } 633 634 ober_free_elements(elm); 635 ober_free(&ber); 636 return 0; 637 } 638 639 int 640 test_ber_printf_elements_snmp_v3_encode(void) { 641 int len = 0; 642 u_int8_t f = 0x01; /* verbose */ 643 long long secmodel = 3; /* USM */ 644 long long msgid = 1, max_msg_size = 8192; 645 struct ber_element *elm = NULL; 646 struct ber ber; 647 648 unsigned char exp[] = { 649 0x30, 0x0d, 0x02, 0x01, 0x01, 0x02, 0x02, 0x20, 650 0x00, 0x04, 0x01, 0x01, 0x02, 0x01, 0x03 651 }; 652 653 elm = ober_printf_elements(elm, "{iixi}", msgid, max_msg_size, 654 &f, sizeof(f), secmodel); 655 if (elm == NULL) { 656 printf("failed ober_printf_elements\n"); 657 return 1; 658 } 659 660 bzero(&ber, sizeof(ber)); 661 ber.br_wbuf = NULL; 662 len = ober_write_elements(&ber, elm); 663 if (len != sizeof(exp)) { 664 printf("failed length check (was %d want %zd)\n", len, 665 sizeof(exp)); 666 return 1; 667 } 668 669 if (memcmp(ber.br_wbuf, exp, len) != 0) { 670 printf("failed (snmp_v3_encode) byte stream compare\n"); 671 hexdump(ber.br_wbuf, len); 672 return 1; 673 } 674 675 ober_free_elements(elm); 676 ober_free(&ber); 677 return 0; 678 } 679 680 int 681 test_ber_null(void) 682 { 683 long long val; 684 struct ber_element *elm = NULL; 685 686 /* scanning into a null ber_element should fail */ 687 if (ober_scanf_elements(elm, "0", &val) != -1) { 688 printf("failed (null ber_element) ober_scanf_elements empty\n"); 689 goto fail; 690 } 691 692 if ((elm = ober_printf_elements(elm, "{d}", 1)) == NULL) { 693 printf("failed (null ber_element) ober_printf_elements\n"); 694 } 695 696 /* 697 * Scanning after the last valid element should be able to descend back 698 * into the parent level. 699 */ 700 if (ober_scanf_elements(elm, "{i}", &val) != 0) { 701 printf("failed (null ber_element) ober_scanf_elements valid\n"); 702 goto fail; 703 } 704 /* 705 * Scanning for a non-existent element should fail, even if it's just a 706 * skip. 707 */ 708 if (ober_scanf_elements(elm, "{lS}", &val) != -1) { 709 printf("failed (null ber_element) ober_scanf_elements invalid\n"); 710 goto fail; 711 } 712 713 ober_free_elements(elm); 714 return 0; 715 716 fail: 717 ober_free_elements(elm); 718 return 1; 719 } 720 721 int 722 main(void) 723 { 724 extern char *__progname; 725 726 ssize_t len = 0; 727 int i, ret = 0; 728 729 /* 730 * drive test vectors for ber byte stream input validation, etc. 731 */ 732 for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) { 733 if (test(i) != 0) { 734 printf("FAILED: %s\n", test_vectors[i].title); 735 ret = 1; 736 } else 737 printf("SUCCESS: %s\n", test_vectors[i].title); 738 } 739 740 /* 741 * run standalone functions for ber byte stream creation, etc. 742 * (e.g. ldap, snmpd) 743 */ 744 if (test_ber_printf_elements_integer() != 0) { 745 printf("FAILED: test_ber_printf_elements_integer\n"); 746 ret = 1; 747 } else 748 printf("SUCCESS: test_ber_printf_elements_integer\n"); 749 750 if (test_ber_printf_elements_ldap_bind() != 0) { 751 printf("FAILED: test_ber_printf_elements_ldap_bind\n"); 752 ret = 1; 753 } else 754 printf("SUCCESS: test_ber_printf_elements_ldap_bind\n"); 755 756 if (test_ber_printf_elements_ldap_search() != 0) { 757 printf("FAILED: test_ber_printf_elements_ldap_search\n"); 758 ret = 1; 759 } else 760 printf("SUCCESS: test_ber_printf_elements_ldap_search\n"); 761 762 if (test_ber_printf_elements_snmp_v3_encode() != 0) { 763 printf("FAILED: test_ber_printf_elements_snmpd_v3_encode\n"); 764 ret = 1; 765 } else 766 printf("SUCCESS: test_ber_printf_elements_snmpd_v3_encode\n"); 767 768 if (test_ber_null() != 0) { 769 printf("FAILED: test_ber_null\n"); 770 ret = 1; 771 } else 772 printf("SUCCESS: test_ber_null\n"); 773 774 if (ret != 0) { 775 printf("FAILED: %s\n", __progname); 776 return 1; 777 } 778 779 return 0; 780 } 781