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