#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>
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);
+ key->credentialType = kSecCredentialTypeDefault;
+ key->cdsaKeyMutex = new Mutex();
return errSecSuccess;
}
// 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;
delete keyItem;
}
+ delete keyRef->cdsaKeyMutex;
+
(void) kc; // Tell the compiler we're actually using this variable. At destruction time, it'll release the keychain.
}
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,
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,
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,
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) {
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;
#pragma clang diagnostic pop
static SecKeyRef SecCDSAKeyCopyPublicKey(SecKeyRef privateKey) {
- CFErrorRef *error;
+ CFErrorRef *error = NULL;
BEGIN_SECKEYAPI(SecKeyRef, NULL)
result = NULL;
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) {
+ CSSM_ALGORITHMS &paddingAlgorithm, CFIndex &inputSizeLimit) {
KeyItem *keyItem = key->key;
CSSM_KEYCLASS keyClass = keyItem->key()->header().keyClass();
baseAlgorithm = keyItem->key()->header().algorithm();
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;
+ inputSizeLimit = -11;
} 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;
+ inputSizeLimit = 224 / 8;
} 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;
+ inputSizeLimit = 384 / 8;
} 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;
+ inputSizeLimit = 16;
} else {
return NULL;
}
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;
+ inputSizeLimit = operation == kSecKeyOperationTypeEncrypt ? -11 : 0;
} 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;
}
CFArrayRef allAlgorithms, SecKeyOperationMode mode,
CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
BEGIN_SECKEYAPI(CFTypeRef, kCFNull)
+ CFIndex inputSizeLimit = 0;
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;
+ } else if (baseAlgorithm == CSSM_ALGID_RSA) {
+ if (inputSizeLimit <= 0) {
+ inputSizeLimit += SecCDSAKeyGetBlockSize(key);
+ }
+ if (CFDataGetLength((CFDataRef)in1) > inputSizeLimit) {
+ MacOSError::throwMe(errSecParam);
+ }
}
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, key->credentialType));
signContext.add(CSSM_ATTRIBUTE_PADDING, paddingAlgorithm);
CFRef<CFDataRef> input = SecCDSAKeyCopyPaddedPlaintext(key, CFRef<CFDataRef>::check(in1, errSecParam), algorithm);
CssmAutoData signature(signContext.allocator());
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, key->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)));
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, key->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());
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, key->credentialType));
CssmAutoData output(decryptContext.allocator()), remainingData(decryptContext.allocator());
size_t length = decryptContext.decrypt(CssmData(CFRef<CFDataRef>::check(in1, errSecParam)),
output.get(), remainingData.get());
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)
result = key1->key->equal(*key2->key);
END_SECKEYAPI
}
+static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
+ BEGIN_SECKEYAPI(Boolean, false)
+
+ if (CFEqual(name, kSecUseAuthenticationUI)) {
+ key->credentialType = CFEqual(value, kSecUseAuthenticationUIAllow) ? kSecCredentialTypeDefault : kSecCredentialTypeNoUI;
+ result = true;
+ } else {
+ result = SecError(errSecUnimplemented, error, CFSTR("Unsupported parameter '%@' for SecKeyCDSASetParameter"), name);
+ }
+
+ END_SECKEYAPI
+}
+
const SecKeyDescriptor kSecCDSAKeyDescriptor = {
.version = kSecKeyDescriptorVersion,
.name = "CDSAKey",
.copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
.copyPublicKey = SecCDSAKeyCopyPublicKey,
.copyOperationResult = SecCDSAKeyCopyOperationResult,
- .isEqual = SecCDSAIsEqual,
+ .isEqual = SecCDSAKeyIsEqual,
+ .setParameter = SecCDSAKeySetParameter,
+
+ .extraBytes = (sizeof(struct OpaqueSecKeyRef) > sizeof(struct __SecKey) ? (sizeof(struct OpaqueSecKeyRef) - sizeof(struct __SecKey)) : 0),
};
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);
+ }
}
}
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)
// 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
}
// 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;
}
SecKeychainAttribute attributes[numToModify];
int i = 0;
+ void *data = NULL;
if (label != NULL)
{
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);
}
}
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;
}
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);
}
}
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[] = {
CFRelease(ka);
return sk;
} else {
+ CFRelease(ka);
if (error) {
*error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, 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;
}
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;
}
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;
}
} else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) {
algorithm = kCCPRFHmacAlgSHA512;
} else {
- *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+ if(error) {
+ *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL);
+ }
goto errOut;
}
}
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;
}
retval = SecKeyCreateFromData(parameters, keyData, error);
CFRelease(keyData);
} else {
- *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+ if(error) {
+ *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL);
+ }
}
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;
}