ks_keychain.c revision 178825
1275970Scy/* 2275970Scy * Copyright (c) 2007 Kungliga Tekniska H�gskolan 3275970Scy * (Royal Institute of Technology, Stockholm, Sweden). 4275970Scy * All rights reserved. 5275970Scy * 6275970Scy * Redistribution and use in source and binary forms, with or without 7275970Scy * modification, are permitted provided that the following conditions 8275970Scy * are met: 9275970Scy * 10275970Scy * 1. Redistributions of source code must retain the above copyright 11275970Scy * notice, this list of conditions and the following disclaimer. 12275970Scy * 13275970Scy * 2. Redistributions in binary form must reproduce the above copyright 14275970Scy * notice, this list of conditions and the following disclaimer in the 15275970Scy * documentation and/or other materials provided with the distribution. 16275970Scy * 17275970Scy * 3. Neither the name of the Institute nor the names of its contributors 18275970Scy * may be used to endorse or promote products derived from this software 19275970Scy * without specific prior written permission. 20275970Scy * 21275970Scy * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24275970Scy * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31275970Scy * SUCH DAMAGE. 32275970Scy */ 33275970Scy 34275970Scy#include "hx_locl.h" 35275970ScyRCSID("$Id: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $"); 36275970Scy 37275970Scy#ifdef HAVE_FRAMEWORK_SECURITY 38275970Scy 39275970Scy#include <Security/Security.h> 40275970Scy 41275970Scy/* Missing function decls in pre Leopard */ 42275970Scy#ifdef NEED_SECKEYGETCSPHANDLE_PROTO 43275970ScyOSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); 44275970ScyOSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, 45275970Scy int, const CSSM_ACCESS_CREDENTIALS **); 46275970Scy#define kSecCredentialTypeDefault 0 47275970Scy#endif 48275970Scy 49275970Scy 50275970Scystatic int 51275970ScygetAttribute(SecKeychainItemRef itemRef, SecItemAttr item, 52275970Scy SecKeychainAttributeList **attrs) 53275970Scy{ 54275970Scy SecKeychainAttributeInfo attrInfo; 55275970Scy UInt32 attrFormat = 0; 56275970Scy OSStatus ret; 57275970Scy 58275970Scy *attrs = NULL; 59275970Scy 60275970Scy attrInfo.count = 1; 61275970Scy attrInfo.tag = &item; 62275970Scy attrInfo.format = &attrFormat; 63275970Scy 64275970Scy ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 65275970Scy attrs, NULL, NULL); 66275970Scy if (ret) 67275970Scy return EINVAL; 68275970Scy return 0; 69275970Scy} 70275970Scy 71275970Scy 72275970Scy/* 73275970Scy * 74275970Scy */ 75275970Scy 76275970Scystruct kc_rsa { 77275970Scy SecKeychainItemRef item; 78275970Scy size_t keysize; 79275970Scy}; 80275970Scy 81275970Scy 82275970Scystatic int 83275970Scykc_rsa_public_encrypt(int flen, 84275970Scy const unsigned char *from, 85275970Scy unsigned char *to, 86275970Scy RSA *rsa, 87275970Scy int padding) 88275970Scy{ 89275970Scy return -1; 90275970Scy} 91275970Scy 92275970Scystatic int 93275970Scykc_rsa_public_decrypt(int flen, 94275970Scy const unsigned char *from, 95275970Scy unsigned char *to, 96275970Scy RSA *rsa, 97275970Scy int padding) 98275970Scy{ 99275970Scy return -1; 100275970Scy} 101275970Scy 102275970Scy 103275970Scystatic int 104275970Scykc_rsa_private_encrypt(int flen, 105275970Scy const unsigned char *from, 106275970Scy unsigned char *to, 107275970Scy RSA *rsa, 108275970Scy int padding) 109275970Scy{ 110275970Scy struct kc_rsa *kc = RSA_get_app_data(rsa); 111275970Scy 112275970Scy CSSM_RETURN cret; 113275970Scy OSStatus ret; 114275970Scy const CSSM_ACCESS_CREDENTIALS *creds; 115275970Scy SecKeyRef privKeyRef = (SecKeyRef)kc->item; 116275970Scy CSSM_CSP_HANDLE cspHandle; 117275970Scy const CSSM_KEY *cssmKey; 118275970Scy CSSM_CC_HANDLE sigHandle = 0; 119275970Scy CSSM_DATA sig, in; 120275970Scy int fret = 0; 121275970Scy 122275970Scy 123275970Scy cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 124275970Scy if(cret) abort(); 125275970Scy 126275970Scy cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 127275970Scy if(cret) abort(); 128275970Scy 129275970Scy ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 130275970Scy kSecCredentialTypeDefault, &creds); 131275970Scy if(ret) abort(); 132275970Scy 133275970Scy ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 134275970Scy creds, cssmKey, &sigHandle); 135275970Scy if(ret) abort(); 136275970Scy 137275970Scy in.Data = (uint8 *)from; 138275970Scy in.Length = flen; 139275970Scy 140275970Scy sig.Data = (uint8 *)to; 141275970Scy sig.Length = kc->keysize; 142275970Scy 143275970Scy cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 144275970Scy if(cret) { 145275970Scy /* cssmErrorString(cret); */ 146275970Scy fret = -1; 147275970Scy } else 148275970Scy fret = sig.Length; 149275970Scy 150275970Scy if(sigHandle) 151275970Scy CSSM_DeleteContext(sigHandle); 152275970Scy 153275970Scy return fret; 154275970Scy} 155275970Scy 156275970Scystatic int 157275970Scykc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 158275970Scy RSA * rsa, int padding) 159275970Scy{ 160275970Scy return -1; 161275970Scy} 162275970Scy 163275970Scystatic int 164275970Scykc_rsa_init(RSA *rsa) 165275970Scy{ 166275970Scy return 1; 167275970Scy} 168275970Scy 169275970Scystatic int 170275970Scykc_rsa_finish(RSA *rsa) 171275970Scy{ 172275970Scy struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); 173275970Scy CFRelease(kc_rsa->item); 174275970Scy memset(kc_rsa, 0, sizeof(*kc_rsa)); 175275970Scy free(kc_rsa); 176275970Scy return 1; 177275970Scy} 178275970Scy 179275970Scystatic const RSA_METHOD kc_rsa_pkcs1_method = { 180275970Scy "hx509 Keychain PKCS#1 RSA", 181275970Scy kc_rsa_public_encrypt, 182275970Scy kc_rsa_public_decrypt, 183275970Scy kc_rsa_private_encrypt, 184275970Scy kc_rsa_private_decrypt, 185275970Scy NULL, 186275970Scy NULL, 187275970Scy kc_rsa_init, 188275970Scy kc_rsa_finish, 189275970Scy 0, 190275970Scy NULL, 191275970Scy NULL, 192275970Scy NULL 193275970Scy}; 194275970Scy 195275970Scystatic int 196275970Scyset_private_key(hx509_context context, 197275970Scy SecKeychainItemRef itemRef, 198275970Scy hx509_cert cert) 199275970Scy{ 200275970Scy struct kc_rsa *kc; 201275970Scy hx509_private_key key; 202275970Scy RSA *rsa; 203275970Scy int ret; 204275970Scy 205275970Scy ret = _hx509_private_key_init(&key, NULL, NULL); 206275970Scy if (ret) 207275970Scy return ret; 208275970Scy 209275970Scy kc = calloc(1, sizeof(*kc)); 210275970Scy if (kc == NULL) 211275970Scy _hx509_abort("out of memory"); 212275970Scy 213275970Scy kc->item = itemRef; 214275970Scy 215275970Scy rsa = RSA_new(); 216275970Scy if (rsa == NULL) 217275970Scy _hx509_abort("out of memory"); 218275970Scy 219275970Scy /* Argh, fake modulus since OpenSSL API is on crack */ 220275970Scy { 221275970Scy SecKeychainAttributeList *attrs = NULL; 222275970Scy uint32_t size; 223275970Scy void *data; 224275970Scy 225275970Scy rsa->n = BN_new(); 226275970Scy if (rsa->n == NULL) abort(); 227275970Scy 228275970Scy ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs); 229275970Scy if (ret) abort(); 230275970Scy 231275970Scy size = *(uint32_t *)attrs->attr[0].data; 232275970Scy SecKeychainItemFreeAttributesAndData(attrs, NULL); 233275970Scy 234275970Scy kc->keysize = (size + 7) / 8; 235275970Scy 236275970Scy data = malloc(kc->keysize); 237275970Scy memset(data, 0xe0, kc->keysize); 238275970Scy BN_bin2bn(data, kc->keysize, rsa->n); 239275970Scy free(data); 240275970Scy } 241275970Scy rsa->e = NULL; 242275970Scy 243275970Scy RSA_set_method(rsa, &kc_rsa_pkcs1_method); 244275970Scy ret = RSA_set_app_data(rsa, kc); 245275970Scy if (ret != 1) 246275970Scy _hx509_abort("RSA_set_app_data"); 247275970Scy 248275970Scy _hx509_private_key_assign_rsa(key, rsa); 249275970Scy _hx509_cert_assign_key(cert, key); 250275970Scy 251275970Scy return 0; 252275970Scy} 253275970Scy 254275970Scy/* 255275970Scy * 256275970Scy */ 257275970Scy 258275970Scystruct ks_keychain { 259275970Scy int anchors; 260275970Scy SecKeychainRef keychain; 261275970Scy}; 262275970Scy 263275970Scystatic int 264275970Scykeychain_init(hx509_context context, 265275970Scy hx509_certs certs, void **data, int flags, 266275970Scy const char *residue, hx509_lock lock) 267275970Scy{ 268275970Scy struct ks_keychain *ctx; 269275970Scy 270275970Scy ctx = calloc(1, sizeof(*ctx)); 271275970Scy if (ctx == NULL) { 272275970Scy hx509_clear_error_string(context); 273275970Scy return ENOMEM; 274275970Scy } 275275970Scy 276275970Scy if (residue) { 277275970Scy if (strcasecmp(residue, "system-anchors") == 0) { 278275970Scy ctx->anchors = 1; 279275970Scy } else if (strncasecmp(residue, "FILE:", 5) == 0) { 280275970Scy OSStatus ret; 281275970Scy 282275970Scy ret = SecKeychainOpen(residue + 5, &ctx->keychain); 283275970Scy if (ret != noErr) { 284275970Scy hx509_set_error_string(context, 0, ENOENT, 285275970Scy "Failed to open %s", residue); 286275970Scy return ENOENT; 287275970Scy } 288275970Scy } else { 289275970Scy hx509_set_error_string(context, 0, ENOENT, 290275970Scy "Unknown subtype %s", residue); 291275970Scy return ENOENT; 292275970Scy } 293275970Scy } 294275970Scy 295275970Scy *data = ctx; 296275970Scy return 0; 297275970Scy} 298275970Scy 299275970Scy/* 300275970Scy * 301275970Scy */ 302275970Scy 303275970Scystatic int 304275970Scykeychain_free(hx509_certs certs, void *data) 305275970Scy{ 306275970Scy struct ks_keychain *ctx = data; 307275970Scy if (ctx->keychain) 308275970Scy CFRelease(ctx->keychain); 309275970Scy memset(ctx, 0, sizeof(*ctx)); 310275970Scy free(ctx); 311275970Scy return 0; 312275970Scy} 313275970Scy 314275970Scy/* 315275970Scy * 316275970Scy */ 317275970Scy 318275970Scystruct iter { 319275970Scy hx509_certs certs; 320275970Scy void *cursor; 321275970Scy SecKeychainSearchRef searchRef; 322275970Scy}; 323275970Scy 324275970Scystatic int 325275970Scykeychain_iter_start(hx509_context context, 326275970Scy hx509_certs certs, void *data, void **cursor) 327275970Scy{ 328275970Scy struct ks_keychain *ctx = data; 329275970Scy struct iter *iter; 330275970Scy 331275970Scy iter = calloc(1, sizeof(*iter)); 332275970Scy if (iter == NULL) { 333275970Scy hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 334275970Scy return ENOMEM; 335275970Scy } 336275970Scy 337275970Scy if (ctx->anchors) { 338275970Scy CFArrayRef anchors; 339275970Scy int ret; 340275970Scy int i; 341275970Scy 342275970Scy ret = hx509_certs_init(context, "MEMORY:ks-file-create", 343275970Scy 0, NULL, &iter->certs); 344275970Scy if (ret) { 345275970Scy free(iter); 346275970Scy return ret; 347275970Scy } 348275970Scy 349275970Scy ret = SecTrustCopyAnchorCertificates(&anchors); 350275970Scy if (ret != 0) { 351275970Scy hx509_certs_free(&iter->certs); 352275970Scy free(iter); 353275970Scy hx509_set_error_string(context, 0, ENOMEM, 354275970Scy "Can't get trust anchors from Keychain"); 355275970Scy return ENOMEM; 356275970Scy } 357275970Scy for (i = 0; i < CFArrayGetCount(anchors); i++) { 358275970Scy SecCertificateRef cr; 359275970Scy hx509_cert cert; 360275970Scy CSSM_DATA cssm; 361275970Scy 362275970Scy cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); 363275970Scy 364275970Scy SecCertificateGetData(cr, &cssm); 365275970Scy 366275970Scy ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert); 367275970Scy if (ret) 368275970Scy continue; 369275970Scy 370275970Scy ret = hx509_certs_add(context, iter->certs, cert); 371275970Scy hx509_cert_free(cert); 372275970Scy } 373275970Scy CFRelease(anchors); 374275970Scy } 375275970Scy 376275970Scy if (iter->certs) { 377275970Scy int ret; 378275970Scy ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); 379275970Scy if (ret) { 380275970Scy hx509_certs_free(&iter->certs); 381275970Scy free(iter); 382275970Scy return ret; 383275970Scy } 384275970Scy } else { 385275970Scy OSStatus ret; 386275970Scy 387275970Scy ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, 388275970Scy kSecCertificateItemClass, 389275970Scy NULL, 390275970Scy &iter->searchRef); 391275970Scy if (ret) { 392275970Scy free(iter); 393275970Scy hx509_set_error_string(context, 0, ret, 394275970Scy "Failed to start search for attributes"); 395275970Scy return ENOMEM; 396275970Scy } 397275970Scy } 398275970Scy 399275970Scy *cursor = iter; 400275970Scy return 0; 401275970Scy} 402275970Scy 403275970Scy/* 404275970Scy * 405275970Scy */ 406275970Scy 407275970Scystatic int 408275970Scykeychain_iter(hx509_context context, 409275970Scy hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 410275970Scy{ 411275970Scy SecKeychainAttributeList *attrs = NULL; 412275970Scy SecKeychainAttributeInfo attrInfo; 413275970Scy UInt32 attrFormat[1] = { 0 }; 414275970Scy SecKeychainItemRef itemRef; 415275970Scy SecItemAttr item[1]; 416275970Scy struct iter *iter = cursor; 417275970Scy OSStatus ret; 418275970Scy UInt32 len; 419275970Scy void *ptr = NULL; 420275970Scy 421275970Scy if (iter->certs) 422275970Scy return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); 423275970Scy 424275970Scy *cert = NULL; 425275970Scy 426275970Scy ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); 427275970Scy if (ret == errSecItemNotFound) 428275970Scy return 0; 429275970Scy else if (ret != 0) 430275970Scy return EINVAL; 431275970Scy 432275970Scy /* 433275970Scy * Pick out certificate and matching "keyid" 434275970Scy */ 435275970Scy 436275970Scy item[0] = kSecPublicKeyHashItemAttr; 437275970Scy 438275970Scy attrInfo.count = 1; 439275970Scy attrInfo.tag = item; 440275970Scy attrInfo.format = attrFormat; 441275970Scy 442275970Scy ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 443275970Scy &attrs, &len, &ptr); 444275970Scy if (ret) 445275970Scy return EINVAL; 446275970Scy 447275970Scy ret = hx509_cert_init_data(context, ptr, len, cert); 448275970Scy if (ret) 449275970Scy goto out; 450275970Scy 451275970Scy /* 452275970Scy * Find related private key if there is one by looking at 453275970Scy * kSecPublicKeyHashItemAttr == kSecKeyLabel 454275970Scy */ 455275970Scy { 456275970Scy SecKeychainSearchRef search; 457275970Scy SecKeychainAttribute attrKeyid; 458275970Scy SecKeychainAttributeList attrList; 459275970Scy 460275970Scy attrKeyid.tag = kSecKeyLabel; 461275970Scy attrKeyid.length = attrs->attr[0].length; 462275970Scy attrKeyid.data = attrs->attr[0].data; 463275970Scy 464275970Scy attrList.count = 1; 465275970Scy attrList.attr = &attrKeyid; 466275970Scy 467275970Scy ret = SecKeychainSearchCreateFromAttributes(NULL, 468275970Scy CSSM_DL_DB_RECORD_PRIVATE_KEY, 469275970Scy &attrList, 470275970Scy &search); 471275970Scy if (ret) { 472275970Scy ret = 0; 473275970Scy goto out; 474275970Scy } 475275970Scy 476275970Scy ret = SecKeychainSearchCopyNext(search, &itemRef); 477275970Scy CFRelease(search); 478275970Scy if (ret == errSecItemNotFound) { 479275970Scy ret = 0; 480275970Scy goto out; 481275970Scy } else if (ret) { 482275970Scy ret = EINVAL; 483275970Scy goto out; 484275970Scy } 485275970Scy set_private_key(context, itemRef, *cert); 486275970Scy } 487275970Scy 488275970Scyout: 489275970Scy SecKeychainItemFreeAttributesAndData(attrs, ptr); 490275970Scy 491275970Scy return ret; 492275970Scy} 493275970Scy 494275970Scy/* 495275970Scy * 496275970Scy */ 497275970Scy 498275970Scystatic int 499275970Scykeychain_iter_end(hx509_context context, 500275970Scy hx509_certs certs, 501275970Scy void *data, 502275970Scy void *cursor) 503275970Scy{ 504275970Scy struct iter *iter = cursor; 505275970Scy 506275970Scy if (iter->certs) { 507275970Scy int ret; 508275970Scy ret = hx509_certs_end_seq(context, iter->certs, iter->cursor); 509275970Scy hx509_certs_free(&iter->certs); 510275970Scy } else { 511275970Scy CFRelease(iter->searchRef); 512275970Scy } 513275970Scy 514275970Scy memset(iter, 0, sizeof(*iter)); 515275970Scy free(iter); 516275970Scy return 0; 517275970Scy} 518275970Scy 519275970Scy/* 520275970Scy * 521275970Scy */ 522275970Scy 523275970Scystruct hx509_keyset_ops keyset_keychain = { 524275970Scy "KEYCHAIN", 525275970Scy 0, 526275970Scy keychain_init, 527275970Scy NULL, 528275970Scy keychain_free, 529275970Scy NULL, 530275970Scy NULL, 531275970Scy keychain_iter_start, 532275970Scy keychain_iter, 533275970Scy keychain_iter_end 534275970Scy}; 535275970Scy 536275970Scy#endif /* HAVE_FRAMEWORK_SECURITY */ 537275970Scy 538275970Scy/* 539275970Scy * 540275970Scy */ 541275970Scy 542275970Scyvoid 543275970Scy_hx509_ks_keychain_register(hx509_context context) 544285612Sdelphij{ 545285612Sdelphij#ifdef HAVE_FRAMEWORK_SECURITY 546285612Sdelphij _hx509_ks_register(context, &keyset_keychain); 547285612Sdelphij#endif 548285612Sdelphij} 549285612Sdelphij