X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/866f8763175ff60e4fa455b92b5eb660a12fe6c7..bf028f67fd3bb2266df81b80fb6f25a77112e308:/OSX/libsecurity_keychain/lib/SecKey.cpp?ds=sidebyside diff --git a/OSX/libsecurity_keychain/lib/SecKey.cpp b/OSX/libsecurity_keychain/lib/SecKey.cpp index 229ee8bb..7ef6027b 100644 --- a/OSX/libsecurity_keychain/lib/SecKey.cpp +++ b/OSX/libsecurity_keychain/lib/SecKey.cpp @@ -21,10 +21,11 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include "SecKey.h" -#include "SecKeyPriv.h" -#include "SecItem.h" -#include "SecItemPriv.h" +#include +#include +#include +#include +#include #include #include #include @@ -35,6 +36,10 @@ #include #include +#include +// 'verify' macro is somehow dragged in from CFPriv.h and breaks compilation of signclient.h, so undef it, we don't need it. +#undef verify + #include "SecBridge.h" #include @@ -53,9 +58,11 @@ static OSStatus SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) { - key->key = const_cast(reinterpret_cast(keyData)); - key->key->initializeWithSecKeyRef(key); - key->credentialType = kSecCredentialTypeDefault; + CDSASecKey *cdsaKey = (CDSASecKey *)key; + cdsaKey->key = const_cast(reinterpret_cast(keyData)); + CDSASecKey::keyItem(key)->initializeWithSecKeyRef(key); + cdsaKey->credentialType = kSecCredentialTypeDefault; + cdsaKey->cdsaKeyMutex = new Mutex(); return errSecSuccess; } @@ -65,17 +72,26 @@ SecCDSAKeyDestroy(SecKeyRef keyRef) { // If we hold the keychain's mutex (the key's 'mutexForObject') during this destruction, pthread gets upset. // Hold a reference to the keychain (if it exists) until after we release the keychain's mutex. - KeyItem *keyItem = keyRef->key; + CDSASecKey *cdsaKey = static_cast(keyRef); + StMaybeLock cdsaMutex(cdsaKey->cdsaKeyMutex); + + KeyItem *keyItem = static_cast(keyRef->key); + if (keyItem == NULL) { // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. + cdsaMutex.unlock(); + delete cdsaKey->cdsaKeyMutex; return; } Keychain kc = keyItem->keychain(); + // We have a +1 reference to the KeyItem now; no need to protect our storage any more + cdsaMutex.unlock(); + { StMaybeLock _(keyItem->getMutexForObject()); - keyItem = keyRef->key; + keyItem = static_cast(keyRef->key); if (keyItem == NULL) { // 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. return; @@ -85,6 +101,8 @@ SecCDSAKeyDestroy(SecKeyRef keyRef) { delete keyItem; } + delete cdsaKey->cdsaKeyMutex; + (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. } @@ -94,7 +112,7 @@ SecCDSAKeyGetBlockSize(SecKeyRef key) { CFErrorRef *error = NULL; BEGIN_SECKEYAPI(size_t,0) - const CssmKey::Header keyHeader = key->key->unverifiedKeyHeader(); + const CssmKey::Header keyHeader = CDSASecKey::keyItem(key)->unverifiedKeyHeader(); switch(keyHeader.algorithm()) { case CSSM_ALGID_RSA: @@ -143,7 +161,7 @@ SecCDSAKeyGetAlgorithmId(SecKeyRef key) { BEGIN_SECKEYAPI(CFIndex, 0) result = kSecNullAlgorithmID; - switch (key->key->unverifiedKeyHeader().AlgorithmId) { + switch (CDSASecKey::keyItem(key)->unverifiedKeyHeader().AlgorithmId) { case CSSM_ALGID_RSA: result = kSecRSAAlgorithmID; break; @@ -242,7 +260,7 @@ static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serializatio CFErrorRef *error = NULL; BEGIN_SECKEYAPI(OSStatus, errSecSuccess) - const CssmKey::Header &header = key->key->key().header(); + const CssmKey::Header &header = CDSASecKey::keyItem(key)->key().header(); switch (header.algorithm()) { case CSSM_ALGID_RSA: { switch (header.keyClass()) { @@ -338,7 +356,7 @@ SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { BEGIN_SECKEYAPI(CFDataRef, NULL) result = NULL; - const CssmKey::Header header = key->key->unverifiedKeyHeader(); + const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader(); CFRef keyData; switch (header.algorithm()) { case CSSM_ALGID_RSA: @@ -385,16 +403,16 @@ SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) { static CFDataRef SecCDSAKeyCopyLabel(SecKeyRef key) { CFDataRef label = NULL; - if (key->key->isPersistent()) { + if (CDSASecKey::keyItem(key)->isPersistent()) { UInt32 tags[] = { kSecKeyLabel }, formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB }; SecKeychainAttributeInfo info = { 1, tags, formats }; SecKeychainAttributeList *list = NULL; - key->key->getAttributesAndData(&info, NULL, &list, NULL, NULL); + CDSASecKey::keyItem(key)->getAttributesAndData(&info, NULL, &list, NULL, NULL); if (list->count == 1) { SecKeychainAttribute *attr = list->attr; label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attr->data, (CFIndex)attr->length); } - key->key->freeAttributesAndData(list, NULL); + CDSASecKey::keyItem(key)->freeAttributesAndData(list, NULL); } return label; } @@ -410,7 +428,7 @@ SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) { CFDictionarySetValue(dict, kSecClass, kSecClassKey); - const CssmKey::Header header = key->key->unverifiedKeyHeader(); + const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader(); CFIndex sizeValue = header.LogicalKeySizeInBits; CFRef sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue); CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits); @@ -475,7 +493,7 @@ SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) { if (header.algorithm() == CSSM_ALGID_RSA && header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY && header.blobType() == CSSM_KEYBLOB_RAW) { - const CssmData &keyData = key->key->key()->keyData(); + const CssmData &keyData = CDSASecKey::keyItem(key)->key()->keyData(); DERItem keyItem = { static_cast(keyData.data()), keyData.length() }; DERRSAPubKeyPKCS1 decodedKey; if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs, @@ -501,11 +519,11 @@ static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, (char*) "Label", 0, NULL, #pragma clang diagnostic pop static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) { - CFErrorRef *error; + CFErrorRef *error = NULL; BEGIN_SECKEYAPI(SecKeyRef, NULL) result = NULL; - KeyItem *key = privateKey->key; + KeyItem *key = CDSASecKey::keyItem(privateKey); CFRef label = SecCDSAKeyCopyLabel(privateKey); if (label) { // Lookup public key in the database. @@ -531,7 +549,7 @@ static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) { static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm, CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm, CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) { - KeyItem *keyItem = key->key; + KeyItem *keyItem = CDSASecKey::keyItem(key); CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass(); baseAlgorithm = keyItem->key()->header().algorithm(); switch (baseAlgorithm) { @@ -632,7 +650,7 @@ static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType & static CFDataRef SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key, CFDataRef plaintext, SecKeyAlgorithm algorithm) { - CFIndex blockSize = key->key->key().header().LogicalKeySizeInBits / 8; + CFIndex blockSize = CDSASecKey::keyItem(key)->key().header().LogicalKeySizeInBits / 8; CFIndex plaintextLength = CFDataGetLength(plaintext); if ((algorithm == kSecKeyAlgorithmRSAEncryptionRaw || algorithm == kSecKeyAlgorithmRSASignatureRaw) && plaintextLength < blockSize) { @@ -669,11 +687,12 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp } } + CDSASecKey *cdsaKey = static_cast(key); switch (operation) { case kSecKeyOperationTypeSign: { CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm); signContext.key(keyItem->key()); - signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, key->credentialType)); + signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, cdsaKey->credentialType)); signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm); CFRef input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef::check(in1, errSecParam), algorithm); CssmAutoData signature(signContext.allocator()); @@ -684,7 +703,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp case kSecKeyOperationTypeVerify: { CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm); verifyContext.key(keyItem->key()); - verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, key->credentialType)); + verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, cdsaKey->credentialType)); verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm); CFRef input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef::check(in1, errSecParam), algorithm); verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef::check(in2, errSecParam))); @@ -695,7 +714,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm); encryptContext.key(keyItem->key()); encryptContext.padding(paddingAlgorithm); - encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, key->credentialType)); + encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, cdsaKey->credentialType)); CFRef input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef::check(in1, errSecParam), algorithm); CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator()); size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get()); @@ -709,7 +728,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm); decryptContext.key(keyItem->key()); decryptContext.padding(paddingAlgorithm); - decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, key->credentialType)); + decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, cdsaKey->credentialType)); CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator()); size_t length = decryptContext.decrypt(CssmData(CFRef::check(in1, errSecParam)), output.get(), remainingData.get()); @@ -761,10 +780,10 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp } static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) { - CFErrorRef *error; + CFErrorRef *error = NULL; BEGIN_SECKEYAPI(Boolean, false) - result = key1->key->equal(*key2->key); + result = CDSASecKey::keyItem(key1)->equal(*CDSASecKey::keyItem(key2)); END_SECKEYAPI } @@ -773,7 +792,7 @@ static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropert BEGIN_SECKEYAPI(Boolean, false) if (CFEqual(name, kSecUseAuthenticationUI)) { - key->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI; + static_cast(key)->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI; result = true; } else { result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name); @@ -797,6 +816,8 @@ const SecKeyDescriptor kSecCDSAKeyDescriptor = { .copyOperationResult = SecCDSAKeyCopyOperationResult, .isEqual = SecCDSAKeyIsEqual, .setParameter = SecCDSAKeySetParameter, + + .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0), }; namespace Security { @@ -811,22 +832,52 @@ namespace Security { return static_cast(key->key); } - if (key->cdsaKey == NULL) { + CFRef cdsaKey = SecKeyCopyAuxilliaryCDSAKeyForKey(key); + if (!cdsaKey) { // Create CDSA key from exported data of existing key. - CFRef keyData = SecKeyCopyExternalRepresentation(key, NULL); CFRef keyAttributes = SecKeyCopyAttributes(key); - if (keyData && keyAttributes) { - key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); + if (keyAttributes) { + CFRef keyData = SecKeyCopyExternalRepresentation(key, NULL); + if (!keyData) { + CFTypeRef pubKeyHash = CFDictionaryGetValue(keyAttributes, kSecAttrApplicationLabel); + const void *keys[] = { kSecClass, kSecUseDataProtectionKeychain, kSecReturnRef, kSecMatchLimit }; + const void *values[] = { kSecClassIdentity, kCFBooleanFalse, kCFBooleanTrue, kSecMatchLimitAll }; + CFRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, + sizeof(keys) / sizeof(*keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFRef identities; + OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take()); + if (status == errSecSuccess) { + for (int i = 0; i < CFArrayGetCount(identities); ++i) { + CFRef privateKey; + if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) { + continue; + } + CFRef attrs = SecKeyCopyAttributes(privateKey); + if (CFEqual(CFDictionaryGetValue(attrs, kSecAttrApplicationLabel), pubKeyHash)) { + cdsaKey = privateKey; + SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get()); + break; + } + } + } + } else { + cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL)); + if (cdsaKey) { + SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get()); + } + } } } - return (key->cdsaKey != NULL) ? key->cdsaKey->key : NULL; + return cdsaKey ? CDSASecKey::keyItem(cdsaKey.get()) : NULL; } // You need to hold this key's MutexForObject when you run this void KeyItem::attachSecKeyRef() const { SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast(this), 0, 0); - key->key->mWeakSecKeyRef = key; + CDSASecKey::keyItem(key)->mWeakSecKeyRef = key; } } @@ -910,7 +961,7 @@ SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey) // static ModuleNexus gSecReturnedKeyCSPsMutex; -static std::set gSecReturnedKeyCSPs; +static ModuleNexus> gSecReturnedKeyCSPs; OSStatus SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) @@ -924,7 +975,7 @@ SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) CssmClient::CSP returnedKeyCSP = keyItem->csp(); { StLock _(gSecReturnedKeyCSPsMutex()); - gSecReturnedKeyCSPs.insert(returnedKeyCSP); + gSecReturnedKeyCSPs().insert(returnedKeyCSP); } Required(cspHandle) = returnedKeyCSP->handle(); @@ -1544,19 +1595,32 @@ SecKeyGeneratePairInternal( Required(publicKey); Required(privateKey); - CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL); - CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL); - CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs); - CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?: - GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs); - CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?: - GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs); - - // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). - if (tokenID != NULL || - (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) || - (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) || - accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken))) { + bool forceIOSKey = false; + if (_CFMZEnabled()) { + // On Marzipan, always go iOS SecItem/SecKey route, do not drag CSSM keys in. + forceIOSKey = true; + } else { + CFTypeRef tokenID = GetAttributeFromParams(parameters, kSecAttrTokenID, NULL); + CFTypeRef noLegacy = GetAttributeFromParams(parameters, kSecUseDataProtectionKeychain, NULL); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (!noLegacy) { // Also lookup via deprecated symbol because we do CFDictionaryGetValue and your CFDict might be an idiot + noLegacy = GetAttributeFromParams(parameters, kSecAttrNoLegacy, NULL); + } +#pragma clang diagnostic pop + CFTypeRef sync = GetAttributeFromParams(parameters, kSecAttrSynchronizable, kSecPrivateKeyAttrs); + CFTypeRef accessControl = GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPrivateKeyAttrs) ?: + GetAttributeFromParams(parameters, kSecAttrAccessControl, kSecPublicKeyAttrs); + CFTypeRef accessGroup = GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPrivateKeyAttrs) ?: + GetAttributeFromParams(parameters, kSecAttrAccessGroup, kSecPublicKeyAttrs); + // If any of these attributes are present, forward the call to iOS implementation (and create keys in iOS keychain). + forceIOSKey = (tokenID != NULL || + (noLegacy != NULL && CFBooleanGetValue((CFBooleanRef)noLegacy)) || + (sync != NULL && CFBooleanGetValue((CFBooleanRef)sync)) || + accessControl != NULL || (accessGroup != NULL && CFEqual(accessGroup, kSecAttrAccessGroupToken))); + } + + if (forceIOSKey) { // Generate keys in iOS keychain. return SecKeyGeneratePair_ios(parameters, publicKey, privateKey); }