1 /* $OpenBSD: x509_extensions_test.c,v 1.3 2024/06/17 05:04:54 tb Exp $ */ 2 3 /* 4 * Copyright (c) 2024 Theo Buehler <tb@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 <err.h> 20 #include <stdio.h> 21 22 #include <openssl/asn1.h> 23 #include <openssl/err.h> 24 #include <openssl/x509.h> 25 #include <openssl/x509v3.h> 26 27 #define ASN1_BOOLEAN_TRUE 0xff 28 #define ASN1_BOOLEAN_FALSE 0x00 29 30 #define X509V3_EXT_CRITICAL 1 31 #define X509V3_EXT_NONCRITICAL 0 32 33 static BASIC_CONSTRAINTS * 34 create_basic_constraints(int ca) 35 { 36 BASIC_CONSTRAINTS *bc; 37 38 if ((bc = BASIC_CONSTRAINTS_new()) == NULL) 39 errx(1, "BASIC_CONSTRAINTS_new"); 40 41 bc->ca = ca ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE; 42 43 return bc; 44 } 45 46 static X509_EXTENSION * 47 ext_create_basic_constraints(int ca, int critical) 48 { 49 X509_EXTENSION *ext; 50 BASIC_CONSTRAINTS *bc; 51 52 bc = create_basic_constraints(ca); 53 if ((ext = X509V3_EXT_i2d(NID_basic_constraints, critical, bc)) == NULL) 54 errx(1, "X509V3_EXT_i2d"); 55 BASIC_CONSTRAINTS_free(bc); 56 57 return ext; 58 } 59 60 static int 61 test_x509v3_add1_i2d_empty_stack(STACK_OF(X509_EXTENSION) **extensions) 62 { 63 unsigned long error; 64 int op, got; 65 int nid = NID_basic_constraints; 66 int failed = 1; 67 68 if (X509v3_get_ext_count(*extensions) != 0) { 69 fprintf(stderr, "%s: FAIL: need empty stack\n", __func__); 70 goto err; 71 } 72 73 ERR_clear_error(); 74 75 op = X509V3_ADD_REPLACE_EXISTING; 76 77 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) { 78 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING " 79 "want %d, got %d.\n", __func__, 0, got); 80 goto err; 81 } 82 83 error = ERR_get_error(); 84 if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_NOT_FOUND) { 85 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING " 86 "pushed %d for empty stack, want %d.\n", __func__, 87 ERR_GET_REASON(error), X509V3_R_EXTENSION_NOT_FOUND); 88 goto err; 89 } 90 if ((error = ERR_get_error()) != 0) { 91 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING " 92 "expected exactly one error.\n", __func__); 93 goto err; 94 } 95 96 op = X509V3_ADD_REPLACE_EXISTING | X509V3_ADD_SILENT; 97 98 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) { 99 fprintf(stderr, "%s: FAIL: silent X509V3_ADD_REPLACE_EXISTING " 100 "want %d, got %d.\n", __func__, 0, got); 101 goto err; 102 } 103 if ((error = ERR_get_error()) != 0) { 104 fprintf(stderr, "%s: FAIL: silent X509V3_ADD_REPLACE_EXISTING " 105 "added error %d, want %d.\n", __func__, 106 ERR_GET_REASON(error), 0); 107 goto err; 108 } 109 110 op = X509V3_ADD_DELETE; 111 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) { 112 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 113 "want %d, got %d.\n", __func__, 0, got); 114 goto err; 115 } 116 117 error = ERR_get_error(); 118 if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_NOT_FOUND) { 119 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 120 "pushed %d for empty stack, want %d.\n", __func__, 121 ERR_GET_REASON(error), X509V3_R_EXTENSION_NOT_FOUND); 122 goto err; 123 } 124 125 if ((error = ERR_get_error()) != 0) { 126 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 127 "expected exactly one error.\n", __func__); 128 goto err; 129 } 130 131 failed = 0; 132 133 err: 134 135 return failed; 136 } 137 138 static int 139 test_x509v3_add1_i2d_single_nid(STACK_OF(X509_EXTENSION) **extensions) 140 { 141 BASIC_CONSTRAINTS *bc = NULL; 142 unsigned long error; 143 int crit, got, nid, op; 144 int failed = 1; 145 146 if (X509v3_get_ext_count(*extensions) != 0) { 147 fprintf(stderr, "%s: FAIL: need an empty stack.\n", __func__); 148 goto err; 149 } 150 151 /* 152 * Add basic ca constraints. 153 */ 154 155 nid = NID_basic_constraints; 156 bc = create_basic_constraints(1); 157 op = X509V3_ADD_DEFAULT; 158 if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) { 159 fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT failed to add " 160 "basic constraints to empty stack: want %d, got %d.\n", 161 __func__, 1, got); 162 goto err; 163 } 164 BASIC_CONSTRAINTS_free(bc); 165 bc = NULL; 166 167 if ((got = X509v3_get_ext_count(*extensions)) != 1) { 168 fprintf(stderr, "%s: FAIL: expected 1 extension, have %d.\n", 169 __func__, got); 170 goto err; 171 } 172 173 /* 174 * Can't delete or replace non-existent extension. 175 */ 176 177 nid = NID_policy_constraints; 178 op = X509V3_ADD_DELETE; 179 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) { 180 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE non-existent " 181 "want %d, got %d,\n", __func__, 0, got); 182 goto err; 183 } 184 nid = NID_policy_constraints; 185 op = X509V3_ADD_REPLACE_EXISTING; 186 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 0) { 187 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING non-existent " 188 "want %d, got %d.\n", __func__, 0, got); 189 goto err; 190 } 191 192 /* 193 * X509V3_ADD_DEFAULT refuses to add second basic constraints extension. 194 */ 195 196 ERR_clear_error(); 197 198 nid = NID_basic_constraints; 199 bc = create_basic_constraints(0); 200 op = X509V3_ADD_DEFAULT; 201 if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 0) { 202 fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second constraints " 203 "want %d, got %d.\n", __func__, 0, got); 204 goto err; 205 } 206 BASIC_CONSTRAINTS_free(bc); 207 bc = NULL; 208 209 error = ERR_get_error(); 210 if (ERR_GET_REASON(error) != X509V3_R_EXTENSION_EXISTS) { 211 fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second constraints " 212 " pushed %d, want %d.\n", __func__, 213 ERR_GET_REASON(error), X509V3_R_EXTENSION_EXISTS); 214 goto err; 215 } 216 217 if ((got = X509v3_get_ext_count(*extensions)) != 1) { 218 fprintf(stderr, "%s: FAIL: X509V3_ADD_DEFAULT second contraints " 219 "expected 1 extension, have %d.\n", __func__, got); 220 goto err; 221 } 222 223 /* 224 * We can replace existing basic constraints using X509V3_ADD_REPLACE. 225 */ 226 227 nid = NID_basic_constraints; 228 bc = create_basic_constraints(0); 229 op = X509V3_ADD_REPLACE; 230 if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) { 231 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 232 "want %d, got %d.\n", __func__, 1, got); 233 goto err; 234 } 235 BASIC_CONSTRAINTS_free(bc); 236 bc = NULL; 237 238 if ((got = X509v3_get_ext_count(*extensions)) != 1) { 239 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 240 "expected 1 extension, have %d.\n", __func__, got); 241 goto err; 242 } 243 244 /* Check that the extension was actually replaced. */ 245 nid = NID_basic_constraints; 246 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) { 247 if (crit != -1) 248 errx(1, "X509V3_get_d2i"); 249 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 250 "expected basic constraints\n", __func__); 251 goto err; 252 } 253 if (bc->ca != ASN1_BOOLEAN_FALSE) { 254 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 255 "expected cA = false in basic constraints\n", __func__); 256 goto err; 257 } 258 BASIC_CONSTRAINTS_free(bc); 259 bc = NULL; 260 261 /* 262 * X509V3_ADD_KEEP_EXISTING existing does what it is supposed to do 263 * if basic constraints are already present. 264 */ 265 266 nid = NID_basic_constraints; 267 bc = create_basic_constraints(1); 268 op = X509V3_ADD_KEEP_EXISTING; 269 if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) { 270 fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING " 271 "want %d, got %d.\n", __func__, 1, got); 272 goto err; 273 } 274 BASIC_CONSTRAINTS_free(bc); 275 bc = NULL; 276 277 /* 278 * Check we still have non-ca basic constraints. 279 */ 280 281 nid = NID_basic_constraints; 282 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) { 283 if (crit != -1) 284 errx(1, "X509V3_get_d2i"); 285 fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING " 286 "expected basic constraints\n", __func__); 287 goto err; 288 } 289 if (bc->ca != ASN1_BOOLEAN_FALSE) { 290 fprintf(stderr, "%s: FAIL: X509V3_ADD_KEEP_EXISTING " 291 "expected non-ca basic constraints\n", __func__); 292 goto err; 293 } 294 BASIC_CONSTRAINTS_free(bc); 295 bc = NULL; 296 297 /* 298 * X509V3_ADD_REPLACE_EXISTING also works. 299 */ 300 301 nid = NID_basic_constraints; 302 bc = create_basic_constraints(1); 303 op = X509V3_ADD_REPLACE_EXISTING; 304 if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) { 305 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING " 306 "want %d, got %d.\n", __func__, 1, got); 307 goto err; 308 } 309 BASIC_CONSTRAINTS_free(bc); 310 bc = NULL; 311 312 /* 313 * Check we again have ca basic constraints. 314 */ 315 316 nid = NID_basic_constraints; 317 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, NULL)) == NULL) { 318 if (crit != -1) 319 errx(1, "X509V3_get_d2i"); 320 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING " 321 "expected basic constraints\n", __func__); 322 goto err; 323 } 324 if (bc->ca != ASN1_BOOLEAN_TRUE) { 325 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE_EXISTING " 326 "expected ca basic constraints\n", __func__); 327 goto err; 328 } 329 BASIC_CONSTRAINTS_free(bc); 330 bc = NULL; 331 332 /* 333 * And X509V3_ADD_DELETE now works. 334 */ 335 336 nid = NID_basic_constraints; 337 op = X509V3_ADD_DELETE; 338 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) { 339 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 340 "want %d, got %d.\n", __func__, 0, got); 341 goto err; 342 } 343 344 if ((got = X509v3_get_ext_count(*extensions)) != 0) { 345 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 346 "expected 0 extensions, have %d.\n", __func__, got); 347 goto err; 348 } 349 350 /* 351 * X509V3_ADD_REPLACE adds the extension to empty stack as it should. 352 */ 353 354 nid = NID_basic_constraints; 355 bc = create_basic_constraints(0); 356 op = X509V3_ADD_REPLACE; 357 if ((got = X509V3_add1_i2d(extensions, nid, bc, 1, op)) != 1) { 358 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE on empty stack " 359 "want %d, got %d.\n", __func__, 1, got); 360 goto err; 361 } 362 BASIC_CONSTRAINTS_free(bc); 363 bc = NULL; 364 365 if ((got = X509v3_get_ext_count(*extensions)) != 1) { 366 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 367 "expected 1 extension, have %d.\n", __func__, got); 368 goto err; 369 } 370 371 /* 372 * And X509V3_ADD_DELETE works again. 373 */ 374 375 nid = NID_basic_constraints; 376 op = X509V3_ADD_DELETE; 377 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) { 378 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE after add replace " 379 "want %d, got %d.\n", __func__, 0, got); 380 goto err; 381 } 382 383 if ((got = X509v3_get_ext_count(*extensions)) != 0) { 384 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 385 "expected 0 extensions, have %d.\n", __func__, got); 386 goto err; 387 } 388 389 failed = 0; 390 391 err: 392 BASIC_CONSTRAINTS_free(bc); 393 394 return failed; 395 } 396 397 static int 398 test_x509v3_add1_i2d_add_append(STACK_OF(X509_EXTENSION) **extensions) 399 { 400 BASIC_CONSTRAINTS *bc = NULL; 401 int crit, got, idx, nid, op; 402 int failed = 1; 403 404 if (X509v3_get_ext_count(*extensions) != 0) { 405 fprintf(stderr, "%s: FAIL: need empty stack.\n", __func__); 406 goto err; 407 } 408 409 /* 410 * Let the toolkit add two basic constraints extensions. 411 */ 412 413 nid = NID_basic_constraints; 414 bc = create_basic_constraints(1); 415 crit = 1; 416 op = X509V3_ADD_APPEND; 417 if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) { 418 fprintf(stderr, "%s: FAIL: first X509V3_ADD_APPEND " 419 "want %d, got %d.\n", __func__, 0, got); 420 goto err; 421 } 422 BASIC_CONSTRAINTS_free(bc); 423 bc = NULL; 424 425 nid = NID_basic_constraints; 426 bc = create_basic_constraints(0); 427 crit = 1; 428 op = X509V3_ADD_APPEND; 429 if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) { 430 fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND " 431 "want %d, got %d.\n", __func__, 0, got); 432 goto err; 433 } 434 BASIC_CONSTRAINTS_free(bc); 435 bc = NULL; 436 437 if ((got = X509v3_get_ext_count(*extensions)) != 2) { 438 fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND " 439 "expected 2 extensions, have %d.\n", __func__, got); 440 goto err; 441 } 442 443 /* 444 * Inspect the extensions on the stack. First we should get the one 445 * with the ca bit set and it should be critical. 446 */ 447 448 nid = NID_basic_constraints; 449 idx = -1; 450 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) { 451 fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND " 452 "expected basic constraints.\n", __func__); 453 goto err; 454 } 455 if (bc->ca != ASN1_BOOLEAN_TRUE) { 456 fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND " 457 "expected ca basic constraints.\n", __func__); 458 goto err; 459 } 460 if (crit != 1) { 461 fprintf(stderr, "%s: FAIL: X509V3_ADD_APPEND " 462 "expected critical basic constraints.\n", __func__); 463 goto err; 464 } 465 BASIC_CONSTRAINTS_free(bc); 466 bc = NULL; 467 468 /* Redo the exercise and get the basic constraints with ca bit unset. */ 469 nid = NID_basic_constraints; 470 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) { 471 fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND " 472 "expected basic constraints.\n", __func__); 473 goto err; 474 } 475 if (bc->ca != ASN1_BOOLEAN_FALSE) { 476 fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND " 477 "expected basic constraints to be non-ca.\n", __func__); 478 goto err; 479 } 480 if (crit != 1) { 481 fprintf(stderr, "%s: FAIL: second X509V3_ADD_APPEND " 482 "expected critical basic constraints.\n", __func__); 483 goto err; 484 } 485 BASIC_CONSTRAINTS_free(bc); 486 bc = NULL; 487 488 /* 489 * Now X509V3_ADD_REPLACE non-critical ca constraints. They should 490 * replace the critical ca constraints we added before. 491 */ 492 493 nid = NID_basic_constraints; 494 bc = create_basic_constraints(1); 495 crit = 0; 496 op = X509V3_ADD_REPLACE; 497 if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != 1) { 498 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 499 "want %d, got %d\n", __func__, 1, got); 500 goto err; 501 } 502 BASIC_CONSTRAINTS_free(bc); 503 bc = NULL; 504 505 /* 506 * If we get basic constraints now, we get the non-critical one with the 507 * ca bit set. 508 */ 509 510 nid = NID_basic_constraints; 511 idx = -1; 512 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) { 513 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 514 "expected basic constraints.\n", __func__); 515 goto err; 516 } 517 if (bc->ca != ASN1_BOOLEAN_TRUE) { 518 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 519 "expected ca basic constraints.\n", __func__); 520 goto err; 521 } 522 if (crit != 0) { 523 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 524 "expected non-critical basic constraints.\n", __func__); 525 goto err; 526 } 527 BASIC_CONSTRAINTS_free(bc); 528 bc = NULL; 529 530 if ((got = X509v3_get_ext_count(*extensions)) != 2) { 531 fprintf(stderr, "%s: FAIL: X509V3_ADD_REPLACE " 532 "expected 2 extensions, got %d.\n", __func__, got); 533 goto err; 534 } 535 536 nid = NID_basic_constraints; 537 op = X509V3_ADD_DELETE; 538 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) { 539 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 540 "want %d, got %d\n", __func__, 1, got); 541 goto err; 542 } 543 544 if ((got = X509v3_get_ext_count(*extensions)) != 1) { 545 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 546 "expected 1 extension, got %d.\n", __func__, got); 547 goto err; 548 } 549 550 /* The last deletion will have left the critical non-ca constraints. */ 551 nid = NID_basic_constraints; 552 idx = -1; 553 if ((bc = X509V3_get_d2i(*extensions, nid, &crit, &idx)) == NULL) { 554 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 555 "expected basic constraints.\n", __func__); 556 goto err; 557 } 558 if (bc->ca != ASN1_BOOLEAN_FALSE) { 559 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 560 "expected ca basic constraints.\n", __func__); 561 goto err; 562 } 563 if (crit != 1) { 564 fprintf(stderr, "%s: FAIL: X509V3_ADD_DELETE " 565 "expected critical basic constraints.\n", __func__); 566 goto err; 567 } 568 BASIC_CONSTRAINTS_free(bc); 569 bc = NULL; 570 571 /* Now delete the last extension. */ 572 nid = NID_basic_constraints; 573 op = X509V3_ADD_DELETE; 574 if ((got = X509V3_add1_i2d(extensions, nid, NULL, 0, op)) != 1) { 575 fprintf(stderr, "%s: FAIL: second X509V3_ADD_DELETE " 576 "want %d, got %d\n", __func__, 1, got); 577 goto err; 578 } 579 580 if ((got = X509v3_get_ext_count(*extensions)) != 0) { 581 fprintf(stderr, "%s: FAIL: second X509V3_ADD_DELETE " 582 "expected 0 extensions, got %d.\n", __func__, got); 583 goto err; 584 } 585 586 failed = 0; 587 588 err: 589 BASIC_CONSTRAINTS_free(bc); 590 591 return failed; 592 } 593 594 static int 595 test_x509v3_add1_i2d_invalid_operations(STACK_OF(X509_EXTENSION) **extensions) 596 { 597 BASIC_CONSTRAINTS *bc = NULL; 598 long error; 599 int crit, got, nid, op; 600 int failed = 1; 601 602 if (X509v3_get_ext_count(*extensions) != 0) { 603 fprintf(stderr, "%s: FAIL: need empty stack.\n", __func__); 604 goto err; 605 } 606 607 /* 608 * Attempt to add a basic constraint extension with invalid operations 609 */ 610 611 nid = NID_basic_constraints; 612 bc = create_basic_constraints(1); 613 crit = 1; 614 for (op = X509V3_ADD_DELETE + 1; op <= X509V3_ADD_OP_MASK; op++) { 615 if ((got = X509V3_add1_i2d(extensions, nid, bc, crit, op)) != -1) { 616 fprintf(stderr, "%s: FAIL: operation %d " 617 "want %d, got %d.\n", __func__, op, -1, got); 618 goto err; 619 } 620 error = ERR_get_error(); 621 if (ERR_GET_REASON(error) != X509V3_R_UNSUPPORTED_OPTION) { 622 fprintf(stderr, "%s: FAIL: invalid operation %d " 623 " pushed %d, want %d.\n", __func__, op, 624 ERR_GET_REASON(error), X509V3_R_EXTENSION_EXISTS); 625 goto err; 626 } 627 } 628 BASIC_CONSTRAINTS_free(bc); 629 bc = NULL; 630 631 if ((got = X509v3_get_ext_count(*extensions)) != 0) { 632 fprintf(stderr, "%s: FAIL: expected 0 extensions, have %d.\n", 633 __func__, got); 634 goto err; 635 } 636 637 failed = 0; 638 639 err: 640 BASIC_CONSTRAINTS_free(bc); 641 642 return failed; 643 } 644 645 static int 646 test_x509v3_add1_i2d(void) 647 { 648 STACK_OF(X509_EXTENSION) *extensions; 649 int failed = 0; 650 651 if ((extensions = sk_X509_EXTENSION_new_null()) == NULL) 652 errx(1, "sk_X509_EXTENSION_new_null"); 653 654 failed |= test_x509v3_add1_i2d_empty_stack(&extensions); 655 failed |= test_x509v3_add1_i2d_single_nid(&extensions); 656 failed |= test_x509v3_add1_i2d_add_append(&extensions); 657 failed |= test_x509v3_add1_i2d_invalid_operations(&extensions); 658 659 sk_X509_EXTENSION_pop_free(extensions, X509_EXTENSION_free); 660 661 return failed; 662 } 663 664 static int 665 test_x509v3_get_d2i_null(void) 666 { 667 X509_EXTENSION *ext; 668 int crit, idx; 669 int failed = 1; 670 671 if ((ext = X509V3_get_d2i(NULL, NID_undef, NULL, NULL)) != NULL) { 672 fprintf(stderr, "FAIL: %s: expected X509V3_get_d2i with three " 673 "NULL arguments to return NULL\n", __func__); 674 goto err; 675 } 676 677 idx = -5; 678 if (X509V3_get_d2i(NULL, NID_undef, &crit, &idx) != NULL) { 679 /* Leaks whatever garbage libcrypto decoded. What to do... */ 680 fprintf(stderr, "FAIL: %s: expected X509V3_get_d2i NULL stack" 681 "to return NULL\n", __func__); 682 goto err; 683 } 684 685 if (crit != -1 || idx != -1) { 686 fprintf(stderr, "FAIL: %s: crit: want: %d, got: %d; " 687 "idx: want: %d, got: %d\n", __func__, -1, crit, -1, idx); 688 goto err; 689 } 690 691 failed = 0; 692 693 err: 694 X509_EXTENSION_free(ext); 695 696 return failed; 697 } 698 699 static int 700 test_x509v3_get_d2i_multiple_basic_constraints(void) 701 { 702 STACK_OF(X509_EXTENSION) *exts = NULL; 703 ASN1_BIT_STRING *abs = NULL; 704 BASIC_CONSTRAINTS *bc = NULL; 705 X509_EXTENSION *ext; 706 int crit, idx; 707 int ca, nid; 708 int failed = 1; 709 710 /* 711 * Create extension stack containing three basic constraints extensions: 712 * 1. critical CA basic constraints, 713 * 2. non-critical CA basic constraints, 714 * 3. critical non-CA basic constraints. 715 */ 716 717 if ((exts = sk_X509_EXTENSION_new_null()) == NULL) 718 errx(1, "sk_X509_EXTENSION_new_null"); 719 720 ca = 1; 721 ext = ext_create_basic_constraints(ca, X509V3_EXT_CRITICAL); 722 723 if (sk_X509_EXTENSION_push(exts, ext) <= 0) 724 errx(1, "sk_X509_EXTENSION_push"); 725 ext = NULL; 726 727 ca = 1; 728 ext = ext_create_basic_constraints(ca, X509V3_EXT_NONCRITICAL); 729 730 if (sk_X509_EXTENSION_push(exts, ext) <= 0) 731 errx(1, "sk_X509_EXTENSION_push"); 732 ext = NULL; 733 734 ca = 0; 735 ext = ext_create_basic_constraints(ca, X509V3_EXT_CRITICAL); 736 737 if (sk_X509_EXTENSION_push(exts, ext) <= 0) 738 errx(1, "sk_X509_EXTENSION_push"); 739 ext = NULL; 740 741 /* 742 * There is no key usage in this stack, so we shouldn't find any. 743 */ 744 745 nid = NID_key_usage; 746 if ((abs = X509V3_get_d2i(exts, nid, &crit, NULL)) != NULL) { 747 fprintf(stderr, "FAIL: %s: found key usage extension\n", 748 __func__); 749 goto err; 750 } 751 if (crit != -1) { 752 fprintf(stderr, "FAIL: %s: key usage: crit: want %d, got %d\n", 753 __func__, -1, crit); 754 goto err; 755 } 756 757 /* 758 * If we pass no idx and look for basic constraints, 759 * we should fail with crit == -2. 760 */ 761 762 nid = NID_basic_constraints; 763 if ((bc = X509V3_get_d2i(exts, nid, &crit, NULL)) != NULL) { 764 fprintf(stderr, "FAIL: %s (NULL idx): did not expect to find " 765 "basic constraints\n", __func__); 766 goto err; 767 } 768 if (crit != -2) { 769 fprintf(stderr, "FAIL: %s: basic constraints, no idx: \n" 770 "crit: want %d, got %d\n", __func__, -2, crit); 771 goto err; 772 } 773 774 /* 775 * If we pass idx = -1 and look for basic constraints, we should find 776 * the first one: it is critical at idx = 0, with ca bit set to true. 777 */ 778 779 nid = NID_basic_constraints; 780 idx = -1; 781 if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) == NULL) { 782 fprintf(stderr, "FAIL: %s (idx %d): expected to find" 783 "basic constraints\n", __func__, -1); 784 goto err; 785 } 786 if (crit != 1) { 787 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 788 "crit: want %d, got %d\n", __func__, -1, 1, crit); 789 goto err; 790 } 791 if (idx != 0) { 792 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 793 "idx: want %d, got %d\n", __func__, -1, 0, idx); 794 goto err; 795 } 796 if (bc->ca != ASN1_BOOLEAN_TRUE) { 797 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 798 "cA bit: want %x, got %x\n", __func__, -1, 799 ASN1_BOOLEAN_TRUE, bc->ca); 800 goto err; 801 } 802 BASIC_CONSTRAINTS_free(bc); 803 bc = NULL; 804 805 /* 806 * Now pass idx = 0 and look for basic constraints, we should find 807 * the second one: non-critical at idx = 1, with ca bit set to true. 808 */ 809 810 nid = NID_basic_constraints; 811 idx = 0; 812 if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) == NULL) { 813 fprintf(stderr, "FAIL: %s (idx %d): expected to find" 814 "basic constraints\n", __func__, 0); 815 goto err; 816 } 817 if (crit != 0) { 818 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 819 "crit: want %d, got %d\n", __func__, 0, 0, crit); 820 goto err; 821 } 822 if (idx != 1) { 823 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 824 "idx: want %d, got %d\n", __func__, 0, 1, idx); 825 goto err; 826 } 827 if (bc->ca != ASN1_BOOLEAN_TRUE) { 828 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 829 "cA bit: want %x, got %x\n", __func__, 0, 830 ASN1_BOOLEAN_TRUE, bc->ca); 831 goto err; 832 } 833 BASIC_CONSTRAINTS_free(bc); 834 bc = NULL; 835 836 /* 837 * Now pass idx = 1 and look for basic constraints, we should find the 838 * third one: critical at idx = 2, with ca bit set to false. 839 */ 840 841 nid = NID_basic_constraints; 842 idx = 1; 843 if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) == NULL) { 844 fprintf(stderr, "FAIL: %s (idx %d): expected to find" 845 "basic constraints\n", __func__, 1); 846 goto err; 847 } 848 if (crit != 1) { 849 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 850 "crit: want %d, got %d\n", __func__, 1, 0, crit); 851 goto err; 852 } 853 if (idx != 2) { 854 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 855 "idx: want %d, got %d\n", __func__, 1, 2, idx); 856 goto err; 857 } 858 if (bc->ca != ASN1_BOOLEAN_FALSE) { 859 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 860 "cA bit: want %x, got %x\n", __func__, 1, 861 ASN1_BOOLEAN_FALSE, bc->ca); 862 goto err; 863 } 864 BASIC_CONSTRAINTS_free(bc); 865 bc = NULL; 866 867 /* 868 * Finally, pass idx = 2 and we should find no basic constraints. 869 */ 870 871 nid = NID_basic_constraints; 872 idx = 2; 873 if ((bc = X509V3_get_d2i(exts, nid, &crit, &idx)) != NULL) { 874 fprintf(stderr, "FAIL: %s (idx %d): expected to find" 875 "no basic constraints\n", __func__, 2); 876 goto err; 877 } 878 if (crit != -1) { 879 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 880 "crit: want %d, got %d\n", __func__, 2, -1, crit); 881 goto err; 882 } 883 if (idx != -1) { 884 fprintf(stderr, "FAIL: %s: basic constraints (idx %d): " 885 "idx: want %d, got %d\n", __func__, 2, -1, idx); 886 goto err; 887 } 888 889 failed = 0; 890 891 err: 892 sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 893 ASN1_BIT_STRING_free(abs); 894 BASIC_CONSTRAINTS_free(bc); 895 896 return failed; 897 } 898 899 static int 900 test_x509v3_get_d2i(void) 901 { 902 int failed = 0; 903 904 failed |= test_x509v3_get_d2i_null(); 905 failed |= test_x509v3_get_d2i_multiple_basic_constraints(); 906 907 return failed; 908 } 909 910 int 911 main(void) 912 { 913 int failed = 0; 914 915 failed |= test_x509v3_add1_i2d(); 916 failed |= test_x509v3_get_d2i(); 917 918 return failed; 919 } 920