ks_keychain.c revision 302408
1276881Sbapt/* 2276881Sbapt * Copyright (c) 2007 Kungliga Tekniska H��gskolan 31573Srgrimes * (Royal Institute of Technology, Stockholm, Sweden). 41573Srgrimes * All rights reserved. 51573Srgrimes * 61573Srgrimes * Redistribution and use in source and binary forms, with or without 71573Srgrimes * modification, are permitted provided that the following conditions 81573Srgrimes * are met: 91573Srgrimes * 101573Srgrimes * 1. Redistributions of source code must retain the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer. 121573Srgrimes * 131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer in the 151573Srgrimes * documentation and/or other materials provided with the distribution. 161573Srgrimes * 171573Srgrimes * 3. Neither the name of the Institute nor the names of its contributors 18148834Sstefanf * may be used to endorse or promote products derived from this software 191573Srgrimes * without specific prior written permission. 201573Srgrimes * 211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311573Srgrimes * SUCH DAMAGE. 321573Srgrimes */ 331573Srgrimes 341573Srgrimes#include "hx_locl.h" 3584260Sobrien 361573Srgrimes#ifdef HAVE_FRAMEWORK_SECURITY 371573Srgrimes 381573Srgrimes#include <Security/Security.h> 391573Srgrimes 401573Srgrimes/* Missing function decls in pre Leopard */ 411573Srgrimes#ifdef NEED_SECKEYGETCSPHANDLE_PROTO 4284260SobrienOSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); 431573SrgrimesOSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, 441573Srgrimes int, const CSSM_ACCESS_CREDENTIALS **); 451573Srgrimes#define kSecCredentialTypeDefault 0 4684260Sobrien#define CSSM_SIZE uint32_t 4784260Sobrien#endif 4884260Sobrien 491573Srgrimes 50276881Sbaptstatic int 51276881SbaptgetAttribute(SecKeychainItemRef itemRef, SecItemAttr item, 521573Srgrimes SecKeychainAttributeList **attrs) 531573Srgrimes{ 541573Srgrimes SecKeychainAttributeInfo attrInfo; 55276881Sbapt UInt32 attrFormat = 0; 561573Srgrimes OSStatus ret; 57148834Sstefanf 58148834Sstefanf *attrs = NULL; 59148834Sstefanf 60148834Sstefanf attrInfo.count = 1; 61276881Sbapt attrInfo.tag = &item; 62276881Sbapt attrInfo.format = &attrFormat; 63276881Sbapt 64276881Sbapt ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 651573Srgrimes attrs, NULL, NULL); 661573Srgrimes if (ret) 671573Srgrimes return EINVAL; 681573Srgrimes return 0; 691573Srgrimes} 701573Srgrimes 7184260Sobrien 7284260Sobrien/* 731573Srgrimes * 741573Srgrimes */ 751573Srgrimes 76276881Sbaptstruct kc_rsa { 77276881Sbapt SecKeychainItemRef item; 78276881Sbapt size_t keysize; 79276881Sbapt}; 801573Srgrimes 811573Srgrimes 821573Srgrimesstatic int 831573Srgrimeskc_rsa_public_encrypt(int flen, 841573Srgrimes const unsigned char *from, 851573Srgrimes unsigned char *to, 8684260Sobrien RSA *rsa, 8784260Sobrien int padding) 8884260Sobrien{ 8984260Sobrien return -1; 9084260Sobrien} 91148834Sstefanf 92276881Sbaptstatic int 931573Srgrimeskc_rsa_public_decrypt(int flen, 941573Srgrimes const unsigned char *from, 951573Srgrimes unsigned char *to, 961573Srgrimes RSA *rsa, 971573Srgrimes int padding) 9884260Sobrien{ 9984260Sobrien return -1; 10084260Sobrien} 1011573Srgrimes 1021573Srgrimes 1031573Srgrimesstatic int 104276881Sbaptkc_rsa_private_encrypt(int flen, 105276881Sbapt const unsigned char *from, 1061573Srgrimes unsigned char *to, 1071573Srgrimes RSA *rsa, 1081573Srgrimes int padding) 1091573Srgrimes{ 1101573Srgrimes struct kc_rsa *kc = RSA_get_app_data(rsa); 1111573Srgrimes 1121573Srgrimes CSSM_RETURN cret; 1131573Srgrimes OSStatus ret; 1141573Srgrimes const CSSM_ACCESS_CREDENTIALS *creds; 115148834Sstefanf SecKeyRef privKeyRef = (SecKeyRef)kc->item; 1161573Srgrimes CSSM_CSP_HANDLE cspHandle; 1171573Srgrimes const CSSM_KEY *cssmKey; 118276881Sbapt CSSM_CC_HANDLE sigHandle = 0; 119170511Sstefanf CSSM_DATA sig, in; 12084260Sobrien int fret = 0; 12184260Sobrien 12284260Sobrien if (padding != RSA_PKCS1_PADDING) 123276881Sbapt return -1; 124276881Sbapt 12584260Sobrien cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 126238378Spfg if(cret) abort(); 12784260Sobrien 128276881Sbapt cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 129276881Sbapt if(cret) abort(); 130148834Sstefanf 13184260Sobrien ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 13284260Sobrien kSecCredentialTypeDefault, &creds); 133276881Sbapt if(ret) abort(); 13484260Sobrien 13584260Sobrien ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 13684260Sobrien creds, cssmKey, &sigHandle); 13784260Sobrien if(ret) abort(); 13884260Sobrien 13984260Sobrien in.Data = (uint8 *)from; 140276881Sbapt in.Length = flen; 14184260Sobrien 14284260Sobrien sig.Data = (uint8 *)to; 14384260Sobrien sig.Length = kc->keysize; 144148834Sstefanf 145276881Sbapt cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 146276881Sbapt if(cret) { 147276881Sbapt /* cssmErrorString(cret); */ 148276881Sbapt fret = -1; 149276881Sbapt } else 1501573Srgrimes fret = sig.Length; 1511573Srgrimes 152276881Sbapt if(sigHandle) 15384260Sobrien CSSM_DeleteContext(sigHandle); 15484260Sobrien 155148834Sstefanf return fret; 156148834Sstefanf} 157148834Sstefanf 158148834Sstefanfstatic int 159148834Sstefanfkc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 160148834Sstefanf RSA * rsa, int padding) 16184260Sobrien{ 16284260Sobrien struct kc_rsa *kc = RSA_get_app_data(rsa); 16384260Sobrien 1641573Srgrimes CSSM_RETURN cret; 165 OSStatus ret; 166 const CSSM_ACCESS_CREDENTIALS *creds; 167 SecKeyRef privKeyRef = (SecKeyRef)kc->item; 168 CSSM_CSP_HANDLE cspHandle; 169 const CSSM_KEY *cssmKey; 170 CSSM_CC_HANDLE handle = 0; 171 CSSM_DATA out, in, rem; 172 int fret = 0; 173 CSSM_SIZE outlen = 0; 174 char remdata[1024]; 175 176 if (padding != RSA_PKCS1_PADDING) 177 return -1; 178 179 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 180 if(cret) abort(); 181 182 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 183 if(cret) abort(); 184 185 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, 186 kSecCredentialTypeDefault, &creds); 187 if(ret) abort(); 188 189 190 ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, 191 CSSM_ALGID_RSA, 192 creds, 193 cssmKey, 194 CSSM_PADDING_PKCS1, 195 &handle); 196 if(ret) abort(); 197 198 in.Data = (uint8 *)from; 199 in.Length = flen; 200 201 out.Data = (uint8 *)to; 202 out.Length = kc->keysize; 203 204 rem.Data = (uint8 *)remdata; 205 rem.Length = sizeof(remdata); 206 207 cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); 208 if(cret) { 209 /* cssmErrorString(cret); */ 210 fret = -1; 211 } else 212 fret = out.Length; 213 214 if(handle) 215 CSSM_DeleteContext(handle); 216 217 return fret; 218} 219 220static int 221kc_rsa_init(RSA *rsa) 222{ 223 return 1; 224} 225 226static int 227kc_rsa_finish(RSA *rsa) 228{ 229 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); 230 CFRelease(kc_rsa->item); 231 memset(kc_rsa, 0, sizeof(*kc_rsa)); 232 free(kc_rsa); 233 return 1; 234} 235 236static const RSA_METHOD kc_rsa_pkcs1_method = { 237 "hx509 Keychain PKCS#1 RSA", 238 kc_rsa_public_encrypt, 239 kc_rsa_public_decrypt, 240 kc_rsa_private_encrypt, 241 kc_rsa_private_decrypt, 242 NULL, 243 NULL, 244 kc_rsa_init, 245 kc_rsa_finish, 246 0, 247 NULL, 248 NULL, 249 NULL 250}; 251 252static int 253set_private_key(hx509_context context, 254 SecKeychainItemRef itemRef, 255 hx509_cert cert) 256{ 257 struct kc_rsa *kc; 258 hx509_private_key key; 259 RSA *rsa; 260 int ret; 261 262 ret = hx509_private_key_init(&key, NULL, NULL); 263 if (ret) 264 return ret; 265 266 kc = calloc(1, sizeof(*kc)); 267 if (kc == NULL) 268 _hx509_abort("out of memory"); 269 270 kc->item = itemRef; 271 272 rsa = RSA_new(); 273 if (rsa == NULL) 274 _hx509_abort("out of memory"); 275 276 /* Argh, fake modulus since OpenSSL API is on crack */ 277 { 278 SecKeychainAttributeList *attrs = NULL; 279 uint32_t size; 280 void *data; 281 282 rsa->n = BN_new(); 283 if (rsa->n == NULL) abort(); 284 285 ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs); 286 if (ret) abort(); 287 288 size = *(uint32_t *)attrs->attr[0].data; 289 SecKeychainItemFreeAttributesAndData(attrs, NULL); 290 291 kc->keysize = (size + 7) / 8; 292 293 data = malloc(kc->keysize); 294 memset(data, 0xe0, kc->keysize); 295 BN_bin2bn(data, kc->keysize, rsa->n); 296 free(data); 297 } 298 rsa->e = NULL; 299 300 RSA_set_method(rsa, &kc_rsa_pkcs1_method); 301 ret = RSA_set_app_data(rsa, kc); 302 if (ret != 1) 303 _hx509_abort("RSA_set_app_data"); 304 305 hx509_private_key_assign_rsa(key, rsa); 306 _hx509_cert_assign_key(cert, key); 307 308 return 0; 309} 310 311/* 312 * 313 */ 314 315struct ks_keychain { 316 int anchors; 317 SecKeychainRef keychain; 318}; 319 320static int 321keychain_init(hx509_context context, 322 hx509_certs certs, void **data, int flags, 323 const char *residue, hx509_lock lock) 324{ 325 struct ks_keychain *ctx; 326 327 ctx = calloc(1, sizeof(*ctx)); 328 if (ctx == NULL) { 329 hx509_clear_error_string(context); 330 return ENOMEM; 331 } 332 333 if (residue) { 334 if (strcasecmp(residue, "system-anchors") == 0) { 335 ctx->anchors = 1; 336 } else if (strncasecmp(residue, "FILE:", 5) == 0) { 337 OSStatus ret; 338 339 ret = SecKeychainOpen(residue + 5, &ctx->keychain); 340 if (ret != noErr) { 341 hx509_set_error_string(context, 0, ENOENT, 342 "Failed to open %s", residue); 343 return ENOENT; 344 } 345 } else { 346 hx509_set_error_string(context, 0, ENOENT, 347 "Unknown subtype %s", residue); 348 return ENOENT; 349 } 350 } 351 352 *data = ctx; 353 return 0; 354} 355 356/* 357 * 358 */ 359 360static int 361keychain_free(hx509_certs certs, void *data) 362{ 363 struct ks_keychain *ctx = data; 364 if (ctx->keychain) 365 CFRelease(ctx->keychain); 366 memset(ctx, 0, sizeof(*ctx)); 367 free(ctx); 368 return 0; 369} 370 371/* 372 * 373 */ 374 375struct iter { 376 hx509_certs certs; 377 void *cursor; 378 SecKeychainSearchRef searchRef; 379}; 380 381static int 382keychain_iter_start(hx509_context context, 383 hx509_certs certs, void *data, void **cursor) 384{ 385 struct ks_keychain *ctx = data; 386 struct iter *iter; 387 388 iter = calloc(1, sizeof(*iter)); 389 if (iter == NULL) { 390 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 391 return ENOMEM; 392 } 393 394 if (ctx->anchors) { 395 CFArrayRef anchors; 396 int ret; 397 int i; 398 399 ret = hx509_certs_init(context, "MEMORY:ks-file-create", 400 0, NULL, &iter->certs); 401 if (ret) { 402 free(iter); 403 return ret; 404 } 405 406 ret = SecTrustCopyAnchorCertificates(&anchors); 407 if (ret != 0) { 408 hx509_certs_free(&iter->certs); 409 free(iter); 410 hx509_set_error_string(context, 0, ENOMEM, 411 "Can't get trust anchors from Keychain"); 412 return ENOMEM; 413 } 414 for (i = 0; i < CFArrayGetCount(anchors); i++) { 415 SecCertificateRef cr; 416 hx509_cert cert; 417 CSSM_DATA cssm; 418 419 cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); 420 421 SecCertificateGetData(cr, &cssm); 422 423 ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert); 424 if (ret) 425 continue; 426 427 ret = hx509_certs_add(context, iter->certs, cert); 428 hx509_cert_free(cert); 429 } 430 CFRelease(anchors); 431 } 432 433 if (iter->certs) { 434 int ret; 435 ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); 436 if (ret) { 437 hx509_certs_free(&iter->certs); 438 free(iter); 439 return ret; 440 } 441 } else { 442 OSStatus ret; 443 444 ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, 445 kSecCertificateItemClass, 446 NULL, 447 &iter->searchRef); 448 if (ret) { 449 free(iter); 450 hx509_set_error_string(context, 0, ret, 451 "Failed to start search for attributes"); 452 return ENOMEM; 453 } 454 } 455 456 *cursor = iter; 457 return 0; 458} 459 460/* 461 * 462 */ 463 464static int 465keychain_iter(hx509_context context, 466 hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 467{ 468 SecKeychainAttributeList *attrs = NULL; 469 SecKeychainAttributeInfo attrInfo; 470 UInt32 attrFormat[1] = { 0 }; 471 SecKeychainItemRef itemRef; 472 SecItemAttr item[1]; 473 struct iter *iter = cursor; 474 OSStatus ret; 475 UInt32 len; 476 void *ptr = NULL; 477 478 if (iter->certs) 479 return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); 480 481 *cert = NULL; 482 483 ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); 484 if (ret == errSecItemNotFound) 485 return 0; 486 else if (ret != 0) 487 return EINVAL; 488 489 /* 490 * Pick out certificate and matching "keyid" 491 */ 492 493 item[0] = kSecPublicKeyHashItemAttr; 494 495 attrInfo.count = 1; 496 attrInfo.tag = item; 497 attrInfo.format = attrFormat; 498 499 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 500 &attrs, &len, &ptr); 501 if (ret) 502 return EINVAL; 503 504 ret = hx509_cert_init_data(context, ptr, len, cert); 505 if (ret) 506 goto out; 507 508 /* 509 * Find related private key if there is one by looking at 510 * kSecPublicKeyHashItemAttr == kSecKeyLabel 511 */ 512 { 513 SecKeychainSearchRef search; 514 SecKeychainAttribute attrKeyid; 515 SecKeychainAttributeList attrList; 516 517 attrKeyid.tag = kSecKeyLabel; 518 attrKeyid.length = attrs->attr[0].length; 519 attrKeyid.data = attrs->attr[0].data; 520 521 attrList.count = 1; 522 attrList.attr = &attrKeyid; 523 524 ret = SecKeychainSearchCreateFromAttributes(NULL, 525 CSSM_DL_DB_RECORD_PRIVATE_KEY, 526 &attrList, 527 &search); 528 if (ret) { 529 ret = 0; 530 goto out; 531 } 532 533 ret = SecKeychainSearchCopyNext(search, &itemRef); 534 CFRelease(search); 535 if (ret == errSecItemNotFound) { 536 ret = 0; 537 goto out; 538 } else if (ret) { 539 ret = EINVAL; 540 goto out; 541 } 542 set_private_key(context, itemRef, *cert); 543 } 544 545out: 546 SecKeychainItemFreeAttributesAndData(attrs, ptr); 547 548 return ret; 549} 550 551/* 552 * 553 */ 554 555static int 556keychain_iter_end(hx509_context context, 557 hx509_certs certs, 558 void *data, 559 void *cursor) 560{ 561 struct iter *iter = cursor; 562 563 if (iter->certs) { 564 hx509_certs_end_seq(context, iter->certs, iter->cursor); 565 hx509_certs_free(&iter->certs); 566 } else { 567 CFRelease(iter->searchRef); 568 } 569 570 memset(iter, 0, sizeof(*iter)); 571 free(iter); 572 return 0; 573} 574 575/* 576 * 577 */ 578 579struct hx509_keyset_ops keyset_keychain = { 580 "KEYCHAIN", 581 0, 582 keychain_init, 583 NULL, 584 keychain_free, 585 NULL, 586 NULL, 587 keychain_iter_start, 588 keychain_iter, 589 keychain_iter_end 590}; 591 592#endif /* HAVE_FRAMEWORK_SECURITY */ 593 594/* 595 * 596 */ 597 598void 599_hx509_ks_keychain_register(hx509_context context) 600{ 601#ifdef HAVE_FRAMEWORK_SECURITY 602 _hx509_ks_register(context, &keyset_keychain); 603#endif 604} 605