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 36 #ifdef HAVE_FRAMEWORK_SECURITY 37 38 #include <Security/Security.h> 39 40 /* Missing function decls in pre Leopard */ 41 #ifdef NEED_SECKEYGETCSPHANDLE_PROTO 42 OSStatus SecKeyGetCSPHandle(SecKeyRef, CSSM_CSP_HANDLE *); 43 OSStatus SecKeyGetCredentials(SecKeyRef, CSSM_ACL_AUTHORIZATION_TAG, 44 int, const CSSM_ACCESS_CREDENTIALS **); 45 #define kSecCredentialTypeDefault 0 46 #define CSSM_SIZE uint32_t 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 if (padding != RSA_PKCS1_PADDING) 123 return -1; 124 125 cret = SecKeyGetCSSMKey(privKeyRef, &cssmKey); 126 if(cret) abort(); 127 128 cret = SecKeyGetCSPHandle(privKeyRef, &cspHandle); 129 if(cret) abort(); 130 131 ret = SecKeyGetCredentials(privKeyRef, CSSM_ACL_AUTHORIZATION_SIGN, 132 kSecCredentialTypeDefault, &creds); 133 if(ret) abort(); 134 135 ret = CSSM_CSP_CreateSignatureContext(cspHandle, CSSM_ALGID_RSA, 136 creds, cssmKey, &sigHandle); 137 if(ret) abort(); 138 139 in.Data = (uint8 *)from; 140 in.Length = flen; 141 142 sig.Data = (uint8 *)to; 143 sig.Length = kc->keysize; 144 145 cret = CSSM_SignData(sigHandle, &in, 1, CSSM_ALGID_NONE, &sig); 146 if(cret) { 147 /* cssmErrorString(cret); */ 148 fret = -1; 149 } else 150 fret = sig.Length; 151 152 if(sigHandle) 153 CSSM_DeleteContext(sigHandle); 154 155 return fret; 156 } 157 158 static int 159 kc_rsa_private_decrypt(int flen, const unsigned char *from, unsigned char *to, 160 RSA * rsa, int padding) 161 { 162 struct kc_rsa *kc = RSA_get_app_data(rsa); 163 164 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 220 static int 221 kc_rsa_init(RSA *rsa) 222 { 223 return 1; 224 } 225 226 static int 227 kc_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 236 static 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 252 static int 253 set_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 315 struct ks_keychain { 316 int anchors; 317 SecKeychainRef keychain; 318 }; 319 320 static int 321 keychain_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 360 static int 361 keychain_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 375 struct iter { 376 hx509_certs certs; 377 void *cursor; 378 SecKeychainSearchRef searchRef; 379 }; 380 381 static int 382 keychain_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 464 static int 465 keychain_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 545 out: 546 SecKeychainItemFreeAttributesAndData(attrs, ptr); 547 548 return ret; 549 } 550 551 /* 552 * 553 */ 554 555 static int 556 keychain_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 579 struct 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 598 void 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