1/* $NetBSD: print.c,v 1.3 2019/12/15 22:50:50 christos 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 size_t 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 * Don't 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; 487 size_t i; 488 489 check_Null(ctx, status, cf, e); 490 491 ret = decode_CRLDistributionPoints(e->extnValue.data, 492 e->extnValue.length, 493 &dp, &size); 494 if (ret) { 495 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 496 "Decoding CRL Distribution Points failed: %d\n", ret); 497 return 1; 498 } 499 500 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n"); 501 for (i = 0 ; i < dp.len; i++) { 502 if (dp.val[i].distributionPoint) { 503 DistributionPointName dpname; 504 heim_any *data = dp.val[i].distributionPoint; 505 size_t j; 506 507 ret = decode_DistributionPointName(data->data, data->length, 508 &dpname, NULL); 509 if (ret) { 510 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 511 "Failed to parse CRL Distribution Point Name: %d\n", ret); 512 continue; 513 } 514 515 switch (dpname.element) { 516 case choice_DistributionPointName_fullName: 517 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n"); 518 519 for (j = 0 ; j < dpname.u.fullName.len; j++) { 520 char *s; 521 GeneralName *name = &dpname.u.fullName.val[j]; 522 523 ret = hx509_general_name_unparse(name, &s); 524 if (ret == 0 && s != NULL) { 525 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " %s\n", s); 526 free(s); 527 } 528 } 529 break; 530 case choice_DistributionPointName_nameRelativeToCRLIssuer: 531 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 532 "Unknown nameRelativeToCRLIssuer"); 533 break; 534 default: 535 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 536 "Unknown DistributionPointName"); 537 break; 538 } 539 free_DistributionPointName(&dpname); 540 } 541 } 542 free_CRLDistributionPoints(&dp); 543 544 status->haveCRLDP = 1; 545 546 return 0; 547} 548 549 550struct { 551 const char *name; 552 const heim_oid *oid; 553 int (*func)(hx509_validate_ctx, heim_any *); 554} altname_types[] = { 555 { "pk-init", &asn1_oid_id_pkinit_san, check_pkinit_san }, 556 { "jabber", &asn1_oid_id_pkix_on_xmppAddr, check_utf8_string_san }, 557 { "dns-srv", &asn1_oid_id_pkix_on_dnsSRV, check_altnull }, 558 { "card-id", &asn1_oid_id_uspkicommon_card_id, check_altnull }, 559 { "Microsoft NT-PRINCIPAL-NAME", &asn1_oid_id_pkinit_ms_san, check_utf8_string_san } 560}; 561 562static int 563check_altName(hx509_validate_ctx ctx, 564 struct cert_status *status, 565 const char *name, 566 enum critical_flag cf, 567 const Extension *e) 568{ 569 GeneralNames gn; 570 size_t size; 571 int ret; 572 size_t i; 573 574 check_Null(ctx, status, cf, e); 575 576 if (e->extnValue.length == 0) { 577 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 578 "%sAltName empty, not allowed", name); 579 return 1; 580 } 581 ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length, 582 &gn, &size); 583 if (ret) { 584 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 585 "\tret = %d while decoding %s GeneralNames\n", 586 ret, name); 587 return 1; 588 } 589 if (gn.len == 0) { 590 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 591 "%sAltName generalName empty, not allowed\n", name); 592 return 1; 593 } 594 595 for (i = 0; i < gn.len; i++) { 596 switch (gn.val[i].element) { 597 case choice_GeneralName_otherName: { 598 unsigned j; 599 600 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 601 "%sAltName otherName ", name); 602 603 for (j = 0; j < sizeof(altname_types)/sizeof(altname_types[0]); j++) { 604 if (der_heim_oid_cmp(altname_types[j].oid, 605 &gn.val[i].u.otherName.type_id) != 0) 606 continue; 607 608 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ", 609 altname_types[j].name); 610 (*altname_types[j].func)(ctx, &gn.val[i].u.otherName.value); 611 break; 612 } 613 if (j == sizeof(altname_types)/sizeof(altname_types[0])) { 614 hx509_oid_print(&gn.val[i].u.otherName.type_id, 615 validate_vprint, ctx); 616 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown"); 617 } 618 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n"); 619 break; 620 } 621 default: { 622 char *s; 623 ret = hx509_general_name_unparse(&gn.val[i], &s); 624 if (ret) { 625 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 626 "ret = %d unparsing GeneralName\n", ret); 627 return 1; 628 } 629 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s\n", s); 630 free(s); 631 break; 632 } 633 } 634 } 635 636 free_GeneralNames(&gn); 637 638 return 0; 639} 640 641static int 642check_subjectAltName(hx509_validate_ctx ctx, 643 struct cert_status *status, 644 enum critical_flag cf, 645 const Extension *e) 646{ 647 status->haveSAN = 1; 648 return check_altName(ctx, status, "subject", cf, e); 649} 650 651static int 652check_issuerAltName(hx509_validate_ctx ctx, 653 struct cert_status *status, 654 enum critical_flag cf, 655 const Extension *e) 656{ 657 status->haveIAN = 1; 658 return check_altName(ctx, status, "issuer", cf, e); 659} 660 661 662static int 663check_basicConstraints(hx509_validate_ctx ctx, 664 struct cert_status *status, 665 enum critical_flag cf, 666 const Extension *e) 667{ 668 BasicConstraints b; 669 size_t size; 670 int ret; 671 672 check_Null(ctx, status, cf, e); 673 674 ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length, 675 &b, &size); 676 if (ret) { 677 printf("\tret = %d while decoding BasicConstraints\n", ret); 678 return 0; 679 } 680 if (size != e->extnValue.length) 681 printf("\tlength of der data isn't same as extension\n"); 682 683 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 684 "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT "); 685 if (b.pathLenConstraint) 686 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 687 "\tpathLenConstraint: %d\n", *b.pathLenConstraint); 688 689 if (b.cA) { 690 if (*b.cA) { 691 if (!e->critical) 692 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 693 "Is a CA and not BasicConstraints CRITICAL\n"); 694 status->isca = 1; 695 } 696 else 697 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 698 "cA is FALSE, not allowed to be\n"); 699 } 700 free_BasicConstraints(&b); 701 702 return 0; 703} 704 705static int 706check_proxyCertInfo(hx509_validate_ctx ctx, 707 struct cert_status *status, 708 enum critical_flag cf, 709 const Extension *e) 710{ 711 check_Null(ctx, status, cf, e); 712 status->isproxy = 1; 713 return 0; 714} 715 716static int 717check_authorityInfoAccess(hx509_validate_ctx ctx, 718 struct cert_status *status, 719 enum critical_flag cf, 720 const Extension *e) 721{ 722 AuthorityInfoAccessSyntax aia; 723 size_t size; 724 int ret; 725 size_t i; 726 727 check_Null(ctx, status, cf, e); 728 729 ret = decode_AuthorityInfoAccessSyntax(e->extnValue.data, 730 e->extnValue.length, 731 &aia, &size); 732 if (ret) { 733 printf("\tret = %d while decoding AuthorityInfoAccessSyntax\n", ret); 734 return 0; 735 } 736 737 for (i = 0; i < aia.len; i++) { 738 char *str; 739 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 740 "\ttype: "); 741 hx509_oid_print(&aia.val[i].accessMethod, validate_vprint, ctx); 742 hx509_general_name_unparse(&aia.val[i].accessLocation, &str); 743 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 744 "\n\tdirname: %s\n", str); 745 free(str); 746 } 747 free_AuthorityInfoAccessSyntax(&aia); 748 749 return 0; 750} 751 752/* 753 * 754 */ 755 756struct { 757 const char *name; 758 const heim_oid *oid; 759 int (*func)(hx509_validate_ctx ctx, 760 struct cert_status *status, 761 enum critical_flag cf, 762 const Extension *); 763 enum critical_flag cf; 764} check_extension[] = { 765#define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname 766 { ext(subjectDirectoryAttributes, Null), M_N_C }, 767 { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C }, 768 { ext(keyUsage, Null), S_C }, 769 { ext(subjectAltName, subjectAltName), M_N_C }, 770 { ext(issuerAltName, issuerAltName), S_N_C }, 771 { ext(basicConstraints, basicConstraints), D_C }, 772 { ext(cRLNumber, Null), M_N_C }, 773 { ext(cRLReason, Null), M_N_C }, 774 { ext(holdInstructionCode, Null), M_N_C }, 775 { ext(invalidityDate, Null), M_N_C }, 776 { ext(deltaCRLIndicator, Null), M_C }, 777 { ext(issuingDistributionPoint, Null), M_C }, 778 { ext(certificateIssuer, Null), M_C }, 779 { ext(nameConstraints, Null), M_C }, 780 { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C }, 781 { ext(certificatePolicies, Null), 0 }, 782 { ext(policyMappings, Null), M_N_C }, 783 { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C }, 784 { ext(policyConstraints, Null), D_C }, 785 { ext(extKeyUsage, extKeyUsage), D_C }, 786 { ext(freshestCRL, Null), M_N_C }, 787 { ext(inhibitAnyPolicy, Null), M_C }, 788#undef ext 789#define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname 790 { ext(proxyCertInfo, proxyCertInfo), M_C }, 791 { ext(authorityInfoAccess, authorityInfoAccess), M_C }, 792#undef ext 793 { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim, 794 check_Null, D_C }, 795 { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment, 796 check_Null, D_C }, 797 { NULL, NULL, NULL, 0 } 798}; 799 800/** 801 * Allocate a hx509 validation/printing context. 802 * 803 * @param context A hx509 context. 804 * @param ctx a new allocated hx509 validation context, free with 805 * hx509_validate_ctx_free(). 806 807 * @return An hx509 error code, see hx509_get_error_string(). 808 * 809 * @ingroup hx509_print 810 */ 811 812int 813hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx) 814{ 815 *ctx = malloc(sizeof(**ctx)); 816 if (*ctx == NULL) 817 return ENOMEM; 818 memset(*ctx, 0, sizeof(**ctx)); 819 return 0; 820} 821 822/** 823 * Set the printing functions for the validation context. 824 * 825 * @param ctx a hx509 valication context. 826 * @param func the printing function to usea. 827 * @param c the context variable to the printing function. 828 * 829 * @return An hx509 error code, see hx509_get_error_string(). 830 * 831 * @ingroup hx509_print 832 */ 833 834void 835hx509_validate_ctx_set_print(hx509_validate_ctx ctx, 836 hx509_vprint_func func, 837 void *c) 838{ 839 ctx->vprint_func = func; 840 ctx->ctx = c; 841} 842 843/** 844 * Add flags to control the behaivor of the hx509_validate_cert() 845 * function. 846 * 847 * @param ctx A hx509 validation context. 848 * @param flags flags to add to the validation context. 849 * 850 * @return An hx509 error code, see hx509_get_error_string(). 851 * 852 * @ingroup hx509_print 853 */ 854 855void 856hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags) 857{ 858 ctx->flags |= flags; 859} 860 861/** 862 * Free an hx509 validate context. 863 * 864 * @param ctx the hx509 validate context to free. 865 * 866 * @ingroup hx509_print 867 */ 868 869void 870hx509_validate_ctx_free(hx509_validate_ctx ctx) 871{ 872 free(ctx); 873} 874 875/** 876 * Validate/Print the status of the certificate. 877 * 878 * @param context A hx509 context. 879 * @param ctx A hx509 validation context. 880 * @param cert the cerificate to validate/print. 881 882 * @return An hx509 error code, see hx509_get_error_string(). 883 * 884 * @ingroup hx509_print 885 */ 886 887int 888hx509_validate_cert(hx509_context context, 889 hx509_validate_ctx ctx, 890 hx509_cert cert) 891{ 892 Certificate *c = _hx509_get_cert(cert); 893 TBSCertificate *t = &c->tbsCertificate; 894 hx509_name issuer, subject; 895 char *str; 896 struct cert_status status; 897 int ret; 898 899 memset(&status, 0, sizeof(status)); 900 901 if (_hx509_cert_get_version(c) != 3) 902 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 903 "Not version 3 certificate\n"); 904 905 if ((t->version == NULL || *t->version < 2) && t->extensions) 906 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 907 "Not version 3 certificate with extensions\n"); 908 909 if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL) 910 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 911 "Version 3 certificate without extensions\n"); 912 913 ret = hx509_cert_get_subject(cert, &subject); 914 if (ret) abort(); 915 hx509_name_to_string(subject, &str); 916 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 917 "subject name: %s\n", str); 918 free(str); 919 920 ret = hx509_cert_get_issuer(cert, &issuer); 921 if (ret) abort(); 922 hx509_name_to_string(issuer, &str); 923 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 924 "issuer name: %s\n", str); 925 free(str); 926 927 if (hx509_name_cmp(subject, issuer) == 0) { 928 status.selfsigned = 1; 929 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 930 "\tis a self-signed certificate\n"); 931 } 932 933 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 934 "Validity:\n"); 935 936 Time2string(&t->validity.notBefore, &str); 937 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str); 938 free(str); 939 Time2string(&t->validity.notAfter, &str); 940 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str); 941 free(str); 942 943 if (t->extensions) { 944 size_t i, j; 945 946 if (t->extensions->len == 0) { 947 validate_print(ctx, 948 HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, 949 "The empty extensions list is not " 950 "allowed by PKIX\n"); 951 } 952 953 for (i = 0; i < t->extensions->len; i++) { 954 955 for (j = 0; check_extension[j].name; j++) 956 if (der_heim_oid_cmp(check_extension[j].oid, 957 &t->extensions->val[i].extnID) == 0) 958 break; 959 if (check_extension[j].name == NULL) { 960 int flags = HX509_VALIDATE_F_VERBOSE; 961 if (t->extensions->val[i].critical) 962 flags |= HX509_VALIDATE_F_VALIDATE; 963 validate_print(ctx, flags, "don't know what "); 964 if (t->extensions->val[i].critical) 965 validate_print(ctx, flags, "and is CRITICAL "); 966 if (ctx->flags & flags) 967 hx509_oid_print(&t->extensions->val[i].extnID, 968 validate_vprint, ctx); 969 validate_print(ctx, flags, " is\n"); 970 continue; 971 } 972 validate_print(ctx, 973 HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE, 974 "checking extension: %s\n", 975 check_extension[j].name); 976 (*check_extension[j].func)(ctx, 977 &status, 978 check_extension[j].cf, 979 &t->extensions->val[i]); 980 } 981 } else 982 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extensions\n"); 983 984 if (status.isca) { 985 if (!status.haveSKI) 986 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 987 "CA certificate have no SubjectKeyIdentifier\n"); 988 989 } else { 990 if (!status.haveAKI) 991 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 992 "Is not CA and doesn't have " 993 "AuthorityKeyIdentifier\n"); 994 } 995 996 997 if (!status.haveSKI) 998 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 999 "Doesn't have SubjectKeyIdentifier\n"); 1000 1001 if (status.isproxy && status.isca) 1002 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1003 "Proxy and CA at the same time!\n"); 1004 1005 if (status.isproxy) { 1006 if (status.haveSAN) 1007 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1008 "Proxy and have SAN\n"); 1009 if (status.haveIAN) 1010 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1011 "Proxy and have IAN\n"); 1012 } 1013 1014 if (hx509_name_is_null_p(subject) && !status.haveSAN) 1015 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1016 "NULL subject DN and doesn't have a SAN\n"); 1017 1018 if (!status.selfsigned && !status.haveCRLDP) 1019 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1020 "Not a CA nor PROXY and doesn't have" 1021 "CRL Dist Point\n"); 1022 1023 if (status.selfsigned) { 1024 ret = _hx509_verify_signature_bitstring(context, 1025 cert, 1026 &c->signatureAlgorithm, 1027 &c->tbsCertificate._save, 1028 &c->signatureValue); 1029 if (ret == 0) 1030 validate_print(ctx, HX509_VALIDATE_F_VERBOSE, 1031 "Self-signed certificate was self-signed\n"); 1032 else 1033 validate_print(ctx, HX509_VALIDATE_F_VALIDATE, 1034 "Self-signed certificate NOT really self-signed!\n"); 1035 } 1036 1037 hx509_name_free(&subject); 1038 hx509_name_free(&issuer); 1039 1040 return 0; 1041} 1042