]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/SecKey.cpp
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecKey.cpp
index c346136cfbe933a76d25582f344ffeaccad403bf..6fb96593e71eb45e30e4345e6681f93a7c96fb66 100644 (file)
 #include <security_utilities/casts.h>
 #include <CommonCrypto/CommonKeyDerivation.h>
 
 #include <security_utilities/casts.h>
 #include <CommonCrypto/CommonKeyDerivation.h>
 
+#include <CoreFoundation/CFPriv.h>
+// '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 <security_keychain/Access.h>
 #include "SecBridge.h"
 
 #include <security_keychain/Access.h>
@@ -56,6 +60,7 @@ SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, Sec
     key->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
     key->key->initializeWithSecKeyRef(key);
     key->credentialType = kSecCredentialTypeDefault;
     key->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
     key->key->initializeWithSecKeyRef(key);
     key->credentialType = kSecCredentialTypeDefault;
+    key->cdsaKeyMutex = new Mutex();
     return errSecSuccess;
 }
 
     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.
 
     // 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<Mutex> cdsaMutex(keyRef->cdsaKeyMutex);
+
     KeyItem *keyItem = keyRef->key;
     KeyItem *keyItem = keyRef->key;
+
     if (keyItem == NULL) {
         // KeyImpl::attachSecKeyRef disconnected us from KeyItem instance, there is nothing to do for us.
     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();
 
         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<Mutex> _(keyItem->getMutexForObject());
         keyItem = keyRef->key;
     {
         StMaybeLock<Mutex> _(keyItem->getMutexForObject());
         keyItem = keyRef->key;
@@ -85,6 +98,8 @@ SecCDSAKeyDestroy(SecKeyRef keyRef) {
         delete keyItem;
     }
 
         delete keyItem;
     }
 
+    delete keyRef->cdsaKeyMutex;
+
     (void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
 }
 
     (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) {
 #pragma clang diagnostic pop
 
 static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
-    CFErrorRef *error;
+    CFErrorRef *error = NULL;
     BEGIN_SECKEYAPI(SecKeyRef, NULL)
 
     result = NULL;
     BEGIN_SECKEYAPI(SecKeyRef, NULL)
 
     result = NULL;
@@ -521,14 +536,14 @@ static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
     }
 
     if (result == NULL && key->publicKey()) {
     }
 
     if (result == NULL && key->publicKey()) {
-        KeyItem *publicKey = new KeyItem(key->publicKey());
+        SecPointer<KeyItem> publicKey(new KeyItem(key->publicKey()));
         result = reinterpret_cast<SecKeyRef>(publicKey->handle());
     }
 
     END_SECKEYAPI
 }
 
         result = reinterpret_cast<SecKeyRef>(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;
                                             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 {
                     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;
             }
             } else {
                 return NULL;
             }
@@ -753,7 +776,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp
 }
 
 static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
 }
 
 static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
-    CFErrorRef *error;
+    CFErrorRef *error = NULL;
     BEGIN_SECKEYAPI(Boolean, false)
 
     result = key1->key->equal(*key2->key);
     BEGIN_SECKEYAPI(Boolean, false)
 
     result = key1->key->equal(*key2->key);
@@ -789,6 +812,8 @@ const SecKeyDescriptor kSecCDSAKeyDescriptor = {
     .copyOperationResult = SecCDSAKeyCopyOperationResult,
     .isEqual = SecCDSAKeyIsEqual,
     .setParameter = SecCDSAKeySetParameter,
     .copyOperationResult = SecCDSAKeyCopyOperationResult,
     .isEqual = SecCDSAKeyIsEqual,
     .setParameter = SecCDSAKeySetParameter,
+
+    .extraBytes = (sizeof(struct OpaqueSecKeyRef) > sizeof(struct __SecKey) ? (sizeof(struct OpaqueSecKeyRef) - sizeof(struct __SecKey)) : 0),
 };
 
 namespace Security {
 };
 
 namespace Security {
@@ -805,10 +830,35 @@ namespace Security {
 
             if (key->cdsaKey == NULL) {
                 // Create CDSA key from exported data of existing key.
 
             if (key->cdsaKey == NULL) {
                 // Create CDSA key from exported data of existing key.
-                CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
                 CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
                 CFRef<CFDictionaryRef> keyAttributes = SecKeyCopyAttributes(key);
-                if (keyData && keyAttributes) {
-                    key->cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL);
+                if (keyAttributes) {
+                    CFRef<CFDataRef> 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<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
+                                                                          sizeof(keys) / sizeof(*keys),
+                                                                          &kCFTypeDictionaryKeyCallBacks,
+                                                                          &kCFTypeDictionaryValueCallBacks);
+                        CFRef<CFArrayRef> identities;
+                        OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)identities.take());
+                        if (status == errSecSuccess) {
+                            for (int i = 0; i < CFArrayGetCount(identities); ++i) {
+                                CFRef<SecKeyRef> privateKey;
+                                if (SecIdentityCopyPrivateKey((SecIdentityRef)CFArrayGetValueAtIndex(identities, i), privateKey.take()) != errSecSuccess) {
+                                    continue;
+                                }
+                                CFRef<CFDictionaryRef> 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<KeyItem> pubItem, privItem;
     if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) {
         keychain = Keychain::optional(keychainRef);
     SecPointer<KeyItem> pubItem, privItem;
     if (((publicKeyAttr | privateKeyAttr) & CSSM_KEYATTR_PERMANENT) != 0) {
         keychain = Keychain::optional(keychainRef);
-        StLock<Mutex> _(*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<Mutex> _(keychain ? keychain->getKeychainMutex() : NULL);
+    KeyItem::createPair(keychain, algorithm, keySizeInBits, contextHandle, publicKeyUsage, publicKeyAttr,
+                        privateKeyUsage, privateKeyAttr, theAccess, pubItem, privItem);
 
        // Return the generated keys.
        if (publicKeyRef)
 
        // Return the generated keys.
        if (publicKeyRef)
@@ -904,13 +951,24 @@ SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey)
 // Private APIs
 //
 
 // Private APIs
 //
 
+static ModuleNexus<Mutex> gSecReturnedKeyCSPsMutex;
+static ModuleNexus<std::set<CssmClient::CSP>> gSecReturnedKeyCSPs;
+
 OSStatus
 SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
 {
     BEGIN_SECAPI
 
        SecPointer<KeyItem> keyItem(KeyItem::required(keyRef));
 OSStatus
 SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle)
 {
     BEGIN_SECAPI
 
        SecPointer<KeyItem> 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<Mutex> _(gSecReturnedKeyCSPsMutex());
+        gSecReturnedKeyCSPs().insert(returnedKeyCSP);
+    }
+       Required(cspHandle) = returnedKeyCSP->handle();
 
        END_SECAPI
 }
 
        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);
 
        // 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))
        {
        if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8))
        {
+        free(buffer);
                MacOSError::throwMe(errSecParam);
        }
 
                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;
        SecKeychainAttribute attributes[numToModify];
 
        int i = 0;
+    void *data = NULL;
 
        if (label != 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 = (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<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
                                if (NULL == attributes[i].data) {
                                        UnixError::throwMe(ENOMEM);
                                }
                                if (!CFStringGetCString(label_string, static_cast<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
+                    free(data);
                                        MacOSError::throwMe(errSecParam);
                                }
                        }
                                        MacOSError::throwMe(errSecParam);
                                }
                        }
@@ -1479,8 +1545,14 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t
 
        attrList.count = numToModify;
        attrList.attr = attributes;
 
        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);
 
     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);
     }
         // 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
        }
        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);
                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);
                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);
 
                char *appTagBuf = (char *)malloc(appTagBufLen);
 
-               if (label && !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8))
+               if (!label || !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8))
                        labelBuf[0]=0;
                        labelBuf[0]=0;
-               if (appLabel && !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8))
+               if (!appLabel || !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8))
                        appLabelBuf[0]=0;
                        appLabelBuf[0]=0;
-               if (appTag && !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8))
+               if (!appTag || !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8))
                        appTagBuf[0]=0;
 
                SecKeychainAttribute attrs[] = {
                        appTagBuf[0]=0;
 
                SecKeychainAttribute attrs[] = {
@@ -1918,6 +1997,7 @@ SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *
                CFRelease(ka);
                return sk;
        } else {
                CFRelease(ka);
                return sk;
        } else {
+        CFRelease(ka);
                if (error) {
                        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL);
                }
                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) {
     /* 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;
     }
 
         goto errOut;
     }
 
@@ -1995,7 +2077,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
 
     saltLen = CFDataGetLength(saltDictValue);
     if((salt = (uint8_t *) malloc(saltLen)) == NULL) {
 
     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;
     }
 
         goto errOut;
     }
 
@@ -2003,13 +2087,17 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
 
     passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1;
     if((thePassword = (char *) malloc(passwordLen)) == NULL) {
 
     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) {
         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;
     }
 
         goto errOut;
     }
 
@@ -2037,7 +2125,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
     }
 
     if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) {
     }
 
     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;
     }
 
         goto errOut;
     }