]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/SecKey.cpp
Security-59306.101.1.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecKey.cpp
index a80fe3be30355a1b342c6b2d98b2bc1c4eeb6a48..7ef6027bf481f69692e8523c84ffde40384840ba 100644 (file)
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include "SecKey.h"
-#include "SecKeyPriv.h"
-#include "SecItem.h"
-#include "SecItemPriv.h"
+#include <Security/SecKey.h>
+#include <Security/SecKeyPriv.h>
+#include <Security/SecKeyInternal.h>
+#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
 #include <libDER/asn1Types.h>
 #include <libDER/DER_Encode.h>
 #include <libDER/DER_Decode.h>
 #include <libDER/asn1Types.h>
 #include <libDER/DER_Encode.h>
 #include <libDER/DER_Decode.h>
 #include <Security/SecAsn1Types.h>
 #include <Security/SecAsn1Coder.h>
 #include <security_keychain/KeyItem.h>
 #include <Security/SecAsn1Types.h>
 #include <Security/SecAsn1Coder.h>
 #include <security_keychain/KeyItem.h>
+#include <security_utilities/casts.h>
 #include <CommonCrypto/CommonKeyDerivation.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>
 
 static OSStatus
 SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
 
 static OSStatus
 SecCDSAKeyInit(SecKeyRef key, const uint8_t *keyData, CFIndex keyDataLength, SecKeyEncoding encoding) {
-    key->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
-    key->key->initializeWithSecKeyRef(key);
+    CDSASecKey *cdsaKey = (CDSASecKey *)key;
+    cdsaKey->key = const_cast<KeyItem *>(reinterpret_cast<const KeyItem *>(keyData));
+    CDSASecKey::keyItem(key)->initializeWithSecKeyRef(key);
+    cdsaKey->credentialType = kSecCredentialTypeDefault;
+    cdsaKey->cdsaKeyMutex = new Mutex();
     return errSecSuccess;
 }
 
     return errSecSuccess;
 }
 
@@ -63,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.
 
     // 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<CDSASecKey *>(keyRef);
+    StMaybeLock<Mutex> cdsaMutex(cdsaKey->cdsaKeyMutex);
+
+    KeyItem *keyItem = static_cast<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 cdsaKey->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());
     {
         StMaybeLock<Mutex> _(keyItem->getMutexForObject());
-        keyItem = keyRef->key;
+        keyItem = static_cast<KeyItem *>(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;
         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;
@@ -83,6 +101,8 @@ SecCDSAKeyDestroy(SecKeyRef keyRef) {
         delete keyItem;
     }
 
         delete keyItem;
     }
 
+    delete cdsaKey->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.
 }
 
@@ -92,7 +112,7 @@ SecCDSAKeyGetBlockSize(SecKeyRef key) {
     CFErrorRef *error = NULL;
     BEGIN_SECKEYAPI(size_t,0)
 
     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:
     switch(keyHeader.algorithm())
     {
         case CSSM_ALGID_RSA:
@@ -141,7 +161,7 @@ SecCDSAKeyGetAlgorithmId(SecKeyRef key) {
     BEGIN_SECKEYAPI(CFIndex, 0)
 
     result = kSecNullAlgorithmID;
     BEGIN_SECKEYAPI(CFIndex, 0)
 
     result = kSecNullAlgorithmID;
-    switch (key->key->unverifiedKeyHeader().AlgorithmId) {
+    switch (CDSASecKey::keyItem(key)->unverifiedKeyHeader().AlgorithmId) {
         case CSSM_ALGID_RSA:
             result = kSecRSAAlgorithmID;
             break;
         case CSSM_ALGID_RSA:
             result = kSecRSAAlgorithmID;
             break;
@@ -161,7 +181,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.
 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,
     DERByte numUnused;
     DERSubjPubKeyInfo subjPubKey;
     if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
@@ -176,7 +196,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.
 
 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,
     DERSubjPubKeyInfo subjPubKey;
     if (DERParseSequence(&keyItem, DERNumSubjPubKeyInfoItemSpecs,
                          DERSubjPubKeyInfoItemSpecs,
@@ -214,10 +234,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);
         } 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);
         } 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,
         }
     }
     DERSize size = DERLengthOfEncodedSequence(ASN1_CONSTR_SEQUENCE, &subjPubKey,
@@ -240,7 +260,7 @@ static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serializatio
     CFErrorRef *error = NULL;
     BEGIN_SECKEYAPI(OSStatus, errSecSuccess)
 
     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()) {
     switch (header.algorithm()) {
         case CSSM_ALGID_RSA: {
             switch (header.keyClass()) {
@@ -248,7 +268,7 @@ static OSStatus SecCDSAKeyCopyPublicBytes(SecKeyRef key, CFDataRef *serializatio
                     CFRef<CFDataRef> privKeyData;
                     result = SecItemExport(key, kSecFormatOpenSSL, 0, NULL, privKeyData.take());
                     if (result == errSecSuccess) {
                     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) {
                         DERRSAKeyPair keyPair;
                         if (DERParseSequence(&keyItem, DERNumRSAKeyPairItemSpecs, DERRSAKeyPairItemSpecs,
                                              &keyPair, sizeof(keyPair)) == DR_Success) {
@@ -336,7 +356,7 @@ SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
     BEGIN_SECKEYAPI(CFDataRef, NULL)
 
     result = NULL;
     BEGIN_SECKEYAPI(CFDataRef, NULL)
 
     result = NULL;
-    const CssmKey::Header header = key->key->unverifiedKeyHeader();
+    const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
     CFRef<CFDataRef> keyData;
     switch (header.algorithm()) {
         case CSSM_ALGID_RSA:
     CFRef<CFDataRef> keyData;
     switch (header.algorithm()) {
         case CSSM_ALGID_RSA:
@@ -346,7 +366,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.
             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;
                 DERECPrivateKey privateKey;
                 DERECPrivateKeyPublicKey privateKeyPublicKey;
                 DERByte numUnused;
@@ -383,16 +403,16 @@ SecCDSAKeyCopyExternalRepresentation(SecKeyRef key, CFErrorRef *error) {
 
 static CFDataRef SecCDSAKeyCopyLabel(SecKeyRef key) {
     CFDataRef label = NULL;
 
 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;
         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);
         }
         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;
 }
     }
     return label;
 }
@@ -408,7 +428,7 @@ SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) {
 
     CFDictionarySetValue(dict, kSecClass, kSecClassKey);
 
 
     CFDictionarySetValue(dict, kSecClass, kSecClassKey);
 
-    const CssmKey::Header header = key->key->unverifiedKeyHeader();
+    const CssmKey::Header header = CDSASecKey::keyItem(key)->unverifiedKeyHeader();
     CFIndex sizeValue = header.LogicalKeySizeInBits;
     CFRef<CFNumberRef> sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue);
     CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits);
     CFIndex sizeValue = header.LogicalKeySizeInBits;
     CFRef<CFNumberRef> sizeInBits = CFNumberCreate(NULL, kCFNumberCFIndexType, &sizeValue);
     CFDictionarySetValue(dict, kSecAttrKeySizeInBits, sizeInBits);
@@ -473,7 +493,7 @@ SecCDSAKeyCopyAttributeDictionary(SecKeyRef key) {
 
     if (header.algorithm() == CSSM_ALGID_RSA && header.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY &&
         header.blobType() == CSSM_KEYBLOB_RAW) {
 
     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<DERByte *>(keyData.data()), keyData.length() };
         DERRSAPubKeyPKCS1 decodedKey;
         if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs,
         DERItem keyItem = { static_cast<DERByte *>(keyData.data()), keyData.length() };
         DERRSAPubKeyPKCS1 decodedKey;
         if (DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs,
@@ -499,11 +519,11 @@ 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;
-    KeyItem *key = privateKey->key;
+    KeyItem *key = CDSASecKey::keyItem(privateKey);
     CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(privateKey);
     if (label) {
         // Lookup public key in the database.
     CFRef<CFDataRef> label = SecCDSAKeyCopyLabel(privateKey);
     if (label) {
         // Lookup public key in the database.
@@ -516,18 +536,20 @@ static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
             Item publicKey = key->keychain()->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, uniqueId);
             result = reinterpret_cast<SecKeyRef>(publicKey->handle());
         }
             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
 }
 
         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 &baseAlgorithm, CSSM_ALGORITHMS &secondaryAlgorithm,
-                                            CSSM_ALGORITHMS &paddingAlgorithm) {
-    KeyItem *keyItem = key->key;
+                                            CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) {
+    KeyItem *keyItem = CDSASecKey::keyItem(key);
     CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass();
     baseAlgorithm = keyItem->key()->header().algorithm();
     switch (baseAlgorithm) {
     CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass();
     baseAlgorithm = keyItem->key()->header().algorithm();
     switch (baseAlgorithm) {
@@ -537,27 +559,35 @@ static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType o
                 if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_NONE;
                 if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureRaw)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_NONE;
+                    inputSizeLimit = 0;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = -11;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA1;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA1;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = 20;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA224;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA224)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA224;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = 224 / 8;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA256;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA256;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = 256 / 8;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA384;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA384;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = 384 / 8;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA512;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512)) {
                     secondaryAlgorithm = CSSM_ALGID_SHA512;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = 512 / 8;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) {
                     secondaryAlgorithm = CSSM_ALGID_MD5;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSASignatureDigestPKCS1v15MD5)) {
                     secondaryAlgorithm = CSSM_ALGID_MD5;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = 16;
                 } else {
                     return NULL;
                 }
                 } else {
                     return NULL;
                 }
@@ -566,12 +596,22 @@ static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType o
                 if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_NONE;
                 if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionRaw)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_NONE;
+                    inputSizeLimit = 0;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
                 } else if (CFEqual(algorithm, kSecKeyAlgorithmRSAEncryptionPKCS1)) {
                     secondaryAlgorithm = CSSM_ALGID_NONE;
                     paddingAlgorithm = CSSM_PADDING_PKCS1;
+                    inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0;
                 } 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;
             }
@@ -610,7 +650,7 @@ static KeyItem *SecCDSAKeyPrepareParameters(SecKeyRef key, SecKeyOperationType o
 
 static CFDataRef
 SecCDSAKeyCopyPaddedPlaintext(SecKeyRef key, CFDataRef plaintext, SecKeyAlgorithm algorithm) {
 
 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) {
     CFIndex plaintextLength = CFDataGetLength(plaintext);
     if ((algorithm == kSecKeyAlgorithmRSAEncryptionRaw || algorithm == kSecKeyAlgorithmRSASignatureRaw)
         && plaintextLength < blockSize) {
@@ -629,21 +669,30 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp
                                                CFArrayRef allAlgorithms, SecKeyOperationMode mode,
                                                CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
     BEGIN_SECKEYAPI(CFTypeRef, kCFNull)
                                                CFArrayRef allAlgorithms, SecKeyOperationMode mode,
                                                CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
     BEGIN_SECKEYAPI(CFTypeRef, kCFNull)
+    CFIndex inputSizeLimit = 0;
     CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm;
     CSSM_ALGORITHMS baseAlgorithm, secondaryAlgorithm, paddingAlgorithm;
-    KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm);
+    KeyItem *keyItem = SecCDSAKeyPrepareParameters(key, operation, algorithm, baseAlgorithm, secondaryAlgorithm, paddingAlgorithm, inputSizeLimit);
     if (keyItem == NULL) {
         // Operation/algorithm/key combination is not supported.
         return kCFNull;
     } else if (mode == kSecKeyOperationModeCheckIfSupported) {
         // Operation is supported and caller wants to just know that.
         return kCFBooleanTrue;
     if (keyItem == NULL) {
         // Operation/algorithm/key combination is not supported.
         return kCFNull;
     } else if (mode == kSecKeyOperationModeCheckIfSupported) {
         // Operation is supported and caller wants to just know that.
         return kCFBooleanTrue;
+    } else if (baseAlgorithm == CSSM_ALGID_RSA) {
+        if (inputSizeLimit <= 0) {
+            inputSizeLimit += SecCDSAKeyGetBlockSize(key);
+        }
+        if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) {
+            MacOSError::throwMe(errSecParam);
+        }
     }
 
     }
 
+    CDSASecKey *cdsaKey = static_cast<CDSASecKey *>(key);
     switch (operation) {
         case kSecKeyOperationTypeSign: {
             CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
             signContext.key(keyItem->key());
     switch (operation) {
         case kSecKeyOperationTypeSign: {
             CssmClient::Sign signContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
             signContext.key(keyItem->key());
-            signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault));
+            signContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, cdsaKey->credentialType));
             signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
             CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
             CssmAutoData signature(signContext.allocator());
             signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
             CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
             CssmAutoData signature(signContext.allocator());
@@ -654,7 +703,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp
         case kSecKeyOperationTypeVerify: {
             CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
             verifyContext.key(keyItem->key());
         case kSecKeyOperationTypeVerify: {
             CssmClient::Verify verifyContext(keyItem->csp(), baseAlgorithm, secondaryAlgorithm);
             verifyContext.key(keyItem->key());
-            verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, kSecCredentialTypeDefault));
+            verifyContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, cdsaKey->credentialType));
             verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
             CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
             verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam)));
             verifyContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
             CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
             verifyContext.verify(CssmData(CFDataRef(input)), CssmData(CFRef<CFDataRef>::check(in2, errSecParam)));
@@ -665,7 +714,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp
             CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm);
             encryptContext.key(keyItem->key());
             encryptContext.padding(paddingAlgorithm);
             CssmClient::Encrypt encryptContext(keyItem->csp(), baseAlgorithm);
             encryptContext.key(keyItem->key());
             encryptContext.padding(paddingAlgorithm);
-            encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, kSecCredentialTypeDefault));
+            encryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, cdsaKey->credentialType));
             CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
             CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator());
             size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get());
             CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
             CssmAutoData output(encryptContext.allocator()), remainingData(encryptContext.allocator());
             size_t length = encryptContext.encrypt(CssmData(CFDataRef(input)), output.get(), remainingData.get());
@@ -679,7 +728,7 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp
             CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm);
             decryptContext.key(keyItem->key());
             decryptContext.padding(paddingAlgorithm);
             CssmClient::Decrypt decryptContext(keyItem->csp(), baseAlgorithm);
             decryptContext.key(keyItem->key());
             decryptContext.padding(paddingAlgorithm);
-            decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault));
+            decryptContext.cred(keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, cdsaKey->credentialType));
             CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator());
             size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)),
                                                    output.get(), remainingData.get());
             CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator());
             size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)),
                                                    output.get(), remainingData.get());
@@ -730,11 +779,24 @@ static CFTypeRef SecCDSAKeyCopyOperationResult(SecKeyRef key, SecKeyOperationTyp
     END_SECKEYAPI
 }
 
     END_SECKEYAPI
 }
 
-static Boolean SecCDSAIsEqual(SecKeyRef key1, SecKeyRef key2) {
-    CFErrorRef *error;
+static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
+    CFErrorRef *error = NULL;
     BEGIN_SECKEYAPI(Boolean, false)
 
     BEGIN_SECKEYAPI(Boolean, false)
 
-    result = key1->key->equal(*key2->key);
+    result = CDSASecKey::keyItem(key1)->equal(*CDSASecKey::keyItem(key2));
+
+    END_SECKEYAPI
+}
+
+static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
+    BEGIN_SECKEYAPI(Boolean, false)
+
+    if (CFEqual(name, kSecUseAuthenticationUI)) {
+        static_cast<CDSASecKey *>(key)->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI;
+        result = true;
+    } else {
+        result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name);
+    }
 
     END_SECKEYAPI
 }
 
     END_SECKEYAPI
 }
@@ -752,7 +814,10 @@ const SecKeyDescriptor kSecCDSAKeyDescriptor = {
     .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
     .copyPublicKey = SecCDSAKeyCopyPublicKey,
     .copyOperationResult = SecCDSAKeyCopyOperationResult,
     .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
     .copyPublicKey = SecCDSAKeyCopyPublicKey,
     .copyOperationResult = SecCDSAKeyCopyOperationResult,
-    .isEqual = SecCDSAIsEqual,
+    .isEqual = SecCDSAKeyIsEqual,
+    .setParameter = SecCDSAKeySetParameter,
+
+    .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0),
 };
 
 namespace Security {
 };
 
 namespace Security {
@@ -767,22 +832,52 @@ namespace Security {
                 return static_cast<SecCFObject *>(key->key);
             }
 
                 return static_cast<SecCFObject *>(key->key);
             }
 
-            if (key->cdsaKey == NULL) {
+            CFRef<SecKeyRef> cdsaKey = SecKeyCopyAuxilliaryCDSAKeyForKey(key);
+            if (!cdsaKey) {
                 // Create CDSA key from exported data of existing key.
                 // 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, kSecUseDataProtectionKeychain, 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)) {
+                                    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<const uint8_t *>(this), 0, 0);
         }
 
         // You need to hold this key's MutexForObject when you run this
         void KeyItem::attachSecKeyRef() const {
             SecKeyRef key = SecKeyCreate(NULL, &kSecCDSAKeyDescriptor, reinterpret_cast<const uint8_t *>(this), 0, 0);
-            key->key->mWeakSecKeyRef = key;
+            CDSASecKey::keyItem(key)->mWeakSecKeyRef = key;
         }
 
     }
         }
 
     }
@@ -814,13 +909,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)
@@ -868,13 +960,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
 }
@@ -1040,13 +1143,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;
 }
 
 
 }
 
 
@@ -1403,6 +1512,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)
        {
@@ -1412,11 +1522,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);
                                }
                        }
@@ -1443,8 +1554,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;
 }
 
 
 }
 
 
@@ -1478,19 +1595,32 @@ 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, 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);
     }
         // Generate keys in iOS keychain.
         return SecKeyGeneratePair_ios(parameters, publicKey, privateKey);
     }
@@ -1787,18 +1917,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[] = {
@@ -1882,6 +2012,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);
                }
@@ -1943,7 +2074,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;
     }
 
@@ -1959,7 +2092,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;
     }
 
@@ -1967,13 +2102,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;
     }
 
@@ -1990,7 +2129,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
     } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
         algorithm = kCCPRFHmacAlgSHA512;
     } else {
     } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
         algorithm = kCCPRFHmacAlgSHA512;
     } else {
-        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+        if(error) {
+            *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+        }
         goto errOut;
     }
 
         goto errOut;
     }
 
@@ -1999,7 +2140,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;
     }
 
@@ -2007,7 +2150,9 @@ SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErr
         retval =  SecKeyCreateFromData(parameters, keyData, error);
         CFRelease(keyData);
     } else {
         retval =  SecKeyCreateFromData(parameters, keyData, error);
         CFRelease(keyData);
     } else {
-        *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+        if(error) {
+            *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+        }
     }
 
 errOut:
     }
 
 errOut:
@@ -2020,13 +2165,17 @@ errOut:
 CFDataRef
 SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *error)
 {
 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)
 {
     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;
 }
     return NULL;
 }