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