SecKey.cpp
1 /* 2 * Copyright (c) 2002-2015 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 #include <Security/SecKey.h> 25 #include <Security/SecKeyPriv.h> 26 #include <Security/SecKeyInternal.h> 27 #include <Security/SecItem.h> 28 #include <Security/SecItemPriv.h> 29 #include <libDER/asn1Types.h> 30 #include <libDER/DER_Encode.h> 31 #include <libDER/DER_Decode.h> 32 #include <libDER/DER_Keys.h> 33 #include <Security/SecAsn1Types.h> 34 #include <Security/SecAsn1Coder.h> 35 #include <security_keychain/KeyItem.h> 36 #include <security_utilities/casts.h> 37 #include <CommonCrypto/CommonKeyDerivation.h> 38 39 #include <CoreFoundation/CFPriv.h> 40 // 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it. 41 #undef verify 42 43 #include "SecBridge.h" 44 45 #include <security_keychain/Access.h> 46 #include <security_keychain/Keychains.h> 47 #include <security_keychain/KeyItem.h> 48 #include <string.h> 49 #include <syslog.h> 50 51 #include <security_cdsa_utils/cuCdsaUtils.h> 52 #include <security_cdsa_client/wrapkey.h> 53 #include <security_cdsa_client/genkey.h> 54 #include <security_cdsa_client/signclient.h> 55 #include <security_cdsa_client/cryptoclient.h> 56 57 #include "SecImportExportCrypto.h" 58 59 static OSStatus 60 SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { 61 CDSASecKey *cdsaKey = (CDSASecKey *)key; 62 cdsaKey->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData)); 63 CDSASecKey::keyItem(key)->initializeWithSecKeyRef(key); 64 cdsaKey->credentialType = kSecCredentialTypeDefault; 65 cdsaKey->cdsaKeyMutex = new Mutex(); 66 return errSecSuccess; 67 } 68 69 static void 70 SecCDSAKeyDestroy(SecKeyRef keyRef) { 71 // Note: If this key is holding the last strong reference to its keychain, the keychain will be released during this operation. 72 // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset. 73 // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex. 74 75 CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(keyRef); 76 StMaybeLock<Mutex> cdsaMutex(cdsaKey->cdsaKeyMutex); 77 78 KeyItem *keyItem = static_cast<KeyItem *>(keyRef->key); 79 80 if (keyItem == NULL) { 81 // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. 82 cdsaMutex.unlock(); 83 delete cdsaKey->cdsaKeyMutex; 84 return; 85 } 86 87 Keychain kc = keyItem->keychain(); 88 89 // We have a +1 reference to the KeyItem now; no need to protect our storage any more 90 cdsaMutex.unlock(); 91 92 { 93 StMaybeLock<Mutex> _(keyItem->getMutexForObject()); 94 keyItem = static_cast<KeyItem *>(keyRef->key); 95 if (keyItem == NULL) { 96 // Second version of the check above, the definitive one because this one is performed with locked object's mutex, therefore we can be sure that KeyImpl is still connected to this keyRef instance. 97 return; 98 } 99 100 keyItem->aboutToDestruct(); 101 delete keyItem; 102 } 103 104 delete cdsaKey->cdsaKeyMutex; 105 106 (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. 107 } 108 109 static size_t 110 SecCDSAKeyGetBlockSize(SecKeyRef key) { 111 112 CFErrorRef *error = NULL; 113 BEGIN_SECKEYAPI(size_t,0) 114 115 const CssmKey::Header keyHeader = CDSASecKey::keyItem(key)->unverifiedKeyHeader(); 116 switch(keyHeader.algorithm()) 117 { 118 case CSSM_ALGID_RSA: 119 case CSSM_ALGID_DSA: 120 result = keyHeader.LogicalKeySizeInBits / 8; 121 break; 122 case CSSM_ALGID_ECDSA: 123 { 124 /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers, 125 * plus both coordinates for the point used */ 126 #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8) 127 #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1) 128 size_t coordSize = ECDSA_MAX_COORD_SIZE_IN_BYTES(keyHeader.LogicalKeySizeInBits); 129 assert(coordSize < 256); /* size must fit in a byte for DER */ 130 size_t coordDERLen = (coordSize > 127) ? 2 : 1; 131 size_t coordLen = 1 + coordDERLen + coordSize; 132 133 size_t pointSize = 2 * coordLen; 134 assert(pointSize < 256); /* size must fit in a byte for DER */ 135 size_t pointDERLen = (pointSize > 127) ? 2 : 1; 136 size_t pointLen = 1 + pointDERLen + pointSize; 137 138 result = pointLen; 139 } 140 break; 141 case CSSM_ALGID_AES: 142 result = 16; /* all AES keys use 128-bit blocks */ 143 break; 144 case CSSM_ALGID_DES: 145 case CSSM_ALGID_3DES_3KEY: 146 result = 8; /* all DES keys use 64-bit blocks */ 147 break; 148 default: 149 assert(0); /* some other key algorithm */ 150 result = 16; /* FIXME: revisit this */ 151 break; 152 } 153 154 END_SECKEYAPI 155 } 156 157 static CFIndex 158 SecCDSAKeyGetAlgorithmId(SecKeyRef key) { 159 160 CFErrorRef *error = NULL; 161 BEGIN_SECKEYAPI(CFIndex, 0) 162 163 result = kSecNullAlgorithmID; 164 switch (CDSASecKey::keyItem(key)->unverifiedKeyHeader().AlgorithmId) { 165 case CSSM_ALGID_RSA: 166 result = kSecRSAAlgorithmID; 167 break; 168 case CSSM_ALGID_DSA: 169 result = kSecDSAAlgorithmID; 170 break; 171 case CSSM_ALGID_ECDSA: 172 result = kSecECDSAAlgorithmID; 173 break; 174 default: 175 assert(0); /* other algorithms TBA */ 176 } 177 178 END_SECKEYAPI 179 } 180 181 static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo) { 182 // First of all, consider x509 format and try to strip SubjPubKey envelope. If it fails, do not panic 183 // and export data as is. 184 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }, pubKeyItem; 185 DERByte numUnused; 186 DERSubjPubKeyInfo subjPubKey; 187 if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs, 188 DERSubjPubKeyInfoItemSpecs, 189 &subjPubKey, sizeof(subjPubKey)) == DR_Success && 190 DERParseBitString(&subjPubKey.pubKey, &pubKeyItem, &numUnused) == DR_Success) { 191 return CFDataCreate(kCFAllocatorDefault, pubKeyItem.data, pubKeyItem.length); 192 } 193 194 return CFDataRef(CFRetain(pubKeyInfo)); 195 } 196 197 static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFDataRef pubKeyInfo) { 198 // First check, whether X509 pubkeyinfo is already present. If not, add it according to the key type. 199 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }; 200 DERSubjPubKeyInfo subjPubKey; 201 if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs, 202 DERSubjPubKeyInfoItemSpecs, 203 &subjPubKey, sizeof(subjPubKey)) == DR_Success) { 204 return CFDataRef(CFRetain(pubKeyInfo)); 205 } 206 207 // We have always size rounded to full bytes so bitstring encodes leading 00. 208 CFRef<CFMutableDataRef> bitStringPubKey = CFDataCreateMutable(kCFAllocatorDefault, 0); 209 CFDataSetLength(bitStringPubKey, 1); 210 CFDataAppendBytes(bitStringPubKey, CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo)); 211 subjPubKey.pubKey.data = static_cast<DERByte *>(const_cast<UInt8 *>(CFDataGetBytePtr(bitStringPubKey))); 212 subjPubKey.pubKey.length = CFDataGetLength(bitStringPubKey); 213 214 // Encode algId according to algorithm used. 215 static const DERByte oidRSA[] = { 216 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 217 }; 218 static const DERByte oidECsecp256[] = { 219 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 220 }; 221 static const DERByte oidECsecp384[] = { 222 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, 223 }; 224 static const DERByte oidECsecp521[] = { 225 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, 226 }; 227 subjPubKey.algId.length = 0; 228 if (algorithm == CSSM_ALGID_RSA) { 229 subjPubKey.algId.data = const_cast<DERByte *>(oidRSA); 230 subjPubKey.algId.length = sizeof(oidRSA); 231 } else if (algorithm == CSSM_ALGID_ECDSA) { 232 if (keySizeInBits == 256) { 233 subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp256); 234 subjPubKey.algId.length = sizeof(oidECsecp256); 235 } else if (keySizeInBits == 384) { 236 subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp384); 237 subjPubKey.algId.length = sizeof(oidECsecp384); 238 } if (keySizeInBits == 521) { 239 subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp521); 240 subjPubKey.algId.length = sizeof(oidECsecp521); 241 } 242 } 243 DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey, 244 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs); 245 CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size); 246 CFDataSetLength(keyData, size); 247 if (DEREncodeSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey, 248 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, 249 static_cast<DERByte *>(CFDataGetMutableBytePtr(keyData)), &size) == DR_Success) { 250 CFDataSetLength(keyData, size); 251 } else { 252 keyData.release(); 253 } 254 255 return keyData.yield(); 256 } 257 258 static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serialization) { 259 260 CFErrorRef *error = NULL; 261 BEGIN_SECKEYAPI(OSStatus, errSecSuccess) 262 263 const CssmKey::Header &header = CDSASecKey::keyItem(key)->key().header(); 264 switch (header.algorithm()) { 265 case CSSM_ALGID_RSA: { 266 switch (header.keyClass()) { 267 case CSSM_KEYCLASS_PRIVATE_KEY: { 268 CFRef<CFDataRef> privKeyData; 269 result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take()); 270 if (result == errSecSuccess) { 271 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), int_cast<CFIndex, DERSize>(CFDataGetLength(privKeyData)) }; 272 DERRSAKeyPair keyPair; 273 if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs, 274 &keyPair, sizeof(keyPair)) == DR_Success) { 275 DERRSAPubKeyPKCS1 pubKey = { keyPair.n, keyPair.e }; 276 DERSize size = DERLengthOfEncodedSequence(ASN1_SEQUENCE, &pubKey, 277 DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs); 278 CFRef<CFMutableDataRef> keyData = CFDataCreateMutable(kCFAllocatorDefault, size); 279 CFDataSetLength(keyData, size); 280 UInt8 *data = CFDataGetMutableBytePtr(keyData); 281 if (DEREncodeSequence(ASN1_SEQUENCE, &pubKey, 282 DERNumRSAPubKeyPKCS1ItemSpecs, DERRSAPubKeyPKCS1ItemSpecs, 283 data, &size) == DR_Success) { 284 CFDataSetLength(keyData, size); 285 *data = ONE_BYTE_ASN1_CONSTR_SEQUENCE; 286 *serialization = keyData.yield(); 287 } else { 288 *serialization = NULL; 289 result = errSecParam; 290 } 291 } 292 } 293 break; 294 } 295 case CSSM_KEYCLASS_PUBLIC_KEY: 296 result = SecItemExport(key, kSecFormatBSAFE, 0, NULL, serialization); 297 break; 298 } 299 break; 300 } 301 case CSSM_ALGID_ECDSA: { 302 *serialization = NULL; 303 CFRef<CFDataRef> tempPublicData; 304 result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, tempPublicData.take()); 305 if (result == errSecSuccess) { 306 *serialization = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(tempPublicData); 307 } 308 break; 309 } 310 default: 311 result = errSecUnimplemented; 312 } 313 314 END_SECKEYAPI 315 } 316 317 typedef struct { 318 DERItem privateKey; 319 DERItem publicKey; 320 } DERECPrivateKey; 321 322 static const DERItemSpec DERECPrivateKeyItemSpecs[] = 323 { 324 { 0, 325 ASN1_INTEGER, 326 DER_DEC_SKIP }, 327 { DER_OFFSET(DERECPrivateKey, privateKey), 328 ASN1_OCTET_STRING, 329 DER_DEC_NO_OPTS | DER_ENC_NO_OPTS }, 330 { 0, 331 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0, 332 DER_DEC_SKIP | DER_ENC_NO_OPTS }, 333 { DER_OFFSET(DERECPrivateKey, publicKey), 334 ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1, 335 DER_DEC_NO_OPTS | DER_ENC_SIGNED_INT }, 336 }; 337 static const DERSize DERNumECPrivateKeyItemSpecs = 338 sizeof(DERECPrivateKeyItemSpecs) / sizeof(DERItemSpec); 339 340 typedef struct { 341 DERItem bitString; 342 } DERECPrivateKeyPublicKey; 343 344 static const DERItemSpec DERECPrivateKeyPublicKeyItemSpecs[] = 345 { 346 { DER_OFFSET(DERECPrivateKeyPublicKey, bitString), 347 ASN1_BIT_STRING, 348 DER_DEC_NO_OPTS | DER_ENC_NO_OPTS }, 349 }; 350 static const DERSize DERNumECPrivateKeyPublicKeyItemSpecs = 351 sizeof(DERECPrivateKeyPublicKeyItemSpecs) / sizeof(DERItemSpec); 352 353 static CFDataRef 354 SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { 355 356 BEGIN_SECKEYAPI(CFDataRef, NULL) 357 358 result = NULL; 359 const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader(); 360 CFRef<CFDataRef> keyData; 361 switch (header.algorithm()) { 362 case CSSM_ALGID_RSA: 363 MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take())); 364 break; 365 case CSSM_ALGID_ECDSA: { 366 MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take())); 367 if (header.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY) { 368 // Convert DER format into x9.63 format, which is expected for exported key. 369 DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), int_cast<CFIndex, DERSize>(CFDataGetLength(keyData)) }; 370 DERECPrivateKey privateKey; 371 DERECPrivateKeyPublicKey privateKeyPublicKey; 372 DERByte numUnused; 373 DERItem pubKeyItem; 374 if (DERParseSequence(&keyItem, DERNumECPrivateKeyItemSpecs, DERECPrivateKeyItemSpecs, 375 &privateKey, sizeof(privateKey)) == DR_Success && 376 DERParseSequenceContent(&privateKey.publicKey, DERNumECPrivateKeyPublicKeyItemSpecs, 377 DERECPrivateKeyPublicKeyItemSpecs, 378 &privateKeyPublicKey, sizeof(privateKeyPublicKey)) == DR_Success && 379 DERParseBitString(&privateKeyPublicKey.bitString, &pubKeyItem, &numUnused) == DR_Success) { 380 CFRef<CFMutableDataRef> key = CFDataCreateMutable(kCFAllocatorDefault, 381 pubKeyItem.length + privateKey.privateKey.length); 382 CFDataSetLength(key, pubKeyItem.length + privateKey.privateKey.length); 383 CFDataReplaceBytes(key, CFRangeMake(0, pubKeyItem.length), pubKeyItem.data, pubKeyItem.length); 384 CFDataReplaceBytes(key, CFRangeMake(pubKeyItem.length, privateKey.privateKey.length), 385 privateKey.privateKey.data, privateKey.privateKey.length); 386 keyData = key.as<CFDataRef>(); 387 } 388 } 389 break; 390 } 391 default: 392 MacOSError::throwMe(errSecUnimplemented); 393 } 394 395 if (header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) { 396 result = SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(keyData); 397 } else { 398 result = keyData.yield(); 399 } 400 401 END_SECKEYAPI 402 } 403 404 static CFDataRef SecCDSAKeyCopyLabel(SecKeyRef key) { 405 CFDataRef label = NULL; 406 if (CDSASecKey::keyItem(key)->isPersistent()) { 407 UInt32 tags[] = { kSecKeyLabel }, formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB }; 408 SecKeychainAttributeInfo info = { 1, tags, formats }; 409 SecKeychainAttributeList *list = NULL; 410 CDSASecKey::keyItem(key)->getAttributesAndData(&info, NULL, &list, NULL, NULL); 411 if (list->count == 1) { 412 SecKeychainAttribute *attr = list->attr; 413 label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attr->data, (CFIndex)attr->length); 414 } 415 CDSASecKey::keyItem(key)->freeAttributesAndData(list, NULL); 416 } 417 return label; 418 } 419 420 static CFDictionaryRef 421 SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) { 422 423 CFErrorRef *error = NULL; 424 BEGIN_SECKEYAPI(CFDictionaryRef, NULL) 425 426 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, 427 &kCFTypeDictionaryValueCallBacks); 428 429 CFDictionarySetValue(dict, kSecClass, kSecClassKey); 430 431 const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader(); 432 CFIndex sizeValue = header.LogicalKeySizeInBits; 433 CFRef<CFNumberRef> sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue); 434 CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits); 435 CFDictionarySetValue(dict, kSecAttrEffectiveKeySize, sizeInBits); 436 437 CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(key); 438 if (!label) { 439 // For floating keys, calculate label as SHA1 of pubkey bytes. 440 CFRef<CFDataRef> pubKeyBlob; 441 if (SecCDSAKeyCopyPublicBytes(key, pubKeyBlob.take()) == errSecSuccess) { 442 uint8_t pubKeyHash[CC_SHA1_DIGEST_LENGTH]; 443 CC_SHA1(CFDataGetBytePtr(pubKeyBlob), CC_LONG(CFDataGetLength(pubKeyBlob)), pubKeyHash); 444 label.take(CFDataCreate(kCFAllocatorDefault, pubKeyHash, sizeof(pubKeyHash))); 445 } 446 } 447 448 if (label) { 449 CFDictionarySetValue(dict, kSecAttrApplicationLabel, label); 450 } 451 452 CSSM_KEYATTR_FLAGS attrs = header.attributes(); 453 CFDictionarySetValue(dict, kSecAttrIsPermanent, (attrs & CSSM_KEYATTR_PERMANENT) ? kCFBooleanTrue : kCFBooleanFalse); 454 CFDictionarySetValue(dict, kSecAttrIsPrivate, (attrs & CSSM_KEYATTR_PRIVATE) ? kCFBooleanTrue : kCFBooleanFalse); 455 CFDictionarySetValue(dict, kSecAttrIsModifiable, (attrs & CSSM_KEYATTR_MODIFIABLE) ? kCFBooleanTrue : kCFBooleanFalse); 456 CFDictionarySetValue(dict, kSecAttrIsSensitive, (attrs & CSSM_KEYATTR_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse); 457 CFDictionarySetValue(dict, kSecAttrIsExtractable, (attrs & CSSM_KEYATTR_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse); 458 CFDictionarySetValue(dict, kSecAttrWasAlwaysSensitive, (attrs & CSSM_KEYATTR_ALWAYS_SENSITIVE) ? kCFBooleanTrue : kCFBooleanFalse); 459 CFDictionarySetValue(dict, kSecAttrWasNeverExtractable, (attrs & CSSM_KEYATTR_NEVER_EXTRACTABLE) ? kCFBooleanTrue : kCFBooleanFalse); 460 461 CFDictionarySetValue(dict, kSecAttrCanEncrypt, (header.useFor(CSSM_KEYUSE_ENCRYPT)) ? kCFBooleanTrue : kCFBooleanFalse); 462 CFDictionarySetValue(dict, kSecAttrCanDecrypt, (header.useFor(CSSM_KEYUSE_DECRYPT)) ? kCFBooleanTrue : kCFBooleanFalse); 463 CFDictionarySetValue(dict, kSecAttrCanSign, (header.useFor(CSSM_KEYUSE_SIGN)) ? kCFBooleanTrue : kCFBooleanFalse); 464 CFDictionarySetValue(dict, kSecAttrCanVerify, (header.useFor(CSSM_KEYUSE_VERIFY)) ? kCFBooleanTrue : kCFBooleanFalse); 465 CFDictionarySetValue(dict, kSecAttrCanSignRecover, (header.useFor(CSSM_KEYUSE_SIGN_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse); 466 CFDictionarySetValue(dict, kSecAttrCanVerifyRecover, (header.useFor(CSSM_KEYUSE_VERIFY_RECOVER)) ? kCFBooleanTrue : kCFBooleanFalse); 467 CFDictionarySetValue(dict, kSecAttrCanWrap, (header.useFor(CSSM_KEYUSE_WRAP)) ? kCFBooleanTrue : kCFBooleanFalse); 468 CFDictionarySetValue(dict, kSecAttrCanUnwrap, (header.useFor(CSSM_KEYUSE_UNWRAP)) ? kCFBooleanTrue : kCFBooleanFalse); 469 CFDictionarySetValue(dict, kSecAttrCanDerive, (header.useFor(CSSM_KEYUSE_DERIVE)) ? kCFBooleanTrue : kCFBooleanFalse); 470 471 switch (header.keyClass()) { 472 case CSSM_KEYCLASS_PUBLIC_KEY: 473 CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic); 474 break; 475 case CSSM_KEYCLASS_PRIVATE_KEY: 476 CFDictionarySetValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPrivate); 477 break; 478 } 479 480 switch (header.algorithm()) { 481 case CSSM_ALGID_RSA: 482 CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeRSA); 483 break; 484 case CSSM_ALGID_ECDSA: 485 CFDictionarySetValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECDSA); 486 break; 487 } 488 489 CFRef<CFDataRef> keyData; 490 if (SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()) == errSecSuccess) { 491 CFDictionarySetValue(dict, kSecValueData, keyData); 492 } 493 494 if (header.algorithm() == CSSM_ALGID_RSA && header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY && 495 header.blobType() == CSSM_KEYBLOB_RAW) { 496 const CssmData &keyData = CDSASecKey::keyItem(key)->key()->keyData(); 497 DERItem keyItem = { static_cast<DERByte *>(keyData.data()), keyData.length() }; 498 DERRSAPubKeyPKCS1 decodedKey; 499 if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs, 500 DERRSAPubKeyPKCS1ItemSpecs, 501 &decodedKey, sizeof(decodedKey)) == DR_Success) { 502 CFRef<CFDataRef> modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data, 503 decodedKey.modulus.length); 504 CFDictionarySetValue(dict, CFSTR("_rsam"), modulus); 505 CFRef<CFDataRef> exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data, 506 decodedKey.pubExponent.length); 507 CFDictionarySetValue(dict, CFSTR("_rsae"), exponent); 508 } 509 } 510 511 result = dict; 512 513 END_SECKEYAPI 514 } 515 516 #pragma clang diagnostic push 517 #pragma clang diagnostic ignored "-Wunused-const-variable" 518 static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, (char*) "Label", 0, NULL, BLOB); 519 #pragma clang diagnostic pop 520 521 static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) { 522 CFErrorRef *error = NULL; 523 BEGIN_SECKEYAPI(SecKeyRef, NULL) 524 525 result = NULL; 526 KeyItem *key = CDSASecKey::keyItem(privateKey); 527 CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(privateKey); 528 if (label) { 529 // Lookup public key in the database. 530 DbUniqueRecord uniqueId; 531 SSDb ssDb(dynamic_cast<SSDbImpl *>(&(*key->keychain()->database()))); 532 SSDbCursor dbCursor(ssDb, 1); 533 dbCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY); 534 dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, CssmData(CFDataRef(label))); 535 if (dbCursor->next(NULL, NULL, uniqueId)) { 536 Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId); 537 result = reinterpret_cast<SecKeyRef>(publicKey->handle()); 538 } 539 } 540 541 if (result == NULL && key->publicKey()) { 542 SecPointer<KeyItem> publicKey(new KeyItem(key->publicKey())); 543 result = reinterpret_cast<SecKeyRef>(publicKey->handle()); 544 } 545 546 END_SECKEYAPI 547 } 548 549 static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm, 550 CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm, 551 CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) { 552 KeyItem *keyItem = CDSASecKey::keyItem(key); 553 CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass(); 554 baseAlgorithm = keyItem->key()->header().algorithm(); 555 switch (baseAlgorithm) { 556 case CSSM_ALGID_RSA: 557 if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) || 558 (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) { 559 if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) { 560 secondaryAlgorithm = CSSM_ALGID_NONE; 561 paddingAlgorithm = CSSM_PADDING_NONE; 562 inputSizeLimit = 0; 563 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) { 564 secondaryAlgorithm = CSSM_ALGID_NONE; 565 paddingAlgorithm = CSSM_PADDING_PKCS1; 566 inputSizeLimit = -11; 567 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) { 568 secondaryAlgorithm = CSSM_ALGID_SHA1; 569 paddingAlgorithm = CSSM_PADDING_PKCS1; 570 inputSizeLimit = 20; 571 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) { 572 secondaryAlgorithm = CSSM_ALGID_SHA224; 573 paddingAlgorithm = CSSM_PADDING_PKCS1; 574 inputSizeLimit = 224 / 8; 575 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) { 576 secondaryAlgorithm = CSSM_ALGID_SHA256; 577 paddingAlgorithm = CSSM_PADDING_PKCS1; 578 inputSizeLimit = 256 / 8; 579 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) { 580 secondaryAlgorithm = CSSM_ALGID_SHA384; 581 paddingAlgorithm = CSSM_PADDING_PKCS1; 582 inputSizeLimit = 384 / 8; 583 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) { 584 secondaryAlgorithm = CSSM_ALGID_SHA512; 585 paddingAlgorithm = CSSM_PADDING_PKCS1; 586 inputSizeLimit = 512 / 8; 587 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) { 588 secondaryAlgorithm = CSSM_ALGID_MD5; 589 paddingAlgorithm = CSSM_PADDING_PKCS1; 590 inputSizeLimit = 16; 591 } else { 592 return NULL; 593 } 594 } else if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeDecrypt) || 595 (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeEncrypt)) { 596 if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { 597 secondaryAlgorithm = CSSM_ALGID_NONE; 598 paddingAlgorithm = CSSM_PADDING_NONE; 599 inputSizeLimit = 0; 600 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) { 601 secondaryAlgorithm = CSSM_ALGID_NONE; 602 paddingAlgorithm = CSSM_PADDING_PKCS1; 603 inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0; 604 } else { 605 return NULL; 606 } 607 } else if (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeDecrypt && 608 CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { 609 // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, 610 // because CDSA keys refuses to perform decrypt using public key. 611 operation = kSecKeyOperationTypeEncrypt; 612 secondaryAlgorithm = CSSM_ALGID_NONE; 613 paddingAlgorithm = CSSM_PADDING_NONE; 614 inputSizeLimit = 0; 615 } else { 616 return NULL; 617 } 618 break; 619 case CSSM_ALGID_ECDSA: 620 if ((keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeSign) || 621 (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeVerify)) { 622 if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureRFC4754)) { 623 secondaryAlgorithm = CSSM_ALGID_NONE; 624 paddingAlgorithm = CSSM_PADDING_SIGRAW; 625 } else if (CFEqual(algorithm, kSecKeyAlgorithmECDSASignatureDigestX962)) { 626 secondaryAlgorithm = CSSM_ALGID_NONE; 627 paddingAlgorithm = CSSM_PADDING_PKCS1; 628 } else { 629 return NULL; 630 } 631 } else if (keyClass == CSSM_KEYCLASS_PRIVATE_KEY && operation == kSecKeyOperationTypeKeyExchange) { 632 if (CFEqual(algorithm,kSecKeyAlgorithmECDHKeyExchangeStandard) || 633 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactor)) { 634 baseAlgorithm = CSSM_ALGID_ECDH; 635 } else if (CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeStandardX963SHA1) || 636 CFEqual(algorithm, kSecKeyAlgorithmECDHKeyExchangeCofactorX963SHA1)) { 637 baseAlgorithm = CSSM_ALGID_ECDH_X963_KDF; 638 } else { 639 return NULL; 640 } 641 } else { 642 return NULL; 643 } 644 break; 645 default: 646 MacOSError::throwMe(errSecParam); 647 } 648 return keyItem; 649 } 650 651 static CFDataRef 652 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key, CFDataRef plaintext, SecKeyAlgorithm algorithm) { 653 CFIndex blockSize = CDSASecKey::keyItem(key)->key().header().LogicalKeySizeInBits / 8; 654 CFIndex plaintextLength = CFDataGetLength(plaintext); 655 if ((algorithm == kSecKeyAlgorithmRSAEncryptionRaw || algorithm == kSecKeyAlgorithmRSASignatureRaw) 656 && plaintextLength < blockSize) { 657 // Pre-pad with zeroes. 658 CFMutableDataRef result(CFDataCreateMutable(kCFAllocatorDefault, blockSize)); 659 CFDataSetLength(result, blockSize); 660 CFDataReplaceBytes(result, CFRangeMake(blockSize - plaintextLength, plaintextLength), 661 CFDataGetBytePtr(plaintext), plaintextLength); 662 return result; 663 } else { 664 return CFDataRef(CFRetain(plaintext)); 665 } 666 } 667 668 static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, 669 CFArrayRef allAlgorithms, SecKeyOperationMode mode, 670 CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) { 671 BEGIN_SECKEYAPI(CFTypeRef, kCFNull) 672 CFIndex inputSizeLimit = 0; 673 CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm; 674 KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm, inputSizeLimit); 675 if (keyItem == NULL) { 676 // Operation/algorithm/key combination is not supported. 677 return kCFNull; 678 } else if (mode == kSecKeyOperationModeCheckIfSupported) { 679 // Operation is supported and caller wants to just know that. 680 return kCFBooleanTrue; 681 } else if (baseAlgorithm == CSSM_ALGID_RSA) { 682 if (inputSizeLimit <= 0) { 683 inputSizeLimit += SecCDSAKeyGetBlockSize(key); 684 } 685 if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) { 686 MacOSError::throwMe(errSecParam); 687 } 688 } 689 690 CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(key); 691 switch (operation) { 692 case kSecKeyOperationTypeSign: { 693 CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm); 694 signContext.key(keyItem->key()); 695 signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, cdsaKey->credentialType)); 696 signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm); 697 CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm); 698 CssmAutoData signature(signContext.allocator()); 699 signContext.sign(CssmData(CFDataRef(input)), signature.get()); 700 result = CFDataCreate(NULL, static_cast<const UInt8 *>(signature.data()), CFIndex(signature.length())); 701 break; 702 } 703 case kSecKeyOperationTypeVerify: { 704 CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm); 705 verifyContext.key(keyItem->key()); 706 verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, cdsaKey->credentialType)); 707 verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm); 708 CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm); 709 verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam))); 710 result = kCFBooleanTrue; 711 break; 712 } 713 case kSecKeyOperationTypeEncrypt: { 714 CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm); 715 encryptContext.key(keyItem->key()); 716 encryptContext.padding(paddingAlgorithm); 717 encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, cdsaKey->credentialType)); 718 CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm); 719 CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator()); 720 size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get()); 721 result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length()); 722 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length()); 723 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length()); 724 CFDataSetLength(CFMutableDataRef(result), length); 725 break; 726 } 727 case kSecKeyOperationTypeDecrypt: { 728 CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm); 729 decryptContext.key(keyItem->key()); 730 decryptContext.padding(paddingAlgorithm); 731 decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, cdsaKey->credentialType)); 732 CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator()); 733 size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)), 734 output.get(), remainingData.get()); 735 result = CFDataCreateMutable(kCFAllocatorDefault, output.length() + remainingData.length()); 736 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(output.data()), output.length()); 737 CFDataAppendBytes(CFMutableDataRef(result), static_cast<const UInt8 *>(remainingData.data()), remainingData.length()); 738 CFDataSetLength(CFMutableDataRef(result), length); 739 break; 740 } 741 case kSecKeyOperationTypeKeyExchange: { 742 CFIndex requestedLength = 0; 743 CssmData sharedInfo; 744 switch (baseAlgorithm) { 745 case CSSM_ALGID_ECDH: 746 requestedLength = (keyItem->key().header().LogicalKeySizeInBits + 7) / 8; 747 break; 748 case CSSM_ALGID_ECDH_X963_KDF: 749 CFDictionaryRef params = CFRef<CFDictionaryRef>::check(in2, errSecParam); 750 CFTypeRef value = params ? CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterRequestedSize) : NULL; 751 if (value == NULL || CFGetTypeID(value) != CFNumberGetTypeID() || 752 !CFNumberGetValue(CFNumberRef(value), kCFNumberCFIndexType, &requestedLength)) { 753 MacOSError::throwMe(errSecParam); 754 } 755 value = CFDictionaryGetValue(params, kSecKeyKeyExchangeParameterSharedInfo); 756 if (value != NULL && CFGetTypeID(value) == CFDataGetTypeID()) { 757 sharedInfo = CssmData(CFDataRef(value)); 758 } 759 break; 760 } 761 762 CssmClient::DeriveKey derive(keyItem->csp(), baseAlgorithm, CSSM_ALGID_AES, uint32(requestedLength * 8)); 763 derive.key(keyItem->key()); 764 derive.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DERIVE, kSecCredentialTypeDefault)); 765 derive.salt(sharedInfo); 766 CssmData param(CFRef<CFDataRef>::check(in1, errSecParam)); 767 Key derivedKey = derive(¶m, KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE)); 768 769 // Export raw data of newly derived key (by wrapping with an empty key). 770 CssmClient::WrapKey wrapper(keyItem->csp(), CSSM_ALGID_NONE); 771 Key wrappedKey = wrapper(derivedKey); 772 result = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)wrappedKey->data(), CFIndex(wrappedKey->length())); 773 break; 774 } 775 default: 776 break; 777 } 778 779 END_SECKEYAPI 780 } 781 782 static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) { 783 CFErrorRef *error = NULL; 784 BEGIN_SECKEYAPI(Boolean, false) 785 786 result = CDSASecKey::keyItem(key1)->equal(*CDSASecKey::keyItem(key2)); 787 788 END_SECKEYAPI 789 } 790 791 static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) { 792 BEGIN_SECKEYAPI(Boolean, false) 793 794 if (CFEqual(name, kSecUseAuthenticationUI)) { 795 static_cast<CDSASecKey *>(key)->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI; 796 result = true; 797 } else { 798 result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name); 799 } 800 801 END_SECKEYAPI 802 } 803 804 const SecKeyDescriptor kSecCDSAKeyDescriptor = { 805 .version = kSecKeyDescriptorVersion, 806 .name = "CDSAKey", 807 .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0), 808 809 .init = SecCDSAKeyInit, 810 .destroy = SecCDSAKeyDestroy, 811 .blockSize = SecCDSAKeyGetBlockSize, 812 .copyDictionary = SecCDSAKeyCopyAttributeDictionary, 813 .getAlgorithmID = SecCDSAKeyGetAlgorithmId, 814 .copyPublic = SecCDSAKeyCopyPublicBytes, 815 .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation, 816 .copyPublicKey = SecCDSAKeyCopyPublicKey, 817 .copyOperationResult = SecCDSAKeyCopyOperationResult, 818 .isEqual = SecCDSAKeyIsEqual, 819 .setParameter = SecCDSAKeySetParameter, 820 }; 821 822 namespace Security { 823 namespace KeychainCore { 824 SecCFObject *KeyItem::fromSecKeyRef(CFTypeRef ptr) { 825 if (ptr == NULL || CFGetTypeID(ptr) != SecKeyGetTypeID()) { 826 return NULL; 827 } 828 829 SecKeyRef key = static_cast<SecKeyRef>(const_cast<void *>(ptr)); 830 if (key->key_class == &kSecCDSAKeyDescriptor) { 831 return static_cast<SecCFObject *>(key->key); 832 } 833 834 CFRef<SecKeyRef> cdsaKey = SecKeyCopyAuxilliaryCDSAKeyForKey(key); 835 if (!cdsaKey) { 836 // Create CDSA key from exported data of existing key. 837 CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key); 838 if (keyAttributes) { 839 CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL); 840 if (!keyData) { 841 CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel); 842 const void *keys[] = { kSecClass, kSecUseDataProtectionKeychain, kSecReturnRef, kSecMatchLimit }; 843 const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll }; 844 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 845 sizeof(keys) / sizeof(*keys), 846 &kCFTypeDictionaryKeyCallBacks, 847 &kCFTypeDictionaryValueCallBacks); 848 CFRef<CFArrayRef> identities; 849 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take()); 850 if (status == errSecSuccess) { 851 for (int i = 0; i < CFArrayGetCount(identities); ++i) { 852 CFRef<SecKeyRef> privateKey; 853 if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) { 854 continue; 855 } 856 CFRef<CFDictionaryRef> attrs = SecKeyCopyAttributes(privateKey); 857 if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) { 858 cdsaKey = privateKey; 859 SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get()); 860 break; 861 } 862 } 863 } 864 } else { 865 cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL)); 866 if (cdsaKey) { 867 SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get()); 868 } 869 } 870 } 871 } 872 873 return cdsaKey ? CDSASecKey::keyItem(cdsaKey.get()) : NULL; 874 } 875 876 // You need to hold this key's MutexForObject when you run this 877 void KeyItem::attachSecKeyRef() const { 878 SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast<const uint8_t *>(this), 0, 0); 879 CDSASecKey::keyItem(key)->mWeakSecKeyRef = key; 880 } 881 882 } 883 } 884 885 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref); 886 Boolean SecKeyIsCDSAKey(SecKeyRef ref) { 887 return ref->key_class == &kSecCDSAKeyDescriptor; 888 } 889 890 891 static OSStatus SecKeyCreatePairInternal( 892 SecKeychainRef keychainRef, 893 CSSM_ALGORITHMS algorithm, 894 uint32 keySizeInBits, 895 CSSM_CC_HANDLE contextHandle, 896 CSSM_KEYUSE publicKeyUsage, 897 uint32 publicKeyAttr, 898 CSSM_KEYUSE privateKeyUsage, 899 uint32 privateKeyAttr, 900 SecAccessRef initialAccess, 901 SecKeyRef* publicKeyRef, 902 SecKeyRef* privateKeyRef) 903 { 904 BEGIN_SECAPI 905 906 Keychain keychain; 907 SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>")); 908 SecPointer<KeyItem> pubItem, privItem; 909 if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) { 910 keychain = Keychain::optional(keychainRef); 911 } 912 StMaybeLock<Mutex> _(keychain ? keychain->getKeychainMutex() : NULL); 913 KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, 914 privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); 915 916 // Return the generated keys. 917 if (publicKeyRef) 918 *publicKeyRef = pubItem->handle(); 919 if (privateKeyRef) 920 *privateKeyRef = privItem->handle(); 921 922 END_SECAPI 923 } 924 925 OSStatus 926 SecKeyCreatePair( 927 SecKeychainRef keychainRef, 928 CSSM_ALGORITHMS algorithm, 929 uint32 keySizeInBits, 930 CSSM_CC_HANDLE contextHandle, 931 CSSM_KEYUSE publicKeyUsage, 932 uint32 publicKeyAttr, 933 CSSM_KEYUSE privateKeyUsage, 934 uint32 privateKeyAttr, 935 SecAccessRef initialAccess, 936 SecKeyRef* publicKeyRef, 937 SecKeyRef* privateKeyRef) 938 { 939 OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage, 940 publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef); 941 942 return result; 943 } 944 945 946 947 OSStatus 948 SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey) 949 { 950 BEGIN_SECAPI 951 952 Required(cssmKey) = KeyItem::required(key)->key(); 953 954 END_SECAPI 955 } 956 957 958 // 959 // Private APIs 960 // 961 962 static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex; 963 static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeyCSPs; 964 965 OSStatus 966 SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) 967 { 968 BEGIN_SECAPI 969 970 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); 971 972 // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). 973 // Keep a global pointer to it to force the CSP to stay live forever. 974 CssmClient::CSP returnedKeyCSP = keyItem->csp(); 975 { 976 StLock<Mutex> _(gSecReturnedKeyCSPsMutex()); 977 gSecReturnedKeyCSPs().insert(returnedKeyCSP); 978 } 979 Required(cspHandle) = returnedKeyCSP->handle(); 980 981 END_SECAPI 982 } 983 984 /* deprecated as of 10.8 */ 985 OSStatus 986 SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) 987 { 988 BEGIN_SECAPI 989 990 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); 991 Required(algid) = &keyItem->algorithmIdentifier(); 992 993 END_SECAPI 994 } 995 996 OSStatus 997 SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength) 998 { 999 BEGIN_SECAPI 1000 1001 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); 1002 Required(strength) = keyItem->strengthInBits(algid); 1003 1004 END_SECAPI 1005 } 1006 1007 OSStatus 1008 SecKeyGetCredentials( 1009 SecKeyRef keyRef, 1010 CSSM_ACL_AUTHORIZATION_TAG operation, 1011 SecCredentialType credentialType, 1012 const CSSM_ACCESS_CREDENTIALS **outCredentials) 1013 { 1014 BEGIN_SECAPI 1015 1016 SecPointer<KeyItem> keyItem(KeyItem::required(keyRef)); 1017 Required(outCredentials) = keyItem->getCredentials(operation, credentialType); 1018 1019 END_SECAPI 1020 } 1021 1022 OSStatus 1023 SecKeyImportPair( 1024 SecKeychainRef keychainRef, 1025 const CSSM_KEY *publicCssmKey, 1026 const CSSM_KEY *privateCssmKey, 1027 SecAccessRef initialAccess, 1028 SecKeyRef* publicKey, 1029 SecKeyRef* privateKey) 1030 { 1031 BEGIN_SECAPI 1032 1033 Keychain keychain = Keychain::optional(keychainRef); 1034 SecPointer<Access> theAccess(initialAccess ? Access::required(initialAccess) : new Access("<key>")); 1035 SecPointer<KeyItem> pubItem, privItem; 1036 1037 KeyItem::importPair(keychain, 1038 Required(publicCssmKey), 1039 Required(privateCssmKey), 1040 theAccess, 1041 pubItem, 1042 privItem); 1043 1044 // Return the generated keys. 1045 if (publicKey) 1046 *publicKey = pubItem->handle(); 1047 if (privateKey) 1048 *privateKey = privItem->handle(); 1049 1050 END_SECAPI 1051 } 1052 1053 static OSStatus 1054 SecKeyGenerateWithAttributes( 1055 SecKeychainAttributeList* attrList, 1056 SecKeychainRef keychainRef, 1057 CSSM_ALGORITHMS algorithm, 1058 uint32 keySizeInBits, 1059 CSSM_CC_HANDLE contextHandle, 1060 CSSM_KEYUSE keyUsage, 1061 uint32 keyAttr, 1062 SecAccessRef initialAccess, 1063 SecKeyRef* keyRef) 1064 { 1065 BEGIN_SECAPI 1066 1067 Keychain keychain; 1068 SecPointer<Access> theAccess; 1069 1070 if (keychainRef) 1071 keychain = KeychainImpl::required(keychainRef); 1072 if (initialAccess) 1073 theAccess = Access::required(initialAccess); 1074 1075 SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList, 1076 keychain, 1077 algorithm, 1078 keySizeInBits, 1079 contextHandle, 1080 keyUsage, 1081 keyAttr, 1082 theAccess); 1083 1084 // Return the generated key. 1085 if (keyRef) 1086 *keyRef = item->handle(); 1087 1088 END_SECAPI 1089 } 1090 1091 OSStatus 1092 SecKeyGenerate( 1093 SecKeychainRef keychainRef, 1094 CSSM_ALGORITHMS algorithm, 1095 uint32 keySizeInBits, 1096 CSSM_CC_HANDLE contextHandle, 1097 CSSM_KEYUSE keyUsage, 1098 uint32 keyAttr, 1099 SecAccessRef initialAccess, 1100 SecKeyRef* keyRef) 1101 { 1102 return SecKeyGenerateWithAttributes(NULL, 1103 keychainRef, algorithm, keySizeInBits, 1104 contextHandle, keyUsage, keyAttr, 1105 initialAccess, keyRef); 1106 } 1107 1108 /* new in 10.6 */ 1109 /* Generate a floating key reference from a CSSM_KEY */ 1110 OSStatus 1111 SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey, 1112 SecKeyRef *keyRef) 1113 { 1114 BEGIN_SECAPI 1115 1116 Required(cssmKey); 1117 if(cssmKey->KeyData.Length == 0){ 1118 MacOSError::throwMe(errSecInvalidAttributeKeyLength); 1119 } 1120 if(cssmKey->KeyData.Data == NULL){ 1121 MacOSError::throwMe(errSecInvalidPointer); 1122 } 1123 CssmClient::CSP csp(cssmKey->KeyHeader.CspId); 1124 CssmClient::Key key(csp, *cssmKey); 1125 KeyItem *item = new KeyItem(key); 1126 1127 // Return the generated key. 1128 if (keyRef) 1129 *keyRef = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, (const uint8_t *)item, 0, 0); 1130 1131 END_SECAPI 1132 } 1133 1134 1135 1136 static u_int32_t ConvertCFStringToInteger(CFStringRef ref) 1137 { 1138 if (ref == NULL) 1139 { 1140 return 0; 1141 } 1142 1143 // figure out the size of the string 1144 CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8); 1145 char *buffer = (char *)malloc(numChars); 1146 if (NULL == buffer) { 1147 UnixError::throwMe(ENOMEM); 1148 } 1149 if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8)) 1150 { 1151 free(buffer); 1152 MacOSError::throwMe(errSecParam); 1153 } 1154 1155 u_int32_t result = atoi(buffer); 1156 free(buffer); 1157 return result; 1158 } 1159 1160 1161 1162 static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms) 1163 { 1164 // figure out the algorithm to use 1165 CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType); 1166 if (ktype == NULL) 1167 { 1168 return errSecParam; 1169 } 1170 1171 if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { 1172 algorithms = CSSM_ALGID_RSA; 1173 return errSecSuccess; 1174 } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) || 1175 CFEqual(ktype, kSecAttrKeyTypeEC)) { 1176 algorithms = CSSM_ALGID_ECDSA; 1177 return errSecSuccess; 1178 } else if(CFEqual(ktype, kSecAttrKeyTypeAES)) { 1179 algorithms = CSSM_ALGID_AES; 1180 return errSecSuccess; 1181 } else if(CFEqual(ktype, kSecAttrKeyType3DES)) { 1182 algorithms = CSSM_ALGID_3DES; 1183 return errSecSuccess; 1184 } else { 1185 return errSecUnsupportedAlgorithm; 1186 } 1187 } 1188 1189 1190 1191 static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits) 1192 { 1193 1194 // get the key size and check it for validity 1195 CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); 1196 1197 keySizeInBits = kSecDefaultKeySize; 1198 1199 CFTypeID bitSizeType = CFGetTypeID(ref); 1200 if (bitSizeType == CFStringGetTypeID()) 1201 keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref); 1202 else if (bitSizeType == CFNumberGetTypeID()) 1203 CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits); 1204 else return errSecParam; 1205 1206 1207 switch (algorithms) { 1208 case CSSM_ALGID_ECDSA: 1209 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1; 1210 if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess; 1211 break; 1212 case CSSM_ALGID_RSA: 1213 if(keySizeInBits % 8) return errSecParam; 1214 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048; 1215 if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess; 1216 break; 1217 case CSSM_ALGID_AES: 1218 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128; 1219 if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess; 1220 break; 1221 case CSSM_ALGID_3DES: 1222 if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192; 1223 if(keySizeInBits == kSec3DES192) return errSecSuccess; 1224 break; 1225 default: 1226 break; 1227 } 1228 return errSecParam; 1229 } 1230 1231 1232 1233 enum AttributeType 1234 { 1235 kStringType, 1236 kBooleanType, 1237 kIntegerType 1238 }; 1239 1240 1241 1242 struct ParameterAttribute 1243 { 1244 const CFStringRef *name; 1245 AttributeType type; 1246 }; 1247 1248 1249 1250 static ParameterAttribute gAttributes[] = 1251 { 1252 { 1253 &kSecAttrLabel, 1254 kStringType 1255 }, 1256 { 1257 &kSecAttrIsPermanent, 1258 kBooleanType 1259 }, 1260 { 1261 &kSecAttrApplicationTag, 1262 kStringType 1263 }, 1264 { 1265 &kSecAttrEffectiveKeySize, 1266 kBooleanType 1267 }, 1268 { 1269 &kSecAttrCanEncrypt, 1270 kBooleanType 1271 }, 1272 { 1273 &kSecAttrCanDecrypt, 1274 kBooleanType 1275 }, 1276 { 1277 &kSecAttrCanDerive, 1278 kBooleanType 1279 }, 1280 { 1281 &kSecAttrCanSign, 1282 kBooleanType 1283 }, 1284 { 1285 &kSecAttrCanVerify, 1286 kBooleanType 1287 }, 1288 { 1289 &kSecAttrCanUnwrap, 1290 kBooleanType 1291 } 1292 }; 1293 1294 const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute); 1295 1296 static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[]) 1297 { 1298 int i; 1299 for (i = 0; i < kNumberOfAttributes; ++i) 1300 { 1301 // see if the corresponding tag exists in the dictionary 1302 CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name)); 1303 if (value != NULL) 1304 { 1305 switch (gAttributes[i].type) 1306 { 1307 case kStringType: 1308 // just return the value 1309 *(CFTypeRef*) attributePointers[i] = value; 1310 break; 1311 1312 case kBooleanType: 1313 { 1314 CFBooleanRef bRef = (CFBooleanRef) value; 1315 *(bool*) attributePointers[i] = CFBooleanGetValue(bRef); 1316 } 1317 break; 1318 1319 case kIntegerType: 1320 { 1321 CFNumberRef nRef = (CFNumberRef) value; 1322 CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]); 1323 } 1324 break; 1325 } 1326 } 1327 } 1328 1329 return errSecSuccess; 1330 } 1331 1332 1333 1334 static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef) 1335 { 1336 // establish default values 1337 labelRef = NULL; 1338 bool isPermanent = false; 1339 applicationTagRef = NULL; 1340 CFTypeRef effectiveKeySize = NULL; 1341 bool canDecrypt = isPublic ? false : true; 1342 bool canEncrypt = !canDecrypt; 1343 bool canDerive = true; 1344 bool canSign = isPublic ? false : true; 1345 bool canVerify = !canSign; 1346 bool canUnwrap = isPublic ? false : true; 1347 attrs = CSSM_KEYATTR_EXTRACTABLE; 1348 keyUse = 0; 1349 1350 void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt, 1351 &canDerive, &canSign, &canVerify, &canUnwrap}; 1352 1353 // look for modifiers in the general dictionary 1354 OSStatus result = ScanDictionaryForParameters(parameters, attributePointers); 1355 if (result != errSecSuccess) 1356 { 1357 return result; 1358 } 1359 1360 // see if we have anything which modifies the defaults 1361 CFTypeRef key; 1362 if (isPublic) 1363 { 1364 key = kSecPublicKeyAttrs; 1365 } 1366 else 1367 { 1368 key = kSecPrivateKeyAttrs; 1369 } 1370 1371 CFTypeRef dType = CFDictionaryGetValue(parameters, key); 1372 if (dType != NULL) 1373 { 1374 // this had better be a dictionary 1375 if (CFGetTypeID(dType) != CFDictionaryGetTypeID()) 1376 { 1377 return errSecParam; 1378 } 1379 1380 // pull any additional parameters out of this dictionary 1381 result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers); 1382 if (result != errSecSuccess) 1383 { 1384 return result; 1385 } 1386 } 1387 1388 // figure out the key usage 1389 keyUse = 0; 1390 if (canDecrypt) 1391 { 1392 keyUse |= CSSM_KEYUSE_DECRYPT; 1393 } 1394 1395 if (canEncrypt) 1396 { 1397 keyUse |= CSSM_KEYUSE_ENCRYPT; 1398 } 1399 1400 if (canDerive) 1401 { 1402 keyUse |= CSSM_KEYUSE_DERIVE; 1403 } 1404 1405 if (canSign) 1406 { 1407 keyUse |= CSSM_KEYUSE_SIGN; 1408 } 1409 1410 if (canVerify) 1411 { 1412 keyUse |= CSSM_KEYUSE_VERIFY; 1413 } 1414 1415 if (canUnwrap) 1416 { 1417 keyUse |= CSSM_KEYUSE_UNWRAP; 1418 } 1419 1420 // public key is always extractable; 1421 // private key is extractable by default unless explicitly set to false 1422 CFTypeRef value = NULL; 1423 if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value) 1424 { 1425 Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value); 1426 if (!keyIsExtractable) 1427 attrs = 0; 1428 } 1429 1430 if (isPermanent) { 1431 attrs |= CSSM_KEYATTR_PERMANENT; 1432 } 1433 1434 return errSecSuccess; 1435 } 1436 1437 1438 1439 static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters, 1440 CSSM_ALGORITHMS &algorithms, 1441 uint32 &keySizeInBits, 1442 CSSM_KEYUSE &publicKeyUse, 1443 uint32 &publicKeyAttr, 1444 CFTypeRef &publicKeyLabelRef, 1445 CFDataRef &publicKeyAttributeTagRef, 1446 CSSM_KEYUSE &privateKeyUse, 1447 uint32 &privateKeyAttr, 1448 CFTypeRef &privateKeyLabelRef, 1449 CFDataRef &privateKeyAttributeTagRef, 1450 SecAccessRef &initialAccess) 1451 { 1452 OSStatus result; 1453 1454 result = CheckAlgorithmType(parameters, algorithms); 1455 if (result != errSecSuccess) 1456 { 1457 return result; 1458 } 1459 1460 result = GetKeySize(parameters, algorithms, keySizeInBits); 1461 if (result != errSecSuccess) 1462 { 1463 return result; 1464 } 1465 1466 result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef); 1467 if (result != errSecSuccess) 1468 { 1469 return result; 1470 } 1471 1472 result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef); 1473 if (result != errSecSuccess) 1474 { 1475 return result; 1476 } 1477 1478 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess)) 1479 { 1480 initialAccess = NULL; 1481 } 1482 else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess)) 1483 { 1484 return errSecParam; 1485 } 1486 1487 return errSecSuccess; 1488 } 1489 1490 1491 1492 static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag) 1493 { 1494 int numToModify = 0; 1495 if (label != NULL) 1496 { 1497 numToModify += 1; 1498 } 1499 1500 if (tag != NULL) 1501 { 1502 numToModify += 1; 1503 } 1504 1505 if (numToModify == 0) 1506 { 1507 return errSecSuccess; 1508 } 1509 1510 SecKeychainAttributeList attrList; 1511 SecKeychainAttribute attributes[numToModify]; 1512 1513 int i = 0; 1514 void *data = NULL; 1515 1516 if (label != NULL) 1517 { 1518 if (CFStringGetTypeID() == CFGetTypeID(label)) { 1519 CFStringRef label_string = static_cast<CFStringRef>(label); 1520 attributes[i].tag = kSecKeyPrintName; 1521 attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8); 1522 if (NULL == attributes[i].data) { 1523 CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8); 1524 data = attributes[i].data = malloc((size_t)buffer_length); 1525 if (NULL == attributes[i].data) { 1526 UnixError::throwMe(ENOMEM); 1527 } 1528 if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) { 1529 free(data); 1530 MacOSError::throwMe(errSecParam); 1531 } 1532 } 1533 attributes[i].length = (UInt32)strlen(static_cast<char *>(attributes[i].data)); 1534 } else if (CFDataGetTypeID() == CFGetTypeID(label)) { 1535 // 10.6 bug compatibility 1536 CFDataRef label_data = static_cast<CFDataRef>(label); 1537 attributes[i].tag = kSecKeyLabel; 1538 attributes[i].data = (void*) CFDataGetBytePtr(label_data); 1539 attributes[i].length = (UInt32)CFDataGetLength(label_data); 1540 } else { 1541 MacOSError::throwMe(errSecParam); 1542 } 1543 i++; 1544 } 1545 1546 if (tag != NULL) 1547 { 1548 attributes[i].tag = kSecKeyApplicationTag; 1549 attributes[i].data = (void*) CFDataGetBytePtr(tag); 1550 attributes[i].length = (UInt32)CFDataGetLength(tag); 1551 i++; 1552 } 1553 1554 attrList.count = numToModify; 1555 attrList.attr = attributes; 1556 1557 OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); 1558 if (data) 1559 { 1560 free(data); 1561 } 1562 1563 return result; 1564 } 1565 1566 1567 static CFTypeRef GetAttributeFromParams(CFDictionaryRef parameters, CFTypeRef attr, CFTypeRef subParams) { 1568 if (subParams != NULL) { 1569 CFDictionaryRef subParamsDict = (CFDictionaryRef)CFDictionaryGetValue(parameters, subParams); 1570 if (subParamsDict != NULL) { 1571 CFTypeRef value = CFDictionaryGetValue(subParamsDict, attr); 1572 if (value != NULL) { 1573 return value; 1574 } 1575 } 1576 } 1577 return CFDictionaryGetValue(parameters, attr); 1578 } 1579 1580 extern "C" OSStatus SecKeyGeneratePair_ios(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey); 1581 1582 /* new in 10.6 */ 1583 /* Generate a private/public keypair. */ 1584 static OSStatus 1585 SecKeyGeneratePairInternal( 1586 bool alwaysPermanent, 1587 CFDictionaryRef parameters, 1588 SecKeyRef *publicKey, 1589 SecKeyRef *privateKey) 1590 { 1591 BEGIN_SECAPI 1592 1593 Required(parameters); 1594 Required(publicKey); 1595 Required(privateKey); 1596 1597 bool forceIOSKey = false; 1598 if (_CFMZEnabled()) { 1599 // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in. 1600 forceIOSKey = true; 1601 } else { 1602 CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL); 1603 CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecUseDataProtectionKeychain, NULL); 1604 #pragma clang diagnostic push 1605 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 1606 if (!noLegacy) { // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot 1607 noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL); 1608 } 1609 #pragma clang diagnostic pop 1610 CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs); 1611 CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?: 1612 GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs); 1613 CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?: 1614 GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs); 1615 // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). 1616 forceIOSKey = (tokenID != NULL || 1617 (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) || 1618 (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) || 1619 accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken))); 1620 } 1621 1622 if (forceIOSKey) { 1623 // Generate keys in iOS keychain. 1624 return SecKeyGeneratePair_ios(parameters, publicKey, privateKey); 1625 } 1626 1627 CSSM_ALGORITHMS algorithms; 1628 uint32 keySizeInBits; 1629 CSSM_KEYUSE publicKeyUse; 1630 uint32 publicKeyAttr; 1631 CFTypeRef publicKeyLabelRef; 1632 CFDataRef publicKeyAttributeTagRef; 1633 CSSM_KEYUSE privateKeyUse; 1634 uint32 privateKeyAttr; 1635 CFTypeRef privateKeyLabelRef; 1636 CFDataRef privateKeyAttributeTagRef; 1637 SecAccessRef initialAccess; 1638 SecKeychainRef keychain; 1639 1640 OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef, 1641 publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef, 1642 initialAccess); 1643 1644 if (result != errSecSuccess) { 1645 return result; 1646 } 1647 1648 // verify keychain parameter 1649 keychain = (SecKeychainRef)CFDictionaryGetValue(parameters, kSecUseKeychain); 1650 if (keychain != NULL && SecKeychainGetTypeID() != CFGetTypeID(keychain)) { 1651 keychain = NULL; 1652 } 1653 1654 if (alwaysPermanent) { 1655 publicKeyAttr |= CSSM_KEYATTR_PERMANENT; 1656 privateKeyAttr |= CSSM_KEYATTR_PERMANENT; 1657 } 1658 1659 // do the key generation 1660 result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey); 1661 if (result != errSecSuccess) { 1662 return result; 1663 } 1664 1665 // set the label and print attributes on the keys 1666 SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef); 1667 SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef); 1668 return result; 1669 1670 END_SECAPI 1671 } 1672 1673 OSStatus 1674 SecKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) { 1675 return SecKeyGeneratePairInternal(true, parameters, publicKey, privateKey); 1676 } 1677 1678 SecKeyRef 1679 SecKeyCreateRandomKey(CFDictionaryRef parameters, CFErrorRef *error) { 1680 SecKeyRef privateKey = NULL, publicKey = NULL; 1681 OSStatus status = SecKeyGeneratePairInternal(false, parameters, &publicKey, &privateKey); 1682 SecError(status, error, CFSTR("failed to generate asymmetric keypair")); 1683 if (publicKey != NULL) { 1684 CFRelease(publicKey); 1685 } 1686 return privateKey; 1687 } 1688 1689 OSStatus SecKeyRawVerifyOSX( 1690 SecKeyRef key, /* Public key */ 1691 SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ 1692 const uint8_t *signedData, /* signature over this data */ 1693 size_t signedDataLen, /* length of dataToSign */ 1694 const uint8_t *sig, /* signature */ 1695 size_t sigLen) 1696 { 1697 return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen); 1698 } 1699 1700 /* 1701 M4 Additions 1702 */ 1703 1704 static CFTypeRef 1705 utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue) 1706 { 1707 CFTypeRef value = CFDictionaryGetValue(parameters, key); 1708 if (value != NULL) return value; 1709 return defaultValue; 1710 } 1711 1712 static uint32_t 1713 utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue) 1714 { 1715 uint32_t integerValue; 1716 CFTypeRef value = CFDictionaryGetValue(parameters, key); 1717 if (value != NULL) { 1718 CFNumberRef nRef = (CFNumberRef) value; 1719 CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue); 1720 return integerValue; 1721 } 1722 return defaultValue; 1723 } 1724 1725 static uint32_t 1726 utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue) 1727 { 1728 CFTypeRef value = CFDictionaryGetValue(parameters, key); 1729 if (value != NULL) { 1730 CFBooleanRef bRef = (CFBooleanRef) value; 1731 if(CFBooleanGetValue(bRef)) return maskValue; 1732 } 1733 return 0; 1734 } 1735 1736 static void 1737 utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass) 1738 { 1739 CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES); 1740 CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric); 1741 1742 if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) { 1743 *algorithm = CSSM_ALGID_AES; 1744 *keySizeInBits = 128; 1745 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1746 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) { 1747 *algorithm = CSSM_ALGID_DES; 1748 *keySizeInBits = 128; 1749 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1750 } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) { 1751 *algorithm = CSSM_ALGID_3DES_3KEY_EDE; 1752 *keySizeInBits = 128; 1753 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1754 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) { 1755 *algorithm = CSSM_ALGID_RC4; 1756 *keySizeInBits = 128; 1757 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1758 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) { 1759 *algorithm = CSSM_ALGID_RC2; 1760 *keySizeInBits = 128; 1761 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1762 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) { 1763 *algorithm = CSSM_ALGID_CAST; 1764 *keySizeInBits = 128; 1765 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1766 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) { 1767 *algorithm = CSSM_ALGID_RSA; 1768 *keySizeInBits = 128; 1769 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; 1770 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) { 1771 *algorithm = CSSM_ALGID_DSA; 1772 *keySizeInBits = 128; 1773 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; 1774 } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) || 1775 CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) { 1776 *algorithm = CSSM_ALGID_ECDSA; 1777 *keySizeInBits = 128; 1778 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; 1779 } else { 1780 *algorithm = CSSM_ALGID_AES; 1781 *keySizeInBits = 128; 1782 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1783 } 1784 1785 if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) { 1786 *keyClass = CSSM_KEYCLASS_PUBLIC_KEY; 1787 } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) { 1788 *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; 1789 } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) { 1790 *keyClass = CSSM_KEYCLASS_SESSION_KEY; 1791 } 1792 1793 *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits); 1794 *keyUsage = utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) | 1795 utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) | 1796 utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) | 1797 utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP); 1798 1799 1800 if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) { 1801 *keyUsage |= utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) | 1802 utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY); 1803 } 1804 1805 if(*keyUsage == 0) { 1806 switch (*keyClass) { 1807 case CSSM_KEYCLASS_PRIVATE_KEY: 1808 *keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN; 1809 break; 1810 case CSSM_KEYCLASS_PUBLIC_KEY: 1811 *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP; 1812 break; 1813 default: 1814 *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY; 1815 break; 1816 } 1817 } 1818 } 1819 1820 static CFStringRef 1821 utilCopyDefaultKeyLabel(void) 1822 { 1823 // generate a default label from the current date 1824 CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); 1825 CFStringRef defaultLabel = CFCopyDescription(dateNow); 1826 CFRelease(dateNow); 1827 1828 return defaultLabel; 1829 } 1830 1831 SecKeyRef 1832 SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) 1833 { 1834 OSStatus result = errSecParam; // default result for an early exit 1835 SecKeyRef key = NULL; 1836 SecKeychainRef keychain = NULL; 1837 SecAccessRef access; 1838 CFStringRef label; 1839 CFStringRef appLabel; 1840 CFStringRef appTag; 1841 CFStringRef dateLabel = NULL; 1842 1843 CSSM_ALGORITHMS algorithm; 1844 uint32 keySizeInBits; 1845 CSSM_KEYUSE keyUsage; 1846 uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT; 1847 CSSM_KEYCLASS keyClass; 1848 CFTypeRef value; 1849 Boolean isPermanent; 1850 Boolean isExtractable; 1851 1852 // verify keychain parameter 1853 if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain)) 1854 keychain = NULL; 1855 else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) { 1856 keychain = NULL; 1857 goto errorExit; 1858 } 1859 else 1860 CFRetain(keychain); 1861 1862 // verify permanent parameter 1863 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value)) 1864 isPermanent = false; 1865 else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value))) 1866 goto errorExit; 1867 else 1868 isPermanent = CFEqual(kCFBooleanTrue, value); 1869 if (isPermanent) { 1870 if (keychain == NULL) { 1871 // no keychain was specified, so use the default keychain 1872 result = SecKeychainCopyDefault(&keychain); 1873 } 1874 keyAttr |= CSSM_KEYATTR_PERMANENT; 1875 } 1876 1877 // verify extractable parameter 1878 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value)) 1879 isExtractable = true; // default to extractable if value not specified 1880 else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value))) 1881 goto errorExit; 1882 else 1883 isExtractable = CFEqual(kCFBooleanTrue, value); 1884 if (isExtractable) 1885 keyAttr |= CSSM_KEYATTR_EXTRACTABLE; 1886 1887 // verify access parameter 1888 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access)) 1889 access = NULL; 1890 else if (SecAccessGetTypeID() != CFGetTypeID(access)) 1891 goto errorExit; 1892 1893 // verify label parameter 1894 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label)) 1895 label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default 1896 else if (CFStringGetTypeID() != CFGetTypeID(label)) 1897 goto errorExit; 1898 1899 // verify application label parameter 1900 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel)) 1901 appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel()); 1902 else if (CFStringGetTypeID() != CFGetTypeID(appLabel)) 1903 goto errorExit; 1904 1905 // verify application tag parameter 1906 if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag)) 1907 appTag = NULL; 1908 else if (CFStringGetTypeID() != CFGetTypeID(appTag)) 1909 goto errorExit; 1910 1911 utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass); 1912 1913 if (!keychain) { 1914 // the generated key will not be stored in any keychain 1915 result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key); 1916 } 1917 else { 1918 // we can set the label attributes on the generated key if it's a keychain item 1919 size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1; 1920 char *labelBuf = (char *)malloc(labelBufLen); 1921 size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1; 1922 char *appLabelBuf = (char *)malloc(appLabelBufLen); 1923 size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1; 1924 char *appTagBuf = (char *)malloc(appTagBufLen); 1925 1926 if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) 1927 labelBuf[0]=0; 1928 if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) 1929 appLabelBuf[0]=0; 1930 if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) 1931 appTagBuf[0]=0; 1932 1933 SecKeychainAttribute attrs[] = { 1934 { kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf }, 1935 { kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf }, 1936 { kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf } }; 1937 SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; 1938 if (!appTag) --attributes.count; 1939 1940 result = SecKeyGenerateWithAttributes(&attributes, 1941 keychain, algorithm, keySizeInBits, 0, 1942 keyUsage, keyAttr, access, &key); 1943 1944 free(labelBuf); 1945 free(appLabelBuf); 1946 free(appTagBuf); 1947 } 1948 1949 errorExit: 1950 if (result && error) { 1951 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL); 1952 } 1953 if (dateLabel) 1954 CFRelease(dateLabel); 1955 if (keychain) 1956 CFRelease(keychain); 1957 1958 return key; 1959 } 1960 1961 1962 1963 SecKeyRef 1964 SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error) 1965 { 1966 CSSM_ALGORITHMS algorithm; 1967 uint32 keySizeInBits; 1968 CSSM_KEYUSE keyUsage; 1969 CSSM_KEYCLASS keyClass; 1970 CSSM_RETURN crtn; 1971 1972 if(keyData == NULL || CFDataGetLength(keyData) == 0){ 1973 MacOSError::throwMe(errSecUnsupportedKeySize); 1974 } 1975 1976 utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass); 1977 1978 CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL 1979 1980 SecKeyImportExportParameters iparam; 1981 memset(&iparam, 0, sizeof(iparam)); 1982 iparam.keyUsage = keyUsage; 1983 1984 CFRef<CFDataRef> data; 1985 SecExternalItemType itype; 1986 switch (keyClass) { 1987 case CSSM_KEYCLASS_PRIVATE_KEY: 1988 itype = kSecItemTypePrivateKey; 1989 break; 1990 case CSSM_KEYCLASS_PUBLIC_KEY: { 1991 itype = kSecItemTypePublicKey; 1992 // Public key import expects public key in SubjPublicKey X509 format. We want to accept both bare and x509 format, 1993 // so we have to detect bare format here and extend to full X509 if detected. 1994 data.take(SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(algorithm, keySizeInBits, keyData)); 1995 break; 1996 } 1997 case CSSM_KEYCLASS_SESSION_KEY: 1998 itype = kSecItemTypeSessionKey; 1999 break; 2000 default: 2001 itype = kSecItemTypeUnknown; 2002 break; 2003 } 2004 2005 CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 2006 // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful. 2007 crtn = impExpImportRawKey(data ? CFDataRef(data) : keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka); 2008 if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) { 2009 SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0); 2010 CFRetain(sk); 2011 CFRelease(ka); 2012 return sk; 2013 } else { 2014 CFRelease(ka); 2015 if (error) { 2016 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL); 2017 } 2018 return NULL; 2019 } 2020 } 2021 2022 2023 void 2024 SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue, 2025 SecKeyGeneratePairBlock result) 2026 { 2027 CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable); 2028 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 2029 SecKeyRef publicKey = NULL; 2030 SecKeyRef privateKey = NULL; 2031 OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey); 2032 dispatch_async(deliveryQueue, ^{ 2033 CFErrorRef error = NULL; 2034 if (errSecSuccess != status) { 2035 error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL); 2036 } 2037 result(publicKey, privateKey, error); 2038 if (error) { 2039 CFRelease(error); 2040 } 2041 if (publicKey) { 2042 CFRelease(publicKey); 2043 } 2044 if (privateKey) { 2045 CFRelease(privateKey); 2046 } 2047 CFRelease(parameters); 2048 }); 2049 }); 2050 } 2051 2052 static inline void utilClearAndFree(void *p, size_t len) { 2053 if(p) { 2054 if(len) bzero(p, len); 2055 free(p); 2056 } 2057 } 2058 2059 SecKeyRef 2060 SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error) 2061 { 2062 CCPBKDFAlgorithm algorithm; 2063 CFIndex passwordLen = 0; 2064 CFDataRef keyData = NULL; 2065 char *thePassword = NULL; 2066 uint8_t *salt = NULL; 2067 uint8_t *derivedKey = NULL; 2068 size_t saltLen = 0, derivedKeyLen = 0; 2069 uint rounds; 2070 CFDataRef saltDictValue, algorithmDictValue; 2071 SecKeyRef retval = NULL; 2072 2073 /* Pick Values from parameters */ 2074 2075 if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) { 2076 if(error) { 2077 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); 2078 } 2079 goto errOut; 2080 } 2081 2082 derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128); 2083 // This value come in bits but the rest of the code treats it as bytes 2084 derivedKeyLen /= 8; 2085 2086 algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256); 2087 2088 rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0); 2089 2090 /* Convert any remaining parameters and get the password bytes */ 2091 2092 saltLen = CFDataGetLength(saltDictValue); 2093 if((salt = (uint8_t *) malloc(saltLen)) == NULL) { 2094 if(error) { 2095 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); 2096 } 2097 goto errOut; 2098 } 2099 2100 CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt); 2101 2102 passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1; 2103 if((thePassword = (char *) malloc(passwordLen)) == NULL) { 2104 if(error) { 2105 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); 2106 } 2107 goto errOut; 2108 } 2109 CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen); 2110 2111 if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) { 2112 if(error) { 2113 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); 2114 } 2115 goto errOut; 2116 } 2117 2118 if(algorithmDictValue == NULL) { 2119 algorithm = kCCPRFHmacAlgSHA1; /* default */ 2120 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) { 2121 algorithm = kCCPRFHmacAlgSHA1; 2122 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) { 2123 algorithm = kCCPRFHmacAlgSHA224; 2124 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) { 2125 algorithm = kCCPRFHmacAlgSHA256; 2126 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) { 2127 algorithm = kCCPRFHmacAlgSHA384; 2128 } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) { 2129 algorithm = kCCPRFHmacAlgSHA512; 2130 } else { 2131 if(error) { 2132 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL); 2133 } 2134 goto errOut; 2135 } 2136 2137 if(rounds == 0) { 2138 rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count. 2139 } 2140 2141 if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) { 2142 if(error) { 2143 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); 2144 } 2145 goto errOut; 2146 } 2147 2148 if((keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen)) != NULL) { 2149 retval = SecKeyCreateFromData(parameters, keyData, error); 2150 CFRelease(keyData); 2151 } else { 2152 if(error) { 2153 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); 2154 } 2155 } 2156 2157 errOut: 2158 utilClearAndFree(salt, saltLen); 2159 utilClearAndFree(thePassword, passwordLen); 2160 utilClearAndFree(derivedKey, derivedKeyLen); 2161 return retval; 2162 } 2163 2164 CFDataRef 2165 SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error) 2166 { 2167 if(error) { 2168 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL); 2169 } 2170 return NULL; 2171 } 2172 2173 SecKeyRef 2174 SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error) 2175 { 2176 if(error) { 2177 *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL); 2178 } 2179 return NULL; 2180 }