1/* 2 * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 - 2010 Apple Inc. 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#include "crypto-headers.h" 38#include <rtbl.h> 39 40/** 41 * @page page_cert The basic certificate 42 * 43 * The basic hx509 cerificate object in hx509 is hx509_cert. The 44 * hx509_cert object is representing one X509/PKIX certificate and 45 * associated attributes; like private key, friendly name, etc. 46 * 47 * A hx509_cert object is usully found via the keyset interfaces (@ref 48 * page_keyset), but its also possible to create a certificate 49 * directly from a parsed object with hx509_cert_init() and 50 * hx509_cert_init_data(). 51 * 52 * See the library functions here: @ref hx509_cert 53 */ 54 55struct hx509_verify_ctx_data { 56 hx509_certs trust_anchors; 57 int flags; 58#define HX509_VERIFY_CTX_F_TIME_SET 1 59#define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2 60#define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4 61#define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8 62#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16 63#define HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK 32 64 time_t time_now; 65 unsigned int max_depth; 66#define HX509_VERIFY_MAX_DEPTH 30 67 hx509_revoke_ctx revoke_ctx; 68}; 69 70#define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280) 71#define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS) 72#define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0) 73 74struct _hx509_cert_attrs { 75 size_t len; 76 hx509_cert_attribute *val; 77}; 78 79struct hx509_cert_data { 80 struct heim_base_uniq base; 81 char *friendlyname; 82 heim_octet_string persistent; 83 Certificate *data; 84 hx509_private_key private_key; 85 struct _hx509_cert_attrs attrs; 86 hx509_name basename; 87 _hx509_cert_release_func release; 88 void *ctx; 89}; 90 91typedef struct hx509_name_constraints { 92 NameConstraints *val; 93 size_t len; 94} hx509_name_constraints; 95 96/* 97 * 98 */ 99 100#define GeneralSubtrees_SET(g,var) \ 101 (g)->len = (var)->len, (g)->val = (var)->val; 102 103/** 104 * Creates a hx509 context that most functions in the library 105 * uses. The context is only allowed to be used by one thread at each 106 * moment. Free the context with hx509_context_free(). 107 * 108 * @param context Returns a pointer to new hx509 context. 109 * 110 * @return Returns an hx509 error code. 111 * 112 * @ingroup hx509 113 */ 114 115int 116hx509_context_init(hx509_context *context) 117{ 118 *context = calloc(1, sizeof(**context)); 119 if (*context == NULL) 120 return ENOMEM; 121 122 _hx509_ks_null_register(*context); 123 _hx509_ks_mem_register(*context); 124 _hx509_ks_file_register(*context); 125 _hx509_ks_pkcs12_register(*context); 126 _hx509_ks_pkcs11_register(*context); 127 _hx509_ks_dir_register(*context); 128 _hx509_ks_keychain_register(*context); 129 130 ENGINE_add_conf_module(); 131 OpenSSL_add_all_algorithms(); 132 133 (*context)->ocsp_time_diff = HX509_DEFAULT_OCSP_TIME_DIFF; 134 135 initialize_hx_error_table_r(&(*context)->et_list); 136 initialize_asn1_error_table_r(&(*context)->et_list); 137 138#ifdef HX509_DEFAULT_ANCHORS 139 (void)hx509_certs_init(*context, HX509_DEFAULT_ANCHORS, 0, 140 NULL, &(*context)->default_trust_anchors); 141#endif 142 143 return 0; 144} 145 146/** 147 * Selects if the hx509_revoke_verify() function is going to require 148 * the existans of a revokation method (OCSP, CRL) or not. Note that 149 * hx509_verify_path(), hx509_cms_verify_signed(), and other function 150 * call hx509_revoke_verify(). 151 * 152 * @param context hx509 context to change the flag for. 153 * @param flag zero, revokation method required, non zero missing 154 * revokation method ok 155 * 156 * @ingroup hx509_verify 157 */ 158 159void 160hx509_context_set_missing_revoke(hx509_context context, int flag) 161{ 162 if (flag) 163 context->flags |= HX509_CTX_VERIFY_MISSING_OK; 164 else 165 context->flags &= ~HX509_CTX_VERIFY_MISSING_OK; 166} 167 168/** 169 * Free the context allocated by hx509_context_init(). 170 * 171 * @param context context to be freed. 172 * 173 * @ingroup hx509 174 */ 175 176void 177hx509_context_free(hx509_context *context) 178{ 179 hx509_certs_free(&(*context)->default_trust_anchors); 180 hx509_clear_error_string(*context); 181 if ((*context)->ks_ops) { 182 free((*context)->ks_ops); 183 (*context)->ks_ops = NULL; 184 } 185 (*context)->ks_num_ops = 0; 186 free_error_table ((*context)->et_list); 187 memset(*context, 0, sizeof(**context)); 188 free(*context); 189 *context = NULL; 190} 191 192/* 193 * 194 */ 195 196Certificate * 197_hx509_get_cert(hx509_cert cert) 198{ 199 return cert->data; 200} 201 202/* 203 * 204 */ 205 206int 207_hx509_cert_get_version(const Certificate *t) 208{ 209 return t->tbsCertificate.version ? *t->tbsCertificate.version + 1 : 1; 210} 211 212/* 213 * 214 */ 215 216static void 217cert_free(heim_object_t object) 218{ 219 hx509_cert cert = object; 220 int i; 221 222 if (cert->release) 223 (cert->release)(cert, cert->ctx); 224 225 if (cert->private_key) 226 hx509_private_key_free(&cert->private_key); 227 228 if (cert->data) { 229 free_Certificate(cert->data); 230 free(cert->data); 231 } 232 233 for (i = 0; i < cert->attrs.len; i++) { 234 der_free_octet_string(&cert->attrs.val[i]->data); 235 der_free_oid(&cert->attrs.val[i]->oid); 236 free(cert->attrs.val[i]); 237 } 238 free(cert->attrs.val); 239 free(cert->friendlyname); 240 if (cert->basename) 241 hx509_name_free(&cert->basename); 242 der_free_octet_string(&cert->persistent); 243} 244 245 246/** 247 * Allocate and init an hx509 certificate object from the decoded 248 * certificate `c´. 249 * 250 * @param context A hx509 context. 251 * @param c 252 * @param cert 253 * 254 * @return Returns an hx509 error code. 255 * 256 * @ingroup hx509_cert 257 */ 258 259int 260hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert) 261{ 262 int ret; 263 264 *cert = heim_uniq_alloc(sizeof(**cert), "hx509-cert", cert_free); 265 if (*cert == NULL) 266 return ENOMEM; 267 (*cert)->friendlyname = NULL; 268 (*cert)->attrs.len = 0; 269 (*cert)->attrs.val = NULL; 270 (*cert)->private_key = NULL; 271 (*cert)->basename = NULL; 272 (*cert)->release = NULL; 273 (*cert)->ctx = NULL; 274 275 (*cert)->data = calloc(1, sizeof(*(*cert)->data)); 276 if ((*cert)->data == NULL) { 277 heim_release(*cert); 278 *cert = NULL; 279 return ENOMEM; 280 } 281 ret = copy_Certificate(c, (*cert)->data); 282 if (ret) { 283 heim_release(*cert); 284 *cert = NULL; 285 } 286 return ret; 287} 288 289/** 290 * Just like hx509_cert_init(), but instead of a decode certificate 291 * takes an pointer and length to a memory region that contains a 292 * DER/BER encoded certificate. 293 * 294 * If the memory region doesn't contain just the certificate and 295 * nothing more the function will fail with 296 * HX509_EXTRA_DATA_AFTER_STRUCTURE. 297 * 298 * @param context A hx509 context. 299 * @param ptr pointer to memory region containing encoded certificate. 300 * @param len length of memory region. 301 * @param cert a return pointer to a hx509 certificate object, will 302 * contain NULL on error. 303 * 304 * @return An hx509 error code, see hx509_get_error_string(). 305 * 306 * @ingroup hx509_cert 307 */ 308 309int 310hx509_cert_init_data(hx509_context context, 311 const void *ptr, 312 size_t len, 313 hx509_cert *cert) 314{ 315 Certificate t; 316 size_t size; 317 int ret; 318 319 ret = decode_Certificate(ptr, len, &t, &size); 320 if (ret) { 321 hx509_set_error_string(context, 0, ret, "Failed to decode certificate"); 322 return ret; 323 } 324 if (size != len) { 325 free_Certificate(&t); 326 hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE, 327 "Extra data after certificate"); 328 return HX509_EXTRA_DATA_AFTER_STRUCTURE; 329 } 330 331 ret = hx509_cert_init(context, &t, cert); 332 free_Certificate(&t); 333 return ret; 334} 335 336void 337_hx509_cert_set_release(hx509_cert cert, 338 _hx509_cert_release_func release, 339 void *ctx) 340{ 341 cert->release = release; 342 cert->ctx = ctx; 343} 344 345 346/* Doesn't make a copy of `private_key'. */ 347 348int 349_hx509_cert_set_key(hx509_cert cert, hx509_private_key private_key) 350{ 351 if (cert->private_key) 352 hx509_private_key_free(&cert->private_key); 353 cert->private_key = _hx509_private_key_ref(private_key); 354 return 0; 355} 356 357/** 358 * Free reference to the hx509 certificate object, if the refcounter 359 * reaches 0, the object if freed. Its allowed to pass in NULL. 360 * 361 * @param cert the cert to free. 362 * 363 * @ingroup hx509_cert 364 */ 365 366void 367hx509_cert_free(hx509_cert cert) 368{ 369 heim_release(cert); 370} 371 372/** 373 * Add a reference to a hx509 certificate object. 374 * 375 * @param cert a pointer to an hx509 certificate object. 376 * 377 * @return the same object as is passed in. 378 * 379 * @ingroup hx509_cert 380 */ 381 382hx509_cert 383hx509_cert_ref(hx509_cert cert) 384{ 385 return heim_retain(cert); 386} 387 388/** 389 * Allocate an verification context that is used fo control the 390 * verification process. 391 * 392 * @param context A hx509 context. 393 * @param ctx returns a pointer to a hx509_verify_ctx object. 394 * 395 * @return An hx509 error code, see hx509_get_error_string(). 396 * 397 * @ingroup hx509_verify 398 */ 399 400int 401hx509_verify_init_ctx(hx509_context context, hx509_verify_ctx *ctx) 402{ 403 hx509_verify_ctx c; 404 405 c = calloc(1, sizeof(*c)); 406 if (c == NULL) 407 return ENOMEM; 408 409 c->max_depth = HX509_VERIFY_MAX_DEPTH; 410 411 *ctx = c; 412 413 return 0; 414} 415 416/** 417 * Free an hx509 verification context. 418 * 419 * @param ctx the context to be freed. 420 * 421 * @ingroup hx509_verify 422 */ 423 424void 425hx509_verify_destroy_ctx(hx509_verify_ctx ctx) 426{ 427 if (ctx) { 428 hx509_certs_free(&ctx->trust_anchors); 429 hx509_revoke_free(&ctx->revoke_ctx); 430 memset(ctx, 0, sizeof(*ctx)); 431 } 432 free(ctx); 433} 434 435/** 436 * Set the trust anchors in the verification context, makes an 437 * reference to the keyset, so the consumer can free the keyset 438 * independent of the destruction of the verification context (ctx). 439 * If there already is a keyset attached, it's released. 440 * 441 * @param ctx a verification context 442 * @param set a keyset containing the trust anchors. 443 * 444 * @ingroup hx509_verify 445 */ 446 447void 448hx509_verify_attach_anchors(hx509_verify_ctx ctx, hx509_certs set) 449{ 450 if (ctx->trust_anchors) 451 hx509_certs_free(&ctx->trust_anchors); 452 ctx->trust_anchors = hx509_certs_ref(set); 453} 454 455/** 456 * Attach an revocation context to the verfication context, , makes an 457 * reference to the revoke context, so the consumer can free the 458 * revoke context independent of the destruction of the verification 459 * context. If there is no revoke context, the verification process is 460 * NOT going to check any verification status. 461 * 462 * @param ctx a verification context. 463 * @param revoke_ctx a revoke context. 464 * 465 * @ingroup hx509_verify 466 */ 467 468void 469hx509_verify_attach_revoke(hx509_verify_ctx ctx, hx509_revoke_ctx revoke_ctx) 470{ 471 if (ctx->revoke_ctx) 472 hx509_revoke_free(&ctx->revoke_ctx); 473 ctx->revoke_ctx = _hx509_revoke_ref(revoke_ctx); 474} 475 476/** 477 * Set the clock time the the verification process is going to 478 * use. Used to check certificate in the past and future time. If not 479 * set the current time will be used. 480 * 481 * @param ctx a verification context. 482 * @param t the time the verifiation is using. 483 * 484 * 485 * @ingroup hx509_verify 486 */ 487 488void 489hx509_verify_set_time(hx509_verify_ctx ctx, time_t t) 490{ 491 ctx->flags |= HX509_VERIFY_CTX_F_TIME_SET; 492 ctx->time_now = t; 493} 494 495time_t 496_hx509_verify_get_time(hx509_verify_ctx ctx) 497{ 498 return ctx->time_now; 499} 500 501/** 502 * Set the maximum depth of the certificate chain that the path 503 * builder is going to try. 504 * 505 * @param ctx a verification context 506 * @param max_depth maxium depth of the certificate chain, include 507 * trust anchor. 508 * 509 * @ingroup hx509_verify 510 */ 511 512void 513hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth) 514{ 515 ctx->max_depth = max_depth; 516} 517 518/** 519 * Allow or deny the use of proxy certificates 520 * 521 * @param ctx a verification context 522 * @param boolean if non zero, allow proxy certificates. 523 * 524 * @ingroup hx509_verify 525 */ 526 527void 528hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean) 529{ 530 if (boolean) 531 ctx->flags |= HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; 532 else 533 ctx->flags &= ~HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE; 534} 535 536/** 537 * Select strict RFC3280 verification of certificiates. This means 538 * checking key usage on CA certificates, this will make version 1 539 * certificiates unuseable. 540 * 541 * @param ctx a verification context 542 * @param boolean if non zero, use strict verification. 543 * 544 * @ingroup hx509_verify 545 */ 546 547void 548hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean) 549{ 550 if (boolean) 551 ctx->flags |= HX509_VERIFY_CTX_F_REQUIRE_RFC3280; 552 else 553 ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280; 554} 555 556/** 557 * Allow using the operating system builtin trust anchors if no other 558 * trust anchors are configured. 559 * 560 * @param ctx a verification context 561 * @param boolean if non zero, useing the operating systems builtin 562 * trust anchors. 563 * 564 * 565 * @return An hx509 error code, see hx509_get_error_string(). 566 * 567 * @ingroup hx509_cert 568 */ 569 570void 571hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean) 572{ 573 if (boolean) 574 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; 575 else 576 ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; 577} 578 579void 580hx509_verify_ctx_f_allow_best_before_signature_algs(hx509_context ctx, 581 int boolean) 582{ 583 if (boolean) 584 ctx->flags &= ~HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; 585 else 586 ctx->flags |= HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK; 587} 588 589static const Extension * 590find_extension(const Certificate *cert, const heim_oid *oid, size_t *idx) 591{ 592 const TBSCertificate *c = &cert->tbsCertificate; 593 594 if (c->version == NULL || *c->version < 2 || c->extensions == NULL) 595 return NULL; 596 597 for (;*idx < c->extensions->len; (*idx)++) { 598 if (der_heim_oid_cmp(&c->extensions->val[*idx].extnID, oid) == 0) 599 return &c->extensions->val[(*idx)++]; 600 } 601 return NULL; 602} 603 604static int 605find_extension_auth_key_id(const Certificate *subject, 606 AuthorityKeyIdentifier *ai) 607{ 608 const Extension *e; 609 size_t size; 610 size_t i = 0; 611 612 memset(ai, 0, sizeof(*ai)); 613 614 e = find_extension(subject, &asn1_oid_id_x509_ce_authorityKeyIdentifier, &i); 615 if (e == NULL) 616 return HX509_EXTENSION_NOT_FOUND; 617 618 return decode_AuthorityKeyIdentifier(e->extnValue.data, 619 e->extnValue.length, 620 ai, &size); 621} 622 623int 624_hx509_find_extension_subject_key_id(const Certificate *issuer, 625 SubjectKeyIdentifier *si) 626{ 627 const Extension *e; 628 size_t size; 629 size_t i = 0; 630 631 memset(si, 0, sizeof(*si)); 632 633 e = find_extension(issuer, &asn1_oid_id_x509_ce_subjectKeyIdentifier, &i); 634 if (e == NULL) 635 return HX509_EXTENSION_NOT_FOUND; 636 637 return decode_SubjectKeyIdentifier(e->extnValue.data, 638 e->extnValue.length, 639 si, &size); 640} 641 642static int 643find_extension_name_constraints(const Certificate *subject, 644 NameConstraints *nc) 645{ 646 const Extension *e; 647 size_t size; 648 size_t i = 0; 649 650 memset(nc, 0, sizeof(*nc)); 651 652 e = find_extension(subject, &asn1_oid_id_x509_ce_nameConstraints, &i); 653 if (e == NULL) 654 return HX509_EXTENSION_NOT_FOUND; 655 656 return decode_NameConstraints(e->extnValue.data, 657 e->extnValue.length, 658 nc, &size); 659} 660 661static int 662find_extension_subject_alt_name(const Certificate *cert, size_t *i, 663 GeneralNames *sa) 664{ 665 const Extension *e; 666 size_t size; 667 668 memset(sa, 0, sizeof(*sa)); 669 670 e = find_extension(cert, &asn1_oid_id_x509_ce_subjectAltName, i); 671 if (e == NULL) 672 return HX509_EXTENSION_NOT_FOUND; 673 674 return decode_GeneralNames(e->extnValue.data, 675 e->extnValue.length, 676 sa, &size); 677} 678 679static int 680find_extension_eku(const Certificate *cert, ExtKeyUsage *eku) 681{ 682 const Extension *e; 683 size_t size; 684 size_t i = 0; 685 686 memset(eku, 0, sizeof(*eku)); 687 688 e = find_extension(cert, &asn1_oid_id_x509_ce_extKeyUsage, &i); 689 if (e == NULL) 690 return HX509_EXTENSION_NOT_FOUND; 691 692 return decode_ExtKeyUsage(e->extnValue.data, 693 e->extnValue.length, 694 eku, &size); 695} 696 697static int 698add_to_list(hx509_octet_string_list *list, const heim_octet_string *entry) 699{ 700 void *p; 701 int ret; 702 703 p = realloc(list->val, (list->len + 1) * sizeof(list->val[0])); 704 if (p == NULL) 705 return ENOMEM; 706 list->val = p; 707 ret = der_copy_octet_string(entry, &list->val[list->len]); 708 if (ret) 709 return ret; 710 list->len++; 711 return 0; 712} 713 714/** 715 * Free a list of octet strings returned by another hx509 library 716 * function. 717 * 718 * @param list list to be freed. 719 * 720 * @ingroup hx509_misc 721 */ 722 723void 724hx509_free_octet_string_list(hx509_octet_string_list *list) 725{ 726 size_t i; 727 for (i = 0; i < list->len; i++) 728 der_free_octet_string(&list->val[i]); 729 free(list->val); 730 list->val = NULL; 731 list->len = 0; 732} 733 734/** 735 * Return a list of subjectAltNames specified by oid in the 736 * certificate. On error the 737 * 738 * The returned list of octet string should be freed with 739 * hx509_free_octet_string_list(). 740 * 741 * @param context A hx509 context. 742 * @param cert a hx509 certificate object. 743 * @param oid an oid to for SubjectAltName. 744 * @param list list of matching SubjectAltName. 745 * 746 * @return An hx509 error code, see hx509_get_error_string(). 747 * 748 * @ingroup hx509_cert 749 */ 750 751int 752hx509_cert_find_subjectAltName_otherName(hx509_context context, 753 hx509_cert cert, 754 const heim_oid *oid, 755 hx509_octet_string_list *list) 756{ 757 GeneralNames sa; 758 int ret; 759 size_t i, j; 760 761 list->val = NULL; 762 list->len = 0; 763 764 i = 0; 765 while (1) { 766 ret = find_extension_subject_alt_name(_hx509_get_cert(cert), &i, &sa); 767 i++; 768 if (ret == HX509_EXTENSION_NOT_FOUND) { 769 return 0; 770 } else if (ret != 0) { 771 hx509_set_error_string(context, 0, ret, "Error searching for SAN"); 772 hx509_free_octet_string_list(list); 773 return ret; 774 } 775 776 for (j = 0; j < sa.len; j++) { 777 if (sa.val[j].element == choice_GeneralName_otherName && 778 der_heim_oid_cmp(&sa.val[j].u.otherName.type_id, oid) == 0) 779 { 780 ret = add_to_list(list, &sa.val[j].u.otherName.value); 781 if (ret) { 782 hx509_set_error_string(context, 0, ret, 783 "Error adding an exra SAN to " 784 "return list"); 785 hx509_free_octet_string_list(list); 786 free_GeneralNames(&sa); 787 return ret; 788 } 789 } 790 } 791 free_GeneralNames(&sa); 792 } 793} 794 795 796static int 797check_key_usage(hx509_context context, const Certificate *cert, 798 unsigned flags, int req_present) 799{ 800 const Extension *e; 801 KeyUsage ku; 802 size_t size; 803 int ret; 804 size_t i = 0; 805 unsigned ku_flags; 806 807 if (_hx509_cert_get_version(cert) < 3) 808 return 0; 809 810 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); 811 if (e == NULL) { 812 if (req_present) { 813 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, 814 "Required extension key " 815 "usage missing from certifiate"); 816 return HX509_KU_CERT_MISSING; 817 } 818 return 0; 819 } 820 821 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, &ku, &size); 822 if (ret) 823 return ret; 824 ku_flags = KeyUsage2int(ku); 825 if ((ku_flags & flags) != flags) { 826 unsigned missing = (~ku_flags) & flags; 827 char buf[256], *name; 828 829 unparse_flags(missing, asn1_KeyUsage_units(), buf, sizeof(buf)); 830 _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); 831 hx509_set_error_string(context, 0, HX509_KU_CERT_MISSING, 832 "Key usage %s required but missing " 833 "from certifiate %s", buf, name); 834 free(name); 835 return HX509_KU_CERT_MISSING; 836 } 837 return 0; 838} 839 840/* 841 * Return 0 on matching key usage 'flags' for 'cert', otherwise return 842 * an error code. If 'req_present' the existance is required of the 843 * KeyUsage extension. 844 */ 845 846int 847_hx509_check_key_usage(hx509_context context, hx509_cert cert, 848 unsigned flags, int req_present) 849{ 850 return check_key_usage(context, _hx509_get_cert(cert), flags, req_present); 851} 852 853enum certtype { PROXY_CERT, EE_CERT, CA_CERT }; 854 855static int 856check_basic_constraints(hx509_context context, const Certificate *cert, 857 enum certtype type, size_t depth) 858{ 859 BasicConstraints bc; 860 const Extension *e; 861 size_t size; 862 int ret; 863 size_t i = 0; 864 865 if (_hx509_cert_get_version(cert) < 3) 866 return 0; 867 868 e = find_extension(cert, &asn1_oid_id_x509_ce_basicConstraints, &i); 869 if (e == NULL) { 870 switch(type) { 871 case PROXY_CERT: 872 case EE_CERT: 873 return 0; 874 case CA_CERT: { 875 char *name; 876 ret = _hx509_unparse_Name(&cert->tbsCertificate.subject, &name); 877 assert(ret == 0); 878 hx509_set_error_string(context, 0, HX509_EXTENSION_NOT_FOUND, 879 "basicConstraints missing from " 880 "CA certifiacte %s", name); 881 free(name); 882 return HX509_EXTENSION_NOT_FOUND; 883 } 884 } 885 } 886 887 ret = decode_BasicConstraints(e->extnValue.data, 888 e->extnValue.length, &bc, 889 &size); 890 if (ret) 891 return ret; 892 switch(type) { 893 case PROXY_CERT: 894 if (bc.cA != NULL && *bc.cA) 895 ret = HX509_PARENT_IS_CA; 896 break; 897 case EE_CERT: 898 ret = 0; 899 break; 900 case CA_CERT: 901 if (bc.cA == NULL || !*bc.cA) 902 ret = HX509_PARENT_NOT_CA; 903 else if (bc.pathLenConstraint) 904 if (depth - 1 > *bc.pathLenConstraint) 905 ret = HX509_CA_PATH_TOO_DEEP; 906 break; 907 } 908 free_BasicConstraints(&bc); 909 return ret; 910} 911 912int 913_hx509_cert_is_parent_cmp(const Certificate *subject, 914 const Certificate *issuer, 915 int allow_self_signed) 916{ 917 int diff; 918 AuthorityKeyIdentifier ai; 919 SubjectKeyIdentifier si; 920 int ret_ai, ret_si, ret; 921 922 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject, 923 &subject->tbsCertificate.issuer, 924 &diff); 925 if (ret) 926 return ret; 927 if (diff) 928 return diff; 929 930 memset(&ai, 0, sizeof(ai)); 931 memset(&si, 0, sizeof(si)); 932 933 /* 934 * Try to find AuthorityKeyIdentifier, if it's not present in the 935 * subject certificate nor the parent. 936 */ 937 938 ret_ai = find_extension_auth_key_id(subject, &ai); 939 if (ret_ai && ret_ai != HX509_EXTENSION_NOT_FOUND) 940 return 1; 941 ret_si = _hx509_find_extension_subject_key_id(issuer, &si); 942 if (ret_si && ret_si != HX509_EXTENSION_NOT_FOUND) 943 return -1; 944 945 if (ret_si && ret_ai) 946 goto out; 947 if (ret_ai) 948 goto out; 949 if (ret_si) { 950 if (allow_self_signed) { 951 diff = 0; 952 goto out; 953 } else if (ai.keyIdentifier) { 954 diff = -1; 955 goto out; 956 } 957 } 958 959 if (ai.keyIdentifier == NULL) { 960 Name name; 961 962 if (ai.authorityCertIssuer == NULL) 963 return -1; 964 if (ai.authorityCertSerialNumber == NULL) 965 return -1; 966 967 diff = der_heim_integer_cmp(ai.authorityCertSerialNumber, 968 &issuer->tbsCertificate.serialNumber); 969 if (diff) 970 return diff; 971 if (ai.authorityCertIssuer->len != 1) 972 return -1; 973 if (ai.authorityCertIssuer->val[0].element != choice_GeneralName_directoryName) 974 return -1; 975 976 name.element = (enum Name_enum) 977 ai.authorityCertIssuer->val[0].u.directoryName.element; 978 name.u.rdnSequence = 979 ai.authorityCertIssuer->val[0].u.directoryName.u.rdnSequence; 980 981 ret = _hx509_name_cmp(&issuer->tbsCertificate.subject, 982 &name, 983 &diff); 984 if (ret) 985 return ret; 986 if (diff) 987 return diff; 988 diff = 0; 989 } else 990 diff = der_heim_octet_string_cmp(ai.keyIdentifier, &si); 991 if (diff) 992 goto out; 993 994 out: 995 free_AuthorityKeyIdentifier(&ai); 996 free_SubjectKeyIdentifier(&si); 997 return diff; 998} 999 1000static int 1001certificate_is_anchor(hx509_context context, 1002 hx509_certs trust_anchors, 1003 const hx509_cert cert) 1004{ 1005 hx509_query q; 1006 hx509_cert c; 1007 int ret; 1008 1009 if (trust_anchors == NULL) 1010 return 0; 1011 1012 _hx509_query_clear(&q); 1013 1014 q.match = HX509_QUERY_MATCH_CERTIFICATE; 1015 q.certificate = _hx509_get_cert(cert); 1016 1017 ret = hx509_certs_find(context, trust_anchors, &q, &c); 1018 if (ret == 0) 1019 hx509_cert_free(c); 1020 return ret == 0; 1021} 1022 1023static int 1024certificate_is_self_signed(hx509_context context, 1025 const Certificate *cert, 1026 int *self_signed) 1027{ 1028 int ret, diff; 1029 ret = _hx509_name_cmp(&cert->tbsCertificate.subject, 1030 &cert->tbsCertificate.issuer, &diff); 1031 *self_signed = (diff == 0); 1032 if (ret) { 1033 hx509_set_error_string(context, 0, ret, 1034 "Failed to check if self signed"); 1035 } else 1036 ret = _hx509_self_signed_valid(context, &cert->signatureAlgorithm); 1037 1038 return ret; 1039} 1040 1041/* 1042 * The subjectName is "null" when it's empty set of relative DBs. 1043 */ 1044 1045static int 1046subject_null_p(const Certificate *c) 1047{ 1048 return c->tbsCertificate.subject.u.rdnSequence.len == 0; 1049} 1050 1051 1052static int 1053find_parent(hx509_context context, 1054 time_t time_now, 1055 hx509_certs trust_anchors, 1056 hx509_path *path, 1057 hx509_certs pool, 1058 hx509_cert current, 1059 hx509_cert *parent) 1060{ 1061 AuthorityKeyIdentifier ai; 1062 hx509_query q; 1063 int ret; 1064 1065 *parent = NULL; 1066 memset(&ai, 0, sizeof(ai)); 1067 1068 _hx509_query_clear(&q); 1069 1070 if (!subject_null_p(current->data)) { 1071 q.match |= HX509_QUERY_FIND_ISSUER_CERT; 1072 q.subject = _hx509_get_cert(current); 1073 } else { 1074 ret = find_extension_auth_key_id(current->data, &ai); 1075 if (ret) { 1076 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, 1077 "Subjectless certificate missing AuthKeyID"); 1078 return HX509_CERTIFICATE_MALFORMED; 1079 } 1080 1081 if (ai.keyIdentifier == NULL) { 1082 free_AuthorityKeyIdentifier(&ai); 1083 hx509_set_error_string(context, 0, HX509_CERTIFICATE_MALFORMED, 1084 "Subjectless certificate missing keyIdentifier " 1085 "inside AuthKeyID"); 1086 return HX509_CERTIFICATE_MALFORMED; 1087 } 1088 1089 q.subject_id = ai.keyIdentifier; 1090 q.match = HX509_QUERY_MATCH_SUBJECT_KEY_ID; 1091 } 1092 1093 q.path = path; 1094 q.match |= HX509_QUERY_NO_MATCH_PATH; 1095 1096 if (pool) { 1097 q.timenow = time_now; 1098 q.match |= HX509_QUERY_MATCH_TIME; 1099 1100 ret = hx509_certs_find(context, pool, &q, parent); 1101 if (ret == 0) { 1102 free_AuthorityKeyIdentifier(&ai); 1103 return 0; 1104 } 1105 q.match &= ~HX509_QUERY_MATCH_TIME; 1106 } 1107 1108 if (trust_anchors) { 1109 ret = hx509_certs_find(context, trust_anchors, &q, parent); 1110 if (ret == 0) { 1111 free_AuthorityKeyIdentifier(&ai); 1112 return ret; 1113 } 1114 } 1115 free_AuthorityKeyIdentifier(&ai); 1116 1117 { 1118 hx509_name name; 1119 char *str; 1120 1121 ret = hx509_cert_get_subject(current, &name); 1122 if (ret) { 1123 hx509_clear_error_string(context); 1124 return HX509_ISSUER_NOT_FOUND; 1125 } 1126 ret = hx509_name_to_string(name, &str); 1127 hx509_name_free(&name); 1128 if (ret) { 1129 hx509_clear_error_string(context); 1130 return HX509_ISSUER_NOT_FOUND; 1131 } 1132 1133 hx509_set_error_string(context, 0, HX509_ISSUER_NOT_FOUND, 1134 "Failed to find issuer for " 1135 "certificate with subject: '%s'", str); 1136 free(str); 1137 } 1138 return HX509_ISSUER_NOT_FOUND; 1139} 1140 1141/* 1142 * 1143 */ 1144 1145static int 1146is_proxy_cert(hx509_context context, 1147 const Certificate *cert, 1148 ProxyCertInfo *rinfo) 1149{ 1150 ProxyCertInfo info; 1151 const Extension *e; 1152 size_t size; 1153 int ret; 1154 size_t i = 0; 1155 1156 if (rinfo) 1157 memset(rinfo, 0, sizeof(*rinfo)); 1158 1159 e = find_extension(cert, &asn1_oid_id_pkix_pe_proxyCertInfo, &i); 1160 if (e == NULL) { 1161 hx509_clear_error_string(context); 1162 return HX509_EXTENSION_NOT_FOUND; 1163 } 1164 1165 ret = decode_ProxyCertInfo(e->extnValue.data, 1166 e->extnValue.length, 1167 &info, 1168 &size); 1169 if (ret) { 1170 hx509_clear_error_string(context); 1171 return ret; 1172 } 1173 if (size != e->extnValue.length) { 1174 free_ProxyCertInfo(&info); 1175 hx509_clear_error_string(context); 1176 return HX509_EXTRA_DATA_AFTER_STRUCTURE; 1177 } 1178 if (rinfo == NULL) 1179 free_ProxyCertInfo(&info); 1180 else 1181 *rinfo = info; 1182 1183 return 0; 1184} 1185 1186/* 1187 * Path operations are like MEMORY based keyset, but with exposed 1188 * internal so we can do easy searches. 1189 */ 1190 1191int 1192_hx509_path_append(hx509_context context, hx509_path *path, hx509_cert cert) 1193{ 1194 hx509_cert *val; 1195 val = realloc(path->val, (path->len + 1) * sizeof(path->val[0])); 1196 if (val == NULL) { 1197 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 1198 return ENOMEM; 1199 } 1200 1201 path->val = val; 1202 path->val[path->len] = hx509_cert_ref(cert); 1203 path->len++; 1204 1205 return 0; 1206} 1207 1208void 1209_hx509_path_free(hx509_path *path) 1210{ 1211 unsigned i; 1212 1213 for (i = 0; i < path->len; i++) 1214 hx509_cert_free(path->val[i]); 1215 free(path->val); 1216 path->val = NULL; 1217 path->len = 0; 1218} 1219 1220/* 1221 * Find path by looking up issuer for the top certificate and continue 1222 * until an anchor certificate is found or max limit is found. A 1223 * certificate never included twice in the path. 1224 * 1225 * If the trust anchors are not given, calculate optimistic path, just 1226 * follow the chain upward until we no longer find a parent or we hit 1227 * the max path limit. In this case, a failure will always be returned 1228 * depending on what error condition is hit first. 1229 * 1230 * The path includes a path from the top certificate to the anchor 1231 * certificate. 1232 * 1233 * The caller needs to free `path´ both on successful built path and 1234 * failure. 1235 */ 1236 1237int 1238_hx509_calculate_path(hx509_context context, 1239 int flags, 1240 time_t time_now, 1241 hx509_certs anchors, 1242 unsigned int max_depth, 1243 hx509_cert cert, 1244 hx509_certs pool, 1245 hx509_path *path) 1246{ 1247 hx509_cert parent, current; 1248 int ret; 1249 1250 if (max_depth == 0) 1251 max_depth = HX509_VERIFY_MAX_DEPTH; 1252 1253 ret = _hx509_path_append(context, path, cert); 1254 if (ret) 1255 return ret; 1256 1257 current = hx509_cert_ref(cert); 1258 1259 while (!certificate_is_anchor(context, anchors, current)) { 1260 1261 ret = find_parent(context, time_now, anchors, path, 1262 pool, current, &parent); 1263 hx509_cert_free(current); 1264 if (ret) 1265 return ret; 1266 1267 ret = _hx509_path_append(context, path, parent); 1268 if (ret) 1269 return ret; 1270 current = parent; 1271 1272 if (path->len > max_depth) { 1273 hx509_cert_free(current); 1274 hx509_set_error_string(context, 0, HX509_PATH_TOO_LONG, 1275 "Path too long while bulding " 1276 "certificate chain"); 1277 return HX509_PATH_TOO_LONG; 1278 } 1279 } 1280 1281 if ((flags & HX509_CALCULATE_PATH_NO_ANCHOR) && 1282 path->len > 0 && 1283 certificate_is_anchor(context, anchors, path->val[path->len - 1])) 1284 { 1285 hx509_cert_free(path->val[path->len - 1]); 1286 path->len--; 1287 } 1288 1289 hx509_cert_free(current); 1290 return 0; 1291} 1292 1293int 1294_hx509_AlgorithmIdentifier_cmp(const AlgorithmIdentifier *p, 1295 const AlgorithmIdentifier *q) 1296{ 1297 int diff; 1298 diff = der_heim_oid_cmp(&p->algorithm, &q->algorithm); 1299 if (diff) 1300 return diff; 1301 if (p->parameters) { 1302 if (q->parameters) 1303 return heim_any_cmp(p->parameters, 1304 q->parameters); 1305 else 1306 return 1; 1307 } else { 1308 if (q->parameters) 1309 return -1; 1310 else 1311 return 0; 1312 } 1313} 1314 1315int 1316_hx509_Certificate_cmp(const Certificate *p, const Certificate *q) 1317{ 1318 int diff; 1319 diff = der_heim_bit_string_cmp(&p->signatureValue, &q->signatureValue); 1320 if (diff) 1321 return diff; 1322 diff = _hx509_AlgorithmIdentifier_cmp(&p->signatureAlgorithm, 1323 &q->signatureAlgorithm); 1324 if (diff) 1325 return diff; 1326 diff = der_heim_octet_string_cmp(&p->tbsCertificate._save, 1327 &q->tbsCertificate._save); 1328 return diff; 1329} 1330 1331/** 1332 * Compare to hx509 certificate object, useful for sorting. 1333 * 1334 * @param p a hx509 certificate object. 1335 * @param q a hx509 certificate object. 1336 * 1337 * @return 0 the objects are the same, returns > 0 is p is "larger" 1338 * then q, < 0 if p is "smaller" then q. 1339 * 1340 * @ingroup hx509_cert 1341 */ 1342 1343int 1344hx509_cert_cmp(hx509_cert p, hx509_cert q) 1345{ 1346 return _hx509_Certificate_cmp(p->data, q->data); 1347} 1348 1349/** 1350 * Return the name of the issuer of the hx509 certificate. 1351 * 1352 * @param p a hx509 certificate object. 1353 * @param name a pointer to a hx509 name, should be freed by 1354 * hx509_name_free(). 1355 * 1356 * @return An hx509 error code, see hx509_get_error_string(). 1357 * 1358 * @ingroup hx509_cert 1359 */ 1360 1361int 1362hx509_cert_get_issuer(hx509_cert p, hx509_name *name) 1363{ 1364 return hx509_name_from_Name(&p->data->tbsCertificate.issuer, name); 1365} 1366 1367/** 1368 * Return the name of the subject of the hx509 certificate. 1369 * 1370 * @param p a hx509 certificate object. 1371 * @param name a pointer to a hx509 name, should be freed by 1372 * hx509_name_free(). See also hx509_cert_get_base_subject(). 1373 * 1374 * @return An hx509 error code, see hx509_get_error_string(). 1375 * 1376 * @ingroup hx509_cert 1377 */ 1378 1379int 1380hx509_cert_get_subject(hx509_cert p, hx509_name *name) 1381{ 1382 return hx509_name_from_Name(&p->data->tbsCertificate.subject, name); 1383} 1384 1385/** 1386 * Return the name of the base subject of the hx509 certificate. If 1387 * the certiicate is a verified proxy certificate, the this function 1388 * return the base certificate (root of the proxy chain). If the proxy 1389 * certificate is not verified with the base certificate 1390 * HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED is returned. 1391 * 1392 * @param context a hx509 context. 1393 * @param c a hx509 certificate object. 1394 * @param name a pointer to a hx509 name, should be freed by 1395 * hx509_name_free(). See also hx509_cert_get_subject(). 1396 * 1397 * @return An hx509 error code, see hx509_get_error_string(). 1398 * 1399 * @ingroup hx509_cert 1400 */ 1401 1402int 1403hx509_cert_get_base_subject(hx509_context context, hx509_cert c, 1404 hx509_name *name) 1405{ 1406 if (c->basename) 1407 return hx509_name_copy(context, c->basename, name); 1408 if (is_proxy_cert(context, c->data, NULL) == 0) { 1409 int ret = HX509_PROXY_CERTIFICATE_NOT_CANONICALIZED; 1410 hx509_set_error_string(context, 0, ret, 1411 "Proxy certificate have not been " 1412 "canonicalize yet, no base name"); 1413 return ret; 1414 } 1415 return hx509_name_from_Name(&c->data->tbsCertificate.subject, name); 1416} 1417 1418/** 1419 * Get serial number of the certificate. 1420 * 1421 * @param p a hx509 certificate object. 1422 * @param i serial number, should be freed ith der_free_heim_integer(). 1423 * 1424 * @return An hx509 error code, see hx509_get_error_string(). 1425 * 1426 * @ingroup hx509_cert 1427 */ 1428 1429int 1430hx509_cert_get_serialnumber(hx509_cert p, heim_integer *i) 1431{ 1432 return der_copy_heim_integer(&p->data->tbsCertificate.serialNumber, i); 1433} 1434 1435/** 1436 * Get notBefore time of the certificate. 1437 * 1438 * @param p a hx509 certificate object. 1439 * 1440 * @return return not before time 1441 * 1442 * @ingroup hx509_cert 1443 */ 1444 1445time_t 1446hx509_cert_get_notBefore(hx509_cert p) 1447{ 1448 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notBefore); 1449} 1450 1451/** 1452 * Get notAfter time of the certificate. 1453 * 1454 * @param p a hx509 certificate object. 1455 * 1456 * @return return not after time. 1457 * 1458 * @ingroup hx509_cert 1459 */ 1460 1461time_t 1462hx509_cert_get_notAfter(hx509_cert p) 1463{ 1464 return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter); 1465} 1466 1467/** 1468 * Get the SubjectPublicKeyInfo structure from the hx509 certificate. 1469 * 1470 * @param context a hx509 context. 1471 * @param p a hx509 certificate object. 1472 * @param spki SubjectPublicKeyInfo, should be freed with 1473 * free_SubjectPublicKeyInfo(). 1474 * 1475 * @return An hx509 error code, see hx509_get_error_string(). 1476 * 1477 * @ingroup hx509_cert 1478 */ 1479 1480int 1481hx509_cert_get_SPKI(hx509_context context, hx509_cert p, SubjectPublicKeyInfo *spki) 1482{ 1483 int ret; 1484 1485 ret = copy_SubjectPublicKeyInfo(&p->data->tbsCertificate.subjectPublicKeyInfo, spki); 1486 if (ret) 1487 hx509_set_error_string(context, 0, ret, "Failed to copy SPKI"); 1488 return ret; 1489} 1490 1491/** 1492 * Get the AlgorithmIdentifier from the hx509 certificate. 1493 * 1494 * @param context a hx509 context. 1495 * @param p a hx509 certificate object. 1496 * @param alg AlgorithmIdentifier, should be freed with 1497 * free_AlgorithmIdentifier(). The algorithmidentifier is 1498 * typicly rsaEncryption, or id-ecPublicKey, or some other 1499 * public key mechanism. 1500 * 1501 * @return An hx509 error code, see hx509_get_error_string(). 1502 * 1503 * @ingroup hx509_cert 1504 */ 1505 1506int 1507hx509_cert_get_SPKI_AlgorithmIdentifier(hx509_context context, 1508 hx509_cert p, 1509 AlgorithmIdentifier *alg) 1510{ 1511 int ret; 1512 1513 ret = copy_AlgorithmIdentifier(&p->data->tbsCertificate.subjectPublicKeyInfo.algorithm, alg); 1514 if (ret) 1515 hx509_set_error_string(context, 0, ret, 1516 "Failed to copy SPKI AlgorithmIdentifier"); 1517 return ret; 1518} 1519 1520static int 1521get_x_unique_id(hx509_context context, const char *name, 1522 const heim_bit_string *cert, heim_bit_string *subject) 1523{ 1524 int ret; 1525 1526 if (cert == NULL) { 1527 ret = HX509_EXTENSION_NOT_FOUND; 1528 hx509_set_error_string(context, 0, ret, "%s unique id doesn't exists", name); 1529 return ret; 1530 } 1531 ret = der_copy_bit_string(cert, subject); 1532 if (ret) { 1533 hx509_set_error_string(context, 0, ret, "malloc out of memory", name); 1534 return ret; 1535 } 1536 return 0; 1537} 1538 1539/** 1540 * Get a copy of the Issuer Unique ID 1541 * 1542 * @param context a hx509_context 1543 * @param p a hx509 certificate 1544 * @param issuer the issuer id returned, free with der_free_bit_string() 1545 * 1546 * @return An hx509 error code, see hx509_get_error_string(). The 1547 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate 1548 * doesn't have a issuerUniqueID 1549 * 1550 * @ingroup hx509_cert 1551 */ 1552 1553int 1554hx509_cert_get_issuer_unique_id(hx509_context context, hx509_cert p, heim_bit_string *issuer) 1555{ 1556 return get_x_unique_id(context, "issuer", p->data->tbsCertificate.issuerUniqueID, issuer); 1557} 1558 1559/** 1560 * Get a copy of the Subect Unique ID 1561 * 1562 * @param context a hx509_context 1563 * @param p a hx509 certificate 1564 * @param subject the subject id returned, free with der_free_bit_string() 1565 * 1566 * @return An hx509 error code, see hx509_get_error_string(). The 1567 * error code HX509_EXTENSION_NOT_FOUND is returned if the certificate 1568 * doesn't have a subjectUniqueID 1569 * 1570 * @ingroup hx509_cert 1571 */ 1572 1573int 1574hx509_cert_get_subject_unique_id(hx509_context context, hx509_cert p, heim_bit_string *subject) 1575{ 1576 return get_x_unique_id(context, "subject", p->data->tbsCertificate.subjectUniqueID, subject); 1577} 1578 1579 1580hx509_private_key 1581_hx509_cert_private_key(hx509_cert p) 1582{ 1583 return p->private_key; 1584} 1585 1586int 1587hx509_cert_have_private_key(hx509_cert p) 1588{ 1589 return p->private_key ? 1 : 0; 1590} 1591 1592 1593int 1594_hx509_cert_private_key_exportable(hx509_cert p) 1595{ 1596 if (p->private_key == NULL) 1597 return 0; 1598 return _hx509_private_key_exportable(p->private_key); 1599} 1600 1601int 1602_hx509_cert_private_decrypt(hx509_context context, 1603 const heim_octet_string *ciphertext, 1604 const heim_oid *encryption_oid, 1605 hx509_cert p, 1606 heim_octet_string *cleartext) 1607{ 1608 cleartext->data = NULL; 1609 cleartext->length = 0; 1610 1611 if (p->private_key == NULL) { 1612 hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, 1613 "Private key missing"); 1614 return HX509_PRIVATE_KEY_MISSING; 1615 } 1616 1617 return hx509_private_key_private_decrypt(context, 1618 ciphertext, 1619 encryption_oid, 1620 p->private_key, 1621 cleartext); 1622} 1623 1624int 1625hx509_cert_public_encrypt(hx509_context context, 1626 const heim_octet_string *cleartext, 1627 const hx509_cert p, 1628 heim_oid *encryption_oid, 1629 heim_octet_string *ciphertext) 1630{ 1631 return _hx509_public_encrypt(context, 1632 cleartext, p->data, 1633 encryption_oid, ciphertext); 1634} 1635 1636/* 1637 * 1638 */ 1639 1640time_t 1641_hx509_Time2time_t(const Time *t) 1642{ 1643 switch(t->element) { 1644 case choice_Time_utcTime: 1645 return t->u.utcTime; 1646 case choice_Time_generalTime: 1647 return t->u.generalTime; 1648 case invalid_choice_Time: 1649 return 0; 1650 } 1651 return 0; 1652} 1653 1654static void 1655evaluate_free(heim_object_t object) 1656{ 1657 hx509_evaluate data = object; 1658 heim_release(data->path); 1659} 1660 1661hx509_evaluate 1662_hx509_evaluate_alloc(void) 1663{ 1664 hx509_evaluate eval; 1665 1666 eval = heim_uniq_alloc(sizeof(*eval), "hx509-evaluate", evaluate_free); 1667 if (eval == NULL) 1668 return NULL; 1669 1670 eval->path = heim_array_create(); 1671 if (eval->path == NULL) { 1672 heim_release(eval); 1673 return NULL; 1674 } 1675 return eval; 1676} 1677 1678size_t 1679hx509_evaluate_get_length(hx509_evaluate data) 1680{ 1681 return heim_array_get_length(data->path); 1682} 1683 1684hx509_cert 1685hx509_evaluate_get_cert(hx509_evaluate data, size_t offset) 1686{ 1687 return heim_array_copy_value(data->path, offset); 1688} 1689 1690hx509_cert 1691hx509_evaluate_get_ta(hx509_evaluate data) 1692{ 1693 size_t len = heim_array_get_length(data->path); 1694 if (len == 0) 1695 return NULL; 1696 return heim_array_copy_value(data->path, len - 1); 1697} 1698 1699void 1700hx509_evaluate_free(hx509_evaluate data) 1701{ 1702 heim_release(data); 1703} 1704 1705/* 1706 * 1707 */ 1708 1709static int 1710init_name_constraints(hx509_name_constraints *nc) 1711{ 1712 memset(nc, 0, sizeof(*nc)); 1713 return 0; 1714} 1715 1716static int 1717add_name_constraints(hx509_context context, const Certificate *c, int not_ca, 1718 hx509_name_constraints *nc) 1719{ 1720 NameConstraints tnc; 1721 int ret; 1722 1723 ret = find_extension_name_constraints(c, &tnc); 1724 if (ret == HX509_EXTENSION_NOT_FOUND) 1725 return 0; 1726 else if (ret) { 1727 hx509_set_error_string(context, 0, ret, "Failed getting NameConstraints"); 1728 return ret; 1729 } else if (not_ca) { 1730 ret = HX509_VERIFY_CONSTRAINTS; 1731 hx509_set_error_string(context, 0, ret, "Not a CA and " 1732 "have NameConstraints"); 1733 } else { 1734 NameConstraints *val; 1735 val = realloc(nc->val, sizeof(nc->val[0]) * (nc->len + 1)); 1736 if (val == NULL) { 1737 hx509_clear_error_string(context); 1738 ret = ENOMEM; 1739 goto out; 1740 } 1741 nc->val = val; 1742 ret = copy_NameConstraints(&tnc, &nc->val[nc->len]); 1743 if (ret) { 1744 hx509_clear_error_string(context); 1745 goto out; 1746 } 1747 nc->len += 1; 1748 } 1749out: 1750 free_NameConstraints(&tnc); 1751 return ret; 1752} 1753 1754static int 1755match_RDN(const RelativeDistinguishedName *c, 1756 const RelativeDistinguishedName *n) 1757{ 1758 size_t i; 1759 1760 if (c->len != n->len) 1761 return HX509_NAME_CONSTRAINT_ERROR; 1762 1763 for (i = 0; i < n->len; i++) { 1764 int diff, ret; 1765 1766 if (der_heim_oid_cmp(&c->val[i].type, &n->val[i].type) != 0) 1767 return HX509_NAME_CONSTRAINT_ERROR; 1768 ret = _hx509_name_ds_cmp(&c->val[i].value, &n->val[i].value, &diff); 1769 if (ret) 1770 return ret; 1771 if (diff != 0) 1772 return HX509_NAME_CONSTRAINT_ERROR; 1773 } 1774 return 0; 1775} 1776 1777static int 1778match_X501Name(const Name *c, const Name *n) 1779{ 1780 size_t i; 1781 int ret; 1782 1783 if (c->element != choice_Name_rdnSequence 1784 || n->element != choice_Name_rdnSequence) 1785 return 0; 1786 if (c->u.rdnSequence.len > n->u.rdnSequence.len) 1787 return HX509_NAME_CONSTRAINT_ERROR; 1788 for (i = 0; i < c->u.rdnSequence.len; i++) { 1789 ret = match_RDN(&c->u.rdnSequence.val[i], &n->u.rdnSequence.val[i]); 1790 if (ret) 1791 return ret; 1792 } 1793 return 0; 1794} 1795 1796 1797static int 1798match_general_name(const GeneralName *c, const GeneralName *n, int *match) 1799{ 1800 /* 1801 * Name constraints only apply to the same name type, see RFC3280, 1802 * 4.2.1.11. 1803 */ 1804 assert(c->element == n->element); 1805 1806 switch(c->element) { 1807 case choice_GeneralName_otherName: 1808 if (der_heim_oid_cmp(&c->u.otherName.type_id, 1809 &n->u.otherName.type_id) != 0) 1810 return HX509_NAME_CONSTRAINT_ERROR; 1811 if (heim_any_cmp(&c->u.otherName.value, 1812 &n->u.otherName.value) != 0) 1813 return HX509_NAME_CONSTRAINT_ERROR; 1814 *match = 1; 1815 return 0; 1816 case choice_GeneralName_rfc822Name: { 1817 const char *s; 1818 size_t len1, len2; 1819 s = memchr(c->u.rfc822Name.data, '@', c->u.rfc822Name.length); 1820 if (s) { 1821 if (der_printable_string_cmp(&c->u.rfc822Name, &n->u.rfc822Name) != 0) 1822 return HX509_NAME_CONSTRAINT_ERROR; 1823 } else { 1824 s = memchr(n->u.rfc822Name.data, '@', n->u.rfc822Name.length); 1825 if (s == NULL) 1826 return HX509_NAME_CONSTRAINT_ERROR; 1827 len1 = c->u.rfc822Name.length; 1828 len2 = n->u.rfc822Name.length - 1829 (s - ((char *)n->u.rfc822Name.data)); 1830 if (len1 > len2) 1831 return HX509_NAME_CONSTRAINT_ERROR; 1832 if (memcmp(s + 1 + len2 - len1, c->u.rfc822Name.data, len1) != 0) 1833 return HX509_NAME_CONSTRAINT_ERROR; 1834 if (len1 < len2 && s[len2 - len1 + 1] != '.') 1835 return HX509_NAME_CONSTRAINT_ERROR; 1836 } 1837 *match = 1; 1838 return 0; 1839 } 1840 case choice_GeneralName_dNSName: { 1841 size_t lenc, lenn; 1842 char *ptr; 1843 1844 lenc = c->u.dNSName.length; 1845 lenn = n->u.dNSName.length; 1846 if (lenc > lenn) 1847 return HX509_NAME_CONSTRAINT_ERROR; 1848 ptr = n->u.dNSName.data; 1849 if (memcmp(&ptr[lenn - lenc], c->u.dNSName.data, lenc) != 0) 1850 return HX509_NAME_CONSTRAINT_ERROR; 1851 if (lenn != lenc && ptr[lenn - lenc - 1] != '.') 1852 return HX509_NAME_CONSTRAINT_ERROR; 1853 *match = 1; 1854 return 0; 1855 } 1856 case choice_GeneralName_directoryName: { 1857 Name c_name, n_name; 1858 int ret; 1859 1860 c_name._save.data = NULL; 1861 c_name._save.length = 0; 1862 c_name.element = (enum Name_enum)c->u.directoryName.element; 1863 c_name.u.rdnSequence = c->u.directoryName.u.rdnSequence; 1864 1865 n_name._save.data = NULL; 1866 n_name._save.length = 0; 1867 n_name.element = (enum Name_enum)n->u.directoryName.element; 1868 n_name.u.rdnSequence = n->u.directoryName.u.rdnSequence; 1869 1870 ret = match_X501Name(&c_name, &n_name); 1871 if (ret == 0) 1872 *match = 1; 1873 return ret; 1874 } 1875 case choice_GeneralName_uniformResourceIdentifier: 1876 case choice_GeneralName_iPAddress: 1877 case choice_GeneralName_registeredID: 1878 default: 1879 return HX509_NAME_CONSTRAINT_ERROR; 1880 } 1881} 1882 1883static int 1884match_alt_name(const GeneralName *n, const Certificate *c, 1885 int *same, int *match) 1886{ 1887 GeneralNames sa; 1888 int ret; 1889 size_t i, j; 1890 1891 i = 0; 1892 do { 1893 ret = find_extension_subject_alt_name(c, &i, &sa); 1894 if (ret == HX509_EXTENSION_NOT_FOUND) { 1895 ret = 0; 1896 break; 1897 } else if (ret != 0) 1898 break; 1899 1900 for (j = 0; j < sa.len; j++) { 1901 if (n->element == sa.val[j].element) { 1902 *same = 1; 1903 (void)match_general_name(n, &sa.val[j], match); 1904 } 1905 } 1906 free_GeneralNames(&sa); 1907 } while (1); 1908 return ret; 1909} 1910 1911 1912static int 1913match_tree(const GeneralSubtrees *t, const Certificate *c, int *match) 1914{ 1915 int name, alt_name, same; 1916 unsigned int i; 1917 int ret = 0; 1918 1919 name = alt_name = same = *match = 0; 1920 for (i = 0; i < t->len; i++) { 1921 if (t->val[i].minimum && t->val[i].maximum) 1922 return HX509_RANGE; 1923 1924 /* 1925 * If the constraint apply to directoryNames, test is with 1926 * subjectName of the certificate if the certificate have a 1927 * non-null (empty) subjectName. 1928 */ 1929 1930 if (t->val[i].base.element == choice_GeneralName_directoryName 1931 && !subject_null_p(c)) 1932 { 1933 GeneralName certname; 1934 1935 memset(&certname, 0, sizeof(certname)); 1936 certname.element = choice_GeneralName_directoryName; 1937 certname.u.directoryName.element = 1938 (enum GeneralName_directoryName_enum)c->tbsCertificate.subject.element; 1939 certname.u.directoryName.u.rdnSequence = 1940 c->tbsCertificate.subject.u.rdnSequence; 1941 1942 (void)match_general_name(&t->val[i].base, &certname, &name); 1943 } 1944 1945 /* Handle subjectAltNames, this is icky since they 1946 * restrictions only apply if the subjectAltName is of the 1947 * same type. So if there have been a match of type, require 1948 * altname to be set. 1949 */ 1950 ret = match_alt_name(&t->val[i].base, c, &same, &alt_name); 1951 } 1952 if (name && (!same || alt_name)) 1953 *match = 1; 1954 return ret; 1955} 1956 1957static int 1958check_name_constraints(hx509_context context, 1959 const hx509_name_constraints *nc, 1960 const Certificate *c) 1961{ 1962 int match, ret; 1963 size_t i; 1964 1965 for (i = 0 ; i < nc->len; i++) { 1966 GeneralSubtrees gs; 1967 1968 if (nc->val[i].permittedSubtrees) { 1969 GeneralSubtrees_SET(&gs, nc->val[i].permittedSubtrees); 1970 ret = match_tree(&gs, c, &match); 1971 if (ret) { 1972 hx509_clear_error_string(context); 1973 return ret; 1974 } 1975 /* allow null subjectNames, they wont matches anything */ 1976 if (match == 0 && !subject_null_p(c)) { 1977 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS, 1978 "Error verify constraints, " 1979 "certificate didn't match any " 1980 "permitted subtree"); 1981 return HX509_VERIFY_CONSTRAINTS; 1982 } 1983 } 1984 if (nc->val[i].excludedSubtrees) { 1985 GeneralSubtrees_SET(&gs, nc->val[i].excludedSubtrees); 1986 ret = match_tree(&gs, c, &match); 1987 if (ret) { 1988 hx509_clear_error_string(context); 1989 return ret; 1990 } 1991 if (match) { 1992 hx509_set_error_string(context, 0, HX509_VERIFY_CONSTRAINTS, 1993 "Error verify constraints, " 1994 "certificate included in excluded " 1995 "subtree"); 1996 return HX509_VERIFY_CONSTRAINTS; 1997 } 1998 } 1999 } 2000 return 0; 2001} 2002 2003static void 2004free_name_constraints(hx509_name_constraints *nc) 2005{ 2006 size_t i; 2007 2008 for (i = 0 ; i < nc->len; i++) 2009 free_NameConstraints(&nc->val[i]); 2010 free(nc->val); 2011} 2012 2013/** 2014 * Build and verify the path for the certificate to the trust anchor 2015 * specified in the verify context. The path is constructed from the 2016 * certificate, the pool and the trust anchors. 2017 * 2018 * @param context A hx509 context. 2019 * @param ctx A hx509 verification context. 2020 * @param cert the certificate to build the path from. 2021 * @param pool A keyset of certificates to build the chain from. 2022 * 2023 * @return An hx509 error code, see hx509_get_error_string(). 2024 * 2025 * @ingroup hx509_verify 2026 */ 2027 2028static int 2029_hx509_verify_path_internal(hx509_context context, 2030 hx509_verify_ctx ctx, 2031 hx509_cert cert, 2032 hx509_certs pool, 2033 hx509_evaluate *result) 2034{ 2035 hx509_name_constraints nc; 2036 hx509_path path; 2037 int ret, proxy_cert_depth, selfsigned_depth, diff; 2038 size_t i, k; 2039 enum certtype type; 2040 Name proxy_issuer; 2041 hx509_certs anchors = NULL; 2042 2043 memset(&proxy_issuer, 0, sizeof(proxy_issuer)); 2044 2045 if (result) 2046 *result = NULL; 2047 2048 ret = init_name_constraints(&nc); 2049 if (ret) 2050 return ret; 2051 2052 path.val = NULL; 2053 path.len = 0; 2054 2055 if ((ctx->flags & HX509_VERIFY_CTX_F_TIME_SET) == 0) 2056 ctx->time_now = time(NULL); 2057 2058 /* 2059 * 2060 */ 2061 if (ctx->trust_anchors) 2062 anchors = hx509_certs_ref(ctx->trust_anchors); 2063 else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx)) 2064 anchors = hx509_certs_ref(context->default_trust_anchors); 2065 else { 2066 ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors); 2067 if (ret) 2068 goto out; 2069 } 2070 2071 /* 2072 * Calculate the path from the certificate user presented to the 2073 * to an anchor. 2074 */ 2075 ret = _hx509_calculate_path(context, 0, ctx->time_now, 2076 anchors, ctx->max_depth, 2077 cert, pool, &path); 2078 if (ret) 2079 goto out; 2080 2081 /* 2082 * Check CA and proxy certificate chain from the top of the 2083 * certificate chain. Also check certificate is valid with respect 2084 * to the current time. 2085 * 2086 */ 2087 2088 proxy_cert_depth = 0; 2089 selfsigned_depth = 0; 2090 2091 if (ctx->flags & HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE) 2092 type = PROXY_CERT; 2093 else 2094 type = EE_CERT; 2095 2096 for (i = 0; i < path.len; i++) { 2097 Certificate *c; 2098 time_t t; 2099 2100 c = _hx509_get_cert(path.val[i]); 2101 2102 /* 2103 * Lets do some basic check on issuer like 2104 * keyUsage.keyCertSign and basicConstraints.cA bit depending 2105 * on what type of certificate this is. 2106 */ 2107 2108 switch (type) { 2109 case CA_CERT: 2110 2111 /* XXX make constants for keyusage */ 2112 ret = check_key_usage(context, c, 1 << 5, 2113 REQUIRE_RFC3280(ctx) ? TRUE : FALSE); 2114 if (ret) { 2115 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 2116 "Key usage missing from CA certificate"); 2117 goto out; 2118 } 2119 2120 /* self signed cert doesn't add to path length */ 2121 if (i + 1 != path.len) { 2122 int selfsigned; 2123 2124 ret = certificate_is_self_signed(context, c, &selfsigned); 2125 if (ret) 2126 goto out; 2127 if (selfsigned) 2128 selfsigned_depth++; 2129 } 2130 2131 break; 2132 case PROXY_CERT: { 2133 ProxyCertInfo info; 2134 2135 if (is_proxy_cert(context, c, &info) == 0) { 2136 size_t j; 2137 2138 if (info.pCPathLenConstraint != NULL && 2139 *info.pCPathLenConstraint < i) 2140 { 2141 free_ProxyCertInfo(&info); 2142 ret = HX509_PATH_TOO_LONG; 2143 hx509_set_error_string(context, 0, ret, 2144 "Proxy certificate chain " 2145 "longer then allowed"); 2146 goto out; 2147 } 2148 /* XXX MUST check info.proxyPolicy */ 2149 free_ProxyCertInfo(&info); 2150 2151 j = 0; 2152 if (find_extension(c, &asn1_oid_id_x509_ce_subjectAltName, &j)) { 2153 ret = HX509_PROXY_CERT_INVALID; 2154 hx509_set_error_string(context, 0, ret, 2155 "Proxy certificate have explicity " 2156 "forbidden subjectAltName"); 2157 goto out; 2158 } 2159 2160 j = 0; 2161 if (find_extension(c, &asn1_oid_id_x509_ce_issuerAltName, &j)) { 2162 ret = HX509_PROXY_CERT_INVALID; 2163 hx509_set_error_string(context, 0, ret, 2164 "Proxy certificate have explicity " 2165 "forbidden issuerAltName"); 2166 goto out; 2167 } 2168 2169 /* 2170 * The subject name of the proxy certificate should be 2171 * CN=XXX,<proxy issuer>, prune of CN and check if its 2172 * the same over the whole chain of proxy certs and 2173 * then check with the EE cert when we get to it. 2174 */ 2175 2176 if (proxy_cert_depth) { 2177 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.subject, &diff); 2178 if (ret) { 2179 hx509_set_error_string(context, 0, ret, "Out of memory"); 2180 goto out; 2181 } 2182 if (diff) { 2183 ret = HX509_PROXY_CERT_NAME_WRONG; 2184 hx509_set_error_string(context, 0, ret, 2185 "Base proxy name not right"); 2186 goto out; 2187 } 2188 } 2189 2190 free_Name(&proxy_issuer); 2191 2192 ret = copy_Name(&c->tbsCertificate.subject, &proxy_issuer); 2193 if (ret) { 2194 hx509_clear_error_string(context); 2195 goto out; 2196 } 2197 2198 j = proxy_issuer.u.rdnSequence.len; 2199 if (proxy_issuer.u.rdnSequence.len < 2 2200 || proxy_issuer.u.rdnSequence.val[j - 1].len > 1 2201 || der_heim_oid_cmp(&proxy_issuer.u.rdnSequence.val[j - 1].val[0].type, 2202 &asn1_oid_id_at_commonName)) 2203 { 2204 ret = HX509_PROXY_CERT_NAME_WRONG; 2205 hx509_set_error_string(context, 0, ret, 2206 "Proxy name too short or " 2207 "does not have Common name " 2208 "at the top"); 2209 goto out; 2210 } 2211 2212 free_RelativeDistinguishedName(&proxy_issuer.u.rdnSequence.val[j - 1]); 2213 proxy_issuer.u.rdnSequence.len -= 1; 2214 2215 ret = _hx509_name_cmp(&proxy_issuer, &c->tbsCertificate.issuer, &diff); 2216 if (ret) { 2217 hx509_set_error_string(context, 0, ret, "Out of memory"); 2218 goto out; 2219 } 2220 if (diff != 0) { 2221 ret = HX509_PROXY_CERT_NAME_WRONG; 2222 hx509_set_error_string(context, 0, ret, 2223 "Proxy issuer name not as expected"); 2224 goto out; 2225 } 2226 2227 break; 2228 } else { 2229 /* 2230 * Now we are done with the proxy certificates, this 2231 * cert was an EE cert and we we will fall though to 2232 * EE checking below. 2233 */ 2234 type = EE_CERT; 2235 /* FALLTHOUGH */ 2236 } 2237 } 2238 case EE_CERT: 2239 /* 2240 * If there where any proxy certificates in the chain 2241 * (proxy_cert_depth > 0), check that the proxy issuer 2242 * matched proxy certificates "base" subject. 2243 */ 2244 if (proxy_cert_depth) { 2245 2246 ret = _hx509_name_cmp(&proxy_issuer, 2247 &c->tbsCertificate.subject, &diff); 2248 if (ret) { 2249 hx509_set_error_string(context, 0, ret, "out of memory"); 2250 goto out; 2251 } 2252 if (diff) { 2253 ret = HX509_PROXY_CERT_NAME_WRONG; 2254 hx509_clear_error_string(context); 2255 goto out; 2256 } 2257 if (cert->basename) 2258 hx509_name_free(&cert->basename); 2259 2260 ret = hx509_name_from_Name(&proxy_issuer, &cert->basename); 2261 if (ret) { 2262 hx509_clear_error_string(context); 2263 goto out; 2264 } 2265 } 2266 2267 break; 2268 } 2269 2270 ret = check_basic_constraints(context, c, type, 2271 i - proxy_cert_depth - selfsigned_depth); 2272 if (ret) 2273 goto out; 2274 2275 /* 2276 * Don't check the trust anchors expiration time since they 2277 * are transported out of band, from RFC3820. 2278 */ 2279 if (i + 1 != path.len || CHECK_TA(ctx)) { 2280 2281 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); 2282 if (t > ctx->time_now) { 2283 ret = HX509_CERT_USED_BEFORE_TIME; 2284 hx509_clear_error_string(context); 2285 goto out; 2286 } 2287 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); 2288 if (t < ctx->time_now) { 2289 ret = HX509_CERT_USED_AFTER_TIME; 2290 hx509_clear_error_string(context); 2291 goto out; 2292 } 2293 } 2294 2295 if (type == EE_CERT) 2296 type = CA_CERT; 2297 else if (type == PROXY_CERT) 2298 proxy_cert_depth++; 2299 } 2300 2301 /* 2302 * Verify constraints, do this backward so path constraints are 2303 * checked in the right order. 2304 */ 2305 2306 for (ret = 0, k = path.len; k > 0; k--) { 2307 Certificate *c; 2308 int selfsigned; 2309 i = k - 1; 2310 2311 c = _hx509_get_cert(path.val[i]); 2312 2313 ret = certificate_is_self_signed(context, c, &selfsigned); 2314 if (ret) 2315 goto out; 2316 2317 /* verify name constraints, not for selfsigned and anchor */ 2318 if (!selfsigned || i + 1 != path.len) { 2319 ret = check_name_constraints(context, &nc, c); 2320 if (ret) { 2321 goto out; 2322 } 2323 } 2324 ret = add_name_constraints(context, c, i == 0, &nc); 2325 if (ret) 2326 goto out; 2327 2328 /* XXX verify all other silly constraints */ 2329 2330 } 2331 2332 /* 2333 * Verify that no certificates has been revoked. 2334 */ 2335 2336 if (ctx->revoke_ctx) { 2337 hx509_certs certs; 2338 2339 ret = hx509_certs_init(context, "MEMORY:revoke-certs", 0, 2340 NULL, &certs); 2341 if (ret) 2342 goto out; 2343 2344 for (i = 0; i < path.len; i++) { 2345 ret = hx509_certs_add(context, certs, path.val[i]); 2346 if (ret) { 2347 hx509_certs_free(&certs); 2348 goto out; 2349 } 2350 } 2351 ret = hx509_certs_merge(context, certs, pool); 2352 if (ret) { 2353 hx509_certs_free(&certs); 2354 goto out; 2355 } 2356 2357 for (i = 0; i < path.len - 1; i++) { 2358 size_t parent = (i < path.len - 1) ? i + 1 : i; 2359 2360 ret = hx509_revoke_verify(context, 2361 ctx->revoke_ctx, 2362 certs, 2363 ctx->time_now, 2364 path.val[i], 2365 path.val[parent]); 2366 if (ret) { 2367 hx509_certs_free(&certs); 2368 goto out; 2369 } 2370 } 2371 hx509_certs_free(&certs); 2372 } 2373 2374 /* 2375 * Verify signatures, do this backward so public key working 2376 * parameter is passed up from the anchor up though the chain. 2377 */ 2378 2379 for (k = path.len; k > 0; k--) { 2380 hx509_cert signer; 2381 Certificate *c; 2382 i = k - 1; 2383 2384 c = _hx509_get_cert(path.val[i]); 2385 2386 /* is last in chain (trust anchor) */ 2387 if (i + 1 == path.len) { 2388 int selfsigned; 2389 2390 signer = path.val[i]; 2391 2392 ret = certificate_is_self_signed(context, signer->data, &selfsigned); 2393 if (ret) 2394 goto out; 2395 2396 /* if trust anchor is not self signed, don't check sig */ 2397 if (!selfsigned) 2398 continue; 2399 } else { 2400 /* take next certificate in chain */ 2401 signer = path.val[i + 1]; 2402 } 2403 2404 /* verify signatureValue */ 2405 ret = _hx509_verify_signature_bitstring(context, 2406 signer, 2407 &c->signatureAlgorithm, 2408 &c->tbsCertificate._save, 2409 &c->signatureValue); 2410 if (ret) { 2411 hx509_set_error_string(context, HX509_ERROR_APPEND, ret, 2412 "Failed to verify signature of certificate"); 2413 goto out; 2414 } 2415 /* 2416 * Verify that the sigature algorithm "best-before" date is 2417 * before the creation date of the certificate, do this for 2418 * trust anchors too, since any trust anchor that is created 2419 * after a algorithm is known to be bad deserved to be invalid. 2420 * 2421 * Skip the leaf certificate for now... 2422 */ 2423 2424 if (i != 0 && (ctx->flags & HX509_VERIFY_CTX_F_NO_BEST_BEFORE_CHECK) == 0) { 2425 time_t notBefore = 2426 _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); 2427 ret = _hx509_signature_best_before(context, 2428 &c->signatureAlgorithm, 2429 notBefore); 2430 if (ret) 2431 goto out; 2432 } 2433 } 2434 2435 if (result) { 2436 *result = _hx509_evaluate_alloc(); 2437 if (*result == NULL) { 2438 ret = ENOMEM; 2439 goto out; 2440 } 2441 2442 for (i = 0; i < path.len; i++) 2443 heim_array_append_value((*result)->path, path.val[i]); 2444 } 2445 2446out: 2447 hx509_certs_free(&anchors); 2448 free_Name(&proxy_issuer); 2449 free_name_constraints(&nc); 2450 _hx509_path_free(&path); 2451 2452 return ret; 2453} 2454 2455/** 2456 * Build and verify the path for the certificate to the trust anchor 2457 * specified in the verify context. The path is constructed from the 2458 * certificate, the pool and the trust anchors. 2459 * 2460 * @param context A hx509 context. 2461 * @param ctx A hx509 verification context. 2462 * @param cert the certificate to build the path from. 2463 * @param pool A keyset of certificates to build the chain from. 2464 * 2465 * @return An hx509 error code, see hx509_get_error_string(). 2466 * 2467 * @ingroup hx509_verify 2468 */ 2469 2470int 2471hx509_verify_path(hx509_context context, 2472 hx509_verify_ctx ctx, 2473 hx509_cert cert, 2474 hx509_certs pool) 2475{ 2476 return hx509_evaluate_cert(context, ctx, cert, pool, NULL); 2477} 2478 2479#ifdef __APPLE_TARGET_EMBEDDED__ 2480#include <Security/Security.h> 2481 2482static SecCertificateRef 2483HXCreateCertificateFromHX509Certificate(hx509_context context, hx509_cert cert) 2484{ 2485 SecCertificateRef c = NULL; 2486 heim_octet_string os; 2487 int r; 2488 2489 r = hx509_cert_binary(context, cert, &os); 2490 if (r) 2491 return NULL; 2492 2493 CFDataRef refdata = CFDataCreateWithBytesNoCopy(NULL, os.data, os.length, kCFAllocatorNull); 2494 if (refdata) { 2495 c = SecCertificateCreateWithData(NULL, refdata); 2496 CFRelease(refdata); 2497 } 2498 hx509_xfree(os.data); 2499 return c; 2500} 2501 2502#endif 2503 2504 2505int 2506hx509_evaluate_cert(hx509_context context, 2507 hx509_verify_ctx ctx, 2508 hx509_cert cert, 2509 hx509_certs pool, 2510 hx509_evaluate *validate) 2511{ 2512#ifdef __APPLE_TARGET_EMBEDDED__ 2513 __block CFMutableArrayRef certs; 2514 __block SecCertificateRef c; 2515 int ret; 2516 2517 certs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2518 heim_assert(certs != NULL, "out of memory"); 2519 2520 c = HXCreateCertificateFromHX509Certificate(context, cert); 2521 CFArrayAppendValue(certs, c); 2522 CFRelease(c); 2523 2524 hx509_certs_iter(context, pool, ^(hx509_cert pc) { 2525 c = HXCreateCertificateFromHX509Certificate(context, pc); 2526 CFArrayAppendValue(certs, c); 2527 CFRelease(c); 2528 return 0; 2529 }); 2530 2531 /* XXX pkinit policy */ 2532 SecPolicyRef policy = SecPolicyCreateBasicX509(); 2533 2534 SecTrustRef trust = NULL; 2535 2536 OSStatus status = SecTrustCreateWithCertificates(certs, policy, &trust); 2537 CFRelease(policy); 2538 CFRelease(certs); 2539 if (status) { 2540 ret = HX509_ISSUER_NOT_FOUND; 2541 hx509_set_error_string(context, 0, ret, "Failed to create trust"); 2542 CFRelease(trust); 2543 } 2544 2545 SecTrustResultType result; 2546 2547 status = SecTrustEvaluate(trust, &result); 2548 if (status) { 2549 ret = HX509_ISSUER_NOT_FOUND; 2550 hx509_set_error_string(context, 0, ret, "Failed to validate trust: %d", (int)status); 2551 CFRelease(trust); 2552 return ret; 2553 } 2554 2555 switch (result) { 2556 case kSecTrustResultUnspecified: 2557 case kSecTrustResultProceed: 2558 break; 2559 default: 2560 ret = HX509_ISSUER_NOT_FOUND; 2561 hx509_set_error_string(context, 0, ret, "Failed to validate trust"); 2562 CFRelease(trust); 2563 return ret; 2564 } 2565 2566 if (validate) { 2567 CFIndex count, n; 2568 2569 count = SecTrustGetCertificateCount(trust); 2570 2571 *validate = _hx509_evaluate_alloc(); 2572 if (*validate == NULL) { 2573 CFRelease(trust); 2574 return ENOMEM; 2575 } 2576 2577 for (n = 0; n < count; n++) { 2578 SecCertificateRef tc = SecTrustGetCertificateAtIndex(trust, n); 2579 heim_assert(tc != NULL, "SecTrustGetCertificateAtIndex didn't return a cert"); 2580 2581 CFDataRef data = SecCertificateCopyData(tc); 2582 heim_assert(data != NULL, "cert w/o data ?"); 2583 2584 hx509_cert tcert = NULL; 2585 2586 ret = hx509_cert_init_data(context, CFDataGetBytePtr(data), CFDataGetLength(data), &tcert); 2587 CFRelease(data); 2588 if (ret) { 2589 CFRelease(trust); 2590 hx509_evaluate_free(*validate); 2591 *validate = NULL; 2592 return ret; 2593 } 2594 heim_array_append_value((*validate)->path, tcert); 2595 hx509_cert_free(tcert); 2596 } 2597 } 2598 2599 CFRelease(trust); 2600 2601 return 0; 2602 2603#else /* !__APPLE_TARGET_EMBEDDED__ */ 2604#ifdef HAVE_TRUSTEVALUATIONAGENT 2605 TEACertificateChainRef in, out; 2606 TEAErrorRef e = NULL; 2607 TEAOptionsRef options; 2608 2609 if (validate) 2610 *validate = NULL; 2611 2612 in = TEACertificateChainCreate(); 2613 2614 TEACertificateChainSetEncodingHandler(in, ^(uint8_t *dst, const TEACertificateRef c) { 2615 heim_octet_string os; 2616 int r; 2617 r = hx509_cert_binary(context, (void *)TEACertificateGetData(c), &os); 2618 if (r) 2619 return r; 2620 if (TEACertificateGetSize(c) != os.length) 2621 _hx509_abort("internal TEA encoder error"); 2622 memcpy(dst, os.data, os.length); 2623 hx509_xfree(os.data); 2624 return 0; 2625 }); 2626 2627 TEACertificateChainAddCert(in, cert, length_Certificate(cert->data)); 2628 2629 hx509_certs_iter(context, pool, ^(hx509_cert c) { 2630 TEACertificateChainAddCert(in, c, length_Certificate(c->data)); 2631 return 0; 2632 }); 2633 2634 options = TEAOptionsCreate(); 2635 if (options == NULL) { 2636 TEACertificateChainRelease(in); 2637 return ENOMEM; 2638 } 2639 2640 TEAOptionsSetPurpose(options, kTEAPurposeDefault); 2641 TEAOptionsSetTime(options, 0); 2642 2643 out = TEAVerifyCertChainTrust(in, options, &e); 2644 TEAOptionsRelease(options); 2645 TEACertificateChainRelease(in); 2646 if (e) 2647 TEAErrorRelease(e); 2648 if (out != NULL) { 2649 if (validate) { 2650 __block int ret2 = 0; 2651 2652 *validate = _hx509_evaluate_alloc(); 2653 if (*validate == NULL) { 2654 TEACertificateChainRelease(out); 2655 return ENOMEM; 2656 } 2657 2658 TEACertificateChainEnumerateWithBlock(out, ^(void *data, size_t size, int *shouldStop){ 2659 hx509_cert c; 2660 ret2 = hx509_cert_init_data(context, data, size, &c); 2661 if (ret2) 2662 *shouldStop = 1; 2663 else { 2664 heim_array_append_value((*validate)->path, c); 2665 hx509_cert_free(c); 2666 } 2667 }); 2668 if (ret2) { 2669 TEACertificateChainRelease(out); 2670 hx509_evaluate_free(*validate); 2671 *validate = NULL; 2672 return ret2; 2673 } 2674 } 2675 TEACertificateChainRelease(out); 2676 return 0; 2677 } 2678 static dispatch_once_t setup; 2679 static bool allow_hx509_validation = false; 2680 dispatch_once(&setup, ^{ 2681 CFBooleanRef val; 2682 val = CFPreferencesCopyValue(CFSTR("AllowHX509Validation"), 2683 CFSTR("org.h5l.hx509"), 2684 kCFPreferencesCurrentUser, 2685 kCFPreferencesAnyHost); 2686 if (val && CFBooleanGetTypeID() == CFGetTypeID(val)) 2687 allow_hx509_validation = CFBooleanGetValue(val); 2688 if (val) 2689 CFRelease(val); 2690 }); 2691 if (!allow_hx509_validation) { 2692 int ret = HX509_CRYPTO_SIG_INVALID_FORMAT; 2693 hx509_set_error_string(context, 0, ret, "validation failed"); 2694 return ret; 2695 } 2696#endif 2697 if (validate) 2698 *validate = NULL; 2699 return _hx509_verify_path_internal(context, ctx, cert, pool, validate); 2700#endif /* !__APPLE_TARGET_EMBEDDED__ */ 2701} 2702 2703 2704/** 2705 * Verify a signature made using the private key of an certificate. 2706 * 2707 * @param context A hx509 context. 2708 * @param signer the certificate that made the signature. 2709 * @param alg algorthm that was used to sign the data. 2710 * @param data the data that was signed. 2711 * @param sig the sigature to verify. 2712 * 2713 * @return An hx509 error code, see hx509_get_error_string(). 2714 * 2715 * @ingroup hx509_crypto 2716 */ 2717 2718int 2719hx509_verify_signature(hx509_context context, 2720 const hx509_cert signer, 2721 const AlgorithmIdentifier *alg, 2722 const heim_octet_string *data, 2723 const heim_octet_string *sig) 2724{ 2725 return _hx509_verify_signature(context, signer, alg, data, sig); 2726} 2727 2728int 2729_hx509_verify_signature_bitstring(hx509_context context, 2730 const hx509_cert signer, 2731 const AlgorithmIdentifier *alg, 2732 const heim_octet_string *data, 2733 const heim_bit_string *sig) 2734{ 2735 heim_octet_string os; 2736 2737 if (sig->length & 7) { 2738 hx509_set_error_string(context, 0, HX509_CRYPTO_SIG_INVALID_FORMAT, 2739 "signature not multiple of 8 bits"); 2740 return HX509_CRYPTO_SIG_INVALID_FORMAT; 2741 } 2742 2743 os.data = sig->data; 2744 os.length = sig->length / 8; 2745 2746 return _hx509_verify_signature(context, signer, alg, data, &os); 2747} 2748 2749 2750 2751/** 2752 * Verify that the certificate is allowed to be used for the hostname 2753 * and address. 2754 * 2755 * @param context A hx509 context. 2756 * @param cert the certificate to match with 2757 * @param flags Flags to modify the behavior: 2758 * - HX509_VHN_F_ALLOW_NO_MATCH no match is ok 2759 * @param type type of hostname: 2760 * - HX509_HN_HOSTNAME for plain hostname. 2761 * - HX509_HN_DNSSRV for DNS SRV names. 2762 * @param hostname the hostname to check 2763 * @param sa address of the host 2764 * @param sa_size length of address 2765 * 2766 * @return An hx509 error code, see hx509_get_error_string(). 2767 * 2768 * @ingroup hx509_cert 2769 */ 2770 2771int 2772hx509_verify_hostname(hx509_context context, 2773 const hx509_cert cert, 2774 int flags, 2775 hx509_hostname_type type, 2776 const char *hostname, 2777 const struct sockaddr *sa, 2778 /* XXX krb5_socklen_t */ int sa_size) 2779{ 2780 GeneralNames san; 2781 const Name *name; 2782 int ret; 2783 size_t i, j, k; 2784 2785 if (sa && sa_size <= 0) 2786 return EINVAL; 2787 2788 memset(&san, 0, sizeof(san)); 2789 2790 i = 0; 2791 do { 2792 ret = find_extension_subject_alt_name(cert->data, &i, &san); 2793 if (ret == HX509_EXTENSION_NOT_FOUND) 2794 break; 2795 else if (ret != 0) 2796 return HX509_PARSING_NAME_FAILED; 2797 2798 for (j = 0; j < san.len; j++) { 2799 switch (san.val[j].element) { 2800 case choice_GeneralName_dNSName: { 2801 heim_printable_string hn; 2802 hn.data = rk_UNCONST(hostname); 2803 hn.length = strlen(hostname); 2804 2805 if (der_printable_string_cmp(&san.val[j].u.dNSName, &hn) == 0) { 2806 free_GeneralNames(&san); 2807 return 0; 2808 } 2809 break; 2810 } 2811 default: 2812 break; 2813 } 2814 } 2815 free_GeneralNames(&san); 2816 } while (1); 2817 2818 name = &cert->data->tbsCertificate.subject; 2819 2820 /* Find first CN= in the name, and try to match the hostname on that */ 2821 for (ret = 0, k = name->u.rdnSequence.len; ret == 0 && k > 0; k--) { 2822 i = k - 1; 2823 for (j = 0; ret == 0 && j < name->u.rdnSequence.val[i].len; j++) { 2824 AttributeTypeAndValue *n = &name->u.rdnSequence.val[i].val[j]; 2825 2826 if (der_heim_oid_cmp(&n->type, &asn1_oid_id_at_commonName) == 0) { 2827 DirectoryString *ds = &n->value; 2828 switch (ds->element) { 2829 case choice_DirectoryString_printableString: { 2830 heim_printable_string hn; 2831 hn.data = rk_UNCONST(hostname); 2832 hn.length = strlen(hostname); 2833 2834 if (der_printable_string_cmp(&ds->u.printableString, &hn) == 0) 2835 return 0; 2836 break; 2837 } 2838 case choice_DirectoryString_ia5String: { 2839 heim_ia5_string hn; 2840 hn.data = rk_UNCONST(hostname); 2841 hn.length = strlen(hostname); 2842 2843 if (der_ia5_string_cmp(&ds->u.ia5String, &hn) == 0) 2844 return 0; 2845 break; 2846 } 2847 case choice_DirectoryString_utf8String: 2848 if (strcasecmp(ds->u.utf8String, hostname) == 0) 2849 return 0; 2850 default: 2851 break; 2852 } 2853 ret = HX509_NAME_CONSTRAINT_ERROR; 2854 } 2855 } 2856 } 2857 2858 if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0) 2859 ret = HX509_NAME_CONSTRAINT_ERROR; 2860 2861 return ret; 2862} 2863 2864int 2865_hx509_set_cert_attribute(hx509_context context, 2866 hx509_cert cert, 2867 const heim_oid *oid, 2868 const heim_octet_string *attr) 2869{ 2870 hx509_cert_attribute a; 2871 void *d; 2872 2873 if (hx509_cert_get_attribute(cert, oid) != NULL) 2874 return 0; 2875 2876 d = realloc(cert->attrs.val, 2877 sizeof(cert->attrs.val[0]) * (cert->attrs.len + 1)); 2878 if (d == NULL) { 2879 hx509_clear_error_string(context); 2880 return ENOMEM; 2881 } 2882 cert->attrs.val = d; 2883 2884 a = malloc(sizeof(*a)); 2885 if (a == NULL) 2886 return ENOMEM; 2887 2888 der_copy_octet_string(attr, &a->data); 2889 der_copy_oid(oid, &a->oid); 2890 2891 cert->attrs.val[cert->attrs.len] = a; 2892 cert->attrs.len++; 2893 2894 return 0; 2895} 2896 2897/** 2898 * Get an external attribute for the certificate, examples are 2899 * friendly name and id. 2900 * 2901 * @param cert hx509 certificate object to search 2902 * @param oid an oid to search for. 2903 * 2904 * @return an hx509_cert_attribute, only valid as long as the 2905 * certificate is referenced. 2906 * 2907 * @ingroup hx509_cert 2908 */ 2909 2910hx509_cert_attribute 2911hx509_cert_get_attribute(hx509_cert cert, const heim_oid *oid) 2912{ 2913 size_t i; 2914 for (i = 0; i < cert->attrs.len; i++) 2915 if (der_heim_oid_cmp(oid, &cert->attrs.val[i]->oid) == 0) 2916 return cert->attrs.val[i]; 2917 return NULL; 2918} 2919 2920/** 2921 * Set the friendly name on the certificate. 2922 * 2923 * @param cert The certificate to set the friendly name on 2924 * @param name Friendly name. 2925 * 2926 * @return An hx509 error code, see hx509_get_error_string(). 2927 * 2928 * @ingroup hx509_cert 2929 */ 2930 2931int 2932hx509_cert_set_friendly_name(hx509_cert cert, const char *name) 2933{ 2934 if (cert->friendlyname) 2935 free(cert->friendlyname); 2936 cert->friendlyname = strdup(name); 2937 if (cert->friendlyname == NULL) 2938 return ENOMEM; 2939 return 0; 2940} 2941 2942/** 2943 * Get friendly name of the certificate. 2944 * 2945 * @param cert cert to get the friendly name from. 2946 * 2947 * @return an friendly name or NULL if there is. The friendly name is 2948 * only valid as long as the certificate is referenced. 2949 * 2950 * @ingroup hx509_cert 2951 */ 2952 2953const char * 2954hx509_cert_get_friendly_name(hx509_cert cert) 2955{ 2956 hx509_cert_attribute a; 2957 PKCS9_friendlyName n; 2958 size_t sz; 2959 int ret; 2960 size_t i; 2961 2962 if (cert->friendlyname) 2963 return cert->friendlyname; 2964 2965 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_friendlyName); 2966 if (a == NULL) { 2967 hx509_name name; 2968 2969 ret = hx509_cert_get_subject(cert, &name); 2970 if (ret) 2971 return NULL; 2972 ret = hx509_name_to_string(name, &cert->friendlyname); 2973 hx509_name_free(&name); 2974 if (ret) 2975 return NULL; 2976 return cert->friendlyname; 2977 } 2978 2979 ret = decode_PKCS9_friendlyName(a->data.data, a->data.length, &n, &sz); 2980 if (ret) 2981 return NULL; 2982 2983 if (n.len != 1) { 2984 free_PKCS9_friendlyName(&n); 2985 return NULL; 2986 } 2987 2988 cert->friendlyname = malloc(n.val[0].length + 1); 2989 if (cert->friendlyname == NULL) { 2990 free_PKCS9_friendlyName(&n); 2991 return NULL; 2992 } 2993 2994 for (i = 0; i < n.val[0].length; i++) { 2995 if (n.val[0].data[i] <= 0xff) 2996 cert->friendlyname[i] = n.val[0].data[i] & 0xff; 2997 else 2998 cert->friendlyname[i] = 'X'; 2999 } 3000 cert->friendlyname[i] = '\0'; 3001 free_PKCS9_friendlyName(&n); 3002 3003 return cert->friendlyname; 3004} 3005 3006int 3007hx509_cert_set_persistent(hx509_cert cert, heim_octet_string *persistent) 3008{ 3009 der_free_octet_string(&cert->persistent); 3010 return der_copy_octet_string(persistent, &cert->persistent); 3011} 3012 3013int 3014hx509_cert_get_persistent(hx509_cert cert, heim_octet_string *persistent) 3015{ 3016 heim_octet_string os; 3017 Certificate *c; 3018 int ret; 3019 3020 if (cert->persistent.length) 3021 return der_copy_octet_string(&cert->persistent, persistent); 3022 3023 c = _hx509_get_cert(cert); 3024 3025 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 3026 os.length = 3027 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 3028 3029 ret = _hx509_create_signature(NULL, 3030 NULL, 3031 hx509_signature_sha1(), 3032 &os, 3033 NULL, 3034 persistent); 3035 if (ret) 3036 return ret; 3037 3038 hx509_cert_set_persistent(cert, persistent); 3039 3040 return 0; 3041} 3042 3043void 3044_hx509_query_clear(hx509_query *q) 3045{ 3046 memset(q, 0, sizeof(*q)); 3047} 3048 3049/** 3050 * Allocate an query controller. Free using hx509_query_free(). 3051 * 3052 * @param context A hx509 context. 3053 * @param q return pointer to a hx509_query. 3054 * 3055 * @return An hx509 error code, see hx509_get_error_string(). 3056 * 3057 * @ingroup hx509_cert 3058 */ 3059 3060int 3061hx509_query_alloc(hx509_context context, hx509_query **q) 3062{ 3063 *q = calloc(1, sizeof(**q)); 3064 if (*q == NULL) 3065 return ENOMEM; 3066 return 0; 3067} 3068 3069 3070/** 3071 * Set match options for the hx509 query controller. 3072 * 3073 * @param q query controller. 3074 * @param option options to control the query controller. 3075 * 3076 * @return An hx509 error code, see hx509_get_error_string(). 3077 * 3078 * @ingroup hx509_cert 3079 */ 3080 3081void 3082hx509_query_match_option(hx509_query *q, hx509_query_option option) 3083{ 3084 switch(option) { 3085 case HX509_QUERY_OPTION_PRIVATE_KEY: 3086 q->match |= HX509_QUERY_PRIVATE_KEY; 3087 break; 3088 case HX509_QUERY_OPTION_KU_ENCIPHERMENT: 3089 q->match |= HX509_QUERY_KU_ENCIPHERMENT; 3090 break; 3091 case HX509_QUERY_OPTION_KU_DIGITALSIGNATURE: 3092 q->match |= HX509_QUERY_KU_DIGITALSIGNATURE; 3093 break; 3094 case HX509_QUERY_OPTION_KU_KEYCERTSIGN: 3095 q->match |= HX509_QUERY_KU_KEYCERTSIGN; 3096 break; 3097 case HX509_QUERY_OPTION_END: 3098 default: 3099 break; 3100 } 3101} 3102 3103/** 3104 * Set the issuer and serial number of match in the query 3105 * controller. The function make copies of the isser and serial number. 3106 * 3107 * @param q a hx509 query controller 3108 * @param issuer issuer to search for 3109 * @param serialNumber the serialNumber of the issuer. 3110 * 3111 * @return An hx509 error code, see hx509_get_error_string(). 3112 * 3113 * @ingroup hx509_cert 3114 */ 3115 3116int 3117hx509_query_match_issuer_serial(hx509_query *q, 3118 const Name *issuer, 3119 const heim_integer *serialNumber) 3120{ 3121 int ret; 3122 if (q->serial) { 3123 der_free_heim_integer(q->serial); 3124 free(q->serial); 3125 } 3126 q->serial = malloc(sizeof(*q->serial)); 3127 if (q->serial == NULL) 3128 return ENOMEM; 3129 ret = der_copy_heim_integer(serialNumber, q->serial); 3130 if (ret) { 3131 free(q->serial); 3132 q->serial = NULL; 3133 return ret; 3134 } 3135 if (q->issuer_name) { 3136 free_Name(q->issuer_name); 3137 free(q->issuer_name); 3138 } 3139 q->issuer_name = malloc(sizeof(*q->issuer_name)); 3140 if (q->issuer_name == NULL) 3141 return ENOMEM; 3142 ret = copy_Name(issuer, q->issuer_name); 3143 if (ret) { 3144 free(q->issuer_name); 3145 q->issuer_name = NULL; 3146 return ret; 3147 } 3148 q->match |= HX509_QUERY_MATCH_SERIALNUMBER|HX509_QUERY_MATCH_ISSUER_NAME; 3149 return 0; 3150} 3151 3152/** 3153 * Set the query controller to match on a friendly name 3154 * 3155 * @param q a hx509 query controller. 3156 * @param name a friendly name to match on 3157 * 3158 * @return An hx509 error code, see hx509_get_error_string(). 3159 * 3160 * @ingroup hx509_cert 3161 */ 3162 3163int 3164hx509_query_match_friendly_name(hx509_query *q, const char *name) 3165{ 3166 if (q->friendlyname) 3167 free(q->friendlyname); 3168 q->friendlyname = strdup(name); 3169 if (q->friendlyname == NULL) 3170 return ENOMEM; 3171 q->match |= HX509_QUERY_MATCH_FRIENDLY_NAME; 3172 return 0; 3173} 3174 3175/** 3176 * Set the query controller to require an one specific EKU (extended 3177 * key usage). Any previous EKU matching is overwitten. If NULL is 3178 * passed in as the eku, the EKU requirement is reset. 3179 * 3180 * @param q a hx509 query controller. 3181 * @param eku an EKU to match on. 3182 * 3183 * @return An hx509 error code, see hx509_get_error_string(). 3184 * 3185 * @ingroup hx509_cert 3186 */ 3187 3188int 3189hx509_query_match_eku(hx509_query *q, const heim_oid *eku) 3190{ 3191 int ret; 3192 3193 if (eku == NULL) { 3194 if (q->eku) { 3195 der_free_oid(q->eku); 3196 free(q->eku); 3197 q->eku = NULL; 3198 } 3199 q->match &= ~HX509_QUERY_MATCH_EKU; 3200 } else { 3201 if (q->eku) { 3202 der_free_oid(q->eku); 3203 } else { 3204 q->eku = calloc(1, sizeof(*q->eku)); 3205 if (q->eku == NULL) 3206 return ENOMEM; 3207 } 3208 ret = der_copy_oid(eku, q->eku); 3209 if (ret) { 3210 free(q->eku); 3211 q->eku = NULL; 3212 return ret; 3213 } 3214 q->match |= HX509_QUERY_MATCH_EKU; 3215 } 3216 return 0; 3217} 3218 3219#ifdef HEIM_HX_EXPR 3220int 3221hx509_query_match_expr(hx509_context context, hx509_query *q, const char *expr) 3222{ 3223 if (q->expr) { 3224 _hx509_expr_free(q->expr); 3225 q->expr = NULL; 3226 } 3227 3228 if (expr == NULL) { 3229 q->match &= ~HX509_QUERY_MATCH_EXPR; 3230 } else { 3231 q->expr = _hx509_expr_parse(expr); 3232 if (q->expr) 3233 q->match |= HX509_QUERY_MATCH_EXPR; 3234 } 3235 3236 return 0; 3237} 3238#endif 3239 3240/** 3241 * Set the query controller to match using a specific match function. 3242 * 3243 * @param q a hx509 query controller. 3244 * @param func function to use for matching, if the argument is NULL, 3245 * the match function is removed. 3246 * @param ctx context passed to the function. 3247 * 3248 * @return An hx509 error code, see hx509_get_error_string(). 3249 * 3250 * @ingroup hx509_cert 3251 */ 3252 3253int 3254hx509_query_match_cmp_func(hx509_query *q, 3255 int (*func)(hx509_context, hx509_cert, void *), 3256 void *ctx) 3257{ 3258 if (func) 3259 q->match |= HX509_QUERY_MATCH_FUNCTION; 3260 else 3261 q->match &= ~HX509_QUERY_MATCH_FUNCTION; 3262 q->cmp_func = func; 3263 q->cmp_func_ctx = ctx; 3264 return 0; 3265} 3266 3267/** 3268 * 3269 */ 3270 3271int 3272hx509_query_match_persistent(hx509_query *q, heim_octet_string *ident) 3273{ 3274 if (ident) 3275 q->match |= HX509_QUERY_MATCH_PERSISTENT; 3276 else 3277 q->match &= ~HX509_QUERY_MATCH_PERSISTENT; 3278 q->persistent = ident; 3279 return 0; 3280} 3281 3282/** 3283 * Free the query controller. 3284 * 3285 * @param context A hx509 context. 3286 * @param q a pointer to the query controller. 3287 * 3288 * @ingroup hx509_cert 3289 */ 3290 3291void 3292hx509_query_free(hx509_context context, hx509_query *q) 3293{ 3294 if (q == NULL) 3295 return; 3296 3297 if (q->serial) { 3298 der_free_heim_integer(q->serial); 3299 free(q->serial); 3300 } 3301 if (q->issuer_name) { 3302 free_Name(q->issuer_name); 3303 free(q->issuer_name); 3304 } 3305 if (q->eku) { 3306 der_free_oid(q->eku); 3307 free(q->eku); 3308 } 3309 if (q->friendlyname) 3310 free(q->friendlyname); 3311#ifdef HEIM_HX_EXPR 3312 if (q->expr) 3313 _hx509_expr_free(q->expr); 3314#endif 3315 3316 memset(q, 0, sizeof(*q)); 3317 free(q); 3318} 3319 3320int 3321_hx509_query_match_cert(hx509_context context, const hx509_query *q, hx509_cert cert) 3322{ 3323 Certificate *c = _hx509_get_cert(cert); 3324 int ret, diff; 3325 3326 if ((q->match & HX509_QUERY_FIND_ISSUER_CERT) && 3327 _hx509_cert_is_parent_cmp(q->subject, c, 0) != 0) 3328 return 0; 3329 3330 if ((q->match & HX509_QUERY_MATCH_CERTIFICATE) && 3331 _hx509_Certificate_cmp(q->certificate, c) != 0) 3332 return 0; 3333 3334 if ((q->match & HX509_QUERY_MATCH_SERIALNUMBER) 3335 && der_heim_integer_cmp(&c->tbsCertificate.serialNumber, q->serial) != 0) 3336 return 0; 3337 3338 if (q->match & HX509_QUERY_MATCH_ISSUER_NAME) { 3339 ret = _hx509_name_cmp(&c->tbsCertificate.issuer, q->issuer_name, &diff); 3340 if (ret || diff) 3341 return 0; 3342 } 3343 3344 if (q->match & HX509_QUERY_MATCH_SUBJECT_NAME) { 3345 ret = _hx509_name_cmp(&c->tbsCertificate.subject, q->subject_name, &diff); 3346 if (ret || diff) 3347 return 0; 3348 } 3349 3350 if (q->match & HX509_QUERY_MATCH_SUBJECT_KEY_ID) { 3351 SubjectKeyIdentifier si; 3352 3353 ret = _hx509_find_extension_subject_key_id(c, &si); 3354 if (ret == 0) { 3355 if (der_heim_octet_string_cmp(&si, q->subject_id) != 0) 3356 ret = 1; 3357 free_SubjectKeyIdentifier(&si); 3358 } 3359 if (ret) 3360 return 0; 3361 } 3362 if ((q->match & HX509_QUERY_MATCH_ISSUER_ID)) 3363 return 0; 3364 if ((q->match & HX509_QUERY_PRIVATE_KEY) && 3365 _hx509_cert_private_key(cert) == NULL) 3366 return 0; 3367 3368 { 3369 unsigned ku = 0; 3370 if (q->match & HX509_QUERY_KU_DIGITALSIGNATURE) 3371 ku |= (1 << 0); 3372 if (q->match & HX509_QUERY_KU_NONREPUDIATION) 3373 ku |= (1 << 1); 3374 if (q->match & HX509_QUERY_KU_ENCIPHERMENT) 3375 ku |= (1 << 2); 3376 if (q->match & HX509_QUERY_KU_DATAENCIPHERMENT) 3377 ku |= (1 << 3); 3378 if (q->match & HX509_QUERY_KU_KEYAGREEMENT) 3379 ku |= (1 << 4); 3380 if (q->match & HX509_QUERY_KU_KEYCERTSIGN) 3381 ku |= (1 << 5); 3382 if (q->match & HX509_QUERY_KU_CRLSIGN) 3383 ku |= (1 << 6); 3384 if (ku && check_key_usage(context, c, ku, TRUE)) 3385 return 0; 3386 } 3387 if ((q->match & HX509_QUERY_ANCHOR)) 3388 return 0; 3389 3390 if (q->match & HX509_QUERY_MATCH_LOCAL_KEY_ID) { 3391 hx509_cert_attribute a; 3392 3393 a = hx509_cert_get_attribute(cert, &asn1_oid_id_pkcs_9_at_localKeyId); 3394 if (a == NULL) 3395 return 0; 3396 if (der_heim_octet_string_cmp(&a->data, q->local_key_id) != 0) 3397 return 0; 3398 } 3399 3400 if (q->match & HX509_QUERY_NO_MATCH_PATH) { 3401 size_t i; 3402 3403 for (i = 0; i < q->path->len; i++) 3404 if (hx509_cert_cmp(q->path->val[i], cert) == 0) 3405 return 0; 3406 } 3407 if (q->match & HX509_QUERY_MATCH_FRIENDLY_NAME) { 3408 const char *name = hx509_cert_get_friendly_name(cert); 3409 if (name == NULL) 3410 return 0; 3411 if (strcasecmp(q->friendlyname, name) != 0) 3412 return 0; 3413 } 3414 if (q->match & HX509_QUERY_MATCH_FUNCTION) { 3415 ret = (*q->cmp_func)(context, cert, q->cmp_func_ctx); 3416 if (ret != 0) 3417 return 0; 3418 } 3419 3420 if (q->match & HX509_QUERY_MATCH_KEY_HASH_SHA1) { 3421 heim_octet_string os; 3422 3423 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 3424 os.length = 3425 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 3426 3427 ret = _hx509_verify_signature(context, 3428 NULL, 3429 hx509_signature_sha1(), 3430 &os, 3431 q->keyhash_sha1); 3432 if (ret != 0) 3433 return 0; 3434 } 3435 3436 if (q->match & HX509_QUERY_MATCH_TIME) { 3437 time_t t; 3438 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); 3439 if (t > q->timenow) 3440 return 0; 3441 t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); 3442 if (t < q->timenow) 3443 return 0; 3444 } 3445 3446 /* If an EKU is required, check the cert for it. */ 3447 if ((q->match & HX509_QUERY_MATCH_EKU) && 3448 hx509_cert_check_eku(context, cert, q->eku, 0)) 3449 return 0; 3450 3451 if ((q->match & HX509_QUERY_MATCH_EXPR)) { 3452#ifdef HEIM_HX_EXPR 3453 hx509_env env = NULL; 3454 3455 ret = _hx509_cert_to_env(context, cert, &env); 3456 if (ret) 3457 return 0; 3458 3459 ret = _hx509_expr_eval(context, env, q->expr); 3460 hx509_env_free(&env); 3461 if (ret == 0) 3462 return 0; 3463#else 3464 return 0; 3465#endif 3466 } 3467 if ((q->match & HX509_QUERY_MATCH_PERSISTENT)) { 3468 heim_octet_string p; 3469 3470 ret = hx509_cert_get_persistent(cert, &p); 3471 if (ret) 3472 return 0; 3473 3474 ret = der_heim_octet_string_cmp(&p, q->persistent); 3475 der_free_octet_string(&p); 3476 if (ret != 0) 3477 return 0; 3478 } 3479 3480 if (q->match & ~HX509_QUERY_MASK) 3481 return 0; 3482 3483 return 1; 3484} 3485 3486/** 3487 * Check the extended key usage on the hx509 certificate. 3488 * 3489 * @param context A hx509 context. 3490 * @param cert A hx509 context. 3491 * @param eku the EKU to check for 3492 * @param allow_any_eku if the any EKU is set, allow that to be a 3493 * substitute. 3494 * 3495 * @return An hx509 error code, see hx509_get_error_string(). 3496 * 3497 * @ingroup hx509_cert 3498 */ 3499 3500int 3501hx509_cert_check_eku(hx509_context context, hx509_cert cert, 3502 const heim_oid *eku, int allow_any_eku) 3503{ 3504 ExtKeyUsage e; 3505 int ret; 3506 size_t i; 3507 3508 ret = find_extension_eku(_hx509_get_cert(cert), &e); 3509 if (ret) { 3510 hx509_clear_error_string(context); 3511 return ret; 3512 } 3513 3514 for (i = 0; i < e.len; i++) { 3515 if (der_heim_oid_cmp(eku, &e.val[i]) == 0) { 3516 free_ExtKeyUsage(&e); 3517 return 0; 3518 } 3519 if (allow_any_eku) { 3520#if 0 3521 if (der_heim_oid_cmp(id_any_eku, &e.val[i]) == 0) { 3522 free_ExtKeyUsage(&e); 3523 return 0; 3524 } 3525#endif 3526 } 3527 } 3528 free_ExtKeyUsage(&e); 3529 hx509_clear_error_string(context); 3530 return HX509_CERTIFICATE_MISSING_EKU; 3531} 3532 3533int 3534_hx509_cert_get_keyusage(hx509_context context, 3535 hx509_cert c, 3536 KeyUsage *ku) 3537{ 3538 Certificate *cert; 3539 const Extension *e; 3540 size_t size; 3541 int ret; 3542 size_t i = 0; 3543 3544 memset(ku, 0, sizeof(*ku)); 3545 3546 cert = _hx509_get_cert(c); 3547 3548 if (_hx509_cert_get_version(cert) < 3) 3549 return 0; 3550 3551 e = find_extension(cert, &asn1_oid_id_x509_ce_keyUsage, &i); 3552 if (e == NULL) 3553 return HX509_KU_CERT_MISSING; 3554 3555 ret = decode_KeyUsage(e->extnValue.data, e->extnValue.length, ku, &size); 3556 if (ret) 3557 return ret; 3558 return 0; 3559} 3560 3561int 3562_hx509_cert_get_eku(hx509_context context, 3563 hx509_cert cert, 3564 ExtKeyUsage *e) 3565{ 3566 int ret; 3567 3568 memset(e, 0, sizeof(*e)); 3569 3570 ret = find_extension_eku(_hx509_get_cert(cert), e); 3571 if (ret && ret != HX509_EXTENSION_NOT_FOUND) { 3572 hx509_clear_error_string(context); 3573 return ret; 3574 } 3575 return 0; 3576} 3577 3578/** 3579 * Encodes the hx509 certificate as a DER encode binary. 3580 * 3581 * @param context A hx509 context. 3582 * @param c the certificate to encode. 3583 * @param os the encode certificate, set to NULL, 0 on case of 3584 * error. Free the os->data with hx509_xfree(). 3585 * 3586 * @return An hx509 error code, see hx509_get_error_string(). 3587 * 3588 * @ingroup hx509_cert 3589 */ 3590 3591int 3592hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os) 3593{ 3594 size_t size; 3595 int ret; 3596 3597 os->data = NULL; 3598 os->length = 0; 3599 3600 ASN1_MALLOC_ENCODE(Certificate, os->data, os->length, 3601 _hx509_get_cert(c), &size, ret); 3602 if (ret) { 3603 os->data = NULL; 3604 os->length = 0; 3605 return ret; 3606 } 3607 if (os->length != size) 3608 _hx509_abort("internal ASN.1 encoder error"); 3609 3610 return ret; 3611} 3612 3613/* 3614 * Last to avoid lost __attribute__s due to #undef. 3615 */ 3616 3617#undef __attribute__ 3618#define __attribute__(X) 3619 3620void 3621_hx509_abort(const char *fmt, ...) 3622 HEIMDAL_NORETURN_ATTRIBUTE 3623 HEIMDAL_PRINTF_ATTRIBUTE((printf, 1, 2)) 3624{ 3625 va_list ap; 3626 va_start(ap, fmt); 3627 heim_abortv(fmt, ap); 3628 va_end(ap); 3629} 3630 3631/** 3632 * Free a data element allocated in the library. 3633 * 3634 * @param ptr data to be freed. 3635 * 3636 * @ingroup hx509_misc 3637 */ 3638 3639void 3640hx509_xfree(void *ptr) 3641{ 3642 free(ptr); 3643} 3644 3645/** 3646 * 3647 */ 3648 3649int 3650_hx509_cert_to_env(hx509_context context, hx509_cert cert, hx509_env *env) 3651{ 3652 ExtKeyUsage eku; 3653 hx509_name name; 3654 char *buf; 3655 int ret; 3656 hx509_env envcert = NULL; 3657 3658 *env = NULL; 3659 3660 /* version */ 3661 asprintf(&buf, "%d", _hx509_cert_get_version(_hx509_get_cert(cert))); 3662 ret = hx509_env_add(context, &envcert, "version", buf); 3663 free(buf); 3664 if (ret) 3665 goto out; 3666 3667 /* subject */ 3668 ret = hx509_cert_get_subject(cert, &name); 3669 if (ret) 3670 goto out; 3671 3672 ret = hx509_name_to_string(name, &buf); 3673 if (ret) { 3674 hx509_name_free(&name); 3675 goto out; 3676 } 3677 3678 ret = hx509_env_add(context, &envcert, "subject", buf); 3679 hx509_name_free(&name); 3680 if (ret) 3681 goto out; 3682 3683 /* issuer */ 3684 ret = hx509_cert_get_issuer(cert, &name); 3685 if (ret) 3686 goto out; 3687 3688 ret = hx509_name_to_string(name, &buf); 3689 hx509_name_free(&name); 3690 if (ret) 3691 goto out; 3692 3693 ret = hx509_env_add(context, &envcert, "issuer", buf); 3694 hx509_xfree(buf); 3695 if (ret) 3696 goto out; 3697 3698 /* eku */ 3699 3700 ret = _hx509_cert_get_eku(context, cert, &eku); 3701 if (ret == HX509_EXTENSION_NOT_FOUND) 3702 ; 3703 else if (ret != 0) 3704 goto out; 3705 else { 3706 size_t i; 3707 hx509_env enveku = NULL; 3708 3709 for (i = 0; i < eku.len; i++) { 3710 3711 ret = der_print_heim_oid(&eku.val[i], '.', &buf); 3712 if (ret) { 3713 free_ExtKeyUsage(&eku); 3714 hx509_env_free(&enveku); 3715 goto out; 3716 } 3717 ret = hx509_env_add(context, &enveku, buf, "oid-name-here"); 3718 free(buf); 3719 if (ret) { 3720 free_ExtKeyUsage(&eku); 3721 hx509_env_free(&enveku); 3722 goto out; 3723 } 3724 } 3725 free_ExtKeyUsage(&eku); 3726 3727 ret = hx509_env_add_binding(context, &envcert, "eku", enveku); 3728 if (ret) { 3729 hx509_env_free(&enveku); 3730 goto out; 3731 } 3732 } 3733 3734 { 3735 Certificate *c = _hx509_get_cert(cert); 3736 heim_octet_string os, sig; 3737 hx509_env envhash = NULL; 3738 3739 os.data = c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data; 3740 os.length = 3741 c->tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.length / 8; 3742 3743 ret = _hx509_create_signature(context, 3744 NULL, 3745 hx509_signature_sha1(), 3746 &os, 3747 NULL, 3748 &sig); 3749 if (ret != 0) 3750 goto out; 3751 3752 ret = (int)hex_encode(sig.data, sig.length, &buf); 3753 der_free_octet_string(&sig); 3754 if (ret < 0) { 3755 ret = ENOMEM; 3756 hx509_set_error_string(context, 0, ret, 3757 "Out of memory"); 3758 goto out; 3759 } 3760 3761 ret = hx509_env_add(context, &envhash, "sha1", buf); 3762 free(buf); 3763 if (ret) 3764 goto out; 3765 3766 ret = hx509_env_add_binding(context, &envcert, "hash", envhash); 3767 if (ret) { 3768 hx509_env_free(&envhash); 3769 goto out; 3770 } 3771 } 3772 3773 ret = hx509_env_add_binding(context, env, "certificate", envcert); 3774 if (ret) 3775 goto out; 3776 3777 return 0; 3778 3779out: 3780 hx509_env_free(&envcert); 3781 return ret; 3782} 3783 3784/** 3785 * Print a simple representation of a certificate 3786 * 3787 * @param context A hx509 context, can be NULL 3788 * @param cert certificate to print 3789 * @param out the stdio output stream, if NULL, stdout is used 3790 * 3791 * @return An hx509 error code 3792 * 3793 * @ingroup hx509_cert 3794 */ 3795 3796int 3797hx509_print_cert(hx509_context context, hx509_cert cert, FILE *out) 3798{ 3799 hx509_name name; 3800 char *str; 3801 int ret; 3802 3803 if (out == NULL) 3804 out = stderr; 3805 3806 ret = hx509_cert_get_issuer(cert, &name); 3807 if (ret) 3808 return ret; 3809 hx509_name_to_string(name, &str); 3810 hx509_name_free(&name); 3811 fprintf(out, " issuer: \"%s\"\n", str); 3812 free(str); 3813 3814 ret = hx509_cert_get_subject(cert, &name); 3815 if (ret) 3816 return ret; 3817 hx509_name_to_string(name, &str); 3818 hx509_name_free(&name); 3819 fprintf(out, " subject: \"%s\"\n", str); 3820 free(str); 3821 3822 { 3823 heim_integer serialNumber; 3824 3825 ret = hx509_cert_get_serialnumber(cert, &serialNumber); 3826 if (ret) 3827 return ret; 3828 ret = der_print_hex_heim_integer(&serialNumber, &str); 3829 if (ret) 3830 return ret; 3831 der_free_heim_integer(&serialNumber); 3832 fprintf(out, " serial: %s\n", str); 3833 free(str); 3834 } 3835 3836 printf(" keyusage: "); 3837 ret = hx509_cert_keyusage_print(context, cert, &str); 3838 if (ret == 0) { 3839 fprintf(out, "%s\n", str); 3840 free(str); 3841 } else 3842 fprintf(out, "no"); 3843 3844 return 0; 3845} 3846 3847/** 3848 * Get a fast an loose version of the apple id, can't be used for acl checking 3849 * 3850 * @ingroup hx509_cert 3851 */ 3852 3853int 3854hx509_cert_get_appleid(hx509_context context, hx509_cert cert, char **appleid) 3855{ 3856 unsigned oids[] = { 1, 2, 840, 113635, 100, 3, 2, 1 }; 3857 const heim_oid mobileMe = { sizeof(oids)/sizeof(oids[0]), oids }; 3858 unsigned count = 0; 3859 hx509_name name; 3860 char *str; 3861 int ret; 3862 3863 *appleid = NULL; 3864 3865 ret = hx509_cert_check_eku(context, cert, &mobileMe, 0); 3866 if (ret) 3867 return ret; 3868 3869 ret = hx509_cert_get_subject(cert, &name); 3870 if (ret) 3871 return ret; 3872 3873 ret = hx509_name_get_component(name, 3, &asn1_oid_id_at_commonName, &count, &str); 3874 hx509_name_free(&name); 3875 if (ret) 3876 return ret; 3877 3878 asprintf(appleid, "%s@me.com", str); 3879 free(str); 3880 if (*appleid == NULL) 3881 return ENOMEM; 3882 3883 return 0; 3884} 3885