X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/6b200bc335dc93c5516ccb52f14bd896d8c7fad7..07691282a056c4efea71e1e505527601e8cc166b:/OSX/libsecurity_keychain/lib/SecKey.cpp?ds=inline diff --git a/OSX/libsecurity_keychain/lib/SecKey.cpp b/OSX/libsecurity_keychain/lib/SecKey.cpp index c346136c..6fb96593 100644 --- a/OSX/libsecurity_keychain/lib/SecKey.cpp +++ b/OSX/libsecurity_keychain/lib/SecKey.cpp @@ -35,6 +35,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 @@ -56,6 +60,7 @@ SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, Sec key->key = const_cast(reinterpret_cast(keyData)); key->key->initializeWithSecKeyRef(key); key->credentialType = kSecCredentialTypeDefault; + key->cdsaKeyMutex = new Mutex(); return errSecSuccess; } @@ -65,14 +70,22 @@ 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. + StMaybeLock cdsaMutex(keyRef->cdsaKeyMutex); + KeyItem *keyItem = keyRef->key; + if (keyItem == NULL) { // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us. + cdsaMutex.unlock(); + delete keyRef->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; @@ -85,6 +98,8 @@ SecCDSAKeyDestroy(SecKeyRef keyRef) { delete keyItem; } + delete keyRef->cdsaKeyMutex; + (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain. } @@ -501,7 +516,7 @@ 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; @@ -521,14 +536,14 @@ static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) { } if (result == NULL && key->publicKey()) { - KeyItem *publicKey = new KeyItem(key->publicKey()); + SecPointer publicKey(new KeyItem(key->publicKey())); result = reinterpret_cast(publicKey->handle()); } END_SECKEYAPI } -static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm, +static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType &operation, SecKeyAlgorithm algorithm, CSSM_ALGORITHMS &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm, CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) { KeyItem *keyItem = key->key; @@ -586,6 +601,14 @@ static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType o } else { return NULL; } + } else if (keyClass == CSSM_KEYCLASS_PUBLIC_KEY && operation == kSecKeyOperationTypeDecrypt && + CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) { + // Raw RSA decryption is identical to raw RSA encryption, so lets use encryption instead of decryption, + // because CDSA keys refuses to perform decrypt using public key. + operation = kSecKeyOperationTypeEncrypt; + secondaryAlgorithm = CSSM_ALGID_NONE; + paddingAlgorithm = CSSM_PADDING_NONE; + inputSizeLimit = 0; } else { return NULL; } @@ -753,7 +776,7 @@ 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); @@ -789,6 +812,8 @@ const SecKeyDescriptor kSecCDSAKeyDescriptor = { .copyOperationResult = SecCDSAKeyCopyOperationResult, .isEqual = SecCDSAKeyIsEqual, .setParameter = SecCDSAKeySetParameter, + + .extraBytes = (sizeof(struct OpaqueSecKeyRef) > sizeof(struct __SecKey) ? (sizeof(struct OpaqueSecKeyRef) - sizeof(struct __SecKey)) : 0), }; namespace Security { @@ -805,10 +830,35 @@ namespace Security { if (key->cdsaKey == NULL) { // 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, kSecAttrNoLegacy, 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)) { + key->cdsaKey = privateKey.retain(); + break; + } + } + } + } else { + key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); + } } } @@ -850,13 +900,10 @@ static OSStatus SecKeyCreatePairInternal( SecPointer pubItem, privItem; if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) { keychain = Keychain::optional(keychainRef); - StLock _(*keychain->getKeychainMutex()); - KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, - privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); - } else { - KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, - privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); } + StMaybeLock _(keychain ? keychain->getKeychainMutex() : NULL); + KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr, + privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem); // Return the generated keys. if (publicKeyRef) @@ -904,13 +951,24 @@ SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey) // Private APIs // +static ModuleNexus gSecReturnedKeyCSPsMutex; +static ModuleNexus> gSecReturnedKeyCSPs; + OSStatus SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) { BEGIN_SECAPI SecPointer keyItem(KeyItem::required(keyRef)); - Required(cspHandle) = keyItem->csp()->handle(); + + // Once we vend this handle, we can no longer delete this CSP object via RAII (and thus call CSSM_ModuleDetach on the CSP). + // Keep a global pointer to it to force the CSP to stay live forever. + CssmClient::CSP returnedKeyCSP = keyItem->csp(); + { + StLock _(gSecReturnedKeyCSPsMutex()); + gSecReturnedKeyCSPs().insert(returnedKeyCSP); + } + Required(cspHandle) = returnedKeyCSP->handle(); END_SECAPI } @@ -1076,13 +1134,19 @@ static u_int32_t ConvertCFStringToInteger(CFStringRef ref) // figure out the size of the string CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8); - char buffer[numChars]; + char *buffer = (char *)malloc(numChars); + if (NULL == buffer) { + UnixError::throwMe(ENOMEM); + } if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8)) { + free(buffer); MacOSError::throwMe(errSecParam); } - return atoi(buffer); + u_int32_t result = atoi(buffer); + free(buffer); + return result; } @@ -1439,6 +1503,7 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t SecKeychainAttribute attributes[numToModify]; int i = 0; + void *data = NULL; if (label != NULL) { @@ -1448,11 +1513,12 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t attributes[i].data = (void*) CFStringGetCStringPtr(label_string, kCFStringEncodingUTF8); if (NULL == attributes[i].data) { CFIndex buffer_length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(label_string), kCFStringEncodingUTF8); - attributes[i].data = alloca((size_t)buffer_length); + data = attributes[i].data = malloc((size_t)buffer_length); if (NULL == attributes[i].data) { UnixError::throwMe(ENOMEM); } if (!CFStringGetCString(label_string, static_cast(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) { + free(data); MacOSError::throwMe(errSecParam); } } @@ -1479,8 +1545,14 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t attrList.count = numToModify; attrList.attr = attributes; - - return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); + + OSStatus result = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); + if (data) + { + free(data); + } + + return result; } @@ -1514,19 +1586,26 @@ 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, 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). + 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); } @@ -1823,18 +1902,18 @@ SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) } else { // we can set the label attributes on the generated key if it's a keychain item - size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 0; + size_t labelBufLen = (label) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(label), kCFStringEncodingUTF8) + 1 : 1; char *labelBuf = (char *)malloc(labelBufLen); - size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 0; + size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 1; char *appLabelBuf = (char *)malloc(appLabelBufLen); - size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 0; + size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 1; char *appTagBuf = (char *)malloc(appTagBufLen); - if (label && !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) + if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) labelBuf[0]=0; - if (appLabel && !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) + if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) appLabelBuf[0]=0; - if (appTag && !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) + if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) appTagBuf[0]=0; SecKeychainAttribute attrs[] = { @@ -1918,6 +1997,7 @@ SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef * CFRelease(ka); return sk; } else { + CFRelease(ka); if (error) { *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL); } @@ -1979,7 +2059,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr /* Pick Values from parameters */ if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); + } goto errOut; } @@ -1995,7 +2077,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr saltLen = CFDataGetLength(saltDictValue); if((salt = (uint8_t *) malloc(saltLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + } goto errOut; } @@ -2003,13 +2087,17 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1; if((thePassword = (char *) malloc(passwordLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + } goto errOut; } CFStringGetBytes(password, CFRangeMake(0, CFStringGetLength(password)), kCFStringEncodingUTF8, '?', FALSE, (UInt8*)thePassword, passwordLen, &passwordLen); if((derivedKey = (uint8_t *) malloc(derivedKeyLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); + } goto errOut; } @@ -2037,7 +2125,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr } if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); + if(error) { + *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); + } goto errOut; }