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