#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"
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, CFIndex &inputSizeLimit) {
KeyItem *keyItem = key->key;
} 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;
}
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;
}