]> 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 2c2bd87dc794af2319898f50da7321d7589abef5..6fb96593e71eb45e30e4345e6681f93a7c96fb66 100644 (file)
 #include <Security/SecAsn1Types.h>
 #include <Security/SecAsn1Coder.h>
 #include <security_keychain/KeyItem.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>
@@ -55,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->cdsaKeyMutex = new Mutex();
     return errSecSuccess;
 }
 
@@ -64,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<Mutex> 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<Mutex> _(keyItem->getMutexForObject());
         keyItem = keyRef->key;
@@ -84,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.
 }
 
@@ -162,7 +178,7 @@ SecCDSAKeyGetAlgorithmId(SecKeyRef key) {
 static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo) {
     // First of all, consider x509 format and try to strip SubjPubKey envelope.  If it fails, do not panic
     // and export data as is.
-    DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo) }, pubKeyItem;
+    DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) }, pubKeyItem;
     DERByte numUnused;
     DERSubjPubKeyInfo subjPubKey;
     if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
@@ -177,7 +193,7 @@ static CFDataRef SecCDSAKeyCopyPublicKeyDataFromSubjectInfo(CFDataRef pubKeyInfo
 
 static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CFDataRef pubKeyInfo) {
     // First check, whether X509 pubkeyinfo is already present.  If not, add it according to the key type.
-    DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), CFDataGetLength(pubKeyInfo) };
+    DERItem keyItem = { (DERByte *)CFDataGetBytePtr(pubKeyInfo), int_cast<CFIndex, DERSize>(CFDataGetLength(pubKeyInfo)) };
     DERSubjPubKeyInfo subjPubKey;
     if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
                          DERSubjPubKeyInfoItemSpecs,
@@ -215,10 +231,10 @@ static CFDataRef SecCDSAKeyCopyPublicKeyDataWithSubjectInfo(CSSM_ALGORITHMS algo
             subjPubKey.algId.length = sizeof(oidECsecp256);
         } else if (keySizeInBits == 384) {
             subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp384);
-            subjPubKey.algId.length = sizeof(oidECsecp256);
+            subjPubKey.algId.length = sizeof(oidECsecp384);
         } if (keySizeInBits == 521) {
             subjPubKey.algId.data = const_cast<DERByte *>(oidECsecp521);
-            subjPubKey.algId.length = sizeof(oidECsecp256);
+            subjPubKey.algId.length = sizeof(oidECsecp521);
         }
     }
     DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
@@ -249,7 +265,7 @@ static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serializatio
                     CFRef<CFDataRef> privKeyData;
                     result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take());
                     if (result == errSecSuccess) {
-                        DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), CFDataGetLength(privKeyData) };
+                        DERItem keyItem = { (DERByte *)CFDataGetBytePtr(privKeyData), int_cast<CFIndex, DERSize>(CFDataGetLength(privKeyData)) };
                         DERRSAKeyPair keyPair;
                         if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs,
                                              &keyPair, sizeof(keyPair)) == DR_Success) {
@@ -347,7 +363,7 @@ SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
             MacOSError::check(SecItemExport(key, kSecFormatOpenSSL, 0, NULL, keyData.take()));
             if (header.keyClass() == CSSM_KEYCLASS_PRIVATE_KEY) {
                 // Convert DER format into x9.63 format, which is expected for exported key.
-                DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), CFDataGetLength(keyData) };
+                DERItem keyItem = { (DERByte *)CFDataGetBytePtr(keyData), int_cast<CFIndex, DERSize>(CFDataGetLength(keyData)) };
                 DERECPrivateKey privateKey;
                 DERECPrivateKeyPublicKey privateKeyPublicKey;
                 DERByte numUnused;
@@ -500,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;
@@ -517,15 +533,17 @@ static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
             Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId);
             result = reinterpret_cast<SecKeyRef>(publicKey->handle());
         }
-    } else if (key->publicKey()) {
-        KeyItem *publicKey = new KeyItem(key->publicKey());
+    }
+
+    if (result == NULL && key->publicKey()) {
+        SecPointer<KeyItem> publicKey(new KeyItem(key->publicKey()));
         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;
@@ -583,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;
             }
@@ -750,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);
@@ -786,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 {
@@ -802,10 +830,35 @@ namespace Security {
 
             if (key->cdsaKey == NULL) {
                 // Create CDSA key from exported data of existing key.
-                CFRef<CFDataRef> keyData = SecKeyCopyExternalRepresentation(key, NULL);
                 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);
+                    }
                 }
             }
 
@@ -847,13 +900,10 @@ static OSStatus SecKeyCreatePairInternal(
     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)
@@ -901,13 +951,24 @@ SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey)
 // 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));
-       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
 }
@@ -1073,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;
 }
 
 
@@ -1436,6 +1503,7 @@ static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef t
        SecKeychainAttribute attributes[numToModify];
 
        int i = 0;
+    void *data = NULL;
 
        if (label != NULL)
        {
@@ -1445,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<char *>(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) {
+                    free(data);
                                        MacOSError::throwMe(errSecParam);
                                }
                        }
@@ -1476,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;
 }
 
 
@@ -1511,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);
     }
@@ -1820,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[] = {
@@ -1915,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);
                }
@@ -1976,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;
     }
 
@@ -1992,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;
     }
 
@@ -2000,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;
     }
 
@@ -2023,7 +2114,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
     } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
         algorithm = kCCPRFHmacAlgSHA512;
     } else {
-        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+        if(error) {
+            *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+        }
         goto errOut;
     }
 
@@ -2032,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;
     }
 
@@ -2040,7 +2135,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
         retval =  SecKeyCreateFromData(parameters, keyData, error);
         CFRelease(keyData);
     } else {
-        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+        if(error) {
+            *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+        }
     }
 
 errOut:
@@ -2053,13 +2150,17 @@ errOut:
 CFDataRef
 SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
 {
-    *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+    if(error) {
+        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+    }
     return NULL;
 }
 
 SecKeyRef
 SecKeyUnwrapSymmetric(CFDataRef *keyToUnwrap, SecKeyRef unwrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
 {
-    *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+    if(error) {
+        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecUnimplemented, NULL);
+    }
     return NULL;
 }