1 /* $NetBSD: ks_keychain.c,v 1.1.1.2 2014/04/24 12:45:42 pettai Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * 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 #ifdef HAVE_FRAMEWORK_SECURITY 39 40 #include <Security/Security.h> 41 42 /* Missing function decls in pre Leopard */ 43 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO 44 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); 45 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, 46 int, const CSSM_ACCESS_CREDENTIALS **); 47 #define kSecCredentialTypeDefault 0 48 #define CSSM_SIZE uint32_t 49 #endif 50 51 52 static int 53 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item, 54 SecKeychainAttributeList **attrs) 55 { 56 SecKeychainAttributeInfo attrInfo; 57 UInt32 attrFormat = 0; 58 OSStatus ret; 59 60 *attrs = NULL; 61 62 attrInfo.count = 1; 63 attrInfo.tag = &item; 64 attrInfo.format = &attrFormat; 65 66 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 67 attrs, NULL, NULL); 68 if (ret) 69 return EINVAL; 70 return 0; 71 } 72 73 74 /* 75 * 76 */ 77 78 struct kc_rsa { 79 SecKeychainItemRef item; 80 size_t keysize; 81 }; 82 83 84 static int 85 kc_rsa_public_encrypt(int flen, 86 const unsigned char *from, 87 unsigned char *to, 88 RSA *rsa, 89 int padding) 90 { 91 return -1; 92 } 93 94 static int 95 kc_rsa_public_decrypt(int flen, 96 const unsigned char *from, 97 unsigned char *to, 98 RSA *rsa, 99 int padding) 100 { 101 return -1; 102 } 103 104 105 static int 106 kc_rsa_private_encrypt(int flen, 107 const unsigned char *from, 108 unsigned char *to, 109 RSA *rsa, 110 int padding) 111 { 112 struct kc_rsa *kc = RSA_get_app_data(rsa); 113 114 CSSM_RETURN cret; 115 OSStatus ret; 116 const CSSM_ACCESS_CREDENTIALS *creds; 117 SecKeyRef privKeyRef = (SecKeyRef)kc->item; 118 CSSM_CSP_HANDLE cspHandle; 119 const CSSM_KEY *cssmKey; 120 CSSM_CC_HANDLE sigHandle = 0; 121 CSSM_DATA sig, in; 122 int fret = 0; 123 124 if (padding != RSA_PKCS1_PADDING) 125 return -1; 126 127 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 128 if(cret) abort(); 129 130 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 131 if(cret) abort(); 132 133 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 134 kSecCredentialTypeDefault, &creds); 135 if(ret) abort(); 136 137 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 138 creds, cssmKey, &sigHandle); 139 if(ret) abort(); 140 141 in.Data = (uint8 *)from; 142 in.Length = flen; 143 144 sig.Data = (uint8 *)to; 145 sig.Length = kc->keysize; 146 147 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 148 if(cret) { 149 /* cssmErrorString(cret); */ 150 fret = -1; 151 } else 152 fret = sig.Length; 153 154 if(sigHandle) 155 CSSM_DeleteContext(sigHandle); 156 157 return fret; 158 } 159 160 static int 161 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 162 RSA * rsa, int padding) 163 { 164 struct kc_rsa *kc = RSA_get_app_data(rsa); 165 166 CSSM_RETURN cret; 167 OSStatus ret; 168 const CSSM_ACCESS_CREDENTIALS *creds; 169 SecKeyRef privKeyRef = (SecKeyRef)kc->item; 170 CSSM_CSP_HANDLE cspHandle; 171 const CSSM_KEY *cssmKey; 172 CSSM_CC_HANDLE handle = 0; 173 CSSM_DATA out, in, rem; 174 int fret = 0; 175 CSSM_SIZE outlen = 0; 176 char remdata[1024]; 177 178 if (padding != RSA_PKCS1_PADDING) 179 return -1; 180 181 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 182 if(cret) abort(); 183 184 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 185 if(cret) abort(); 186 187 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_DECRYPT, 188 kSecCredentialTypeDefault, &creds); 189 if(ret) abort(); 190 191 192 ret = CSSM_CSP_CreateAsymmetricContext (cspHandle, 193 CSSM_ALGID_RSA, 194 creds, 195 cssmKey, 196 CSSM_PADDING_PKCS1, 197 &handle); 198 if(ret) abort(); 199 200 in.Data = (uint8 *)from; 201 in.Length = flen; 202 203 out.Data = (uint8 *)to; 204 out.Length = kc->keysize; 205 206 rem.Data = (uint8 *)remdata; 207 rem.Length = sizeof(remdata); 208 209 cret = CSSM_DecryptData(handle, &in, 1, &out, 1, &outlen, &rem); 210 if(cret) { 211 /* cssmErrorString(cret); */ 212 fret = -1; 213 } else 214 fret = out.Length; 215 216 if(handle) 217 CSSM_DeleteContext(handle); 218 219 return fret; 220 } 221 222 static int 223 kc_rsa_init(RSA *rsa) 224 { 225 return 1; 226 } 227 228 static int 229 kc_rsa_finish(RSA *rsa) 230 { 231 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); 232 CFRelease(kc_rsa->item); 233 memset(kc_rsa, 0, sizeof(*kc_rsa)); 234 free(kc_rsa); 235 return 1; 236 } 237 238 static const RSA_METHOD kc_rsa_pkcs1_method = { 239 "hx509 Keychain PKCS#1 RSA", 240 kc_rsa_public_encrypt, 241 kc_rsa_public_decrypt, 242 kc_rsa_private_encrypt, 243 kc_rsa_private_decrypt, 244 NULL, 245 NULL, 246 kc_rsa_init, 247 kc_rsa_finish, 248 0, 249 NULL, 250 NULL, 251 NULL 252 }; 253 254 static int 255 set_private_key(hx509_context context, 256 SecKeychainItemRef itemRef, 257 hx509_cert cert) 258 { 259 struct kc_rsa *kc; 260 hx509_private_key key; 261 RSA *rsa; 262 int ret; 263 264 ret = hx509_private_key_init(&key, NULL, NULL); 265 if (ret) 266 return ret; 267 268 kc = calloc(1, sizeof(*kc)); 269 if (kc == NULL) 270 _hx509_abort("out of memory"); 271 272 kc->item = itemRef; 273 274 rsa = RSA_new(); 275 if (rsa == NULL) 276 _hx509_abort("out of memory"); 277 278 /* Argh, fake modulus since OpenSSL API is on crack */ 279 { 280 SecKeychainAttributeList *attrs = NULL; 281 uint32_t size; 282 void *data; 283 284 rsa->n = BN_new(); 285 if (rsa->n == NULL) abort(); 286 287 ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs); 288 if (ret) abort(); 289 290 size = *(uint32_t *)attrs->attr[0].data; 291 SecKeychainItemFreeAttributesAndData(attrs, NULL); 292 293 kc->keysize = (size + 7) / 8; 294 295 data = malloc(kc->keysize); 296 memset(data, 0xe0, kc->keysize); 297 BN_bin2bn(data, kc->keysize, rsa->n); 298 free(data); 299 } 300 rsa->e = NULL; 301 302 RSA_set_method(rsa, &kc_rsa_pkcs1_method); 303 ret = RSA_set_app_data(rsa, kc); 304 if (ret != 1) 305 _hx509_abort("RSA_set_app_data"); 306 307 hx509_private_key_assign_rsa(key, rsa); 308 _hx509_cert_assign_key(cert, key); 309 310 return 0; 311 } 312 313 /* 314 * 315 */ 316 317 struct ks_keychain { 318 int anchors; 319 SecKeychainRef keychain; 320 }; 321 322 static int 323 keychain_init(hx509_context context, 324 hx509_certs certs, void **data, int flags, 325 const char *residue, hx509_lock lock) 326 { 327 struct ks_keychain *ctx; 328 329 ctx = calloc(1, sizeof(*ctx)); 330 if (ctx == NULL) { 331 hx509_clear_error_string(context); 332 return ENOMEM; 333 } 334 335 if (residue) { 336 if (strcasecmp(residue, "system-anchors") == 0) { 337 ctx->anchors = 1; 338 } else if (strncasecmp(residue, "FILE:", 5) == 0) { 339 OSStatus ret; 340 341 ret = SecKeychainOpen(residue + 5, &ctx->keychain); 342 if (ret != noErr) { 343 hx509_set_error_string(context, 0, ENOENT, 344 "Failed to open %s", residue); 345 return ENOENT; 346 } 347 } else { 348 hx509_set_error_string(context, 0, ENOENT, 349 "Unknown subtype %s", residue); 350 return ENOENT; 351 } 352 } 353 354 *data = ctx; 355 return 0; 356 } 357 358 /* 359 * 360 */ 361 362 static int 363 keychain_free(hx509_certs certs, void *data) 364 { 365 struct ks_keychain *ctx = data; 366 if (ctx->keychain) 367 CFRelease(ctx->keychain); 368 memset(ctx, 0, sizeof(*ctx)); 369 free(ctx); 370 return 0; 371 } 372 373 /* 374 * 375 */ 376 377 struct iter { 378 hx509_certs certs; 379 void *cursor; 380 SecKeychainSearchRef searchRef; 381 }; 382 383 static int 384 keychain_iter_start(hx509_context context, 385 hx509_certs certs, void *data, void **cursor) 386 { 387 struct ks_keychain *ctx = data; 388 struct iter *iter; 389 390 iter = calloc(1, sizeof(*iter)); 391 if (iter == NULL) { 392 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 393 return ENOMEM; 394 } 395 396 if (ctx->anchors) { 397 CFArrayRef anchors; 398 int ret; 399 int i; 400 401 ret = hx509_certs_init(context, "MEMORY:ks-file-create", 402 0, NULL, &iter->certs); 403 if (ret) { 404 free(iter); 405 return ret; 406 } 407 408 ret = SecTrustCopyAnchorCertificates(&anchors); 409 if (ret != 0) { 410 hx509_certs_free(&iter->certs); 411 free(iter); 412 hx509_set_error_string(context, 0, ENOMEM, 413 "Can't get trust anchors from Keychain"); 414 return ENOMEM; 415 } 416 for (i = 0; i < CFArrayGetCount(anchors); i++) { 417 SecCertificateRef cr; 418 hx509_cert cert; 419 CSSM_DATA cssm; 420 421 cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); 422 423 SecCertificateGetData(cr, &cssm); 424 425 ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert); 426 if (ret) 427 continue; 428 429 ret = hx509_certs_add(context, iter->certs, cert); 430 hx509_cert_free(cert); 431 } 432 CFRelease(anchors); 433 } 434 435 if (iter->certs) { 436 int ret; 437 ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); 438 if (ret) { 439 hx509_certs_free(&iter->certs); 440 free(iter); 441 return ret; 442 } 443 } else { 444 OSStatus ret; 445 446 ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, 447 kSecCertificateItemClass, 448 NULL, 449 &iter->searchRef); 450 if (ret) { 451 free(iter); 452 hx509_set_error_string(context, 0, ret, 453 "Failed to start search for attributes"); 454 return ENOMEM; 455 } 456 } 457 458 *cursor = iter; 459 return 0; 460 } 461 462 /* 463 * 464 */ 465 466 static int 467 keychain_iter(hx509_context context, 468 hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 469 { 470 SecKeychainAttributeList *attrs = NULL; 471 SecKeychainAttributeInfo attrInfo; 472 UInt32 attrFormat[1] = { 0 }; 473 SecKeychainItemRef itemRef; 474 SecItemAttr item[1]; 475 struct iter *iter = cursor; 476 OSStatus ret; 477 UInt32 len; 478 void *ptr = NULL; 479 480 if (iter->certs) 481 return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); 482 483 *cert = NULL; 484 485 ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); 486 if (ret == errSecItemNotFound) 487 return 0; 488 else if (ret != 0) 489 return EINVAL; 490 491 /* 492 * Pick out certificate and matching "keyid" 493 */ 494 495 item[0] = kSecPublicKeyHashItemAttr; 496 497 attrInfo.count = 1; 498 attrInfo.tag = item; 499 attrInfo.format = attrFormat; 500 501 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 502 &attrs, &len, &ptr); 503 if (ret) 504 return EINVAL; 505 506 ret = hx509_cert_init_data(context, ptr, len, cert); 507 if (ret) 508 goto out; 509 510 /* 511 * Find related private key if there is one by looking at 512 * kSecPublicKeyHashItemAttr == kSecKeyLabel 513 */ 514 { 515 SecKeychainSearchRef search; 516 SecKeychainAttribute attrKeyid; 517 SecKeychainAttributeList attrList; 518 519 attrKeyid.tag = kSecKeyLabel; 520 attrKeyid.length = attrs->attr[0].length; 521 attrKeyid.data = attrs->attr[0].data; 522 523 attrList.count = 1; 524 attrList.attr = &attrKeyid; 525 526 ret = SecKeychainSearchCreateFromAttributes(NULL, 527 CSSM_DL_DB_RECORD_PRIVATE_KEY, 528 &attrList, 529 &search); 530 if (ret) { 531 ret = 0; 532 goto out; 533 } 534 535 ret = SecKeychainSearchCopyNext(search, &itemRef); 536 CFRelease(search); 537 if (ret == errSecItemNotFound) { 538 ret = 0; 539 goto out; 540 } else if (ret) { 541 ret = EINVAL; 542 goto out; 543 } 544 set_private_key(context, itemRef, *cert); 545 } 546 547 out: 548 SecKeychainItemFreeAttributesAndData(attrs, ptr); 549 550 return ret; 551 } 552 553 /* 554 * 555 */ 556 557 static int 558 keychain_iter_end(hx509_context context, 559 hx509_certs certs, 560 void *data, 561 void *cursor) 562 { 563 struct iter *iter = cursor; 564 565 if (iter->certs) { 566 hx509_certs_end_seq(context, iter->certs, iter->cursor); 567 hx509_certs_free(&iter->certs); 568 } else { 569 CFRelease(iter->searchRef); 570 } 571 572 memset(iter, 0, sizeof(*iter)); 573 free(iter); 574 return 0; 575 } 576 577 /* 578 * 579 */ 580 581 struct hx509_keyset_ops keyset_keychain = { 582 "KEYCHAIN", 583 0, 584 keychain_init, 585 NULL, 586 keychain_free, 587 NULL, 588 NULL, 589 keychain_iter_start, 590 keychain_iter, 591 keychain_iter_end 592 }; 593 594 #endif /* HAVE_FRAMEWORK_SECURITY */ 595 596 /* 597 * 598 */ 599 600 void 601 _hx509_ks_keychain_register(hx509_context context) 602 { 603 #ifdef HAVE_FRAMEWORK_SECURITY 604 _hx509_ks_register(context, &keyset_keychain); 605 #endif 606 } 607