1 /* 2 * Copyright (c) 2007 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "hx_locl.h" 35 RCSID("$Id: ks_keychain.c 22084 2007-11-16 20:12:30Z lha $"); 36 37 #ifdef HAVE_FRAMEWORK_SECURITY 38 39 #include <Security/Security.h> 40 41 /* Missing function decls in pre Leopard */ 42 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO 43 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); 44 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, 45 int, const CSSM_ACCESS_CREDENTIALS **); 46 #define kSecCredentialTypeDefault 0 47 #endif 48 49 50 static int 51 getAttribute(SecKeychainItemRef itemRef, SecItemAttr item, 52 SecKeychainAttributeList **attrs) 53 { 54 SecKeychainAttributeInfo attrInfo; 55 UInt32 attrFormat = 0; 56 OSStatus ret; 57 58 *attrs = NULL; 59 60 attrInfo.count = 1; 61 attrInfo.tag = &item; 62 attrInfo.format = &attrFormat; 63 64 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 65 attrs, NULL, NULL); 66 if (ret) 67 return EINVAL; 68 return 0; 69 } 70 71 72 /* 73 * 74 */ 75 76 struct kc_rsa { 77 SecKeychainItemRef item; 78 size_t keysize; 79 }; 80 81 82 static int 83 kc_rsa_public_encrypt(int flen, 84 const unsigned char *from, 85 unsigned char *to, 86 RSA *rsa, 87 int padding) 88 { 89 return -1; 90 } 91 92 static int 93 kc_rsa_public_decrypt(int flen, 94 const unsigned char *from, 95 unsigned char *to, 96 RSA *rsa, 97 int padding) 98 { 99 return -1; 100 } 101 102 103 static int 104 kc_rsa_private_encrypt(int flen, 105 const unsigned char *from, 106 unsigned char *to, 107 RSA *rsa, 108 int padding) 109 { 110 struct kc_rsa *kc = RSA_get_app_data(rsa); 111 112 CSSM_RETURN cret; 113 OSStatus ret; 114 const CSSM_ACCESS_CREDENTIALS *creds; 115 SecKeyRef privKeyRef = (SecKeyRef)kc->item; 116 CSSM_CSP_HANDLE cspHandle; 117 const CSSM_KEY *cssmKey; 118 CSSM_CC_HANDLE sigHandle = 0; 119 CSSM_DATA sig, in; 120 int fret = 0; 121 122 123 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 124 if(cret) abort(); 125 126 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 127 if(cret) abort(); 128 129 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 130 kSecCredentialTypeDefault, &creds); 131 if(ret) abort(); 132 133 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 134 creds, cssmKey, &sigHandle); 135 if(ret) abort(); 136 137 in.Data = (uint8 *)from; 138 in.Length = flen; 139 140 sig.Data = (uint8 *)to; 141 sig.Length = kc->keysize; 142 143 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 144 if(cret) { 145 /* cssmErrorString(cret); */ 146 fret = -1; 147 } else 148 fret = sig.Length; 149 150 if(sigHandle) 151 CSSM_DeleteContext(sigHandle); 152 153 return fret; 154 } 155 156 static int 157 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 158 RSA * rsa, int padding) 159 { 160 return -1; 161 } 162 163 static int 164 kc_rsa_init(RSA *rsa) 165 { 166 return 1; 167 } 168 169 static int 170 kc_rsa_finish(RSA *rsa) 171 { 172 struct kc_rsa *kc_rsa = RSA_get_app_data(rsa); 173 CFRelease(kc_rsa->item); 174 memset(kc_rsa, 0, sizeof(*kc_rsa)); 175 free(kc_rsa); 176 return 1; 177 } 178 179 static const RSA_METHOD kc_rsa_pkcs1_method = { 180 "hx509 Keychain PKCS#1 RSA", 181 kc_rsa_public_encrypt, 182 kc_rsa_public_decrypt, 183 kc_rsa_private_encrypt, 184 kc_rsa_private_decrypt, 185 NULL, 186 NULL, 187 kc_rsa_init, 188 kc_rsa_finish, 189 0, 190 NULL, 191 NULL, 192 NULL 193 }; 194 195 static int 196 set_private_key(hx509_context context, 197 SecKeychainItemRef itemRef, 198 hx509_cert cert) 199 { 200 struct kc_rsa *kc; 201 hx509_private_key key; 202 RSA *rsa; 203 int ret; 204 205 ret = _hx509_private_key_init(&key, NULL, NULL); 206 if (ret) 207 return ret; 208 209 kc = calloc(1, sizeof(*kc)); 210 if (kc == NULL) 211 _hx509_abort("out of memory"); 212 213 kc->item = itemRef; 214 215 rsa = RSA_new(); 216 if (rsa == NULL) 217 _hx509_abort("out of memory"); 218 219 /* Argh, fake modulus since OpenSSL API is on crack */ 220 { 221 SecKeychainAttributeList *attrs = NULL; 222 uint32_t size; 223 void *data; 224 225 rsa->n = BN_new(); 226 if (rsa->n == NULL) abort(); 227 228 ret = getAttribute(itemRef, kSecKeyKeySizeInBits, &attrs); 229 if (ret) abort(); 230 231 size = *(uint32_t *)attrs->attr[0].data; 232 SecKeychainItemFreeAttributesAndData(attrs, NULL); 233 234 kc->keysize = (size + 7) / 8; 235 236 data = malloc(kc->keysize); 237 memset(data, 0xe0, kc->keysize); 238 BN_bin2bn(data, kc->keysize, rsa->n); 239 free(data); 240 } 241 rsa->e = NULL; 242 243 RSA_set_method(rsa, &kc_rsa_pkcs1_method); 244 ret = RSA_set_app_data(rsa, kc); 245 if (ret != 1) 246 _hx509_abort("RSA_set_app_data"); 247 248 _hx509_private_key_assign_rsa(key, rsa); 249 _hx509_cert_assign_key(cert, key); 250 251 return 0; 252 } 253 254 /* 255 * 256 */ 257 258 struct ks_keychain { 259 int anchors; 260 SecKeychainRef keychain; 261 }; 262 263 static int 264 keychain_init(hx509_context context, 265 hx509_certs certs, void **data, int flags, 266 const char *residue, hx509_lock lock) 267 { 268 struct ks_keychain *ctx; 269 270 ctx = calloc(1, sizeof(*ctx)); 271 if (ctx == NULL) { 272 hx509_clear_error_string(context); 273 return ENOMEM; 274 } 275 276 if (residue) { 277 if (strcasecmp(residue, "system-anchors") == 0) { 278 ctx->anchors = 1; 279 } else if (strncasecmp(residue, "FILE:", 5) == 0) { 280 OSStatus ret; 281 282 ret = SecKeychainOpen(residue + 5, &ctx->keychain); 283 if (ret != noErr) { 284 hx509_set_error_string(context, 0, ENOENT, 285 "Failed to open %s", residue); 286 return ENOENT; 287 } 288 } else { 289 hx509_set_error_string(context, 0, ENOENT, 290 "Unknown subtype %s", residue); 291 return ENOENT; 292 } 293 } 294 295 *data = ctx; 296 return 0; 297 } 298 299 /* 300 * 301 */ 302 303 static int 304 keychain_free(hx509_certs certs, void *data) 305 { 306 struct ks_keychain *ctx = data; 307 if (ctx->keychain) 308 CFRelease(ctx->keychain); 309 memset(ctx, 0, sizeof(*ctx)); 310 free(ctx); 311 return 0; 312 } 313 314 /* 315 * 316 */ 317 318 struct iter { 319 hx509_certs certs; 320 void *cursor; 321 SecKeychainSearchRef searchRef; 322 }; 323 324 static int 325 keychain_iter_start(hx509_context context, 326 hx509_certs certs, void *data, void **cursor) 327 { 328 struct ks_keychain *ctx = data; 329 struct iter *iter; 330 331 iter = calloc(1, sizeof(*iter)); 332 if (iter == NULL) { 333 hx509_set_error_string(context, 0, ENOMEM, "out of memory"); 334 return ENOMEM; 335 } 336 337 if (ctx->anchors) { 338 CFArrayRef anchors; 339 int ret; 340 int i; 341 342 ret = hx509_certs_init(context, "MEMORY:ks-file-create", 343 0, NULL, &iter->certs); 344 if (ret) { 345 free(iter); 346 return ret; 347 } 348 349 ret = SecTrustCopyAnchorCertificates(&anchors); 350 if (ret != 0) { 351 hx509_certs_free(&iter->certs); 352 free(iter); 353 hx509_set_error_string(context, 0, ENOMEM, 354 "Can't get trust anchors from Keychain"); 355 return ENOMEM; 356 } 357 for (i = 0; i < CFArrayGetCount(anchors); i++) { 358 SecCertificateRef cr; 359 hx509_cert cert; 360 CSSM_DATA cssm; 361 362 cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); 363 364 SecCertificateGetData(cr, &cssm); 365 366 ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert); 367 if (ret) 368 continue; 369 370 ret = hx509_certs_add(context, iter->certs, cert); 371 hx509_cert_free(cert); 372 } 373 CFRelease(anchors); 374 } 375 376 if (iter->certs) { 377 int ret; 378 ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); 379 if (ret) { 380 hx509_certs_free(&iter->certs); 381 free(iter); 382 return ret; 383 } 384 } else { 385 OSStatus ret; 386 387 ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, 388 kSecCertificateItemClass, 389 NULL, 390 &iter->searchRef); 391 if (ret) { 392 free(iter); 393 hx509_set_error_string(context, 0, ret, 394 "Failed to start search for attributes"); 395 return ENOMEM; 396 } 397 } 398 399 *cursor = iter; 400 return 0; 401 } 402 403 /* 404 * 405 */ 406 407 static int 408 keychain_iter(hx509_context context, 409 hx509_certs certs, void *data, void *cursor, hx509_cert *cert) 410 { 411 SecKeychainAttributeList *attrs = NULL; 412 SecKeychainAttributeInfo attrInfo; 413 UInt32 attrFormat[1] = { 0 }; 414 SecKeychainItemRef itemRef; 415 SecItemAttr item[1]; 416 struct iter *iter = cursor; 417 OSStatus ret; 418 UInt32 len; 419 void *ptr = NULL; 420 421 if (iter->certs) 422 return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); 423 424 *cert = NULL; 425 426 ret = SecKeychainSearchCopyNext(iter->searchRef, &itemRef); 427 if (ret == errSecItemNotFound) 428 return 0; 429 else if (ret != 0) 430 return EINVAL; 431 432 /* 433 * Pick out certificate and matching "keyid" 434 */ 435 436 item[0] = kSecPublicKeyHashItemAttr; 437 438 attrInfo.count = 1; 439 attrInfo.tag = item; 440 attrInfo.format = attrFormat; 441 442 ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, 443 &attrs, &len, &ptr); 444 if (ret) 445 return EINVAL; 446 447 ret = hx509_cert_init_data(context, ptr, len, cert); 448 if (ret) 449 goto out; 450 451 /* 452 * Find related private key if there is one by looking at 453 * kSecPublicKeyHashItemAttr == kSecKeyLabel 454 */ 455 { 456 SecKeychainSearchRef search; 457 SecKeychainAttribute attrKeyid; 458 SecKeychainAttributeList attrList; 459 460 attrKeyid.tag = kSecKeyLabel; 461 attrKeyid.length = attrs->attr[0].length; 462 attrKeyid.data = attrs->attr[0].data; 463 464 attrList.count = 1; 465 attrList.attr = &attrKeyid; 466 467 ret = SecKeychainSearchCreateFromAttributes(NULL, 468 CSSM_DL_DB_RECORD_PRIVATE_KEY, 469 &attrList, 470 &search); 471 if (ret) { 472 ret = 0; 473 goto out; 474 } 475 476 ret = SecKeychainSearchCopyNext(search, &itemRef); 477 CFRelease(search); 478 if (ret == errSecItemNotFound) { 479 ret = 0; 480 goto out; 481 } else if (ret) { 482 ret = EINVAL; 483 goto out; 484 } 485 set_private_key(context, itemRef, *cert); 486 } 487 488 out: 489 SecKeychainItemFreeAttributesAndData(attrs, ptr); 490 491 return ret; 492 } 493 494 /* 495 * 496 */ 497 498 static int 499 keychain_iter_end(hx509_context context, 500 hx509_certs certs, 501 void *data, 502 void *cursor) 503 { 504 struct iter *iter = cursor; 505 506 if (iter->certs) { 507 int ret; 508 ret = hx509_certs_end_seq(context, iter->certs, iter->cursor); 509 hx509_certs_free(&iter->certs); 510 } else { 511 CFRelease(iter->searchRef); 512 } 513 514 memset(iter, 0, sizeof(*iter)); 515 free(iter); 516 return 0; 517 } 518 519 /* 520 * 521 */ 522 523 struct hx509_keyset_ops keyset_keychain = { 524 "KEYCHAIN", 525 0, 526 keychain_init, 527 NULL, 528 keychain_free, 529 NULL, 530 NULL, 531 keychain_iter_start, 532 keychain_iter, 533 keychain_iter_end 534 }; 535 536 #endif /* HAVE_FRAMEWORK_SECURITY */ 537 538 /* 539 * 540 */ 541 542 void 543 _hx509_ks_keychain_register(hx509_context context) 544 { 545 #ifdef HAVE_FRAMEWORK_SECURITY 546 _hx509_ks_register(context, &keyset_keychain); 547 #endif 548 } 549