root/source4/heimdal/lib/hx509/print.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Time2string
  2. hx509_print_stdout
  3. print_func
  4. hx509_oid_sprint
  5. hx509_oid_print
  6. hx509_bitstring_print
  7. hx509_cert_keyusage_print
  8. validate_vprint
  9. validate_print
  10. check_Null
  11. check_subjectKeyIdentifier
  12. check_authorityKeyIdentifier
  13. check_extKeyUsage
  14. check_pkinit_san
  15. check_utf8_string_san
  16. check_altnull
  17. check_CRLDistributionPoints
  18. check_altName
  19. check_subjectAltName
  20. check_issuerAltName
  21. check_basicConstraints
  22. check_proxyCertInfo
  23. check_authorityInfoAccess
  24. hx509_validate_ctx_init
  25. hx509_validate_ctx_set_print
  26. hx509_validate_ctx_add_flags
  27. hx509_validate_ctx_free
  28. hx509_validate_cert

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

/* [<][>][^][v][top][bottom][index][help] */