1/* 2 * Copyright (c) 2007 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 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 38#if defined(HAVE_FRAMEWORK_SECURITY) 39#include <Security/Security.h> 40 41#if defined(HAVE_CDSA) 42 43/* Missing function decls in pre Leopard */ 44#ifdef NEED_SECKEYGETCSPHANDLE_PROTO 45OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); 46OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, 47 int, const CSSM_ACCESS_CREDENTIALS **); 48#define kSecCredentialTypeDefault 0 49#define CSSM_SIZE uint32_t 50#endif 51 52#endif /* HAVE_CDSA */ 53 54struct kc_rsa { 55 SecKeyRef pkey; 56 size_t keysize; 57}; 58 59 60static int 61kc_rsa_public_encrypt(int flen, 62 const unsigned char *from, 63 unsigned char *to, 64 RSA *rsa, 65 int padding) 66{ 67 return -1; 68} 69 70static int 71kc_rsa_public_decrypt(int flen, 72 const unsigned char *from, 73 unsigned char *to, 74 RSA *rsa, 75 int padding) 76{ 77 return -1; 78} 79 80#if defined(HAVE_CDSA) 81 82/* 83 * 84 */ 85 86static int 87kc_rsa_sign(int type, const unsigned char *from, unsigned int flen, 88 unsigned char *to, unsigned int *tlen, const RSA *rsa) 89{ 90 struct kc_rsa *kc = RSA_get_app_data(rk_UNCONST(rsa)); 91 92 CSSM_RETURN cret; 93 OSStatus ret; 94 const CSSM_ACCESS_CREDENTIALS *creds; 95 SecKeyRef privKeyRef = kc->pkey; 96 CSSM_CSP_HANDLE cspHandle; 97 const CSSM_KEY *cssmKey; 98 CSSM_CC_HANDLE sigHandle = 0; 99 CSSM_DATA sig, in; 100 int fret = 0; 101 CSSM_ALGORITHMS stype; 102 103 if (type == NID_md5) { 104 stype = CSSM_ALGID_MD5; 105 } else if (type == NID_sha1) { 106 stype = CSSM_ALGID_SHA1; 107 } else if (type == NID_sha256) { 108 stype = CSSM_ALGID_SHA256; 109 } else if (type == NID_sha384) { 110 stype = CSSM_ALGID_SHA384; 111 } else if (type == NID_sha512) { 112 stype = CSSM_ALGID_SHA512; 113 } else 114 return -1; 115 116 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 117 if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", cret); 118 119 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 120 if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", cret); 121 122 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 123 kSecCredentialTypeNoUI, &creds); 124 if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret); 125 126 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 127 creds, cssmKey, &sigHandle); 128 if(ret) heim_abort("CSSM_CSP_CreateSignatureContext failed: %d", (int)ret); 129 130 in.Data = (uint8 *)from; 131 in.Length = flen; 132 133 sig.Data = (uint8 *)to; 134 sig.Length = kc->keysize; 135 136 cret = CSSM_SignData(sigHandle, &in, 1, stype, &sig); 137 if(cret) { 138 /* cssmErrorString(cret); */ 139 fret = -1; 140 } else { 141 fret = 1; 142 *tlen = (unsigned int)sig.Length; 143 } 144 145 if(sigHandle) 146 CSSM_DeleteContext(sigHandle); 147 148 return fret; 149} 150 151static int 152kc_rsa_private_encrypt(int flen, 153 const unsigned char *from, 154 unsigned char *to, 155 RSA *rsa, 156 int padding) 157{ 158 struct kc_rsa *kc = RSA_get_app_data(rsa); 159 160 CSSM_RETURN cret; 161 OSStatus ret; 162 const CSSM_ACCESS_CREDENTIALS *creds; 163 SecKeyRef privKeyRef = kc->pkey; 164 CSSM_CSP_HANDLE cspHandle; 165 const CSSM_KEY *cssmKey; 166 CSSM_CC_HANDLE sigHandle = 0; 167 CSSM_DATA sig, in; 168 int fret = 0; 169 170 if (padding != RSA_PKCS1_PADDING) 171 return -1; 172 173 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 174 if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", cret); 175 176 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 177 if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", cret); 178 179 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 180 kSecCredentialTypeNoUI, &creds); 181 if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret); 182 183 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 184 creds, cssmKey, &sigHandle); 185 if(ret) heim_abort("CSSM_CSP_CreateSignatureContext failed: %d", (int)ret); 186 187 in.Data = (uint8 *)from; 188 in.Length = flen; 189 190 sig.Data = (uint8 *)to; 191 sig.Length = kc->keysize; 192 193 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 194 if(cret) { 195 /* cssmErrorString(cret); */ 196 fret = -1; 197 } else 198 fret = (int)sig.Length; 199 200 if(sigHandle) 201 CSSM_DeleteContext(sigHandle); 202 203 return fret; 204} 205 206static int 207kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 208 RSA * rsa, int padding) 209{ 210 struct kc_rsa *kc = RSA_get_app_data(rsa); 211 212 CSSM_RETURN cret; 213 OSStatus ret; 214 const CSSM_ACCESS_CREDENTIALS *creds; 215 SecKeyRef privKeyRef = kc->pkey; 216 CSSM_CSP_HANDLE cspHandle; 217 const CSSM_KEY *cssmKey; 218 CSSM_CC_HANDLE handle = 0; 219 CSSM_DATA out, in, rem; 220 int fret = 0; 221 CSSM_SIZE outlen = 0; 222 char remdata[1024]; 223 224 if (padding != RSA_PKCS1_PADDING) 225 return -1; 226 227 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 228 if(cret) heim_abort("SecKeyGetCSSMKey failed: %d", (int)cret); 229 230 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 231 if(cret) heim_abort("SecKeyGetCSPHandle failed: %d", (int)cret); 232 233 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, 234 kSecCredentialTypeNoUI, &creds); 235 if(ret) heim_abort("SecKeyGetCredentials failed: %d", (int)ret); 236 237 ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, 238 CSSM_ALGID_RSA, 239 creds, 240 cssmKey, 241 CSSM_PADDING_PKCS1, 242 &handle); 243 if(ret) heim_abort("CSSM_CSP_CreateAsymmetricContext failed: %d", (int)ret); 244 245 in.Data = (uint8 *)from; 246 in.Length = flen; 247 248 out.Data = (uint8 *)to; 249 out.Length = kc->keysize; 250 251 rem.Data = (uint8 *)remdata; 252 rem.Length = sizeof(remdata); 253 254 cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); 255 if(cret) { 256 /* cssmErrorString(cret); */ 257 fret = -1; 258 } else 259 fret = (int)out.Length; 260 261 if(handle) 262 CSSM_DeleteContext(handle); 263 264 return fret; 265} 266 267#else 268 269static int 270kc_rsa_sign(int type, const unsigned char *from, unsigned int flen, 271 unsigned char *to, unsigned int *tlen, const RSA *rsa) 272{ 273 struct kc_rsa *kc = RSA_get_app_data(rk_UNCONST(rsa)); 274 size_t sigLen = kc->keysize; 275 SecPadding padding; 276 OSStatus status; 277 278 if (type == NID_md5) { 279 padding = kSecPaddingPKCS1MD5; 280 } else if (type == NID_sha1) { 281 padding = kSecPaddingPKCS1SHA1; 282 } else 283 return -1; 284 285 status = SecKeyRawSign(kc->pkey, 286 padding, 287 from, 288 flen, 289 to, 290 &sigLen); 291 if (status) 292 return -2; 293 294 *tlen = (unsigned int)sigLen; 295 296 return 1; 297} 298 299 300static int 301kc_rsa_private_encrypt(int flen, 302 const unsigned char *from, 303 unsigned char *to, 304 RSA *rsa, 305 int padding) 306{ 307 struct kc_rsa *kc = RSA_get_app_data(rsa); 308 size_t sigLen = kc->keysize; 309 OSStatus status; 310 311 if (padding != RSA_PKCS1_PADDING) 312 return -1; 313 314 status = SecKeyRawSign(kc->pkey, 315 kSecPaddingPKCS1, 316 from, 317 flen, 318 to, 319 &sigLen); 320 if (status) 321 return -2; 322 323 return (int)sigLen; 324} 325 326static int 327kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 328 RSA * rsa, int padding) 329{ 330 struct kc_rsa *kc = RSA_get_app_data(rsa); 331 OSStatus status; 332 333 if (padding != RSA_PKCS1_PADDING) 334 return -1; 335 336 status = SecKeyRawVerify(kc->pkey, 337 kSecPaddingPKCS1, 338 from, 339 flen, 340 to, 341 kc->keysize); 342 if (status) 343 return -2; 344 345 return (int)kc->keysize; 346} 347 348#endif /* HAVE_CDSA */ 349 350 351static int 352kc_rsa_init(RSA *rsa) 353{ 354 return 1; 355} 356 357static int 358kc_rsa_finish(RSA *rsa) 359{ 360 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); 361 if (kc_rsa) { 362 CFRelease(kc_rsa->pkey); 363 free(kc_rsa); 364 } 365 return 1; 366} 367 368static const RSA_METHOD kc_rsa_pkcs1_method = { 369 "hx509 Keychain PKCS#1 RSA", 370 kc_rsa_public_encrypt, 371 kc_rsa_public_decrypt, 372 kc_rsa_private_encrypt, 373 kc_rsa_private_decrypt, 374 NULL, 375 NULL, 376 kc_rsa_init, 377 kc_rsa_finish, 378 0, 379 NULL, 380 kc_rsa_sign, 381 NULL 382}; 383 384 385 386static int 387set_private_key(hx509_context context, hx509_cert cert, SecKeyRef pkey) 388{ 389 const SubjectPublicKeyInfo *spi; 390 const Certificate *c; 391 struct kc_rsa *kc; 392 RSAPublicKey pk; 393 hx509_private_key key; 394 size_t size; 395 RSA *rsa; 396 int ret; 397 398 ret = hx509_private_key_init(&key, NULL, NULL); 399 if (ret) 400 return ret; 401 402 kc = calloc(1, sizeof(*kc)); 403 if (kc == NULL) 404 _hx509_abort("out of memory"); 405 406 CFRetain(pkey); 407 kc->pkey = pkey; 408 409 rsa = RSA_new(); 410 if (rsa == NULL) 411 _hx509_abort("out of memory"); 412 413 RSA_set_method(rsa, &kc_rsa_pkcs1_method); 414 ret = RSA_set_app_data(rsa, kc); 415 if (ret != 1) 416 _hx509_abort("RSA_set_app_data"); 417 418 /* 419 * Set up n and e to please RSA_size() 420 */ 421 422 c = _hx509_get_cert(cert); 423 spi = &c->tbsCertificate.subjectPublicKeyInfo; 424 425 ret = decode_RSAPublicKey(spi->subjectPublicKey.data, 426 spi->subjectPublicKey.length / 8, 427 &pk, &size); 428 if (ret) { 429 RSA_free(rsa); 430 return 0; 431 } 432 rsa->n = _hx509_int2BN(&pk.modulus); 433 rsa->e = _hx509_int2BN(&pk.publicExponent); 434 free_RSAPublicKey(&pk); 435 436 kc->keysize = BN_num_bytes(rsa->n); 437 438 /* 439 * 440 */ 441 442 hx509_private_key_assign_rsa(key, rsa); 443 _hx509_cert_set_key(cert, key); 444 445 hx509_private_key_free(&key); 446 447 return 0; 448} 449 450/* 451 * 452 */ 453 454struct ks_keychain { 455 int anchors; 456#ifndef __APPLE_TARGET_EMBEDDED__ 457 SecKeychainRef keychain; 458#endif 459}; 460 461static int 462keychain_init(hx509_context context, 463 hx509_certs certs, void **data, int flags, 464 const char *residue, hx509_lock lock) 465{ 466 struct ks_keychain *ctx; 467 468 ctx = calloc(1, sizeof(*ctx)); 469 if (ctx == NULL) { 470 hx509_clear_error_string(context); 471 return ENOMEM; 472 } 473 474 if (residue && residue[0]) { 475#ifndef __APPLE_TARGET_EMBEDDED__ 476 if (strcasecmp(residue, "system-anchors") == 0) { 477 ctx->anchors = 1; 478 } else if (strncasecmp(residue, "FILE:", 5) == 0) { 479 OSStatus ret; 480 481 ret = SecKeychainOpen(residue + 5, &ctx->keychain); 482 if (ret != noErr) { 483 free(ctx); 484 hx509_set_error_string(context, 0, ENOENT, 485 "Failed to open %s", residue); 486 return ENOENT; 487 } 488 } else 489#endif 490 { 491 free(ctx); 492 hx509_set_error_string(context, 0, ENOENT, 493 "Unknown subtype %s", residue); 494 return ENOENT; 495 } 496 } 497 498 *data = ctx; 499 return 0; 500} 501 502/* 503 * 504 */ 505 506static int 507keychain_free(hx509_certs certs, void *data) 508{ 509 struct ks_keychain *ctx = data; 510 if (ctx) { 511#ifndef __APPLE_TARGET_EMBEDDED__ 512 if (ctx->keychain) 513 CFRelease(ctx->keychain); 514#endif 515 memset(ctx, 0, sizeof(*ctx)); 516 free(ctx); 517 } 518 return 0; 519} 520 521/* 522 * 523 */ 524 525static int 526keychain_query(hx509_context context, 527 hx509_certs certs, 528 void *data, 529 const hx509_query *query, 530 hx509_cert *retcert) 531{ 532 CFArrayRef identities = NULL; 533 hx509_cert cert = NULL; 534 CFIndex n, count; 535 int ret; 536 int kdcLookupHack = 0; 537 538 /* 539 * First to course filtering using security framework .... 540 */ 541 542#define FASTER_FLAGS (HX509_QUERY_MATCH_PERSISTENT|HX509_QUERY_PRIVATE_KEY) 543 544 if ((query->match & FASTER_FLAGS) == 0) 545 return HX509_UNIMPLEMENTED_OPERATION; 546 547 CFMutableDictionaryRef secQuery = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 548 549 /* 550 * XXX this is so broken, SecItem doesn't find the kdc certificte, 551 * and kdc certificates happend to be searched by friendly name, 552 * so find that and mundge on the structure. 553 */ 554 555 if ((query->match & HX509_QUERY_MATCH_FRIENDLY_NAME) && 556 (query->match & HX509_QUERY_PRIVATE_KEY) && 557 strcmp(query->friendlyname, "O=System Identity,CN=com.apple.kerberos.kdc") == 0) 558 { 559 ((hx509_query *)query)->match &= ~HX509_QUERY_PRIVATE_KEY; 560 kdcLookupHack = 1; 561 } 562 563 if (kdcLookupHack || (query->match & HX509_QUERY_MATCH_PERSISTENT)) { 564 CFDictionaryAddValue(secQuery, kSecClass, kSecClassCertificate); 565 } else 566 CFDictionaryAddValue(secQuery, kSecClass, kSecClassIdentity); 567 568 CFDictionaryAddValue(secQuery, kSecReturnRef, kCFBooleanTrue); 569 CFDictionaryAddValue(secQuery, kSecMatchLimit, kSecMatchLimitAll); 570 571 if (query->match & HX509_QUERY_MATCH_PERSISTENT) { 572 CFDataRef refdata = CFDataCreateWithBytesNoCopy(NULL, query->persistent->data, query->persistent->length, kCFAllocatorNull); 573 CFDictionaryAddValue(secQuery, kSecValuePersistentRef, refdata); 574 CFRelease(refdata); 575 } 576 577 578 OSStatus status = SecItemCopyMatching(secQuery, (CFTypeRef *)&identities); 579 CFRelease(secQuery); 580 if (status || identities == NULL) { 581 hx509_clear_error_string(context); 582 return HX509_CERT_NOT_FOUND; 583 } 584 585 heim_assert(CFArrayGetTypeID() == CFGetTypeID(identities), "return value not an array"); 586 587 /* 588 * ... now do hx509 filtering 589 */ 590 591 count = CFArrayGetCount(identities); 592 for (n = 0; n < count; n++) { 593 CFTypeRef secitem = (CFTypeRef)CFArrayGetValueAtIndex(identities, n); 594 595#ifndef __APPLE_TARGET_EMBEDDED__ 596 597 if (query->match & HX509_QUERY_MATCH_PERSISTENT) { 598 SecIdentityRef other = NULL; 599 OSStatus osret; 600 601 osret = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)secitem, &other); 602 if (osret == noErr) { 603 ret = hx509_cert_init_SecFramework(context, (void *)other, &cert); 604 CFRelease(other); 605 if (ret) 606 continue; 607 } else { 608 ret = hx509_cert_init_SecFramework(context, (void *)secitem, &cert); 609 if (ret) 610 continue; 611 } 612 } else 613#endif 614 { 615 616 ret = hx509_cert_init_SecFramework(context, (void *)secitem, &cert); 617 if (ret) 618 continue; 619 } 620 621 if (_hx509_query_match_cert(context, query, cert)) { 622 623#ifndef __APPLE_TARGET_EMBEDDED__ 624 /* certtool/keychain doesn't glue togheter the cert with keys for system keys */ 625 if (kdcLookupHack) { 626 SecIdentityRef other = NULL; 627 OSStatus osret; 628 629 osret = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)secitem, &other); 630 if (osret == noErr) { 631 hx509_cert_free(cert); 632 ret = hx509_cert_init_SecFramework(context, other, &cert); 633 CFRelease(other); 634 if (ret) 635 continue; 636 } 637 } 638#endif 639 *retcert = cert; 640 break; 641 } 642 hx509_cert_free(cert); 643 } 644 645 if (kdcLookupHack) 646 ((hx509_query *)query)->match |= HX509_QUERY_PRIVATE_KEY; 647 648 CFRelease(identities); 649 650 if (*retcert == NULL) { 651 hx509_clear_error_string(context); 652 return HX509_CERT_NOT_FOUND; 653 } 654 655 return 0; 656} 657 658/* 659 * 660 */ 661 662struct iter { 663 hx509_certs certs; 664 void *cursor; 665 CFArrayRef search; 666 CFIndex index; 667}; 668 669static int 670keychain_iter_start(hx509_context context, 671 hx509_certs certs, void *data, void **cursor) 672{ 673#ifndef __APPLE_TARGET_EMBEDDED__ 674 struct ks_keychain *ctx = data; 675#endif 676 struct iter *iter; 677 678 iter = calloc(1, sizeof(*iter)); 679 if (iter == NULL) { 680 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 681 return ENOMEM; 682 } 683 684#ifndef __APPLE_TARGET_EMBEDDED__ 685 if (ctx->anchors) { 686 CFArrayRef anchors; 687 int ret; 688 int i; 689 690 ret = hx509_certs_init(context, "MEMORY:ks-file-create", 691 0, NULL, &iter->certs); 692 if (ret) { 693 free(iter); 694 return ret; 695 } 696 697 ret = SecTrustCopyAnchorCertificates(&anchors); 698 if (ret != 0) { 699 hx509_certs_free(&iter->certs); 700 free(iter); 701 hx509_set_error_string(context, 0, ENOMEM, 702 "Can't get trust anchors from Keychain"); 703 return ENOMEM; 704 } 705 for (i = 0; i < CFArrayGetCount(anchors); i++) { 706 SecCertificateRef cr; 707 hx509_cert cert; 708 CFDataRef dataref; 709 710 cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); 711 712 dataref = SecCertificateCopyData(cr); 713 if (dataref == NULL) 714 continue; 715 716 ret = hx509_cert_init_data(context, CFDataGetBytePtr(dataref), CFDataGetLength(dataref), &cert); 717 CFRelease(dataref); 718 if (ret) 719 continue; 720 721 ret = hx509_certs_add(context, iter->certs, cert); 722 hx509_cert_free(cert); 723 } 724 CFRelease(anchors); 725 if (ret != 0) { 726 hx509_certs_free(&iter->certs); 727 free(iter); 728 hx509_set_error_string(context, 0, ret, 729 "Failed to add cert"); 730 return ret; 731 } 732 } 733 734 if (iter->certs) { 735 int ret; 736 ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); 737 if (ret) { 738 hx509_certs_free(&iter->certs); 739 free(iter); 740 return ret; 741 } 742 } else 743#endif 744 { 745 OSStatus ret; 746 const void *keys[] = { 747 kSecClass, 748 kSecReturnRef, 749 kSecMatchLimit 750 }; 751 const void *values[] = { 752 kSecClassCertificate, 753 kCFBooleanTrue, 754 kSecMatchLimitAll 755 }; 756 757 CFDictionaryRef secQuery; 758 759 secQuery = CFDictionaryCreate(NULL, keys, values, 760 sizeof(keys) / sizeof(*keys), 761 &kCFTypeDictionaryKeyCallBacks, 762 &kCFTypeDictionaryValueCallBacks); 763 764 ret = SecItemCopyMatching(secQuery, (CFTypeRef *)&iter->search); 765 CFRelease(secQuery); 766 if (ret) { 767 free(iter); 768 return ENOMEM; 769 } 770 } 771 772 *cursor = iter; 773 return 0; 774} 775 776/* 777 * 778 */ 779 780static int 781keychain_iter(hx509_context context, 782 hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 783{ 784 struct iter *iter = cursor; 785 OSStatus ret = 0; 786 787 if (iter->certs) 788 return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); 789 790 *cert = NULL; 791 792next: 793 if (iter->index < CFArrayGetCount(iter->search)) { 794 795 CFTypeRef secCert = CFArrayGetValueAtIndex(iter->search, iter->index); 796 797 ret = hx509_cert_init_SecFramework(context, (void *)secCert, cert); 798 iter->index++; 799 if (ret) 800 goto next; 801 } 802 if (iter->index == CFArrayGetCount(iter->search)) 803 return 0; 804 805 return ret; 806} 807 808/* 809 * 810 */ 811 812static int 813keychain_iter_end(hx509_context context, 814 hx509_certs certs, 815 void *data, 816 void *cursor) 817{ 818 struct iter *iter = cursor; 819 820 if (iter->certs) { 821 hx509_certs_end_seq(context, iter->certs, iter->cursor); 822 hx509_certs_free(&iter->certs); 823 } else { 824 CFRelease(iter->search); 825 } 826 827 memset(iter, 0, sizeof(*iter)); 828 free(iter); 829 return 0; 830} 831 832/* 833 * 834 */ 835 836struct hx509_keyset_ops keyset_keychain = { 837 "KEYCHAIN", 838 0, 839 keychain_init, 840 NULL, 841 keychain_free, 842 NULL, 843 keychain_query, 844 keychain_iter_start, 845 keychain_iter, 846 keychain_iter_end 847}; 848 849#endif /* HAVE_FRAMEWORK_SECURITY */ 850 851/* 852 * 853 */ 854 855void 856_hx509_ks_keychain_register(hx509_context context) 857{ 858#if defined(HAVE_FRAMEWORK_SECURITY) 859 _hx509_ks_register(context, &keyset_keychain); 860#endif 861} 862 863static void 864kc_cert_release(hx509_cert cert, void *ctx) 865{ 866 SecCertificateRef seccert = ctx; 867 CFRelease(seccert); 868} 869 870/* 871 * 872 */ 873 874 875static void 876setPersistentRef(hx509_cert cert, SecCertificateRef itemRef) 877{ 878#if !__APPLE_TARGET_EMBEDDED__ 879 CFDataRef persistent; 880 OSStatus ret; 881 882 ret = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)itemRef, &persistent); 883 if (ret == noErr) { 884 heim_octet_string os; 885 886 os.data = rk_UNCONST(CFDataGetBytePtr(persistent)); 887 os.length = CFDataGetLength(persistent); 888 889 hx509_cert_set_persistent(cert, &os); 890 CFRelease(persistent); 891 } 892#endif 893} 894 895 896int 897hx509_cert_init_SecFramework(hx509_context context, void * identity, hx509_cert *cert) 898{ 899 CFTypeID typeid = CFGetTypeID(identity); 900 SecCertificateRef seccert; 901 CFTypeRef secdata = NULL; 902 SecKeyRef pkey = NULL; 903 CFDataRef data; 904 OSStatus osret; 905 hx509_cert c; 906 int ret; 907 908 *cert = NULL; 909 910 if (CFDataGetTypeID() == typeid) { 911 void const * keys[4] = { 912 kSecClass, 913 kSecReturnRef, 914 kSecMatchLimit, 915 kSecValuePersistentRef 916 }; 917 void const * values[4] = { 918 kSecClassIdentity, 919 kCFBooleanTrue, 920 kSecMatchLimitOne, 921 identity 922 }; 923 CFDictionaryRef query; 924 925 assert(sizeof(keys) == sizeof(values)); 926 927 query = CFDictionaryCreate(NULL, keys, values, 928 sizeof(keys) / sizeof(*keys), 929 &kCFTypeDictionaryKeyCallBacks, 930 &kCFTypeDictionaryValueCallBacks); 931 932 osret = SecItemCopyMatching(query, &secdata); 933 CFRelease(query); 934 if (osret || secdata == NULL) { 935 hx509_set_error_string(context, 0, HX509_CERTIFICATE_UNKNOWN_TYPE, 936 "Failed to turn persistent reference into a certifiate: %d", (int)osret); 937 return HX509_CERTIFICATE_UNKNOWN_TYPE; 938 } 939 940 typeid = CFGetTypeID(secdata); 941 identity = (void *)secdata; 942 } 943 944 if (SecIdentityGetTypeID() == typeid) { 945 osret = SecIdentityCopyCertificate(identity, &seccert); 946 if (osret) { 947 if (secdata) 948 CFRelease(secdata); 949 hx509_set_error_string(context, 0, HX509_CERTIFICATE_UNKNOWN_TYPE, 950 "Failed to convert the identity to a certificate: %d", (int)osret); 951 return HX509_CERTIFICATE_UNKNOWN_TYPE; 952 } 953 } else if (SecCertificateGetTypeID() == typeid) { 954 seccert = (SecCertificateRef)identity; 955 CFRetain(seccert); 956 } else { 957 if (secdata) 958 CFRelease(secdata); 959 hx509_set_error_string(context, 0, HX509_CERTIFICATE_UNKNOWN_TYPE, 960 "Data from persistent ref not a identity or certificate"); 961 return HX509_CERTIFICATE_UNKNOWN_TYPE; 962 } 963 964 data = SecCertificateCopyData(seccert); 965 if (data == NULL) { 966 if (secdata) 967 CFRelease(secdata); 968 CFRelease(seccert); 969 return ENOMEM; 970 } 971 972 ret = hx509_cert_init_data(context, CFDataGetBytePtr(data), 973 CFDataGetLength(data), &c); 974 CFRelease(data); 975 if (ret) { 976 if (secdata) 977 CFRelease(secdata); 978 CFRelease(seccert); 979 return ret; 980 } 981 982 /* 983 * Set Persistent identity 984 */ 985 986 setPersistentRef(c, seccert); 987 988 /* if identity assign private key too */ 989 if (SecIdentityGetTypeID() == typeid) { 990 (void)SecIdentityCopyPrivateKey(identity, &pkey); 991 } 992 993 if (pkey) { 994 set_private_key(context, c, pkey); 995 CFRelease(pkey); 996 } 997 998 _hx509_cert_set_release(c, kc_cert_release, seccert); 999 1000 if (secdata) 1001 CFRelease(secdata); 1002 1003 *cert = c; 1004 1005 return 0; 1006} 1007