1/* 2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * SecKey.c - CoreFoundation based key object 26 */ 27 28 29#include <Security/SecKeyInternal.h> 30#include <Security/SecItem.h> 31#include <Security/SecItemPriv.h> 32#include <Security/SecFramework.h> 33 34#include <utilities/SecIOFormat.h> 35 36#include <utilities/SecCFWrappers.h> 37 38#include "SecRSAKeyPriv.h" 39#include "SecECKeyPriv.h" 40#include "SecBasePriv.h" 41 42#include <CoreFoundation/CFNumber.h> 43#include <CoreFoundation/CFString.h> 44#include <Security/SecBase.h> 45#include <pthread.h> 46#include <string.h> 47#include <AssertMacros.h> 48#include <utilities/debugging.h> 49#include <utilities/SecCFError.h> 50#include <CommonCrypto/CommonDigest.h> 51#include <Security/SecAsn1Coder.h> 52#include <Security/oidsalg.h> 53#include <Security/SecInternal.h> 54#include <Security/SecRandom.h> 55#include <corecrypto/ccrng_system.h> 56#include <asl.h> 57#include <stdlib.h> 58 59/* Static functions. */ 60#define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH) 61 62/* Currently length of SHA512 oid + 1 */ 63#define MAX_OID_LEN (10) 64 65#define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN) 66 67/* Encode the digestInfo header into digestInfo and return the offset from 68 digestInfo at which to put the actual digest. Returns 0 if digestInfo 69 won't fit within digestInfoLength bytes. 70 71 0x30, topLen, 72 0x30, algIdLen, 73 0x06, oid.Len, oid.Data, 74 0x05, 0x00 75 0x04, digestLen 76 digestData 77 */ 78 79static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid *oid, 80 size_t digestLength, uint8_t *digestInfo, size_t digestInfoLength) { 81 size_t algIdLen = oid->Length + 4; 82 size_t topLen = algIdLen + digestLength + 4; 83 size_t totalLen = topLen + 2; 84 85 if (totalLen > digestInfoLength) { 86 return 0; 87 } 88 89 size_t ix = 0; 90 digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED); 91 digestInfo[ix++] = topLen; 92 digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED); 93 digestInfo[ix++] = algIdLen; 94 digestInfo[ix++] = SEC_ASN1_OBJECT_ID; 95 digestInfo[ix++] = oid->Length; 96 memcpy(&digestInfo[ix], oid->Data, oid->Length); 97 ix += oid->Length; 98 digestInfo[ix++] = SEC_ASN1_NULL; 99 digestInfo[ix++] = 0; 100 digestInfo[ix++] = SEC_ASN1_OCTET_STRING; 101 digestInfo[ix++] = digestLength; 102 103 return ix; 104} 105 106static CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key) 107{ 108 CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; 109 110 /* encode the public key. */ 111 require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); 112 require(pubKeyBlob, errOut); 113 114 /* Calculate the digest of the public key. */ 115 require(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key), 116 CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), 117 errOut); 118errOut: 119 CFReleaseNull(pubKeyBlob); 120 return pubKeyDigest; 121} 122 123 124/* 125 */ 126static CFDictionaryRef SecKeyCopyAttributeDictionaryWithLocalKey(SecKeyRef key, 127 CFTypeRef keyType, 128 CFDataRef privateBlob) 129{ 130 CFAllocatorRef allocator = CFGetAllocator(key); 131 DICT_DECLARE(25); 132 CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL; 133 CFDictionaryRef dict = NULL; 134 135 size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits); 136 CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue); 137 138 /* encode the public key. */ 139 require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut); 140 require(pubKeyBlob, errOut); 141 142 /* Calculate the digest of the public key. */ 143 require(pubKeyDigest = SecSHA1DigestCreate(allocator, 144 CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)), 145 errOut); 146 147 DICT_ADDPAIR(kSecClass, kSecClassKey); 148 DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic); 149 DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest); 150 DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue); 151 DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue); 152 DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue); 153 DICT_ADDPAIR(kSecAttrKeyType, keyType); 154 DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits); 155 DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits); 156 DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse); 157 DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse); 158 DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue); 159 DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse); 160 DICT_ADDPAIR(kSecAttrCanEncrypt, kCFBooleanFalse); 161 DICT_ADDPAIR(kSecAttrCanDecrypt, kCFBooleanTrue); 162 DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue); 163 DICT_ADDPAIR(kSecAttrCanSign, kCFBooleanTrue); 164 DICT_ADDPAIR(kSecAttrCanVerify, kCFBooleanFalse); 165 DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse); 166 DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse); 167 DICT_ADDPAIR(kSecAttrCanWrap, kCFBooleanFalse); 168 DICT_ADDPAIR(kSecAttrCanUnwrap, kCFBooleanTrue); 169 DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob); 170 dict = DICT_CREATE(allocator); 171 172errOut: 173 // @@@ Zero out key material. 174 CFReleaseSafe(pubKeyDigest); 175 CFReleaseSafe(pubKeyBlob); 176 CFReleaseSafe(sizeInBits); 177 178 return dict; 179} 180 181CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key, 182 CFTypeRef keyType, 183 CFDataRef privateBlob) 184{ 185 return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, privateBlob); 186} 187 188CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType) 189{ 190 return SecKeyCopyAttributeDictionaryWithLocalKey(key, keyType, NULL); 191} 192 193static CFStringRef SecKeyCopyDescription(CFTypeRef cf) { 194 SecKeyRef key = (SecKeyRef)cf; 195 196 if(key->key_class->describe) 197 return key->key_class->describe(key); 198 else 199 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef: %p>"), key); 200} 201 202static void SecKeyDestroy(CFTypeRef cf) { 203 SecKeyRef key = (SecKeyRef)cf; 204 if (key->key_class->destroy) 205 key->key_class->destroy(key); 206} 207 208static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2) 209{ 210 SecKeyRef key1 = (SecKeyRef)cf1; 211 SecKeyRef key2 = (SecKeyRef)cf2; 212 if (key1 == key2) 213 return true; 214 if (!key2 || key1->key_class != key2->key_class) 215 return false; 216 if (key1->key_class->extraBytes) 217 return !memcmp(key1->key, key2->key, key1->key_class->extraBytes); 218 219 /* TODO: Won't work when we get reference keys. */ 220 CFDictionaryRef d1, d2; 221 d1 = SecKeyCopyAttributeDictionary(key1); 222 d2 = SecKeyCopyAttributeDictionary(key2); 223 Boolean result = CFEqual(d1, d2); 224 CFReleaseSafe(d1); 225 CFReleaseSafe(d2); 226 return result; 227} 228 229struct ccrng_state *ccrng_seckey; 230 231CFGiblisWithFunctions(SecKey, NULL, NULL, SecKeyDestroy, SecKeyEqual, NULL, NULL, SecKeyCopyDescription, NULL, NULL, ^{ 232 static struct ccrng_system_state ccrng_system_state_seckey; 233 ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey; 234 ccrng_system_init(&ccrng_system_state_seckey); 235}) 236 237static bool getBoolForKey(CFDictionaryRef dict, CFStringRef key, bool default_value) { 238 CFTypeRef value = CFDictionaryGetValue(dict, key); 239 if (value) { 240 if (CFGetTypeID(value) == CFBooleanGetTypeID()) { 241 return CFBooleanGetValue(value); 242 } else { 243 secwarning("Value %@ for key %@ is not bool", value, key); 244 } 245 } 246 247 return default_value; 248} 249 250static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) { 251 CFDictionarySetValue(dict, kSecValueRef, item); 252 return SecItemAdd(dict, NULL); 253} 254 255static void merge_params_applier(const void *key, const void *value, 256 void *context) { 257 CFMutableDictionaryRef result = (CFMutableDictionaryRef)context; 258 CFDictionaryAddValue(result, key, value); 259} 260 261/* Create a mutable dictionary that is based on the subdictionary for key 262 with any attributes from the top level dict merged in. */ 263static CFMutableDictionaryRef merge_params(CFDictionaryRef dict, 264 CFStringRef key) { 265 CFDictionaryRef subdict = CFDictionaryGetValue(dict, key); 266 CFMutableDictionaryRef result; 267 268 if (subdict) { 269 result = CFDictionaryCreateMutableCopy(NULL, 0, subdict); 270 /* Add everything in dict not already in result to result. */ 271 CFDictionaryApplyFunction(dict, merge_params_applier, result); 272 } else { 273 result = CFDictionaryCreateMutableCopy(NULL, 0, dict); 274 } 275 276 /* Remove values that only belong in the top level dict. */ 277 CFDictionaryRemoveValue(result, kSecPublicKeyAttrs); 278 CFDictionaryRemoveValue(result, kSecPrivateKeyAttrs); 279 CFDictionaryRemoveValue(result, kSecAttrKeyType); 280 CFDictionaryRemoveValue(result, kSecAttrKeySizeInBits); 281 282 return result; 283} 284 285/* Generate a private/public keypair. */ 286OSStatus SecKeyGeneratePair(CFDictionaryRef parameters, 287 SecKeyRef *publicKey, SecKeyRef *privateKey) { 288 OSStatus result = errSecUnsupportedAlgorithm; 289 SecKeyRef privKey = NULL; 290 SecKeyRef pubKey = NULL; 291 CFMutableDictionaryRef pubParams = merge_params(parameters, kSecPublicKeyAttrs), 292 privParams = merge_params(parameters, kSecPrivateKeyAttrs); 293 CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType); 294 295 require(ktype, errOut); 296 297 if (CFEqual(ktype, kSecAttrKeyTypeEC)) { 298 result = SecECKeyGeneratePair(parameters, &pubKey, &privKey); 299 } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { 300 result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey); 301 } 302 303 require_noerr(result, errOut); 304 305 /* Store the keys in the keychain if they are marked as permanent. */ 306 if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) { 307 require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut); 308 } 309 if (getBoolForKey(privParams, kSecAttrIsPermanent, false)) { 310 require_noerr_quiet(result = add_ref(privKey, privParams), errOut); 311 } 312 313 if (publicKey) { 314 *publicKey = pubKey; 315 pubKey = NULL; 316 } 317 if (privateKey) { 318 *privateKey = privKey; 319 privKey = NULL; 320 } 321 322errOut: 323 CFReleaseSafe(pubParams); 324 CFReleaseSafe(privParams); 325 CFReleaseSafe(pubKey); 326 CFReleaseSafe(privKey); 327 328 return result; 329} 330 331SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) { 332 CFDataRef serializedPublic = NULL; 333 SecKeyRef result = NULL; 334 335 require_noerr_quiet(SecKeyCopyPublicBytes(privateKey, &serializedPublic), fail); 336 require_quiet(serializedPublic, fail); 337 338 result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmID(privateKey), serializedPublic); 339 340fail: 341 CFReleaseSafe(serializedPublic); 342 343 return result; 344} 345 346static CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef) 347{ 348 CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey); 349 350 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 351 kSecClass, kSecClassKey, 352 kSecAttrKeyClass, kSecAttrKeyClassPrivate, 353 kSecAttrSynchronizable, kSecAttrSynchronizableAny, 354 kSecAttrApplicationLabel, public_key_hash, 355 kSecReturnPersistentRef, kCFBooleanTrue, 356 NULL); 357 CFReleaseNull(public_key_hash); 358 359 return query; 360} 361 362CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { 363 CFTypeRef persistentRef = NULL; 364 CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true); 365 366 require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error , 367 CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail); 368fail: 369 CFReleaseNull(query); 370 return (CFDataRef)persistentRef; 371} 372 373SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { 374 CFTypeRef private_key = NULL; 375 376 CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, false); 377 378 require_quiet(SecError(SecItemCopyMatching(query, &private_key), error, 379 CFSTR("Error finding private key from public: %@"), publicKey), fail); 380fail: 381 CFReleaseNull(query); 382 return (SecKeyRef)private_key; 383} 384 385SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator, 386 const SecAsn1Oid *oid, const SecAsn1Item *params, 387 const SecAsn1Item *keyData) { 388 SecKeyRef publicKey = NULL; 389 if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) { 390 /* pkcs1 1 */ 391 publicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault, 392 keyData->Data, keyData->Length, kSecKeyEncodingPkcs1); 393 } else if (SecAsn1OidCompare(oid, &CSSMOID_ecPublicKey)) { 394 SecDERKey derKey = { 395 .oid = oid->Data, 396 .oidLength = oid->Length, 397 .key = keyData->Data, 398 .keyLength = keyData->Length, 399 }; 400 if (params) { 401 derKey.parameters = params->Data; 402 derKey.parametersLength = params->Length; 403 } 404 publicKey = SecKeyCreateECPublicKey(kCFAllocatorDefault, 405 (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding); 406 } else { 407 secwarning("Unsupported algorithm oid"); 408 } 409 410 return publicKey; 411} 412 413SecKeyRef SecKeyCreate(CFAllocatorRef allocator, 414 const SecKeyDescriptor *key_class, const uint8_t *keyData, 415 CFIndex keyDataLength, SecKeyEncoding encoding) { 416 if (!key_class) return NULL; 417 size_t size = sizeof(struct __SecKey) + key_class->extraBytes; 418 SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator, 419 SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL); 420 if (result) { 421 memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base)); 422 result->key_class = key_class; 423 if (key_class->extraBytes) { 424 /* Make result->key point to the extraBytes we allocated. */ 425 result->key = ((char*)result) + sizeof(*result); 426 } 427 if (key_class->init) { 428 OSStatus status; 429 status = key_class->init(result, keyData, keyDataLength, encoding); 430 if (status) { 431 secwarning("init %s key: %" PRIdOSStatus, key_class->name, status); 432 CFRelease(result); 433 result = NULL; 434 } 435 } 436 } 437 return result; 438} 439 440enum { 441 kSecKeyDigestInfoSign, 442 kSecKeyDigestInfoVerify 443}; 444 445static OSStatus SecKeyDigestInfoSignVerify( 446 SecKeyRef key, /* Private key */ 447 SecPadding padding, /* kSecPaddingPKCS1@@@ */ 448 const uint8_t *dataToSign, /* signature over this data */ 449 size_t dataToSignLen, /* length of dataToSign */ 450 uint8_t *sig, /* signature, RETURNED */ 451 size_t *sigLen, /* IN/OUT */ 452 int mode) { 453 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; 454 uint8_t digestInfo[digestInfoLength]; 455 const SecAsn1Oid *digestOid; 456 size_t digestLen; 457 458 switch (padding) { 459#if 0 460 case kSecPaddingPKCS1MD2: 461 digestLen = CC_MD2_DIGEST_LENGTH; 462 digestOid = &CSSMOID_MD2; 463 break; 464 case kSecPaddingPKCS1MD4: 465 digestLen = CC_MD4_DIGEST_LENGTH; 466 digestOid = &CSSMOID_MD4; 467 break; 468 case kSecPaddingPKCS1MD5: 469 digestLen = CC_MD5_DIGEST_LENGTH; 470 digestOid = &CSSMOID_MD5; 471 break; 472#endif 473 case kSecPaddingPKCS1SHA1: 474 digestLen = CC_SHA1_DIGEST_LENGTH; 475 digestOid = &CSSMOID_SHA1; 476 break; 477 case kSecPaddingPKCS1SHA224: 478 digestLen = CC_SHA224_DIGEST_LENGTH; 479 digestOid = &CSSMOID_SHA224; 480 break; 481 case kSecPaddingPKCS1SHA256: 482 digestLen = CC_SHA256_DIGEST_LENGTH; 483 digestOid = &CSSMOID_SHA256; 484 break; 485 case kSecPaddingPKCS1SHA384: 486 digestLen = CC_SHA384_DIGEST_LENGTH; 487 digestOid = &CSSMOID_SHA384; 488 break; 489 case kSecPaddingPKCS1SHA512: 490 digestLen = CC_SHA512_DIGEST_LENGTH; 491 digestOid = &CSSMOID_SHA512; 492 break; 493 default: 494 return errSecUnsupportedPadding; 495 } 496 497 if (dataToSignLen != digestLen) 498 return errSecParam; 499 500 size_t offset = DEREncodeDigestInfoPrefix(digestOid, digestLen, 501 digestInfo, digestInfoLength); 502 if (!offset) 503 return errSecBufferTooSmall; 504 505 /* Append the digest to the digestInfo prefix and adjust the length. */ 506 memcpy(&digestInfo[offset], dataToSign, digestLen); 507 digestInfoLength = offset + digestLen; 508 509 if (mode == kSecKeyDigestInfoSign) { 510 return key->key_class->rawSign(key, kSecPaddingPKCS1, 511 digestInfo, digestInfoLength, sig, sigLen); 512 } else { 513 return key->key_class->rawVerify(key, kSecPaddingPKCS1, 514 digestInfo, digestInfoLength, sig, *sigLen); 515 } 516 517 return errSecSuccess; 518} 519 520OSStatus SecKeyRawSign( 521 SecKeyRef key, /* Private key */ 522 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ 523 const uint8_t *dataToSign, /* signature over this data */ 524 size_t dataToSignLen, /* length of dataToSign */ 525 uint8_t *sig, /* signature, RETURNED */ 526 size_t *sigLen) { /* IN/OUT */ 527 if (!key->key_class->rawSign) 528 return errSecUnsupportedOperation; 529 530 if (padding < kSecPaddingPKCS1MD2) { 531 return key->key_class->rawSign(key, padding, dataToSign, dataToSignLen, 532 sig, sigLen); 533 } else { 534 return SecKeyDigestInfoSignVerify(key, padding, dataToSign, dataToSignLen, 535 sig, sigLen, kSecKeyDigestInfoSign); 536 } 537} 538 539OSStatus SecKeyRawVerify( 540 SecKeyRef key, /* Public key */ 541 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ 542 const uint8_t *signedData, /* signature over this data */ 543 size_t signedDataLen, /* length of dataToSign */ 544 const uint8_t *sig, /* signature */ 545 size_t sigLen) { /* length of signature */ 546 if (!key->key_class->rawVerify) 547 return errSecUnsupportedOperation; 548 549 if (padding < kSecPaddingPKCS1MD2) { 550 return key->key_class->rawVerify(key, padding, signedData, signedDataLen, 551 sig, sigLen); 552 } else { 553 /* Casting away the constness of sig is safe since 554 SecKeyDigestInfoSignVerify only modifies sig if 555 mode == kSecKeyDigestInfoSign. */ 556 return SecKeyDigestInfoSignVerify(key, padding, 557 signedData, signedDataLen, (uint8_t *)sig, &sigLen, 558 kSecKeyDigestInfoVerify); 559 } 560} 561 562OSStatus SecKeyEncrypt( 563 SecKeyRef key, /* Public key */ 564 SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ 565 const uint8_t *plainText, 566 size_t plainTextLen, /* length of plainText */ 567 uint8_t *cipherText, 568 size_t *cipherTextLen) { /* IN/OUT */ 569 if (key->key_class->encrypt) 570 return key->key_class->encrypt(key, padding, plainText, plainTextLen, 571 cipherText, cipherTextLen); 572 return errSecUnsupportedOperation; 573} 574 575OSStatus SecKeyDecrypt( 576 SecKeyRef key, /* Private key */ 577 SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ 578 const uint8_t *cipherText, 579 size_t cipherTextLen, /* length of cipherText */ 580 uint8_t *plainText, 581 size_t *plainTextLen) { /* IN/OUT */ 582 if (key->key_class->decrypt) 583 return key->key_class->decrypt(key, padding, cipherText, cipherTextLen, 584 plainText, plainTextLen); 585 return errSecUnsupportedOperation; 586} 587 588size_t SecKeyGetBlockSize(SecKeyRef key) { 589 if (key->key_class->blockSize) 590 return key->key_class->blockSize(key); 591 return 0; 592} 593 594/* Private API functions. */ 595 596CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) { 597 if (key->key_class->copyDictionary) 598 return key->key_class->copyDictionary(key); 599 return NULL; 600} 601 602SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) { 603 /* TODO: Support having an allocator in refAttributes. */ 604 CFAllocatorRef allocator = NULL; 605 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData); 606 CFTypeRef ktype = CFDictionaryGetValue(refAttributes, kSecAttrKeyType); 607 SInt32 algorithm; 608 SecKeyRef ref; 609 610 /* First figure out the key type (algorithm). */ 611 if (CFGetTypeID(ktype) == CFNumberGetTypeID()) { 612 CFNumberGetValue(ktype, kCFNumberSInt32Type, &algorithm); 613 } else if (isString(ktype)) { 614 algorithm = CFStringGetIntValue(ktype); 615 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) algorithm); 616 if (!CFEqual(t, ktype)) { 617 secwarning("Unsupported key class: %@", ktype); 618 CFReleaseSafe(t); 619 return NULL; 620 } 621 CFReleaseSafe(t); 622 } else { 623 secwarning("Unsupported key type: %@", ktype); 624 return NULL; 625 } 626 627 /* TODO: The code below won't scale well, consider moving to something 628 table driven. */ 629 SInt32 class; 630 CFTypeRef kclass = CFDictionaryGetValue(refAttributes, kSecAttrKeyClass); 631 if (CFGetTypeID(kclass) == CFNumberGetTypeID()) { 632 CFNumberGetValue(kclass, kCFNumberSInt32Type, &class); 633 } else if (isString(kclass)) { 634 class = CFStringGetIntValue(kclass); 635 CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) class); 636 if (!CFEqual(t, kclass)) { 637 CFReleaseSafe(t); 638 secwarning("Unsupported key class: %@", kclass); 639 return NULL; 640 } 641 CFReleaseSafe(t); 642 } else { 643 secwarning("Unsupported key class: %@", kclass); 644 return NULL; 645 } 646 647 switch (class) { 648 case 0: // kSecAttrKeyClassPublic 649 switch (algorithm) { 650 case 42: // kSecAlgorithmRSA 651 ref = SecKeyCreateRSAPublicKey(allocator, 652 CFDataGetBytePtr(data), CFDataGetLength(data), 653 kSecKeyEncodingBytes); 654 break; 655 case 43: // kSecAlgorithmECDSA 656 case 73: // kSecAlgorithmEC 657 ref = SecKeyCreateECPublicKey(allocator, 658 CFDataGetBytePtr(data), CFDataGetLength(data), 659 kSecKeyEncodingBytes); 660 break; 661 default: 662 secwarning("Unsupported public key type: %@", ktype); 663 ref = NULL; 664 break; 665 }; 666 break; 667 case 1: // kSecAttrKeyClassPrivate 668 switch (algorithm) { 669 case 42: // kSecAlgorithmRSA 670 ref = SecKeyCreateRSAPrivateKey(allocator, 671 CFDataGetBytePtr(data), CFDataGetLength(data), 672 kSecKeyEncodingBytes); 673 break; 674 case 43: // kSecAlgorithmECDSA 675 case 73: // kSecAlgorithmEC 676 ref = SecKeyCreateECPrivateKey(allocator, 677 CFDataGetBytePtr(data), CFDataGetLength(data), 678 kSecKeyEncodingBytes); 679 break; 680 default: 681 secwarning("Unsupported private key type: %@", ktype); 682 ref = NULL; 683 break; 684 }; 685 break; 686 case 2: // kSecAttrKeyClassSymmetric 687 secwarning("Unsupported symmetric key type: %@", ktype); 688 ref = NULL; 689 break; 690 default: 691 secwarning("Unsupported key class: %@", kclass); 692 ref = NULL; 693 } 694 695 return ref; 696} 697 698/* TODO: This function should ensure that this keys algorithm matches the 699 signature algorithm. */ 700static OSStatus SecKeyGetDigestInfo(SecKeyRef this, const SecAsn1AlgId *algId, 701 const uint8_t *data, size_t dataLen, bool digestData, 702 uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */) { 703 unsigned char *(*digestFcn)(const void *, CC_LONG, unsigned char *); 704 CFIndex keyAlgID = kSecNullAlgorithmID; 705 const SecAsn1Oid *digestOid; 706 size_t digestLen; 707 size_t offset = 0; 708 709 /* Since these oids all have the same prefix, use switch. */ 710 if ((algId->algorithm.Length == CSSMOID_RSA.Length) && 711 !memcmp(algId->algorithm.Data, CSSMOID_RSA.Data, 712 algId->algorithm.Length - 1)) { 713 keyAlgID = kSecRSAAlgorithmID; 714 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { 715#if 0 716 case 2: /* oidMD2WithRSA */ 717 digestFcn = CC_MD2; 718 digestLen = CC_MD2_DIGEST_LENGTH; 719 digestOid = &CSSMOID_MD2; 720 break; 721 case 3: /* oidMD4WithRSA */ 722 digestFcn = CC_MD4; 723 digestLen = CC_MD4_DIGEST_LENGTH; 724 digestOid = &CSSMOID_MD4; 725 break; 726 case 4: /* oidMD5WithRSA */ 727 digestFcn = CC_MD5; 728 digestLen = CC_MD5_DIGEST_LENGTH; 729 digestOid = &CSSMOID_MD5; 730 break; 731#endif /* 0 */ 732 case 5: /* oidSHA1WithRSA */ 733 digestFcn = CC_SHA1; 734 digestLen = CC_SHA1_DIGEST_LENGTH; 735 digestOid = &CSSMOID_SHA1; 736 break; 737 case 11: /* oidSHA256WithRSA */ 738 digestFcn = CC_SHA256; 739 digestLen = CC_SHA256_DIGEST_LENGTH; 740 digestOid = &CSSMOID_SHA256; 741 break; 742 case 12: /* oidSHA384WithRSA */ 743 /* pkcs1 12 */ 744 digestFcn = CC_SHA384; 745 digestLen = CC_SHA384_DIGEST_LENGTH; 746 digestOid = &CSSMOID_SHA384; 747 break; 748 case 13: /* oidSHA512WithRSA */ 749 digestFcn = CC_SHA512; 750 digestLen = CC_SHA512_DIGEST_LENGTH; 751 digestOid = &CSSMOID_SHA512; 752 break; 753 case 14: /* oidSHA224WithRSA */ 754 digestFcn = CC_SHA224; 755 digestLen = CC_SHA224_DIGEST_LENGTH; 756 digestOid = &CSSMOID_SHA224; 757 break; 758 default: 759 secdebug("key", "unsupported rsa signature algorithm"); 760 return errSecUnsupportedAlgorithm; 761 } 762 } else if ((algId->algorithm.Length == CSSMOID_ECDSA_WithSHA224.Length) && 763 !memcmp(algId->algorithm.Data, CSSMOID_ECDSA_WithSHA224.Data, 764 algId->algorithm.Length - 1)) { 765 keyAlgID = kSecECDSAAlgorithmID; 766 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { 767 case 1: /* oidSHA224WithECDSA */ 768 digestFcn = CC_SHA224; 769 digestLen = CC_SHA224_DIGEST_LENGTH; 770 break; 771 case 2: /* oidSHA256WithECDSA */ 772 digestFcn = CC_SHA256; 773 digestLen = CC_SHA256_DIGEST_LENGTH; 774 break; 775 case 3: /* oidSHA384WithECDSA */ 776 /* pkcs1 12 */ 777 digestFcn = CC_SHA384; 778 digestLen = CC_SHA384_DIGEST_LENGTH; 779 break; 780 case 4: /* oidSHA512WithECDSA */ 781 digestFcn = CC_SHA512; 782 digestLen = CC_SHA512_DIGEST_LENGTH; 783 break; 784 default: 785 secdebug("key", "unsupported ecdsa signature algorithm"); 786 return errSecUnsupportedAlgorithm; 787 } 788 } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_ECDSA_WithSHA1)) { 789 keyAlgID = kSecECDSAAlgorithmID; 790 digestFcn = CC_SHA1; 791 digestLen = CC_SHA1_DIGEST_LENGTH; 792 } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_SHA1)) { 793 digestFcn = CC_SHA1; 794 digestLen = CC_SHA1_DIGEST_LENGTH; 795 digestOid = &CSSMOID_SHA1; 796 } else if ((algId->algorithm.Length == CSSMOID_SHA224.Length) && 797 !memcmp(algId->algorithm.Data, CSSMOID_SHA224.Data, algId->algorithm.Length - 1)) 798 { 799 switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { 800 case 4: /* OID_SHA224 */ 801 digestFcn = CC_SHA224; 802 digestLen = CC_SHA224_DIGEST_LENGTH; 803 digestOid = &CSSMOID_SHA224; 804 break; 805 case 1: /* OID_SHA256 */ 806 digestFcn = CC_SHA256; 807 digestLen = CC_SHA256_DIGEST_LENGTH; 808 digestOid = &CSSMOID_SHA256; 809 break; 810 case 2: /* OID_SHA384 */ 811 /* pkcs1 12 */ 812 digestFcn = CC_SHA384; 813 digestLen = CC_SHA384_DIGEST_LENGTH; 814 digestOid = &CSSMOID_SHA384; 815 break; 816 case 3: /* OID_SHA512 */ 817 digestFcn = CC_SHA512; 818 digestLen = CC_SHA512_DIGEST_LENGTH; 819 digestOid = &CSSMOID_SHA512; 820 break; 821 default: 822 secdebug("key", "unsupported sha-2 signature algorithm"); 823 return errSecUnsupportedAlgorithm; 824 } 825 } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_MD5)) { 826 digestFcn = CC_MD5; 827 digestLen = CC_MD5_DIGEST_LENGTH; 828 digestOid = &CSSMOID_MD5; 829 } else { 830 secdebug("key", "unsupported digesting algorithm"); 831 return errSecUnsupportedAlgorithm; 832 } 833 834 /* check key is appropriate for signature (superfluous for digest only oid) */ 835 if (keyAlgID == kSecNullAlgorithmID) 836 keyAlgID = SecKeyGetAlgorithmID(this); 837 else if (keyAlgID != SecKeyGetAlgorithmID(this)) 838 return errSecUnsupportedAlgorithm; 839 840 switch(keyAlgID) { 841 case kSecRSAAlgorithmID: 842 offset = DEREncodeDigestInfoPrefix(digestOid, digestLen, 843 digestInfo, *digestInfoLen); 844 if (!offset) 845 return errSecBufferTooSmall; 846 break; 847 case kSecDSAAlgorithmID: 848 if (digestOid != &CSSMOID_SHA1) 849 return errSecUnsupportedAlgorithm; 850 break; 851 case kSecECDSAAlgorithmID: 852 break; 853 default: 854 secdebug("key", "unsupported signature algorithm"); 855 return errSecUnsupportedAlgorithm; 856 } 857 858 if (digestData) { 859 if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */ 860 return errSecParam; 861 digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]); 862 *digestInfoLen = offset + digestLen; 863 } else { 864 if (dataLen != digestLen) 865 return errSecParam; 866 memcpy(&digestInfo[offset], data, dataLen); 867 *digestInfoLen = offset + dataLen; 868 } 869 870 return errSecSuccess; 871} 872 873OSStatus SecKeyDigestAndVerify( 874 SecKeyRef this, /* Private key */ 875 const SecAsn1AlgId *algId, /* algorithm oid/params */ 876 const uint8_t *dataToDigest, /* signature over this data */ 877 size_t dataToDigestLen,/* length of dataToDigest */ 878 const uint8_t *sig, /* signature to verify */ 879 size_t sigLen) { /* length of sig */ 880 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; 881 uint8_t digestInfo[digestInfoLength]; 882 OSStatus status; 883 884 if (this == NULL) 885 return errSecParam; 886 887 status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true, 888 digestInfo, &digestInfoLength); 889 if (status) 890 return status; 891 return SecKeyRawVerify(this, kSecPaddingPKCS1, 892 digestInfo, digestInfoLength, sig, sigLen); 893} 894 895OSStatus SecKeyDigestAndSign( 896 SecKeyRef this, /* Private key */ 897 const SecAsn1AlgId *algId, /* algorithm oid/params */ 898 const uint8_t *dataToDigest, /* signature over this data */ 899 size_t dataToDigestLen,/* length of dataToDigest */ 900 uint8_t *sig, /* signature, RETURNED */ 901 size_t *sigLen) { /* IN/OUT */ 902 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; 903 uint8_t digestInfo[digestInfoLength]; 904 OSStatus status; 905 906 status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true /* digest data */, 907 digestInfo, &digestInfoLength); 908 if (status) 909 return status; 910 return SecKeyRawSign(this, kSecPaddingPKCS1, 911 digestInfo, digestInfoLength, sig, sigLen); 912} 913 914OSStatus SecKeyVerifyDigest( 915 SecKeyRef this, /* Private key */ 916 const SecAsn1AlgId *algId, /* algorithm oid/params */ 917 const uint8_t *digestData, /* signature over this digest */ 918 size_t digestDataLen,/* length of dataToDigest */ 919 const uint8_t *sig, /* signature to verify */ 920 size_t sigLen) { /* length of sig */ 921 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; 922 uint8_t digestInfo[digestInfoLength]; 923 OSStatus status; 924 925 status = SecKeyGetDigestInfo(this, algId, digestData, digestDataLen, false /* data is digest */, 926 digestInfo, &digestInfoLength); 927 if (status) 928 return status; 929 return SecKeyRawVerify(this, kSecPaddingPKCS1, 930 digestInfo, digestInfoLength, sig, sigLen); 931} 932 933OSStatus SecKeySignDigest( 934 SecKeyRef this, /* Private key */ 935 const SecAsn1AlgId *algId, /* algorithm oid/params */ 936 const uint8_t *digestData, /* signature over this digest */ 937 size_t digestDataLen,/* length of digestData */ 938 uint8_t *sig, /* signature, RETURNED */ 939 size_t *sigLen) { /* IN/OUT */ 940 size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; 941 uint8_t digestInfo[digestInfoLength]; 942 OSStatus status; 943 944 status = SecKeyGetDigestInfo(this, algId, digestData, digestDataLen, false, 945 digestInfo, &digestInfoLength); 946 if (status) 947 return status; 948 return SecKeyRawSign(this, kSecPaddingPKCS1, 949 digestInfo, digestInfoLength, sig, sigLen); 950} 951 952CFIndex SecKeyGetAlgorithmID(SecKeyRef key) { 953 /* This method was added to version 1 keys. */ 954 if (key->key_class->version > 0 && key->key_class->getAlgorithmID) 955 return key->key_class->getAlgorithmID(key); 956 /* All version 0 key were RSA. */ 957 return kSecRSAAlgorithmID; 958} 959 960 961OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic) { 962 if (key->key_class->version > 1 && key->key_class->copyPublic) 963 return key->key_class->copyPublic(key, serializedPublic); 964 return errSecUnimplemented; 965} 966 967SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength) 968{ 969 switch (algorithmID) 970 { 971 case kSecRSAAlgorithmID: 972 return SecKeyCreateRSAPublicKey(allocator, 973 keyData, keyDataLength, 974 kSecKeyEncodingBytes); 975 case kSecECDSAAlgorithmID: 976 return SecKeyCreateECPublicKey(allocator, 977 keyData, keyDataLength, 978 kSecKeyEncodingBytes); 979 default: 980 return NULL; 981 } 982} 983 984SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized) 985{ 986 return SecKeyCreateFromPublicBytes(allocator, algorithmID, CFDataGetBytePtr(serialized), CFDataGetLength(serialized)); 987} 988 989// This is a bit icky hack to avoid changing the vtable for 990// SecKey. 991size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize) 992{ 993 size_t result = SecKeyGetBlockSize(key); 994 995 if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmID(key)) { 996 switch (whichSize) { 997 case kSecKeyEncryptedDataSize: 998 result = 0; 999 break; 1000 case kSecKeySignatureSize: 1001 result = (result >= 66 ? 9 : 8) + 2 * result; 1002 break; 1003 case kSecKeyKeySizeInBits: 1004 if (result >= 66) 1005 return 521; 1006 } 1007 } 1008 1009 if (whichSize == kSecKeyKeySizeInBits) 1010 result *= 8; 1011 1012 return result; 1013 1014} 1015 1016OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData) 1017{ 1018 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 1019 kSecReturnRef, kCFBooleanTrue, 1020 kSecClass, kSecClassKey, 1021 kSecValuePersistentRef, persistentRef, 1022 NULL); 1023 CFTypeRef foundRef = NULL; 1024 OSStatus status = SecItemCopyMatching(query, &foundRef); 1025 1026 if (status == errSecSuccess) { 1027 if (CFGetTypeID(foundRef) == SecKeyGetTypeID()) { 1028 *lookedUpData = (SecKeyRef) foundRef; 1029 foundRef = NULL; 1030 status = errSecSuccess; 1031 } else { 1032 status = errSecItemNotFound; 1033 } 1034 } 1035 1036 CFReleaseSafe(foundRef); 1037 CFReleaseSafe(query); 1038 1039 return status; 1040} 1041 1042OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef) 1043{ 1044 CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 1045 kSecReturnPersistentRef, kCFBooleanTrue, 1046 kSecValueRef, key, 1047 kSecAttrSynchronizable, kSecAttrSynchronizableAny, 1048 NULL); 1049 CFTypeRef foundRef = NULL; 1050 OSStatus status = SecItemCopyMatching(query, &foundRef); 1051 1052 if (status == errSecSuccess) { 1053 if (CFGetTypeID(foundRef) == CFDataGetTypeID()) { 1054 *persistentRef = foundRef; 1055 foundRef = NULL; 1056 } else { 1057 status = errSecItemNotFound; 1058 } 1059 } 1060 1061 CFReleaseSafe(foundRef); 1062 CFReleaseSafe(query); 1063 1064 return status; 1065} 1066 1067/* 1068 * 1069 */ 1070 1071#define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v)); 1072 1073SEC_CONST_DECL(_kSecKeyWrapPGPSymAlg, "kSecKeyWrapPGPSymAlg"); 1074SEC_CONST_DECL(_kSecKeyWrapPGPFingerprint, "kSecKeyWrapPGPFingerprint"); 1075SEC_CONST_DECL(_kSecKeyWrapPGPWrapAlg, "kSecKeyWrapPGPWrapAlg"); 1076SEC_CONST_DECL(_kSecKeyWrapRFC6637Flags, "kSecKeyWrapPGPECFlags"); 1077SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA256KekAES128, "kSecKeyWrapPGPECWrapDigestSHA256KekAES128"); 1078SEC_CONST_DECL(_kSecKeyWrapRFC6637WrapDigestSHA512KekAES256, "kSecKeyWrapPGPECWrapDigestSHA512KekAES256"); 1079 1080#undef SEC_CONST_DECL 1081 1082CFDataRef 1083_SecKeyCopyWrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef unwrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) 1084{ 1085 if (error) 1086 *error = NULL; 1087 if (outParam) 1088 *outParam = NULL; 1089 if (key->key_class->version > 2 && key->key_class->copyWrapKey) 1090 return key->key_class->copyWrapKey(key, type, unwrappedKey, parameters, outParam, error); 1091 SecError(errSecUnsupportedOperation, error, CFSTR("No key wrap supported for key %@"), key); 1092 return NULL; 1093} 1094 1095CFDataRef 1096_SecKeyCopyUnwrapKey(SecKeyRef key, SecKeyWrapType type, CFDataRef wrappedKey, CFDictionaryRef parameters, CFDictionaryRef *outParam, CFErrorRef *error) 1097{ 1098 if (error) 1099 *error = NULL; 1100 if (outParam) 1101 *outParam = NULL; 1102 if (key->key_class->version > 2 && key->key_class->copyUnwrapKey) 1103 return key->key_class->copyUnwrapKey(key, type, wrappedKey, parameters, outParam, error); 1104 1105 SecError(errSecUnsupportedOperation, error, CFSTR("No key unwrap for key %@"), key); 1106 return NULL; 1107} 1108