1 /* 2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "hx_locl.h" 35 36 /** 37 * @page page_print Hx509 printing functions 38 * 39 * See the library functions here: @ref hx509_print 40 */ 41 42 struct hx509_validate_ctx_data { 43 int flags; 44 hx509_vprint_func vprint_func; 45 void *ctx; 46 }; 47 48 struct cert_status { 49 unsigned int selfsigned:1; 50 unsigned int isca:1; 51 unsigned int isproxy:1; 52 unsigned int haveSAN:1; 53 unsigned int haveIAN:1; 54 unsigned int haveSKI:1; 55 unsigned int haveAKI:1; 56 unsigned int haveCRLDP:1; 57 }; 58 59 60 /* 61 * 62 */ 63 64 static int 65 Time2string(const Time *T, char **str) 66 { 67 time_t t; 68 char *s; 69 struct tm *tm; 70 71 *str = NULL; 72 t = _hx509_Time2time_t(T); 73 tm = gmtime (&t); 74 s = malloc(30); 75 if (s == NULL) 76 return ENOMEM; 77 strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm); 78 *str = s; 79 return 0; 80 } 81 82 /** 83 * Helper function to print on stdout for: 84 * - hx509_oid_print(), 85 * - hx509_bitstring_print(), 86 * - hx509_validate_ctx_set_print(). 87 * 88 * @param ctx the context to the print function. If the ctx is NULL, 89 * stdout is used. 90 * @param fmt the printing format. 91 * @param va the argumet list. 92 * 93 * @ingroup hx509_print 94 */ 95 96 void 97 hx509_print_stdout(void *ctx, const char *fmt, va_list va) 98 { 99 FILE *f = ctx; 100 if (f == NULL) 101 f = stdout; 102 vfprintf(f, fmt, va); 103 } 104 105 static void 106 print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...) 107 { 108 va_list va; 109 va_start(va, fmt); 110 (*func)(ctx, fmt, va); 111 va_end(va); 112 } 113 114 /** 115 * Print a oid to a string. 116 * 117 * @param oid oid to print 118 * @param str allocated string, free with hx509_xfree(). 119 * 120 * @return An hx509 error code, see hx509_get_error_string(). 121 * 122 * @ingroup hx509_print 123 */ 124 125 int 126 hx509_oid_sprint(const heim_oid *oid, char **str) 127 { 128 return der_print_heim_oid(oid, '.', str); 129 } 130 131 /** 132 * Print a oid using a hx509_vprint_func function. To print to stdout 133 * use hx509_print_stdout(). 134 * 135 * @param oid oid to print 136 * @param func hx509_vprint_func to print with. 137 * @param ctx context variable to hx509_vprint_func function. 138 * 139 * @ingroup hx509_print 140 */ 141 142 void 143 hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx) 144 { 145 char *str; 146 hx509_oid_sprint(oid, &str); 147 print_func(func, ctx, "%s", str); 148 free(str); 149 } 150 151 /** 152 * Print a bitstring using a hx509_vprint_func function. To print to 153 * stdout use hx509_print_stdout(). 154 * 155 * @param b bit string to print. 156 * @param func hx509_vprint_func to print with. 157 * @param ctx context variable to hx509_vprint_func function. 158 * 159 * @ingroup hx509_print 160 */ 161 162 void 163 hx509_bitstring_print(const heim_bit_string *b, 164 hx509_vprint_func func, void *ctx) 165 { 166 size_t i; 167 print_func(func, ctx, "\tlength: %d\n\t", b->length); 168 for (i = 0; i < (b->length + 7) / 8; i++) 169 print_func(func, ctx, "%02x%s%s", 170 ((unsigned char *)b->data)[i], 171 i < (b->length - 7) / 8 172 && (i == 0 || (i % 16) != 15) ? ":" : "", 173 i != 0 && (i % 16) == 15 ? 174 (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):""); 175 } 176 177 /** 178 * Print certificate usage for a certificate to a string. 179 * 180 * @param context A hx509 context. 181 * @param c a certificate print the keyusage for. 182 * @param s the return string with the keysage printed in to, free 183 * with hx509_xfree(). 184 * 185 * @return An hx509 error code, see hx509_get_error_string(). 186 * 187 * @ingroup hx509_print 188 */ 189 190 int 191 hx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s) 192 { 193 KeyUsage ku; 194 char buf[256]; 195 int ret; 196 197 *s = NULL; 198 199 ret = _hx509_cert_get_keyusage(context, c, &ku); 200 if (ret) 201 return ret; 202 unparse_flags(KeyUsage2int(ku), asn1_KeyUsage_units(), buf, sizeof(buf)); 203 *s = strdup(buf); 204 if (*s == NULL) { 205 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 206 return ENOMEM; 207 } 208 209 return 0; 210 } 211 212 /* 213 * 214 */ 215 216 static void 217 validate_vprint(void *c, const char *fmt, va_list va) 218 { 219 hx509_validate_ctx ctx = c; 220 if (ctx->vprint_func == NULL) 221 return; 222 (ctx->vprint_func)(ctx->ctx, fmt, va); 223 } 224 225 static void 226 validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...) 227 { 228 va_list va; 229 if ((ctx->flags & flags) == 0) 230 return; 231 va_start(va, fmt); 232 validate_vprint(ctx, fmt, va); 233 va_end(va); 234 } 235 236 /* 237 * Dont Care, SHOULD critical, SHOULD NOT critical, MUST critical, 238 * MUST NOT critical 239 */ 240 enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C }; 241 242 static int 243 check_Null(hx509_validate_ctx ctx, 244 struct cert_status *status, 245 enum critical_flag cf, const Extension *e) 246 { 247 switch(cf) { 248 case D_C: 249 break; 250 case S_C: 251 if (!e->critical) 252 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 253 "\tCritical not set on SHOULD\n"); 254 break; 255 case S_N_C: 256 if (e->critical) 257 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 258 "\tCritical set on SHOULD NOT\n"); 259 break; 260 case M_C: 261 if (!e->critical) 262 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 263 "\tCritical not set on MUST\n"); 264 break; 265 case M_N_C: 266 if (e->critical) 267 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 268 "\tCritical set on MUST NOT\n"); 269 break; 270 default: 271 _hx509_abort("internal check_Null state error"); 272 } 273 return 0; 274 } 275 276 static int 277 check_subjectKeyIdentifier(hx509_validate_ctx ctx, 278 struct cert_status *status, 279 enum critical_flag cf, 280 const Extension *e) 281 { 282 SubjectKeyIdentifier si; 283 size_t size; 284 int ret; 285 286 status->haveSKI = 1; 287 check_Null(ctx, status, cf, e); 288 289 ret = decode_SubjectKeyIdentifier(e->extnValue.data, 290 e->extnValue.length, 291 &si, &size); 292 if (ret) { 293 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 294 "Decoding SubjectKeyIdentifier failed: %d", ret); 295 return 1; 296 } 297 if (size != e->extnValue.length) { 298 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 299 "Decoding SKI ahve extra bits on the end"); 300 return 1; 301 } 302 if (si.length == 0) 303 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 304 "SKI is too short (0 bytes)"); 305 if (si.length > 20) 306 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 307 "SKI is too long"); 308 309 { 310 char *id; 311 hex_encode(si.data, si.length, &id); 312 if (id) { 313 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 314 "\tsubject key id: %s\n", id); 315 free(id); 316 } 317 } 318 319 free_SubjectKeyIdentifier(&si); 320 321 return 0; 322 } 323 324 static int 325 check_authorityKeyIdentifier(hx509_validate_ctx ctx, 326 struct cert_status *status, 327 enum critical_flag cf, 328 const Extension *e) 329 { 330 AuthorityKeyIdentifier ai; 331 size_t size; 332 int ret; 333 334 status->haveAKI = 1; 335 check_Null(ctx, status, cf, e); 336 337 ret = decode_AuthorityKeyIdentifier(e->extnValue.data, 338 e->extnValue.length, 339 &ai, &size); 340 if (ret) { 341 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 342 "Decoding AuthorityKeyIdentifier failed: %d", ret); 343 return 1; 344 } 345 if (size != e->extnValue.length) { 346 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 347 "Decoding SKI ahve extra bits on the end"); 348 return 1; 349 } 350 351 if (ai.keyIdentifier) { 352 char *id; 353 hex_encode(ai.keyIdentifier->data, ai.keyIdentifier->length, &id); 354 if (id) { 355 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 356 "\tauthority key id: %s\n", id); 357 free(id); 358 } 359 } 360 361 return 0; 362 } 363 364 static int 365 check_extKeyUsage(hx509_validate_ctx ctx, 366 struct cert_status *status, 367 enum critical_flag cf, 368 const Extension *e) 369 { 370 ExtKeyUsage eku; 371 size_t size, i; 372 int ret; 373 374 check_Null(ctx, status, cf, e); 375 376 ret = decode_ExtKeyUsage(e->extnValue.data, 377 e->extnValue.length, 378 &eku, &size); 379 if (ret) { 380 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 381 "Decoding ExtKeyUsage failed: %d", ret); 382 return 1; 383 } 384 if (size != e->extnValue.length) { 385 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 386 "Padding data in EKU"); 387 free_ExtKeyUsage(&eku); 388 return 1; 389 } 390 if (eku.len == 0) { 391 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 392 "ExtKeyUsage length is 0"); 393 return 1; 394 } 395 396 for (i = 0; i < eku.len; i++) { 397 char *str; 398 ret = der_print_heim_oid (&eku.val[i], '.', &str); 399 if (ret) { 400 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 401 "\tEKU: failed to print oid %d", i); 402 free_ExtKeyUsage(&eku); 403 return 1; 404 } 405 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 406 "\teku-%d: %s\n", i, str);; 407 free(str); 408 } 409 410 free_ExtKeyUsage(&eku); 411 412 return 0; 413 } 414 415 static int 416 check_pkinit_san(hx509_validate_ctx ctx, heim_any *a) 417 { 418 KRB5PrincipalName kn; 419 unsigned i; 420 size_t size; 421 int ret; 422 423 ret = decode_KRB5PrincipalName(a->data, a->length, &kn, &size); 424 if (ret) { 425 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 426 "Decoding kerberos name in SAN failed: %d", ret); 427 return 1; 428 } 429 430 if (size != a->length) { 431 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 432 "Decoding kerberos name have extra bits on the end"); 433 return 1; 434 } 435 436 /* print kerberos principal, add code to quote / within components */ 437 for (i = 0; i < kn.principalName.name_string.len; i++) { 438 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", 439 kn.principalName.name_string.val[i]); 440 if (i + 1 < kn.principalName.name_string.len) 441 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "/"); 442 } 443 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "@"); 444 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.realm); 445 446 free_KRB5PrincipalName(&kn); 447 return 0; 448 } 449 450 static int 451 check_utf8_string_san(hx509_validate_ctx ctx, heim_any *a) 452 { 453 PKIXXmppAddr jid; 454 size_t size; 455 int ret; 456 457 ret = decode_PKIXXmppAddr(a->data, a->length, &jid, &size); 458 if (ret) { 459 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 460 "Decoding JID in SAN failed: %d", ret); 461 return 1; 462 } 463 464 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", jid); 465 free_PKIXXmppAddr(&jid); 466 467 return 0; 468 } 469 470 static int 471 check_altnull(hx509_validate_ctx ctx, heim_any *a) 472 { 473 return 0; 474 } 475 476 static int 477 check_CRLDistributionPoints(hx509_validate_ctx ctx, 478 struct cert_status *status, 479 enum critical_flag cf, 480 const Extension *e) 481 { 482 CRLDistributionPoints dp; 483 size_t size; 484 int ret; 485 size_t i; 486 487 check_Null(ctx, status, cf, e); 488 489 ret = decode_CRLDistributionPoints(e->extnValue.data, 490 e->extnValue.length, 491 &dp, &size); 492 if (ret) { 493 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 494 "Decoding CRL Distribution Points failed: %d\n", ret); 495 return 1; 496 } 497 498 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n"); 499 for (i = 0 ; i < dp.len; i++) { 500 if (dp.val[i].distributionPoint) { 501 DistributionPointName dpname; 502 heim_any *data = dp.val[i].distributionPoint; 503 size_t j; 504 505 ret = decode_DistributionPointName(data->data, data->length, 506 &dpname, NULL); 507 if (ret) { 508 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 509 "Failed to parse CRL Distribution Point Name: %d\n", ret); 510 continue; 511 } 512 513 switch (dpname.element) { 514 case choice_DistributionPointName_fullName: 515 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n"); 516 517 for (j = 0 ; j < dpname.u.fullName.len; j++) { 518 char *s; 519 GeneralName *name = &dpname.u.fullName.val[j]; 520 521 ret = hx509_general_name_unparse(name, &s); 522 if (ret == 0 && s != NULL) { 523 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " %s\n", s); 524 free(s); 525 } 526 } 527 break; 528 case choice_DistributionPointName_nameRelativeToCRLIssuer: 529 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 530 "Unknown nameRelativeToCRLIssuer"); 531 break; 532 default: 533 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 534 "Unknown DistributionPointName"); 535 break; 536 } 537 free_DistributionPointName(&dpname); 538 } 539 } 540 free_CRLDistributionPoints(&dp); 541 542 status->haveCRLDP = 1; 543 544 return 0; 545 } 546 547 548 struct { 549 const char *name; 550 const heim_oid *oid; 551 int (*func)(hx509_validate_ctx, heim_any *); 552 } altname_types[] = { 553 { "pk-init", &asn1_oid_id_pkinit_san, check_pkinit_san }, 554 { "jabber", &asn1_oid_id_pkix_on_xmppAddr, check_utf8_string_san }, 555 { "dns-srv", &asn1_oid_id_pkix_on_dnsSRV, check_altnull }, 556 { "card-id", &asn1_oid_id_uspkicommon_card_id, check_altnull }, 557 { "Microsoft NT-PRINCIPAL-NAME", &asn1_oid_id_pkinit_ms_san, check_utf8_string_san } 558 }; 559 560 static int 561 check_altName(hx509_validate_ctx ctx, 562 struct cert_status *status, 563 const char *name, 564 enum critical_flag cf, 565 const Extension *e) 566 { 567 GeneralNames gn; 568 size_t size; 569 int ret; 570 size_t i; 571 572 check_Null(ctx, status, cf, e); 573 574 if (e->extnValue.length == 0) { 575 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 576 "%sAltName empty, not allowed", name); 577 return 1; 578 } 579 ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, 580 &gn, &size); 581 if (ret) { 582 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 583 "\tret = %d while decoding %s GeneralNames\n", 584 ret, name); 585 return 1; 586 } 587 if (gn.len == 0) { 588 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 589 "%sAltName generalName empty, not allowed\n", name); 590 return 1; 591 } 592 593 for (i = 0; i < gn.len; i++) { 594 switch (gn.val[i].element) { 595 case choice_GeneralName_otherName: { 596 unsigned j; 597 598 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 599 "%sAltName otherName ", name); 600 601 for (j = 0; j < sizeof(altname_types)/sizeof(altname_types[0]); j++) { 602 if (der_heim_oid_cmp(altname_types[j].oid, 603 &gn.val[i].u.otherName.type_id) != 0) 604 continue; 605 606 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ", 607 altname_types[j].name); 608 (*altname_types[j].func)(ctx, &gn.val[i].u.otherName.value); 609 break; 610 } 611 if (j == sizeof(altname_types)/sizeof(altname_types[0])) { 612 hx509_oid_print(&gn.val[i].u.otherName.type_id, 613 validate_vprint, ctx); 614 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown"); 615 } 616 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); 617 break; 618 } 619 default: { 620 char *s; 621 ret = hx509_general_name_unparse(&gn.val[i], &s); 622 if (ret) { 623 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 624 "ret = %d unparsing GeneralName\n", ret); 625 return 1; 626 } 627 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s\n", s); 628 free(s); 629 break; 630 } 631 } 632 } 633 634 free_GeneralNames(&gn); 635 636 return 0; 637 } 638 639 static int 640 check_subjectAltName(hx509_validate_ctx ctx, 641 struct cert_status *status, 642 enum critical_flag cf, 643 const Extension *e) 644 { 645 status->haveSAN = 1; 646 return check_altName(ctx, status, "subject", cf, e); 647 } 648 649 static int 650 check_issuerAltName(hx509_validate_ctx ctx, 651 struct cert_status *status, 652 enum critical_flag cf, 653 const Extension *e) 654 { 655 status->haveIAN = 1; 656 return check_altName(ctx, status, "issuer", cf, e); 657 } 658 659 660 static int 661 check_basicConstraints(hx509_validate_ctx ctx, 662 struct cert_status *status, 663 enum critical_flag cf, 664 const Extension *e) 665 { 666 BasicConstraints b; 667 size_t size; 668 int ret; 669 670 check_Null(ctx, status, cf, e); 671 672 ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, 673 &b, &size); 674 if (ret) { 675 printf("\tret = %d while decoding BasicConstraints\n", ret); 676 return 0; 677 } 678 if (size != e->extnValue.length) 679 printf("\tlength of der data isn't same as extension\n"); 680 681 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 682 "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT "); 683 if (b.pathLenConstraint) 684 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 685 "\tpathLenConstraint: %d\n", *b.pathLenConstraint); 686 687 if (b.cA) { 688 if (*b.cA) { 689 if (!e->critical) 690 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 691 "Is a CA and not BasicConstraints CRITICAL\n"); 692 status->isca = 1; 693 } 694 else 695 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 696 "cA is FALSE, not allowed to be\n"); 697 } 698 free_BasicConstraints(&b); 699 700 return 0; 701 } 702 703 static int 704 check_proxyCertInfo(hx509_validate_ctx ctx, 705 struct cert_status *status, 706 enum critical_flag cf, 707 const Extension *e) 708 { 709 check_Null(ctx, status, cf, e); 710 status->isproxy = 1; 711 return 0; 712 } 713 714 static int 715 check_authorityInfoAccess(hx509_validate_ctx ctx, 716 struct cert_status *status, 717 enum critical_flag cf, 718 const Extension *e) 719 { 720 AuthorityInfoAccessSyntax aia; 721 size_t size; 722 int ret; 723 size_t i; 724 725 check_Null(ctx, status, cf, e); 726 727 ret = decode_AuthorityInfoAccessSyntax(e->extnValue.data, 728 e->extnValue.length, 729 &aia, &size); 730 if (ret) { 731 printf("\tret = %d while decoding AuthorityInfoAccessSyntax\n", ret); 732 return 0; 733 } 734 735 for (i = 0; i < aia.len; i++) { 736 char *str; 737 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 738 "\ttype: "); 739 hx509_oid_print(&aia.val[i].accessMethod, validate_vprint, ctx); 740 hx509_general_name_unparse(&aia.val[i].accessLocation, &str); 741 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 742 "\n\tdirname: %s\n", str); 743 free(str); 744 } 745 free_AuthorityInfoAccessSyntax(&aia); 746 747 return 0; 748 } 749 750 /* 751 * 752 */ 753 754 struct { 755 const char *name; 756 const heim_oid *oid; 757 int (*func)(hx509_validate_ctx ctx, 758 struct cert_status *status, 759 enum critical_flag cf, 760 const Extension *); 761 enum critical_flag cf; 762 } check_extension[] = { 763 #define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname 764 { ext(subjectDirectoryAttributes, Null), M_N_C }, 765 { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, 766 { ext(keyUsage, Null), S_C }, 767 { ext(subjectAltName, subjectAltName), M_N_C }, 768 { ext(issuerAltName, issuerAltName), S_N_C }, 769 { ext(basicConstraints, basicConstraints), D_C }, 770 { ext(cRLNumber, Null), M_N_C }, 771 { ext(cRLReason, Null), M_N_C }, 772 { ext(holdInstructionCode, Null), M_N_C }, 773 { ext(invalidityDate, Null), M_N_C }, 774 { ext(deltaCRLIndicator, Null), M_C }, 775 { ext(issuingDistributionPoint, Null), M_C }, 776 { ext(certificateIssuer, Null), M_C }, 777 { ext(nameConstraints, Null), M_C }, 778 { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C }, 779 { ext(certificatePolicies, Null), 0 }, 780 { ext(policyMappings, Null), M_N_C }, 781 { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C }, 782 { ext(policyConstraints, Null), D_C }, 783 { ext(extKeyUsage, extKeyUsage), D_C }, 784 { ext(freshestCRL, Null), M_N_C }, 785 { ext(inhibitAnyPolicy, Null), M_C }, 786 #undef ext 787 #define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname 788 { ext(proxyCertInfo, proxyCertInfo), M_C }, 789 { ext(authorityInfoAccess, authorityInfoAccess), M_C }, 790 #undef ext 791 { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim, 792 check_Null, D_C }, 793 { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment, 794 check_Null, D_C }, 795 { NULL, NULL, NULL, 0 } 796 }; 797 798 /** 799 * Allocate a hx509 validation/printing context. 800 * 801 * @param context A hx509 context. 802 * @param ctx a new allocated hx509 validation context, free with 803 * hx509_validate_ctx_free(). 804 805 * @return An hx509 error code, see hx509_get_error_string(). 806 * 807 * @ingroup hx509_print 808 */ 809 810 int 811 hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx) 812 { 813 *ctx = malloc(sizeof(**ctx)); 814 if (*ctx == NULL) 815 return ENOMEM; 816 memset(*ctx, 0, sizeof(**ctx)); 817 return 0; 818 } 819 820 /** 821 * Set the printing functions for the validation context. 822 * 823 * @param ctx a hx509 valication context. 824 * @param func the printing function to usea. 825 * @param c the context variable to the printing function. 826 * 827 * @return An hx509 error code, see hx509_get_error_string(). 828 * 829 * @ingroup hx509_print 830 */ 831 832 void 833 hx509_validate_ctx_set_print(hx509_validate_ctx ctx, 834 hx509_vprint_func func, 835 void *c) 836 { 837 ctx->vprint_func = func; 838 ctx->ctx = c; 839 } 840 841 /** 842 * Add flags to control the behaivor of the hx509_validate_cert() 843 * function. 844 * 845 * @param ctx A hx509 validation context. 846 * @param flags flags to add to the validation context. 847 * 848 * @return An hx509 error code, see hx509_get_error_string(). 849 * 850 * @ingroup hx509_print 851 */ 852 853 void 854 hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags) 855 { 856 ctx->flags |= flags; 857 } 858 859 /** 860 * Free an hx509 validate context. 861 * 862 * @param ctx the hx509 validate context to free. 863 * 864 * @ingroup hx509_print 865 */ 866 867 void 868 hx509_validate_ctx_free(hx509_validate_ctx ctx) 869 { 870 free(ctx); 871 } 872 873 /** 874 * Validate/Print the status of the certificate. 875 * 876 * @param context A hx509 context. 877 * @param ctx A hx509 validation context. 878 * @param cert the cerificate to validate/print. 879 880 * @return An hx509 error code, see hx509_get_error_string(). 881 * 882 * @ingroup hx509_print 883 */ 884 885 int 886 hx509_validate_cert(hx509_context context, 887 hx509_validate_ctx ctx, 888 hx509_cert cert) 889 { 890 Certificate *c = _hx509_get_cert(cert); 891 TBSCertificate *t = &c->tbsCertificate; 892 hx509_name issuer, subject; 893 char *str; 894 struct cert_status status; 895 int ret; 896 897 memset(&status, 0, sizeof(status)); 898 899 if (_hx509_cert_get_version(c) != 3) 900 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 901 "Not version 3 certificate\n"); 902 903 if ((t->version == NULL || *t->version < 2) && t->extensions) 904 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 905 "Not version 3 certificate with extensions\n"); 906 907 if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL) 908 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 909 "Version 3 certificate without extensions\n"); 910 911 ret = hx509_cert_get_subject(cert, &subject); 912 if (ret) abort(); 913 hx509_name_to_string(subject, &str); 914 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 915 "subject name: %s\n", str); 916 free(str); 917 918 ret = hx509_cert_get_issuer(cert, &issuer); 919 if (ret) abort(); 920 hx509_name_to_string(issuer, &str); 921 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 922 "issuer name: %s\n", str); 923 free(str); 924 925 if (hx509_name_cmp(subject, issuer) == 0) { 926 status.selfsigned = 1; 927 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 928 "\tis a self-signed certificate\n"); 929 } 930 931 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 932 "Validity:\n"); 933 934 Time2string(&t->validity.notBefore, &str); 935 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); 936 free(str); 937 Time2string(&t->validity.notAfter, &str); 938 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); 939 free(str); 940 941 if (t->extensions) { 942 size_t i, j; 943 944 if (t->extensions->len == 0) { 945 validate_print(ctx, 946 HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, 947 "The empty extensions list is not " 948 "allowed by PKIX\n"); 949 } 950 951 for (i = 0; i < t->extensions->len; i++) { 952 953 for (j = 0; check_extension[j].name; j++) 954 if (der_heim_oid_cmp(check_extension[j].oid, 955 &t->extensions->val[i].extnID) == 0) 956 break; 957 if (check_extension[j].name == NULL) { 958 int flags = HX509_VALIDATE_F_VERBOSE; 959 if (t->extensions->val[i].critical) 960 flags |= HX509_VALIDATE_F_VALIDATE; 961 validate_print(ctx, flags, "don't know what "); 962 if (t->extensions->val[i].critical) 963 validate_print(ctx, flags, "and is CRITICAL "); 964 if (ctx->flags & flags) 965 hx509_oid_print(&t->extensions->val[i].extnID, 966 validate_vprint, ctx); 967 validate_print(ctx, flags, " is\n"); 968 continue; 969 } 970 validate_print(ctx, 971 HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, 972 "checking extention: %s\n", 973 check_extension[j].name); 974 (*check_extension[j].func)(ctx, 975 &status, 976 check_extension[j].cf, 977 &t->extensions->val[i]); 978 } 979 } else 980 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n"); 981 982 if (status.isca) { 983 if (!status.haveSKI) 984 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 985 "CA certificate have no SubjectKeyIdentifier\n"); 986 987 } else { 988 if (!status.haveAKI) 989 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 990 "Is not CA and doesn't have " 991 "AuthorityKeyIdentifier\n"); 992 } 993 994 995 if (!status.haveSKI) 996 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 997 "Doesn't have SubjectKeyIdentifier\n"); 998 999 if (status.isproxy && status.isca) 1000 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1001 "Proxy and CA at the same time!\n"); 1002 1003 if (status.isproxy) { 1004 if (status.haveSAN) 1005 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1006 "Proxy and have SAN\n"); 1007 if (status.haveIAN) 1008 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1009 "Proxy and have IAN\n"); 1010 } 1011 1012 if (hx509_name_is_null_p(subject) && !status.haveSAN) 1013 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1014 "NULL subject DN and doesn't have a SAN\n"); 1015 1016 if (!status.selfsigned && !status.haveCRLDP) 1017 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1018 "Not a CA nor PROXY and doesn't have" 1019 "CRL Dist Point\n"); 1020 1021 if (status.selfsigned) { 1022 ret = _hx509_verify_signature_bitstring(context, 1023 cert, 1024 &c->signatureAlgorithm, 1025 &c->tbsCertificate._save, 1026 &c->signatureValue); 1027 if (ret == 0) 1028 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 1029 "Self-signed certificate was self-signed\n"); 1030 else 1031 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1032 "Self-signed certificate NOT really self-signed!\n"); 1033 } 1034 1035 hx509_name_free(&subject); 1036 hx509_name_free(&issuer); 1037 1038 return 0; 1039 } 1040