#include <Security/SecAsn1Types.h>
#include <Security/SecAsn1Coder.h>
#include <security_keychain/KeyItem.h>
+#include <security_utilities/casts.h>
#include <CommonCrypto/CommonKeyDerivation.h>
#include "SecBridge.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;
return errSecSuccess;
}
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;
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) {
+static Boolean SecCDSAKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
CFErrorRef *error;
BEGIN_SECKEYAPI(Boolean, false)
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,
};
namespace Security {
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 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;
}
}
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;
}