X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_keychain/lib/SecKey.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/SecKey.cpp b/Security/libsecurity_keychain/lib/SecKey.cpp deleted file mode 100644 index d11deeb1..00000000 --- a/Security/libsecurity_keychain/lib/SecKey.cpp +++ /dev/null @@ -1,2266 +0,0 @@ -/* - * Copyright (c) 2002-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#include "SecKey.h" -#include "SecKeyPriv.h" -#include "SecItem.h" -#include "SecItemPriv.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "SecBridge.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include "SecImportExportCrypto.h" - -CFTypeID -SecKeyGetTypeID(void) -{ - BEGIN_SECAPI - - return gTypes().KeyItem.typeID; - - END_SECAPI1(_kCFRuntimeNotATypeID) -} - -static OSStatus SecKeyCreatePairInternal( - SecKeychainRef keychainRef, - CSSM_ALGORITHMS algorithm, - uint32 keySizeInBits, - CSSM_CC_HANDLE contextHandle, - CSSM_KEYUSE publicKeyUsage, - uint32 publicKeyAttr, - CSSM_KEYUSE privateKeyUsage, - uint32 privateKeyAttr, - SecAccessRef initialAccess, - SecKeyRef* publicKeyRef, - SecKeyRef* privateKeyRef) -{ - BEGIN_SECAPI - - Keychain keychain = Keychain::optional(keychainRef); - SecPointer theAccess(initialAccess ? Access::required(initialAccess) : new Access("")); - SecPointer pubItem, privItem; - - Mutex *keychainMutex = keychain->getKeychainMutex(); - StLock _(*keychainMutex); - - KeyItem::createPair(keychain, - algorithm, - keySizeInBits, - contextHandle, - publicKeyUsage, - publicKeyAttr, - privateKeyUsage, - privateKeyAttr, - theAccess, - pubItem, - privItem); - - // Return the generated keys. - if (publicKeyRef) - *publicKeyRef = pubItem->handle(); - if (privateKeyRef) - *privateKeyRef = privItem->handle(); - - END_SECAPI -} - -OSStatus -SecKeyCreatePair( - SecKeychainRef keychainRef, - CSSM_ALGORITHMS algorithm, - uint32 keySizeInBits, - CSSM_CC_HANDLE contextHandle, - CSSM_KEYUSE publicKeyUsage, - uint32 publicKeyAttr, - CSSM_KEYUSE privateKeyUsage, - uint32 privateKeyAttr, - SecAccessRef initialAccess, - SecKeyRef* publicKeyRef, - SecKeyRef* privateKeyRef) -{ - OSStatus result = SecKeyCreatePairInternal(keychainRef, algorithm, keySizeInBits, contextHandle, publicKeyUsage, - publicKeyAttr, privateKeyUsage, privateKeyAttr, initialAccess, publicKeyRef, privateKeyRef); - - return result; -} - - - -OSStatus -SecKeyGetCSSMKey(SecKeyRef key, const CSSM_KEY **cssmKey) -{ - BEGIN_SECAPI - - Required(cssmKey) = KeyItem::required(key)->key(); - - END_SECAPI -} - - -// -// Private APIs -// - -OSStatus -SecKeyGetCSPHandle(SecKeyRef keyRef, CSSM_CSP_HANDLE *cspHandle) -{ - BEGIN_SECAPI - - SecPointer keyItem(KeyItem::required(keyRef)); - Required(cspHandle) = keyItem->csp()->handle(); - - END_SECAPI -} - -/* deprecated as of 10.8 */ -OSStatus -SecKeyGetAlgorithmID(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) -{ - BEGIN_SECAPI - - SecPointer keyItem(KeyItem::required(keyRef)); - Required(algid) = &keyItem->algorithmIdentifier(); - - END_SECAPI -} - -/* new for 10.8 */ -CFIndex -SecKeyGetAlgorithmId(SecKeyRef key) -{ - const CSSM_KEY *cssmKey; - - if (SecKeyGetCSSMKey(key, &cssmKey) != errSecSuccess) - return kSecNullAlgorithmID; - - switch (cssmKey->KeyHeader.AlgorithmId) { - case CSSM_ALGID_RSA: - return kSecRSAAlgorithmID; - case CSSM_ALGID_DSA: - return kSecDSAAlgorithmID; - case CSSM_ALGID_ECDSA: - return kSecECDSAAlgorithmID; - default: - assert(0); /* other algorithms TBA */ - return kSecNullAlgorithmID; - } -} - -OSStatus -SecKeyGetStrengthInBits(SecKeyRef keyRef, const CSSM_X509_ALGORITHM_IDENTIFIER *algid, unsigned int *strength) -{ - BEGIN_SECAPI - - SecPointer keyItem(KeyItem::required(keyRef)); - Required(strength) = keyItem->strengthInBits(algid); - - END_SECAPI -} - -OSStatus -SecKeyGetCredentials( - SecKeyRef keyRef, - CSSM_ACL_AUTHORIZATION_TAG operation, - SecCredentialType credentialType, - const CSSM_ACCESS_CREDENTIALS **outCredentials) -{ - BEGIN_SECAPI - - SecPointer keyItem(KeyItem::required(keyRef)); - Required(outCredentials) = keyItem->getCredentials(operation, credentialType); - - END_SECAPI -} - -OSStatus -SecKeyImportPair( - SecKeychainRef keychainRef, - const CSSM_KEY *publicCssmKey, - const CSSM_KEY *privateCssmKey, - SecAccessRef initialAccess, - SecKeyRef* publicKey, - SecKeyRef* privateKey) -{ - BEGIN_SECAPI - - Keychain keychain = Keychain::optional(keychainRef); - SecPointer theAccess(initialAccess ? Access::required(initialAccess) : new Access("")); - SecPointer pubItem, privItem; - - KeyItem::importPair(keychain, - Required(publicCssmKey), - Required(privateCssmKey), - theAccess, - pubItem, - privItem); - - // Return the generated keys. - if (publicKey) - *publicKey = pubItem->handle(); - if (privateKey) - *privateKey = privItem->handle(); - - END_SECAPI -} - -static OSStatus -SecKeyGenerateWithAttributes( - SecKeychainAttributeList* attrList, - SecKeychainRef keychainRef, - CSSM_ALGORITHMS algorithm, - uint32 keySizeInBits, - CSSM_CC_HANDLE contextHandle, - CSSM_KEYUSE keyUsage, - uint32 keyAttr, - SecAccessRef initialAccess, - SecKeyRef* keyRef) -{ - BEGIN_SECAPI - - Keychain keychain; - SecPointer theAccess; - - if (keychainRef) - keychain = KeychainImpl::required(keychainRef); - if (initialAccess) - theAccess = Access::required(initialAccess); - - SecPointer item = KeyItem::generateWithAttributes(attrList, - keychain, - algorithm, - keySizeInBits, - contextHandle, - keyUsage, - keyAttr, - theAccess); - - // Return the generated key. - if (keyRef) - *keyRef = item->handle(); - - END_SECAPI -} - -OSStatus -SecKeyGenerate( - SecKeychainRef keychainRef, - CSSM_ALGORITHMS algorithm, - uint32 keySizeInBits, - CSSM_CC_HANDLE contextHandle, - CSSM_KEYUSE keyUsage, - uint32 keyAttr, - SecAccessRef initialAccess, - SecKeyRef* keyRef) -{ - return SecKeyGenerateWithAttributes(NULL, - keychainRef, algorithm, keySizeInBits, - contextHandle, keyUsage, keyAttr, - initialAccess, keyRef); -} - - -/* new in 10.6 */ -/* Create a key from supplied data and parameters */ -SecKeyRef -SecKeyCreate(CFAllocatorRef allocator, - const SecKeyDescriptor *keyClass, - const uint8_t *keyData, - CFIndex keyDataLength, - SecKeyEncoding encoding) -{ - SecKeyRef keyRef = NULL; - OSStatus __secapiresult; - try { - //FIXME: needs implementation - - __secapiresult=errSecSuccess; - } - catch (const MacOSError &err) { __secapiresult=err.osStatus(); } - catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } - catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } - catch (...) { __secapiresult=errSecInternalComponent; } - return keyRef; -} - -/* new in 10.6 */ -/* Generate a floating key reference from a CSSM_KEY */ -OSStatus -SecKeyCreateWithCSSMKey(const CSSM_KEY *cssmKey, - SecKeyRef *keyRef) -{ - BEGIN_SECAPI - - Required(cssmKey); - if(cssmKey->KeyData.Length == 0){ - MacOSError::throwMe(errSecInvalidAttributeKeyLength); - } - if(cssmKey->KeyData.Data == NULL){ - MacOSError::throwMe(errSecInvalidPointer); - } - CssmClient::CSP csp(cssmKey->KeyHeader.CspId); - CssmClient::Key key(csp, *cssmKey); - KeyItem *item = new KeyItem(key); - - // Return the generated key. - if (keyRef) - *keyRef = item->handle(); - - END_SECAPI -} - - - -static u_int32_t ConvertCFStringToInteger(CFStringRef ref) -{ - if (ref == NULL) - { - return 0; - } - - // figure out the size of the string - CFIndex numChars = CFStringGetMaximumSizeForEncoding(CFStringGetLength(ref), kCFStringEncodingUTF8); - char buffer[numChars]; - if (!CFStringGetCString(ref, buffer, numChars, kCFStringEncodingUTF8)) - { - MacOSError::throwMe(errSecParam); - } - - return atoi(buffer); -} - - - -static OSStatus CheckAlgorithmType(CFDictionaryRef parameters, CSSM_ALGORITHMS &algorithms) -{ - // figure out the algorithm to use - CFStringRef ktype = (CFStringRef) CFDictionaryGetValue(parameters, kSecAttrKeyType); - if (ktype == NULL) - { - return errSecParam; - } - - if (CFEqual(ktype, kSecAttrKeyTypeRSA)) { - algorithms = CSSM_ALGID_RSA; - return errSecSuccess; - } else if(CFEqual(ktype, kSecAttrKeyTypeECDSA) || - CFEqual(ktype, kSecAttrKeyTypeEC)) { - algorithms = CSSM_ALGID_ECDSA; - return errSecSuccess; - } else if(CFEqual(ktype, kSecAttrKeyTypeAES)) { - algorithms = CSSM_ALGID_AES; - return errSecSuccess; - } else if(CFEqual(ktype, kSecAttrKeyType3DES)) { - algorithms = CSSM_ALGID_3DES; - return errSecSuccess; - } else { - return errSecUnsupportedAlgorithm; - } -} - - - -static OSStatus GetKeySize(CFDictionaryRef parameters, CSSM_ALGORITHMS algorithms, uint32 &keySizeInBits) -{ - - // get the key size and check it for validity - CFTypeRef ref = CFDictionaryGetValue(parameters, kSecAttrKeySizeInBits); - - keySizeInBits = kSecDefaultKeySize; - - CFTypeID bitSizeType = CFGetTypeID(ref); - if (bitSizeType == CFStringGetTypeID()) - keySizeInBits = ConvertCFStringToInteger((CFStringRef) ref); - else if (bitSizeType == CFNumberGetTypeID()) - CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &keySizeInBits); - else return errSecParam; - - - switch (algorithms) { - case CSSM_ALGID_ECDSA: - if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecp256r1; - if(keySizeInBits == kSecp192r1 || keySizeInBits == kSecp256r1 || keySizeInBits == kSecp384r1 || keySizeInBits == kSecp521r1 ) return errSecSuccess; - break; - case CSSM_ALGID_RSA: - if(keySizeInBits % 8) return errSecParam; - if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = 2048; - if(keySizeInBits >= kSecRSAMin && keySizeInBits <= kSecRSAMax) return errSecSuccess; - break; - case CSSM_ALGID_AES: - if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSecAES128; - if(keySizeInBits == kSecAES128 || keySizeInBits == kSecAES192 || keySizeInBits == kSecAES256) return errSecSuccess; - break; - case CSSM_ALGID_3DES: - if(keySizeInBits == kSecDefaultKeySize) keySizeInBits = kSec3DES192; - if(keySizeInBits == kSec3DES192) return errSecSuccess; - break; - default: - break; - } - return errSecParam; -} - - - -enum AttributeType -{ - kStringType, - kBooleanType, - kIntegerType -}; - - - -struct ParameterAttribute -{ - const CFTypeRef *name; - AttributeType type; -}; - - - -static ParameterAttribute gAttributes[] = -{ - { - &kSecAttrLabel, - kStringType - }, - { - &kSecAttrIsPermanent, - kBooleanType - }, - { - &kSecAttrApplicationTag, - kStringType - }, - { - &kSecAttrEffectiveKeySize, - kBooleanType - }, - { - &kSecAttrCanEncrypt, - kBooleanType - }, - { - &kSecAttrCanDecrypt, - kBooleanType - }, - { - &kSecAttrCanDerive, - kBooleanType - }, - { - &kSecAttrCanSign, - kBooleanType - }, - { - &kSecAttrCanVerify, - kBooleanType - }, - { - &kSecAttrCanUnwrap, - kBooleanType - } -}; - -const int kNumberOfAttributes = sizeof(gAttributes) / sizeof(ParameterAttribute); - -static OSStatus ScanDictionaryForParameters(CFDictionaryRef parameters, void* attributePointers[]) -{ - int i; - for (i = 0; i < kNumberOfAttributes; ++i) - { - // see if the corresponding tag exists in the dictionary - CFTypeRef value = CFDictionaryGetValue(parameters, *(gAttributes[i].name)); - if (value != NULL) - { - switch (gAttributes[i].type) - { - case kStringType: - // just return the value - *(CFTypeRef*) attributePointers[i] = value; - break; - - case kBooleanType: - { - CFBooleanRef bRef = (CFBooleanRef) value; - *(bool*) attributePointers[i] = CFBooleanGetValue(bRef); - } - break; - - case kIntegerType: - { - CFNumberRef nRef = (CFNumberRef) value; - CFNumberGetValue(nRef, kCFNumberSInt32Type, attributePointers[i]); - } - break; - } - } - } - - return errSecSuccess; -} - - - -static OSStatus GetKeyParameters(CFDictionaryRef parameters, int keySize, bool isPublic, CSSM_KEYUSE &keyUse, uint32 &attrs, CFTypeRef &labelRef, CFDataRef &applicationTagRef) -{ - // establish default values - labelRef = NULL; - bool isPermanent = false; - applicationTagRef = NULL; - CFTypeRef effectiveKeySize = NULL; - bool canDecrypt = isPublic ? false : true; - bool canEncrypt = !canDecrypt; - bool canDerive = true; - bool canSign = isPublic ? false : true; - bool canVerify = !canSign; - bool canUnwrap = isPublic ? false : true; - attrs = CSSM_KEYATTR_EXTRACTABLE; - keyUse = 0; - - void* attributePointers[] = {&labelRef, &isPermanent, &applicationTagRef, &effectiveKeySize, &canEncrypt, &canDecrypt, - &canDerive, &canSign, &canVerify, &canUnwrap}; - - // look for modifiers in the general dictionary - OSStatus result = ScanDictionaryForParameters(parameters, attributePointers); - if (result != errSecSuccess) - { - return result; - } - - // see if we have anything which modifies the defaults - CFTypeRef key; - if (isPublic) - { - key = kSecPublicKeyAttrs; - } - else - { - key = kSecPrivateKeyAttrs; - } - - CFTypeRef dType = CFDictionaryGetValue(parameters, key); - if (dType != NULL) - { - // this had better be a dictionary - if (CFGetTypeID(dType) != CFDictionaryGetTypeID()) - { - return errSecParam; - } - - // pull any additional parameters out of this dictionary - result = ScanDictionaryForParameters((CFDictionaryRef)dType, attributePointers); - if (result != errSecSuccess) - { - return result; - } - } - - // figure out the key usage - keyUse = 0; - if (canDecrypt) - { - keyUse |= CSSM_KEYUSE_DECRYPT; - } - - if (canEncrypt) - { - keyUse |= CSSM_KEYUSE_ENCRYPT; - } - - if (canDerive) - { - keyUse |= CSSM_KEYUSE_DERIVE; - } - - if (canSign) - { - keyUse |= CSSM_KEYUSE_SIGN; - } - - if (canVerify) - { - keyUse |= CSSM_KEYUSE_VERIFY; - } - - if (canUnwrap) - { - keyUse |= CSSM_KEYUSE_UNWRAP; - } - - // public key is always extractable; - // private key is extractable by default unless explicitly set to false - CFTypeRef value = NULL; - if (!isPublic && CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value) && value) - { - Boolean keyIsExtractable = CFEqual(kCFBooleanTrue, value); - if (!keyIsExtractable) - attrs = 0; - } - - attrs |= CSSM_KEYATTR_PERMANENT; - - return errSecSuccess; -} - - - -static OSStatus MakeKeyGenParametersFromDictionary(CFDictionaryRef parameters, - CSSM_ALGORITHMS &algorithms, - uint32 &keySizeInBits, - CSSM_KEYUSE &publicKeyUse, - uint32 &publicKeyAttr, - CFTypeRef &publicKeyLabelRef, - CFDataRef &publicKeyAttributeTagRef, - CSSM_KEYUSE &privateKeyUse, - uint32 &privateKeyAttr, - CFTypeRef &privateKeyLabelRef, - CFDataRef &privateKeyAttributeTagRef, - SecAccessRef &initialAccess) -{ - OSStatus result; - - result = CheckAlgorithmType(parameters, algorithms); - if (result != errSecSuccess) - { - return result; - } - - result = GetKeySize(parameters, algorithms, keySizeInBits); - if (result != errSecSuccess) - { - return result; - } - - result = GetKeyParameters(parameters, keySizeInBits, false, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef); - if (result != errSecSuccess) - { - return result; - } - - result = GetKeyParameters(parameters, keySizeInBits, true, publicKeyUse, publicKeyAttr, publicKeyLabelRef, publicKeyAttributeTagRef); - if (result != errSecSuccess) - { - return result; - } - - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&initialAccess)) - { - initialAccess = NULL; - } - else if (SecAccessGetTypeID() != CFGetTypeID(initialAccess)) - { - return errSecParam; - } - - return errSecSuccess; -} - - - -static OSStatus SetKeyLabelAndTag(SecKeyRef keyRef, CFTypeRef label, CFDataRef tag) -{ - int numToModify = 0; - if (label != NULL) - { - numToModify += 1; - } - - if (tag != NULL) - { - numToModify += 1; - } - - if (numToModify == 0) - { - return errSecSuccess; - } - - SecKeychainAttributeList attrList; - SecKeychainAttribute attributes[numToModify]; - - int i = 0; - - if (label != NULL) - { - if (CFStringGetTypeID() == CFGetTypeID(label)) { - CFStringRef label_string = static_cast(label); - attributes[i].tag = kSecKeyPrintName; - 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); - if (NULL == attributes[i].data) { - UnixError::throwMe(ENOMEM); - } - if (!CFStringGetCString(label_string, static_cast(attributes[i].data), buffer_length, kCFStringEncodingUTF8)) { - MacOSError::throwMe(errSecParam); - } - } - attributes[i].length = (UInt32)strlen(static_cast(attributes[i].data)); - } else if (CFDataGetTypeID() == CFGetTypeID(label)) { - // 10.6 bug compatibility - CFDataRef label_data = static_cast(label); - attributes[i].tag = kSecKeyLabel; - attributes[i].data = (void*) CFDataGetBytePtr(label_data); - attributes[i].length = (UInt32)CFDataGetLength(label_data); - } else { - MacOSError::throwMe(errSecParam); - } - i++; - } - - if (tag != NULL) - { - attributes[i].tag = kSecKeyApplicationTag; - attributes[i].data = (void*) CFDataGetBytePtr(tag); - attributes[i].length = (UInt32)CFDataGetLength(tag); - i++; - } - - attrList.count = numToModify; - attrList.attr = attributes; - - return SecKeychainItemModifyAttributesAndData((SecKeychainItemRef) keyRef, &attrList, 0, NULL); -} - - - -/* new in 10.6 */ -/* Generate a private/public keypair. */ -OSStatus -SecKeyGeneratePair( - CFDictionaryRef parameters, - SecKeyRef *publicKey, - SecKeyRef *privateKey) -{ - BEGIN_SECAPI - - Required(parameters); - Required(publicKey); - Required(privateKey); - - CSSM_ALGORITHMS algorithms; - uint32 keySizeInBits; - CSSM_KEYUSE publicKeyUse; - uint32 publicKeyAttr; - CFTypeRef publicKeyLabelRef; - CFDataRef publicKeyAttributeTagRef; - CSSM_KEYUSE privateKeyUse; - uint32 privateKeyAttr; - CFTypeRef privateKeyLabelRef; - CFDataRef privateKeyAttributeTagRef; - SecAccessRef initialAccess; - SecKeychainRef keychain; - - OSStatus result = MakeKeyGenParametersFromDictionary(parameters, algorithms, keySizeInBits, publicKeyUse, publicKeyAttr, publicKeyLabelRef, - publicKeyAttributeTagRef, privateKeyUse, privateKeyAttr, privateKeyLabelRef, privateKeyAttributeTagRef, - initialAccess); - - if (result != errSecSuccess) - { - return result; - } - - // verify keychain parameter - keychain = NULL; - if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain)) - keychain = NULL; - else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) - keychain = NULL; - - // do the key generation - result = SecKeyCreatePair(keychain, algorithms, keySizeInBits, 0, publicKeyUse, publicKeyAttr, privateKeyUse, privateKeyAttr, initialAccess, publicKey, privateKey); - if (result != errSecSuccess) - { - return result; - } - - // set the label and print attributes on the keys - SetKeyLabelAndTag(*publicKey, publicKeyLabelRef, publicKeyAttributeTagRef); - SetKeyLabelAndTag(*privateKey, privateKeyLabelRef, privateKeyAttributeTagRef); - return result; - - END_SECAPI -} - -/* new in 10.6 */ -OSStatus -SecKeyRawSign( - SecKeyRef key, - SecPadding padding, - const uint8_t *dataToSign, - size_t dataToSignLen, - uint8_t *sig, - size_t *sigLen) -{ - BEGIN_SECAPI - - Required(key); - SecPointer keyItem(KeyItem::required(key)); - CSSM_DATA dataInput; - - dataInput.Data = (uint8_t*) dataToSign; - dataInput.Length = dataToSignLen; - - CSSM_DATA output; - output.Data = sig; - output.Length = *sigLen; - - const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault); - - keyItem->RawSign(padding, dataInput, credentials, output); - *sigLen = output.Length; - - END_SECAPI -} - -OSStatus SecKeyRawVerifyOSX( - SecKeyRef key, /* Public key */ - SecPadding padding, /* kSecPaddingNone or kSecPaddingPKCS1 */ - const uint8_t *signedData, /* signature over this data */ - size_t signedDataLen, /* length of dataToSign */ - const uint8_t *sig, /* signature */ - size_t sigLen) -{ - return SecKeyRawVerify(key,padding,signedData,signedDataLen,sig,sigLen); -} - -/* new in 10.6 */ -OSStatus -SecKeyRawVerify( - SecKeyRef key, - SecPadding padding, - const uint8_t *signedData, - size_t signedDataLen, - const uint8_t *sig, - size_t sigLen) -{ - BEGIN_SECAPI - - Required(key); - - SecPointer keyItem(KeyItem::required(key)); - CSSM_DATA dataInput; - - dataInput.Data = (uint8_t*) signedData; - dataInput.Length = signedDataLen; - - CSSM_DATA signature; - signature.Data = (uint8_t*) sig; - signature.Length = sigLen; - - const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ANY, kSecCredentialTypeDefault); - - keyItem->RawVerify(padding, dataInput, credentials, signature); - - END_SECAPI -} - -/* new in 10.6 */ -OSStatus -SecKeyEncrypt( - SecKeyRef key, - SecPadding padding, - const uint8_t *plainText, - size_t plainTextLen, - uint8_t *cipherText, - size_t *cipherTextLen) -{ - BEGIN_SECAPI - - SecPointer keyItem(KeyItem::required(key)); - CSSM_DATA inData, outData; - inData.Data = (uint8*) plainText; - inData.Length = plainTextLen; - outData.Data = cipherText; - outData.Length = *cipherTextLen; - - const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_ENCRYPT, kSecCredentialTypeDefault); - - keyItem->Encrypt(padding, inData, credentials, outData); - *cipherTextLen = outData.Length; - - END_SECAPI -} - -/* new in 10.6 */ -OSStatus -SecKeyDecrypt( - SecKeyRef key, /* Private key */ - SecPadding padding, /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */ - const uint8_t *cipherText, - size_t cipherTextLen, /* length of cipherText */ - uint8_t *plainText, - size_t *plainTextLen) /* IN/OUT */ -{ - BEGIN_SECAPI - - SecPointer keyItem(KeyItem::required(key)); - CSSM_DATA inData, outData; - inData.Data = (uint8*) cipherText; - inData.Length = cipherTextLen; - outData.Data = plainText; - outData.Length = *plainTextLen; - - const AccessCredentials* credentials = keyItem->getCredentials(CSSM_ACL_AUTHORIZATION_DECRYPT, kSecCredentialTypeDefault); - - keyItem->Decrypt(padding, inData, credentials, outData); - *plainTextLen = outData.Length; - - END_SECAPI -} - -/* new in 10.6 */ -size_t -SecKeyGetBlockSize(SecKeyRef key) -{ - size_t blockSize = 0; - OSStatus __secapiresult; - try { - CSSM_KEY cssmKey = KeyItem::required(key)->key(); - switch(cssmKey.KeyHeader.AlgorithmId) - { - case CSSM_ALGID_RSA: - case CSSM_ALGID_DSA: - blockSize = cssmKey.KeyHeader.LogicalKeySizeInBits / 8; - break; - case CSSM_ALGID_ECDSA: - { - /* Block size is up to 9 bytes of DER encoding for sequence of 2 integers, - * plus both coordinates for the point used */ - #define ECDSA_KEY_SIZE_IN_BYTES(bits) (((bits) + 7) / 8) - #define ECDSA_MAX_COORD_SIZE_IN_BYTES(n) (ECDSA_KEY_SIZE_IN_BYTES(n) + 1) - size_t coordSize = ECDSA_MAX_COORD_SIZE_IN_BYTES(cssmKey.KeyHeader.LogicalKeySizeInBits); - assert(coordSize < 256); /* size must fit in a byte for DER */ - size_t coordDERLen = (coordSize > 127) ? 2 : 1; - size_t coordLen = 1 + coordDERLen + coordSize; - - size_t pointSize = 2 * coordLen; - assert(pointSize < 256); /* size must fit in a byte for DER */ - size_t pointDERLen = (pointSize > 127) ? 2 : 1; - size_t pointLen = 1 + pointDERLen + pointSize; - - blockSize = pointLen; - } - break; - case CSSM_ALGID_AES: - blockSize = 16; /* all AES keys use 128-bit blocks */ - break; - case CSSM_ALGID_DES: - case CSSM_ALGID_3DES_3KEY: - blockSize = 8; /* all DES keys use 64-bit blocks */ - break; - default: - assert(0); /* some other key algorithm */ - blockSize = 16; /* FIXME: revisit this */ - break; - } - __secapiresult=errSecSuccess; - } - catch (const MacOSError &err) { __secapiresult=err.osStatus(); } - catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } - catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } - catch (...) { __secapiresult=errSecInternalComponent; } - return blockSize; -} - - -/* - M4 Additions -*/ - -static CFTypeRef -utilGetStringFromCFDict(CFDictionaryRef parameters, CFTypeRef key, CFTypeRef defaultValue) -{ - CFTypeRef value = CFDictionaryGetValue(parameters, key); - if (value != NULL) return value; - return defaultValue; -} - -static uint32_t -utilGetNumberFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t defaultValue) -{ - uint32_t integerValue; - CFTypeRef value = CFDictionaryGetValue(parameters, key); - if (value != NULL) { - CFNumberRef nRef = (CFNumberRef) value; - CFNumberGetValue(nRef, kCFNumberSInt32Type, &integerValue); - return integerValue; - } - return defaultValue; - } - -static uint32_t -utilGetMaskValFromCFDict(CFDictionaryRef parameters, CFTypeRef key, uint32_t maskValue) -{ - CFTypeRef value = CFDictionaryGetValue(parameters, key); - if (value != NULL) { - CFBooleanRef bRef = (CFBooleanRef) value; - if(CFBooleanGetValue(bRef)) return maskValue; - } - return 0; -} - -static void -utilGetKeyParametersFromCFDict(CFDictionaryRef parameters, CSSM_ALGORITHMS *algorithm, uint32 *keySizeInBits, CSSM_KEYUSE *keyUsage, CSSM_KEYCLASS *keyClass) -{ - CFTypeRef algorithmDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyType, kSecAttrKeyTypeAES); - CFTypeRef keyClassDictValue = utilGetStringFromCFDict(parameters, kSecAttrKeyClass, kSecAttrKeyClassSymmetric); - - if(CFEqual(algorithmDictValue, kSecAttrKeyTypeAES)) { - *algorithm = CSSM_ALGID_AES; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDES)) { - *algorithm = CSSM_ALGID_DES; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyType3DES)) { - *algorithm = CSSM_ALGID_3DES_3KEY_EDE; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC4)) { - *algorithm = CSSM_ALGID_RC4; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRC2)) { - *algorithm = CSSM_ALGID_RC2; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeCAST)) { - *algorithm = CSSM_ALGID_CAST; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeRSA)) { - *algorithm = CSSM_ALGID_RSA; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeDSA)) { - *algorithm = CSSM_ALGID_DSA; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; - } else if(CFEqual(algorithmDictValue, kSecAttrKeyTypeECDSA) || - CFEqual(algorithmDictValue, kSecAttrKeyTypeEC)) { - *algorithm = CSSM_ALGID_ECDSA; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; - } else { - *algorithm = CSSM_ALGID_AES; - *keySizeInBits = 128; - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } - - if(CFEqual(keyClassDictValue, kSecAttrKeyClassPublic)) { - *keyClass = CSSM_KEYCLASS_PUBLIC_KEY; - } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassPrivate)) { - *keyClass = CSSM_KEYCLASS_PRIVATE_KEY; - } else if(CFEqual(keyClassDictValue, kSecAttrKeyClassSymmetric)) { - *keyClass = CSSM_KEYCLASS_SESSION_KEY; - } - - *keySizeInBits = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, *keySizeInBits); - *keyUsage = utilGetMaskValFromCFDict(parameters, kSecAttrCanEncrypt, CSSM_KEYUSE_ENCRYPT) | - utilGetMaskValFromCFDict(parameters, kSecAttrCanDecrypt, CSSM_KEYUSE_DECRYPT) | - utilGetMaskValFromCFDict(parameters, kSecAttrCanWrap, CSSM_KEYUSE_WRAP) | - utilGetMaskValFromCFDict(parameters, kSecAttrCanUnwrap, CSSM_KEYUSE_UNWRAP); - - - if(*keyClass == CSSM_KEYCLASS_PRIVATE_KEY || *keyClass == CSSM_KEYCLASS_PUBLIC_KEY) { - *keyUsage |= utilGetMaskValFromCFDict(parameters, kSecAttrCanSign, CSSM_KEYUSE_SIGN) | - utilGetMaskValFromCFDict(parameters, kSecAttrCanVerify, CSSM_KEYUSE_VERIFY); - } - - if(*keyUsage == 0) { - switch (*keyClass) { - case CSSM_KEYCLASS_PRIVATE_KEY: - *keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN; - break; - case CSSM_KEYCLASS_PUBLIC_KEY: - *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP; - break; - default: - *keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY; - break; - } - } -} - -static CFStringRef -utilCopyDefaultKeyLabel(void) -{ - // generate a default label from the current date - CFDateRef dateNow = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); - CFStringRef defaultLabel = CFCopyDescription(dateNow); - CFRelease(dateNow); - - return defaultLabel; -} - -SecKeyRef -SecKeyGenerateSymmetric(CFDictionaryRef parameters, CFErrorRef *error) -{ - OSStatus result = errSecParam; // default result for an early exit - SecKeyRef key = NULL; - SecKeychainRef keychain = NULL; - SecAccessRef access; - CFStringRef label; - CFStringRef appLabel; - CFStringRef appTag; - CFStringRef dateLabel = NULL; - - CSSM_ALGORITHMS algorithm; - uint32 keySizeInBits; - CSSM_KEYUSE keyUsage; - uint32 keyAttr = CSSM_KEYATTR_RETURN_DEFAULT; - CSSM_KEYCLASS keyClass; - CFTypeRef value; - Boolean isPermanent; - Boolean isExtractable; - - // verify keychain parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecUseKeychain, (const void **)&keychain)) - keychain = NULL; - else if (SecKeychainGetTypeID() != CFGetTypeID(keychain)) { - keychain = NULL; - goto errorExit; - } - else - CFRetain(keychain); - - // verify permanent parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsPermanent, (const void **)&value)) - isPermanent = false; - else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value))) - goto errorExit; - else - isPermanent = CFEqual(kCFBooleanTrue, value); - if (isPermanent) { - if (keychain == NULL) { - // no keychain was specified, so use the default keychain - result = SecKeychainCopyDefault(&keychain); - } - keyAttr |= CSSM_KEYATTR_PERMANENT; - } - - // verify extractable parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrIsExtractable, (const void **)&value)) - isExtractable = true; // default to extractable if value not specified - else if (!value || (CFBooleanGetTypeID() != CFGetTypeID(value))) - goto errorExit; - else - isExtractable = CFEqual(kCFBooleanTrue, value); - if (isExtractable) - keyAttr |= CSSM_KEYATTR_EXTRACTABLE; - - // verify access parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrAccess, (const void **)&access)) - access = NULL; - else if (SecAccessGetTypeID() != CFGetTypeID(access)) - goto errorExit; - - // verify label parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrLabel, (const void **)&label)) - label = (dateLabel = utilCopyDefaultKeyLabel()); // no label provided, so use default - else if (CFStringGetTypeID() != CFGetTypeID(label)) - goto errorExit; - - // verify application label parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationLabel, (const void **)&appLabel)) - appLabel = (dateLabel) ? dateLabel : (dateLabel = utilCopyDefaultKeyLabel()); - else if (CFStringGetTypeID() != CFGetTypeID(appLabel)) - goto errorExit; - - // verify application tag parameter - if (!CFDictionaryGetValueIfPresent(parameters, kSecAttrApplicationTag, (const void **)&appTag)) - appTag = NULL; - else if (CFStringGetTypeID() != CFGetTypeID(appTag)) - goto errorExit; - - utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass); - - if (!keychain) { - // the generated key will not be stored in any keychain - result = SecKeyGenerate(keychain, algorithm, keySizeInBits, 0, keyUsage, keyAttr, access, &key); - } - 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; - char *labelBuf = (char *)malloc(labelBufLen); - size_t appLabelBufLen = (appLabel) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appLabel), kCFStringEncodingUTF8) + 1 : 0; - char *appLabelBuf = (char *)malloc(appLabelBufLen); - size_t appTagBufLen = (appTag) ? (size_t)CFStringGetMaximumSizeForEncoding(CFStringGetLength(appTag), kCFStringEncodingUTF8) + 1 : 0; - char *appTagBuf = (char *)malloc(appTagBufLen); - - if (label && !CFStringGetCString(label, labelBuf, labelBufLen-1, kCFStringEncodingUTF8)) - labelBuf[0]=0; - if (appLabel && !CFStringGetCString(appLabel, appLabelBuf, appLabelBufLen-1, kCFStringEncodingUTF8)) - appLabelBuf[0]=0; - if (appTag && !CFStringGetCString(appTag, appTagBuf, appTagBufLen-1, kCFStringEncodingUTF8)) - appTagBuf[0]=0; - - SecKeychainAttribute attrs[] = { - { kSecKeyPrintName, (UInt32)strlen(labelBuf), (char *)labelBuf }, - { kSecKeyLabel, (UInt32)strlen(appLabelBuf), (char *)appLabelBuf }, - { kSecKeyApplicationTag, (UInt32)strlen(appTagBuf), (char *)appTagBuf } }; - SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; - if (!appTag) --attributes.count; - - result = SecKeyGenerateWithAttributes(&attributes, - keychain, algorithm, keySizeInBits, 0, - keyUsage, keyAttr, access, &key); - - free(labelBuf); - free(appLabelBuf); - free(appTagBuf); - } - -errorExit: - if (result && error) { - *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, result, NULL); - } - if (dateLabel) - CFRelease(dateLabel); - if (keychain) - CFRelease(keychain); - - return key; -} - - - -SecKeyRef -SecKeyCreateFromData(CFDictionaryRef parameters, CFDataRef keyData, CFErrorRef *error) -{ - CSSM_ALGORITHMS algorithm; - uint32 keySizeInBits; - CSSM_KEYUSE keyUsage; - CSSM_KEYCLASS keyClass; - CSSM_RETURN crtn; - - if(keyData == NULL || CFDataGetLength(keyData) == 0){ - MacOSError::throwMe(errSecUnsupportedKeySize); - } - - utilGetKeyParametersFromCFDict(parameters, &algorithm, &keySizeInBits, &keyUsage, &keyClass); - - CSSM_CSP_HANDLE cspHandle = cuCspStartup(CSSM_FALSE); // TRUE => CSP, FALSE => CSPDL - - SecKeyImportExportParameters iparam; - memset(&iparam, 0, sizeof(iparam)); - iparam.keyUsage = keyUsage; - - SecExternalItemType itype; - switch (keyClass) { - case CSSM_KEYCLASS_PRIVATE_KEY: - itype = kSecItemTypePrivateKey; - break; - case CSSM_KEYCLASS_PUBLIC_KEY: - itype = kSecItemTypePublicKey; - break; - case CSSM_KEYCLASS_SESSION_KEY: - itype = kSecItemTypeSessionKey; - break; - default: - itype = kSecItemTypeUnknown; - break; - } - - CFMutableArrayRef ka = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - // NOTE: if we had a way to specify values other then kSecFormatUnknown we might be more useful. - crtn = impExpImportRawKey(keyData, kSecFormatUnknown, itype, algorithm, NULL, cspHandle, 0, NULL, NULL, ka); - if (crtn == CSSM_OK && CFArrayGetCount((CFArrayRef)ka)) { - SecKeyRef sk = (SecKeyRef)CFArrayGetValueAtIndex((CFArrayRef)ka, 0); - CFRetain(sk); - CFRelease(ka); - return sk; - } else { - if (error) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, crtn ? crtn : CSSM_ERRCODE_INTERNAL_ERROR, NULL); - } - return NULL; - } -} - - -void -SecKeyGeneratePairAsync(CFDictionaryRef parametersWhichMightBeMutiable, dispatch_queue_t deliveryQueue, - SecKeyGeneratePairBlock result) -{ - CFDictionaryRef parameters = CFDictionaryCreateCopy(NULL, parametersWhichMightBeMutiable); - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - SecKeyRef publicKey = NULL; - SecKeyRef privateKey = NULL; - OSStatus status = SecKeyGeneratePair(parameters, &publicKey, &privateKey); - dispatch_async(deliveryQueue, ^{ - CFErrorRef error = NULL; - if (errSecSuccess != status) { - error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, status, NULL); - } - result(publicKey, privateKey, error); - if (error) { - CFRelease(error); - } - if (publicKey) { - CFRelease(publicKey); - } - if (privateKey) { - CFRelease(privateKey); - } - CFRelease(parameters); - }); - }); -} - -static inline void utilClearAndFree(void *p, size_t len) { - if(p) { - if(len) bzero(p, len); - free(p); - } -} - -SecKeyRef -SecKeyDeriveFromPassword(CFStringRef password, CFDictionaryRef parameters, CFErrorRef *error) -{ - CCPBKDFAlgorithm algorithm; - CFIndex passwordLen = 0; - CFDataRef keyData = NULL; - char *thePassword = NULL; - uint8_t *salt = NULL; - uint8_t *derivedKey = NULL; - size_t saltLen = 0, derivedKeyLen = 0; - uint rounds; - CFDataRef saltDictValue, algorithmDictValue; - SecKeyRef retval = NULL; - - /* Pick Values from parameters */ - - if((saltDictValue = (CFDataRef) CFDictionaryGetValue(parameters, kSecAttrSalt)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecMissingAlgorithmParms, NULL); - goto errOut; - } - - derivedKeyLen = utilGetNumberFromCFDict(parameters, kSecAttrKeySizeInBits, 128); - // This value come in bits but the rest of the code treats it as bytes - derivedKeyLen /= 8; - - algorithmDictValue = (CFDataRef) utilGetStringFromCFDict(parameters, kSecAttrPRF, kSecAttrPRFHmacAlgSHA256); - - rounds = utilGetNumberFromCFDict(parameters, kSecAttrRounds, 0); - - /* Convert any remaining parameters and get the password bytes */ - - saltLen = CFDataGetLength(saltDictValue); - if((salt = (uint8_t *) malloc(saltLen)) == NULL) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecAllocate, NULL); - goto errOut; - } - - CFDataGetBytes(saltDictValue, CFRangeMake(0, saltLen), (UInt8 *) salt); - - passwordLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(password), kCFStringEncodingUTF8) + 1; - if((thePassword = (char *) malloc(passwordLen)) == NULL) { - *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); - goto errOut; - } - - if(algorithmDictValue == NULL) { - algorithm = kCCPRFHmacAlgSHA1; /* default */ - } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA1)) { - algorithm = kCCPRFHmacAlgSHA1; - } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA224)) { - algorithm = kCCPRFHmacAlgSHA224; - } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA256)) { - algorithm = kCCPRFHmacAlgSHA256; - } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA384)) { - algorithm = kCCPRFHmacAlgSHA384; - } else if(CFEqual(algorithmDictValue, kSecAttrPRFHmacAlgSHA512)) { - algorithm = kCCPRFHmacAlgSHA512; - } else { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInvalidAlgorithmParms, NULL); - goto errOut; - } - - if(rounds == 0) { - rounds = 33333; // we need to pass back a consistent value since there's no way to record the round count. - } - - if(CCKeyDerivationPBKDF(kCCPBKDF2, thePassword, passwordLen, salt, saltLen, algorithm, rounds, derivedKey, derivedKeyLen)) { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); - goto errOut; - } - - if((keyData = CFDataCreate(NULL, derivedKey, derivedKeyLen)) != NULL) { - retval = SecKeyCreateFromData(parameters, keyData, error); - CFRelease(keyData); - } else { - *error = CFErrorCreate(NULL, kCFErrorDomainOSStatus, errSecInternalError, NULL); - } - -errOut: - utilClearAndFree(salt, saltLen); - utilClearAndFree(thePassword, passwordLen); - utilClearAndFree(derivedKey, derivedKeyLen); - return retval; -} - -CFDataRef -SecKeyWrapSymmetric(SecKeyRef keyToWrap, SecKeyRef wrappingKey, CFDictionaryRef parameters, CFErrorRef *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); - return NULL; -} - - -/* iOS SecKey shim functions */ - -#define MAX_DIGEST_LEN (CC_SHA512_DIGEST_LENGTH) - -/* Currently length of SHA512 oid + 1 */ -#define MAX_OID_LEN (10) - -#define DER_MAX_DIGEST_INFO_LEN (10 + MAX_DIGEST_LEN + MAX_OID_LEN) - -/* Encode the digestInfo header into digestInfo and return the offset from - digestInfo at which to put the actual digest. Returns 0 if digestInfo - won't fit within digestInfoLength bytes. - - 0x30, topLen, - 0x30, algIdLen, - 0x06, oid.Len, oid.Data, - 0x05, 0x00 - 0x04, digestLen - digestData - */ -static size_t DEREncodeDigestInfoPrefix(const SecAsn1Oid *oid, - size_t digestLength, - uint8_t *digestInfo, - size_t digestInfoLength) -{ - size_t algIdLen = oid->Length + 4; - size_t topLen = algIdLen + digestLength + 4; - size_t totalLen = topLen + 2; - - if (totalLen > digestInfoLength) { - return 0; - } - - size_t ix = 0; - digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED); - digestInfo[ix++] = topLen; - digestInfo[ix++] = (SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED); - digestInfo[ix++] = algIdLen; - digestInfo[ix++] = SEC_ASN1_OBJECT_ID; - digestInfo[ix++] = oid->Length; - memcpy(&digestInfo[ix], oid->Data, oid->Length); - ix += oid->Length; - digestInfo[ix++] = SEC_ASN1_NULL; - digestInfo[ix++] = 0; - digestInfo[ix++] = SEC_ASN1_OCTET_STRING; - digestInfo[ix++] = digestLength; - - return ix; -} - -static OSStatus SecKeyGetDigestInfo(SecKeyRef key, const SecAsn1AlgId *algId, - const uint8_t *data, size_t dataLen, bool digestData, - uint8_t *digestInfo, size_t *digestInfoLen /* IN/OUT */) -{ - unsigned char *(*digestFcn)(const void *, CC_LONG, unsigned char *); - CFIndex keyAlgID = kSecNullAlgorithmID; - const SecAsn1Oid *digestOid; - size_t digestLen; - size_t offset = 0; - - /* Since these oids all have the same prefix, use switch. */ - if ((algId->algorithm.Length == CSSMOID_RSA.Length) && - !memcmp(algId->algorithm.Data, CSSMOID_RSA.Data, - algId->algorithm.Length - 1)) { - keyAlgID = kSecRSAAlgorithmID; - switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { -#if 0 - case 2: /* oidMD2WithRSA */ - digestFcn = CC_MD2; - digestLen = CC_MD2_DIGEST_LENGTH; - digestOid = &CSSMOID_MD2; - break; - case 3: /* oidMD4WithRSA */ - digestFcn = CC_MD4; - digestLen = CC_MD4_DIGEST_LENGTH; - digestOid = &CSSMOID_MD4; - break; - case 4: /* oidMD5WithRSA */ - digestFcn = CC_MD5; - digestLen = CC_MD5_DIGEST_LENGTH; - digestOid = &CSSMOID_MD5; - break; -#endif /* 0 */ - case 5: /* oidSHA1WithRSA */ - digestFcn = CC_SHA1; - digestLen = CC_SHA1_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA1; - break; - case 11: /* oidSHA256WithRSA */ - digestFcn = CC_SHA256; - digestLen = CC_SHA256_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA256; - break; - case 12: /* oidSHA384WithRSA */ - /* pkcs1 12 */ - digestFcn = CC_SHA384; - digestLen = CC_SHA384_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA384; - break; - case 13: /* oidSHA512WithRSA */ - digestFcn = CC_SHA512; - digestLen = CC_SHA512_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA512; - break; - case 14: /* oidSHA224WithRSA */ - digestFcn = CC_SHA224; - digestLen = CC_SHA224_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA224; - break; - default: - secdebug("key", "unsupported rsa signature algorithm"); - return errSecUnsupportedAlgorithm; - } - } else if ((algId->algorithm.Length == CSSMOID_ECDSA_WithSHA224.Length) && - !memcmp(algId->algorithm.Data, CSSMOID_ECDSA_WithSHA224.Data, - algId->algorithm.Length - 1)) { - keyAlgID = kSecECDSAAlgorithmID; - switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { - case 1: /* oidSHA224WithECDSA */ - digestFcn = CC_SHA224; - digestLen = CC_SHA224_DIGEST_LENGTH; - break; - case 2: /* oidSHA256WithECDSA */ - digestFcn = CC_SHA256; - digestLen = CC_SHA256_DIGEST_LENGTH; - break; - case 3: /* oidSHA384WithECDSA */ - /* pkcs1 12 */ - digestFcn = CC_SHA384; - digestLen = CC_SHA384_DIGEST_LENGTH; - break; - case 4: /* oidSHA512WithECDSA */ - digestFcn = CC_SHA512; - digestLen = CC_SHA512_DIGEST_LENGTH; - break; - default: - secdebug("key", "unsupported ecdsa signature algorithm"); - return errSecUnsupportedAlgorithm; - } - } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_ECDSA_WithSHA1)) { - keyAlgID = kSecECDSAAlgorithmID; - digestFcn = CC_SHA1; - digestLen = CC_SHA1_DIGEST_LENGTH; - } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_SHA1)) { - digestFcn = CC_SHA1; - digestLen = CC_SHA1_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA1; - } else if ((algId->algorithm.Length == CSSMOID_SHA224.Length) && - !memcmp(algId->algorithm.Data, CSSMOID_SHA224.Data, algId->algorithm.Length - 1)) - { - switch (algId->algorithm.Data[algId->algorithm.Length - 1]) { - case 4: /* OID_SHA224 */ - digestFcn = CC_SHA224; - digestLen = CC_SHA224_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA224; - break; - case 1: /* OID_SHA256 */ - digestFcn = CC_SHA256; - digestLen = CC_SHA256_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA256; - break; - case 2: /* OID_SHA384 */ - /* pkcs1 12 */ - digestFcn = CC_SHA384; - digestLen = CC_SHA384_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA384; - break; - case 3: /* OID_SHA512 */ - digestFcn = CC_SHA512; - digestLen = CC_SHA512_DIGEST_LENGTH; - digestOid = &CSSMOID_SHA512; - break; - default: - secdebug("key", "unsupported sha-2 signature algorithm"); - return errSecUnsupportedAlgorithm; - } - } else if (SecAsn1OidCompare(&algId->algorithm, &CSSMOID_MD5)) { - digestFcn = CC_MD5; - digestLen = CC_MD5_DIGEST_LENGTH; - digestOid = &CSSMOID_MD5; - } else { - secdebug("key", "unsupported digesting algorithm"); - return errSecUnsupportedAlgorithm; - } - - /* check key is appropriate for signature (superfluous for digest only oid) */ - { - CFIndex supportedKeyAlgID = kSecNullAlgorithmID; - #if TARGET_OS_EMBEDDED - supportedKeyAlgID = SecKeyGetAlgorithmID(key); - #else - const CSSM_KEY* temporaryKey; - SecKeyGetCSSMKey(key, &temporaryKey); - CSSM_ALGORITHMS tempAlgorithm = temporaryKey->KeyHeader.AlgorithmId; - if (CSSM_ALGID_RSA == tempAlgorithm) { - supportedKeyAlgID = kSecRSAAlgorithmID; - } else if (CSSM_ALGID_ECDSA == tempAlgorithm) { - supportedKeyAlgID = kSecECDSAAlgorithmID; - } - #endif - - if (keyAlgID == kSecNullAlgorithmID) { - keyAlgID = supportedKeyAlgID; - } - else if (keyAlgID != supportedKeyAlgID) { - return errSecUnsupportedAlgorithm; - } - } - - switch(keyAlgID) { - case kSecRSAAlgorithmID: - offset = DEREncodeDigestInfoPrefix(digestOid, digestLen, - digestInfo, *digestInfoLen); - if (!offset) - return errSecBufferTooSmall; - break; - case kSecDSAAlgorithmID: - if (digestOid != &CSSMOID_SHA1) - return errSecUnsupportedAlgorithm; - break; - case kSecECDSAAlgorithmID: - break; - default: - secdebug("key", "unsupported signature algorithm"); - return errSecUnsupportedAlgorithm; - } - - if (digestData) { - if(dataLen>UINT32_MAX) /* Check for overflow with CC_LONG cast */ - return errSecParam; - digestFcn(data, (CC_LONG)dataLen, &digestInfo[offset]); - *digestInfoLen = offset + digestLen; - } else { - if (dataLen != digestLen) - return errSecParam; - memcpy(&digestInfo[offset], data, dataLen); - *digestInfoLen = offset + dataLen; - } - - return errSecSuccess; -} - -OSStatus SecKeyVerifyDigest( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen, /* length of dataToDigest */ - const uint8_t *sig, /* signature to verify */ - size_t sigLen) /* length of sig */ -{ - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - OSStatus status; - - status = SecKeyGetDigestInfo(key, algId, digestData, digestDataLen, false /* data is digest */, - digestInfo, &digestInfoLength); - if (status) - return status; - return SecKeyRawVerify(key, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); -} - -OSStatus SecKeySignDigest( - SecKeyRef key, /* Private key */ - const SecAsn1AlgId *algId, /* algorithm oid/params */ - const uint8_t *digestData, /* signature over this digest */ - size_t digestDataLen, /* length of digestData */ - uint8_t *sig, /* signature, RETURNED */ - size_t *sigLen) /* IN/OUT */ -{ - size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN; - uint8_t digestInfo[digestInfoLength]; - OSStatus status; - - status = SecKeyGetDigestInfo(key, algId, digestData, digestDataLen, false, - digestInfo, &digestInfoLength); - if (status) - return status; - return SecKeyRawSign(key, kSecPaddingPKCS1, - digestInfo, digestInfoLength, sig, sigLen); -} - -/* It's debatable whether this belongs here or in the ssl code since the - curve values come from a tls related rfc4492. */ -SecECNamedCurve SecECKeyGetNamedCurve(SecKeyRef key) -{ - try { - SecPointer keyItem(KeyItem::required(key)); - switch (keyItem->key().header().LogicalKeySizeInBits) { -#if 0 - case 192: - return kSecECCurveSecp192r1; - case 224: - return kSecECCurveSecp224r1; -#endif - case 256: - return kSecECCurveSecp256r1; - case 384: - return kSecECCurveSecp384r1; - case 521: - return kSecECCurveSecp521r1; - } - } - catch (...) {} - return kSecECCurveNone; -} - -static inline CFDataRef _CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range) -{ - return CFDataCreateWithBytesNoCopy(allocator, - CFDataGetBytePtr(sourceData) + range.location, range.length, - kCFAllocatorNull); -} - -static inline CFDataRef _CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range) -{ - return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length); -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" -static inline bool _CFDataEquals(CFDataRef left, CFDataRef right) -{ - return (left != NULL) && - (right != NULL) && - (CFDataGetLength(left) == CFDataGetLength(right)) && - (0 == memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), (size_t)CFDataGetLength(left))); -} -#pragma clang diagnostic pop - -#if ECDSA_DEBUG -void secdump(const unsigned char *data, unsigned long len) -{ - unsigned long i; - char s[128]; - char t[32]; - s[0]=0; - for(i=0;imodulusLength; - DERSize e_size = params->exponentLength; - const DERSize seq_size = DERLengthOfItem(ASN1_INTEGER, m_size) + - DERLengthOfItem(ASN1_INTEGER, e_size); - const DERSize result_size = DERLengthOfItem(ASN1_SEQUENCE, seq_size); - DERSize r_size, remaining_size = result_size; - DERReturn drtn; - - CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size); - if (pkcs1 == NULL) { - return NULL; - } - CFDataSetLength(pkcs1, result_size); - uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1); - - *bytes++ = ASN1_CONSTR_SEQUENCE; - remaining_size--; - r_size = 4; - drtn = DEREncodeLength(seq_size, bytes, &r_size); - if (r_size <= remaining_size) { - bytes += r_size; - remaining_size -= r_size; - } - r_size = remaining_size; - drtn = DEREncodeItem(ASN1_INTEGER, m_size, (const DERByte *)params->modulus, (DERByte *)bytes, &r_size); - if (r_size <= remaining_size) { - bytes += r_size; - remaining_size -= r_size; - } - r_size = remaining_size; - drtn = DEREncodeItem(ASN1_INTEGER, e_size, (const DERByte *)params->exponent, (DERByte *)bytes, &r_size); - - pubKeyData = pkcs1; - - } else { - /* unsupported encoding */ - return NULL; - } - SecKeyRef publicKey = SecKeyCreateFromPublicData(allocator, kSecRSAAlgorithmID, pubKeyData); - CFRelease(pubKeyData); - return publicKey; -} - -#if !TARGET_OS_EMBEDDED -// -// Given a CSSM public key, copy its modulus and/or exponent data. -// Caller is responsible for releasing the returned CFDataRefs. -// -static -OSStatus _SecKeyCopyRSAPublicModulusAndExponent(SecKeyRef key, CFDataRef *modulus, CFDataRef *exponent) -{ - const CSSM_KEY *pubKey; - const CSSM_KEYHEADER *hdr; - CSSM_DATA pubKeyBlob; - OSStatus result; - - result = SecKeyGetCSSMKey(key, &pubKey); - if(result != errSecSuccess) { - return result; - } - hdr = &pubKey->KeyHeader; - if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) { - return errSSLInternal; - } - if(hdr->AlgorithmId != CSSM_ALGID_RSA) { - return errSSLInternal; - } - switch(hdr->BlobType) { - case CSSM_KEYBLOB_RAW: - pubKeyBlob.Length = pubKey->KeyData.Length; - pubKeyBlob.Data = pubKey->KeyData.Data; - break; - case CSSM_KEYBLOB_REFERENCE: - // FIXME: currently SSL only uses raw public keys, obtained from the CL - default: - return errSSLInternal; - } - assert(hdr->BlobType == CSSM_KEYBLOB_RAW); - // at this point we should have a PKCS1-encoded blob - - DERItem keyItem = {(DERByte *)pubKeyBlob.Data, pubKeyBlob.Length}; - DERRSAPubKeyPKCS1 decodedKey; - if(DERParseSequence(&keyItem, DERNumRSAPubKeyPKCS1ItemSpecs, - DERRSAPubKeyPKCS1ItemSpecs, - &decodedKey, sizeof(decodedKey)) != DR_Success) { - return errSecDecode; - } - if(modulus) { - *modulus = CFDataCreate(kCFAllocatorDefault, decodedKey.modulus.data, decodedKey.modulus.length); - if(*modulus == NULL) { - return errSecDecode; - } - } - if(exponent) { - *exponent = CFDataCreate(kCFAllocatorDefault, decodedKey.pubExponent.data, decodedKey.pubExponent.length); - if(*exponent == NULL) { - return errSecDecode; - } - } - - return errSecSuccess; -} -#endif /* !TARGET_OS_EMBEDDED */ - -CFDataRef SecKeyCopyModulus(SecKeyRef key) -{ -#if TARGET_OS_EMBEDDED - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - size_t m_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey)); - - CFAllocatorRef allocator = CFGetAllocator(key); - CFMutableDataRef modulusData = CFDataCreateMutable(allocator, m_size); - - if (modulusData == NULL) - return NULL; - - CFDataSetLength(modulusData, m_size); - - ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), m_size, CFDataGetMutableBytePtr(modulusData)); -#else - CFDataRef modulusData; - OSStatus status = _SecKeyCopyRSAPublicModulusAndExponent(key, &modulusData, NULL); - if(status != errSecSuccess) { - modulusData = NULL; - } -#endif - - return modulusData; -} - -CFDataRef SecKeyCopyExponent(SecKeyRef key) -{ -#if TARGET_OS_EMBEDDED - ccrsa_pub_ctx_t pubkey; - pubkey.pub = key->key; - - size_t e_size = ccn_write_uint_size(ccrsa_ctx_n(pubkey), ccrsa_ctx_e(pubkey)); - - CFAllocatorRef allocator = CFGetAllocator(key); - CFMutableDataRef exponentData = CFDataCreateMutable(allocator, e_size); - - if (exponentData == NULL) - return NULL; - - CFDataSetLength(exponentData, e_size); - - ccn_write_uint(ccrsa_ctx_n(pubkey), ccrsa_ctx_m(pubkey), e_size, CFDataGetMutableBytePtr(exponentData)); -#else - CFDataRef exponentData; - OSStatus status = _SecKeyCopyRSAPublicModulusAndExponent(key, NULL, &exponentData); - if(status != errSecSuccess) { - exponentData = NULL; - } -#endif - - return exponentData; -} - -SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) { - OSStatus status = errSecParam; - - CFDataRef serializedPublic = NULL; - - status = SecKeyCopyPublicBytes(privateKey, &serializedPublic); - if ((status == errSecSuccess) && (serializedPublic != NULL)) { - SecKeyRef publicKeyRef = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmId(privateKey), serializedPublic); - CFRelease(serializedPublic); - if (publicKeyRef != NULL) { - return publicKeyRef; - } - } - - const void *keys[] = { kSecClass, kSecValueRef, kSecReturnAttributes }; - const void *values[] = { kSecClassKey, privateKey, kCFBooleanTrue }; - CFDictionaryRef query= CFDictionaryCreate(NULL, keys, values, - (sizeof(values) / sizeof(*values)), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFTypeRef foundItem = NULL; - status = SecItemCopyMatching(query, &foundItem); - - if (status == errSecSuccess) { - if (CFGetTypeID(foundItem) == CFDictionaryGetTypeID()) { - CFMutableDictionaryRef query2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(query2, kSecClass, kSecClassKey); - CFDictionaryAddValue(query2, kSecAttrKeyClass, kSecAttrKeyClassPublic); - CFDictionaryAddValue(query2, kSecAttrApplicationLabel, CFDictionaryGetValue((CFDictionaryRef)foundItem, kSecAttrApplicationLabel)); - CFDictionaryAddValue(query2, kSecReturnRef, kCFBooleanTrue); - - CFTypeRef foundKey = NULL; - status = SecItemCopyMatching(query2, &foundKey); - if (status == errSecSuccess) { - if (CFGetTypeID(foundKey) == SecKeyGetTypeID()) { - CFRelease(query); - CFRelease(query2); - CFRelease(foundItem); - return (SecKeyRef)foundKey; - } else { - status = errSecItemNotFound; - } - } - CFRelease(query2); - - } else { - status = errSecItemNotFound; - } - CFRelease(foundItem); - } - - CFRelease(query); - return NULL; -} -