]> git.saurik.com Git - apple/security.git/blobdiff - sec/Security/SecKey.c
Security-57031.1.35.tar.gz
[apple/security.git] / sec / Security / SecKey.c
diff --git a/sec/Security/SecKey.c b/sec/Security/SecKey.c
deleted file mode 100644 (file)
index 227a6c0..0000000
+++ /dev/null
@@ -1,1099 +0,0 @@
-/*
- * Copyright (c) 2006-2011 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@
- */
-
-/*
- * SecKey.c - CoreFoundation based key object
- */
-
-
-#include <Security/SecKeyInternal.h>
-#include <Security/SecItem.h>
-#include <Security/SecItemPriv.h>
-#include <Security/SecFramework.h>
-
-#include <utilities/SecIOFormat.h>
-
-#include <utilities/SecCFWrappers.h>
-
-#include "SecRSAKeyPriv.h"
-#include "SecECKey.h"
-#include "SecBasePriv.h"
-
-#include <CoreFoundation/CFNumber.h>
-#include <CoreFoundation/CFString.h>
-#include <Security/SecBase.h>
-#include <pthread.h>
-#include <string.h>
-#include <AssertMacros.h>
-#include <utilities/debugging.h>
-#include <utilities/SecCFError.h>
-#include <CommonCrypto/CommonDigest.h>
-#include <Security/SecAsn1Coder.h>
-#include <Security/oidsalg.h>
-#include <Security/SecInternal.h>
-#include <Security/SecRandom.h>
-#include <corecrypto/ccrng_system.h>
-#include <asl.h>
-#include <stdlib.h>
-
-static pthread_once_t kSecKeyRegisterClass = PTHREAD_ONCE_INIT;
-static CFTypeID kSecKeyTypeID = _kCFRuntimeNotATypeID;
-
-/* Forward declartions of static functions. */
-static CFStringRef SecKeyCopyDescription(CFTypeRef cf);
-static void SecKeyDestroy(CFTypeRef cf);
-
-/* Static 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 struct ccrng_system_state ccrng_system_state_seckey;
-
-static void register_algs(void) {
-    ccrng_seckey = (struct ccrng_state *)&ccrng_system_state_seckey;
-    ccrng_system_init(&ccrng_system_state_seckey);
-}
-
-
-static CFDataRef SecKeyCopyPublicKeyHash(SecKeyRef key)
-{
-       CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL;
-
-       /* encode the public key. */
-    require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut);
-    require(pubKeyBlob, errOut);
-    
-       /* Calculate the digest of the public key. */
-       require(pubKeyDigest = SecSHA1DigestCreate(CFGetAllocator(key),
-                                               CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)),
-                       errOut);
-errOut:
-    CFReleaseNull(pubKeyBlob);
-    return pubKeyDigest;
-}
-
-
-/*
- */
-static CF_RETURNS_RETAINED CFDictionaryRef SecKeyGenerateAttributeDictionaryFor(SecKeyRef key,
-                                                                                CFTypeRef keyType,
-                                                                                CFDataRef privateBlob)
-{
-       CFAllocatorRef allocator = CFGetAllocator(key);
-       DICT_DECLARE(25);
-       CFDataRef pubKeyDigest = NULL, pubKeyBlob = NULL;
-       CFDictionaryRef dict = NULL;
-    
-    size_t sizeValue = SecKeyGetSize(key, kSecKeyKeySizeInBits);
-    CFNumberRef sizeInBits = CFNumberCreate(allocator, kCFNumberLongType, &sizeValue);
-    
-       /* encode the public key. */
-    require_noerr(SecKeyCopyPublicBytes(key, &pubKeyBlob), errOut);
-    require(pubKeyBlob, errOut);
-    
-       /* Calculate the digest of the public key. */
-       require(pubKeyDigest = SecSHA1DigestCreate(allocator,
-                                               CFDataGetBytePtr(pubKeyBlob), CFDataGetLength(pubKeyBlob)),
-                       errOut);
-    
-       DICT_ADDPAIR(kSecClass, kSecClassKey);
-       DICT_ADDPAIR(kSecAttrKeyClass, privateBlob ? kSecAttrKeyClassPrivate : kSecAttrKeyClassPublic);
-       DICT_ADDPAIR(kSecAttrApplicationLabel, pubKeyDigest);
-       DICT_ADDPAIR(kSecAttrIsPermanent, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrIsPrivate, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrIsModifiable, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrKeyType, keyType);
-       DICT_ADDPAIR(kSecAttrKeySizeInBits, sizeInBits);
-       DICT_ADDPAIR(kSecAttrEffectiveKeySize, sizeInBits);
-       DICT_ADDPAIR(kSecAttrIsSensitive, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrWasAlwaysSensitive, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrIsExtractable, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrWasNeverExtractable, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrCanEncrypt, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrCanDecrypt, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrCanDerive, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrCanSign, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecAttrCanVerify, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrCanSignRecover, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrCanVerifyRecover, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrCanWrap, kCFBooleanFalse);
-       DICT_ADDPAIR(kSecAttrCanUnwrap, kCFBooleanTrue);
-       DICT_ADDPAIR(kSecValueData, privateBlob ? privateBlob : pubKeyBlob);
-    dict = DICT_CREATE(allocator);
-    
-errOut:
-       // @@@ Zero out key material.
-       CFReleaseSafe(pubKeyDigest);
-       CFReleaseSafe(pubKeyBlob);
-       CFReleaseSafe(sizeInBits);
-    
-       return dict;
-}
-
-CFDictionaryRef SecKeyGeneratePrivateAttributeDictionary(SecKeyRef key,
-                                                         CFTypeRef keyType,
-                                                         CFDataRef privateBlob)
-{
-    return SecKeyGenerateAttributeDictionaryFor(key, keyType, privateBlob);
-}
-
-CFDictionaryRef SecKeyGeneratePublicAttributeDictionary(SecKeyRef key, CFTypeRef keyType)
-{
-    return SecKeyGenerateAttributeDictionaryFor(key, keyType, NULL);
-}
-
-/*
- */
-
-static CFStringRef SecKeyCopyDescription(CFTypeRef cf) {
-    SecKeyRef key = (SecKeyRef)cf;
-    
-    if(key->key_class->describe)
-        return key->key_class->describe(key);
-    else
-        return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecKeyRef: %p>"), key); 
-}
-
-static void SecKeyDestroy(CFTypeRef cf) {
-    SecKeyRef key = (SecKeyRef)cf;
-    if (key->key_class->destroy)
-        key->key_class->destroy(key);
-}
-
-static Boolean SecKeyEqual(CFTypeRef cf1, CFTypeRef cf2)
-{
-    SecKeyRef key1 = (SecKeyRef)cf1;
-    SecKeyRef key2 = (SecKeyRef)cf2;
-    if (key1 == key2)
-        return true;
-    if (!key2 || key1->key_class != key2->key_class)
-        return false;
-    if (key1->key_class->extraBytes)
-        return !memcmp(key1->key, key2->key, key1->key_class->extraBytes);
-    
-    /* TODO: Won't work when we get reference keys. */
-    CFDictionaryRef d1, d2;
-    d1 = SecKeyCopyAttributeDictionary(key1);
-    d2 = SecKeyCopyAttributeDictionary(key2);
-    Boolean result = CFEqual(d1, d2);
-    CFReleaseSafe(d1);
-    CFReleaseSafe(d2);
-    return result;
-}
-
-static void SecKeyRegisterClass(void) {
-       static const CFRuntimeClass kSecKeyClass = {
-               0,                                                                                                      /* version */
-               "SecKey",                                           /* class name */
-               NULL,                                                                                           /* init */
-               NULL,                                                                                           /* copy */
-               SecKeyDestroy,                                      /* dealloc */
-               SecKeyEqual,                                                                            /* equal */
-               NULL,                                                                                           /* hash */
-               NULL,                                                                                           /* copyFormattingDesc */
-               SecKeyCopyDescription                               /* copyDebugDesc */
-       };
-    
-    kSecKeyTypeID = _CFRuntimeRegisterClass(&kSecKeyClass);
-    register_algs();
-}
-
-/* Public API functions. */
-CFTypeID SecKeyGetTypeID(void) {
-    pthread_once(&kSecKeyRegisterClass, SecKeyRegisterClass);
-    return kSecKeyTypeID;
-}
-
-static bool getBoolForKey(CFDictionaryRef dict, CFStringRef key, bool default_value) {
-       CFTypeRef value = CFDictionaryGetValue(dict, key);
-       if (value) {
-               if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
-                       return CFBooleanGetValue(value);
-               } else {
-                       secwarning("Value %@ for key %@ is not bool", value, key);
-               }
-       }
-    
-       return default_value;
-}
-
-static OSStatus add_ref(CFTypeRef item, CFMutableDictionaryRef dict) {
-       CFDictionarySetValue(dict, kSecValueRef, item);
-       return SecItemAdd(dict, NULL);
-}
-
-static void merge_params_applier(const void *key, const void *value,
-                                 void *context) {
-       CFMutableDictionaryRef result = (CFMutableDictionaryRef)context;
-       CFDictionaryAddValue(result, key, value);
-}
-
-/* Create a mutable dictionary that is based on the subdictionary for key
- with any attributes from the top level dict merged in. */
-static CFMutableDictionaryRef merge_params(CFDictionaryRef dict,
-                                           CFStringRef key) {
-       CFDictionaryRef subdict = CFDictionaryGetValue(dict, key);
-       CFMutableDictionaryRef result;
-    
-       if (subdict) {
-               result = CFDictionaryCreateMutableCopy(NULL, 0, subdict);
-               /* Add everything in dict not already in result to result. */
-               CFDictionaryApplyFunction(dict, merge_params_applier, result);
-       } else {
-               result = CFDictionaryCreateMutableCopy(NULL, 0, dict);
-       }
-    
-       /* Remove values that only belong in the top level dict. */
-       CFDictionaryRemoveValue(result, kSecPublicKeyAttrs);
-       CFDictionaryRemoveValue(result, kSecPrivateKeyAttrs);
-       CFDictionaryRemoveValue(result, kSecAttrKeyType);
-       CFDictionaryRemoveValue(result, kSecAttrKeySizeInBits);
-    
-       return result;
-}
-
-/* Generate a private/public keypair. */
-OSStatus SecKeyGeneratePair(CFDictionaryRef parameters,
-                            SecKeyRef *publicKey, SecKeyRef *privateKey) {
-    OSStatus result = errSecUnsupportedAlgorithm;
-    SecKeyRef privKey = NULL;
-       SecKeyRef pubKey = NULL;
-    CFMutableDictionaryRef pubParams = merge_params(parameters, kSecPublicKeyAttrs),
-    privParams = merge_params(parameters, kSecPrivateKeyAttrs);
-       CFStringRef ktype = CFDictionaryGetValue(parameters, kSecAttrKeyType);
-    
-    require(ktype, errOut);
-    
-    if (CFEqual(ktype, kSecAttrKeyTypeEC)) {
-        result = SecECKeyGeneratePair(parameters, &pubKey, &privKey);
-    } else if (CFEqual(ktype, kSecAttrKeyTypeRSA)) {
-        result = SecRSAKeyGeneratePair(parameters, &pubKey, &privKey);
-    }
-    
-    require_noerr(result, errOut);
-    
-    /* Store the keys in the keychain if they are marked as permanent. */
-    if (getBoolForKey(pubParams, kSecAttrIsPermanent, false)) {
-        require_noerr_quiet(result = add_ref(pubKey, pubParams), errOut);
-    }
-    if (getBoolForKey(privParams, kSecAttrIsPermanent, false)) {
-        require_noerr_quiet(result = add_ref(privKey, privParams), errOut);
-    }
-    
-    if (publicKey) {
-        *publicKey = pubKey;
-        pubKey = NULL;
-    }
-    if (privateKey) {
-        *privateKey = privKey;
-        privKey = NULL;
-    }
-    
-errOut:
-       CFReleaseSafe(pubParams);
-       CFReleaseSafe(privParams);
-    CFReleaseSafe(pubKey);
-    CFReleaseSafe(privKey);
-    
-    return result;
-}
-
-SecKeyRef SecKeyCreatePublicFromPrivate(SecKeyRef privateKey) {
-    CFDataRef serializedPublic = NULL;
-    SecKeyRef result = NULL;
-    
-    require_noerr_quiet(SecKeyCopyPublicBytes(privateKey, &serializedPublic), fail);
-    require_quiet(serializedPublic, fail);
-    
-    result = SecKeyCreateFromPublicData(kCFAllocatorDefault, SecKeyGetAlgorithmID(privateKey), serializedPublic);
-    
-fail:
-    CFReleaseSafe(serializedPublic);
-    
-    return result;
-}
-
-static CFDictionaryRef CreatePrivateKeyMatchingQuery(SecKeyRef publicKey, bool returnPersistentRef)
-{
-    CFDataRef public_key_hash = SecKeyCopyPublicKeyHash(publicKey);
-    
-    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
-                                                         kSecClass,                 kSecClassKey,
-                                                         kSecAttrKeyClass,          kSecAttrKeyClassPrivate,
-                                                         kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
-                                                         kSecAttrApplicationLabel,  public_key_hash,
-                                                         kSecReturnPersistentRef,   kCFBooleanTrue,
-                                                         NULL);
-    CFReleaseNull(public_key_hash);
-    
-    return query;
-}
-
-CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) {
-    CFTypeRef persistentRef = NULL;
-    CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true);
-
-    require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error ,
-                           CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail);
-fail:
-    CFReleaseNull(query);
-    return (CFDataRef)persistentRef;
-}
-
-SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) {
-    CFTypeRef private_key = NULL;
-    
-    CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, false);    
-    
-    require_quiet(SecError(SecItemCopyMatching(query, &private_key), error,
-                           CFSTR("Error finding private key from public: %@"), publicKey), fail);
-fail:
-    CFReleaseNull(query);
-    return (SecKeyRef)private_key;
-}
-
-SecKeyRef SecKeyCreatePublicFromDER(CFAllocatorRef allocator,
-                                    const SecAsn1Oid *oid, const SecAsn1Item *params,
-                                    const SecAsn1Item *keyData) {
-    SecKeyRef publicKey = NULL;
-       if (SecAsn1OidCompare(oid, &CSSMOID_RSA)) {
-        /* pkcs1 1 */
-               publicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault,
-                                             keyData->Data, keyData->Length, kSecKeyEncodingPkcs1);
-       } else if (SecAsn1OidCompare(oid, &CSSMOID_ecPublicKey)) {
-        SecDERKey derKey = {
-            .oid = oid->Data,
-            .oidLength = oid->Length,
-            .key = keyData->Data,
-            .keyLength = keyData->Length,
-        };
-        if (params) {
-            derKey.parameters = params->Data;
-            derKey.parametersLength = params->Length;
-        }
-               publicKey = SecKeyCreateECPublicKey(kCFAllocatorDefault,
-                                            (const uint8_t *)&derKey, sizeof(derKey), kSecDERKeyEncoding);
-    } else {
-               secwarning("Unsupported algorithm oid");
-       }
-    
-    return publicKey;
-}
-
-SecKeyRef SecKeyCreate(CFAllocatorRef allocator,
-                       const SecKeyDescriptor *key_class, const uint8_t *keyData,
-                       CFIndex keyDataLength, SecKeyEncoding encoding) {
-       check(key_class);
-    
-    size_t size = sizeof(struct __SecKey) + key_class->extraBytes;
-    SecKeyRef result = (SecKeyRef)_CFRuntimeCreateInstance(allocator,
-                                                           SecKeyGetTypeID(), size - sizeof(CFRuntimeBase), NULL);
-       if (result) {
-               memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base));
-        result->key_class = key_class;
-        if (key_class->extraBytes) {
-            /* Make result->key point to the extraBytes we allocated. */
-            result->key = ((char*)result) + sizeof(*result);
-        }
-        if (key_class->init) {
-                       OSStatus status;
-                       status = key_class->init(result, keyData, keyDataLength, encoding);
-                       if (status) {
-                               secwarning("init %s key: %" PRIdOSStatus, key_class->name, status);
-                               CFRelease(result);
-                               result = NULL;
-                       }
-               }
-    }
-    return result;
-}
-
-enum {
-    kSecKeyDigestInfoSign,
-    kSecKeyDigestInfoVerify
-};
-
-static OSStatus SecKeyDigestInfoSignVerify(
-                                           SecKeyRef           key,            /* Private key */
-                                           SecPadding          padding,                /* kSecPaddingPKCS1@@@ */
-                                           const uint8_t       *dataToSign,    /* signature over this data */
-                                           size_t              dataToSignLen,  /* length of dataToSign */
-                                           uint8_t             *sig,                   /* signature, RETURNED */
-                                           size_t              *sigLen,        /* IN/OUT */
-                                           int mode) {
-    size_t digestInfoLength = DER_MAX_DIGEST_INFO_LEN;
-    uint8_t digestInfo[digestInfoLength];
-    const SecAsn1Oid *digestOid;
-    size_t digestLen;
-    
-    switch (padding) {
-#if 0
-        case kSecPaddingPKCS1MD2:
-            digestLen = CC_MD2_DIGEST_LENGTH;
-            digestOid = &CSSMOID_MD2;
-            break;
-        case kSecPaddingPKCS1MD4:
-            digestLen = CC_MD4_DIGEST_LENGTH;
-            digestOid = &CSSMOID_MD4;
-            break;
-        case kSecPaddingPKCS1MD5:
-            digestLen = CC_MD5_DIGEST_LENGTH;
-            digestOid = &CSSMOID_MD5;
-            break;
-#endif
-        case kSecPaddingPKCS1SHA1:
-            digestLen = CC_SHA1_DIGEST_LENGTH;
-            digestOid = &CSSMOID_SHA1;
-            break;
-        case kSecPaddingPKCS1SHA224:
-            digestLen = CC_SHA224_DIGEST_LENGTH;
-            digestOid = &CSSMOID_SHA224;
-            break;
-        case kSecPaddingPKCS1SHA256:
-            digestLen = CC_SHA256_DIGEST_LENGTH;
-            digestOid = &CSSMOID_SHA256;
-            break;
-        case kSecPaddingPKCS1SHA384:
-            digestLen = CC_SHA384_DIGEST_LENGTH;
-            digestOid = &CSSMOID_SHA384;
-            break;
-        case kSecPaddingPKCS1SHA512:
-            digestLen = CC_SHA512_DIGEST_LENGTH;
-            digestOid = &CSSMOID_SHA512;
-            break;
-        default:
-            return errSecUnsupportedPadding;
-    }
-    
-    if (dataToSignLen != digestLen)
-        return errSecParam;
-    
-    size_t offset = DEREncodeDigestInfoPrefix(digestOid, digestLen,
-                                              digestInfo, digestInfoLength);
-    if (!offset)
-        return errSecBufferTooSmall;
-    
-    /* Append the digest to the digestInfo prefix and adjust the length. */
-    memcpy(&digestInfo[offset], dataToSign, digestLen);
-    digestInfoLength = offset + digestLen;
-    
-    if (mode == kSecKeyDigestInfoSign) {
-        return key->key_class->rawSign(key, kSecPaddingPKCS1,
-                                       digestInfo, digestInfoLength, sig, sigLen);
-    } else {
-        return key->key_class->rawVerify(key, kSecPaddingPKCS1,
-                                         digestInfo, digestInfoLength, sig, *sigLen);
-    }
-    
-    return errSecSuccess;
-}
-
-OSStatus SecKeyRawSign(
-                       SecKeyRef           key,            /* Private key */
-                       SecPadding          padding,            /* kSecPaddingNone or kSecPaddingPKCS1 */
-                       const uint8_t       *dataToSign,        /* signature over this data */
-                       size_t              dataToSignLen,      /* length of dataToSign */
-                       uint8_t             *sig,                       /* signature, RETURNED */
-                       size_t              *sigLen) {          /* IN/OUT */
-    if (!key->key_class->rawSign)
-        return errSecUnsupportedOperation;
-    
-    if (padding < kSecPaddingPKCS1MD2) {
-        return key->key_class->rawSign(key, padding, dataToSign, dataToSignLen,
-                                       sig, sigLen);
-    } else {
-        return SecKeyDigestInfoSignVerify(key, padding, dataToSign, dataToSignLen,
-                                          sig, sigLen, kSecKeyDigestInfoSign);
-    }
-}
-
-OSStatus SecKeyRawVerify(
-                         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) {         /* length of signature */
-    if (!key->key_class->rawVerify)
-        return errSecUnsupportedOperation;
-    
-    if (padding < kSecPaddingPKCS1MD2) {
-        return key->key_class->rawVerify(key, padding, signedData, signedDataLen,
-                                         sig, sigLen);
-    } else {
-        /* Casting away the constness of sig is safe since
-         SecKeyDigestInfoSignVerify only modifies sig if
-         mode == kSecKeyDigestInfoSign. */
-        return SecKeyDigestInfoSignVerify(key, padding,
-                                          signedData, signedDataLen, (uint8_t *)sig, &sigLen,
-                                          kSecKeyDigestInfoVerify);
-    }
-}
-
-OSStatus SecKeyEncrypt(
-                       SecKeyRef           key,                /* Public key */
-                       SecPadding          padding,                    /* kSecPaddingNone, kSecPaddingPKCS1, kSecPaddingOAEP */
-                       const uint8_t           *plainText,
-                       size_t              plainTextLen,               /* length of plainText */
-                       uint8_t             *cipherText,
-                       size_t              *cipherTextLen) {   /* IN/OUT */
-    if (key->key_class->encrypt)
-        return key->key_class->encrypt(key, padding, plainText, plainTextLen,
-                                       cipherText, cipherTextLen);
-    return errSecUnsupportedOperation;
-}
-
-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 */
-    if (key->key_class->decrypt)
-        return key->key_class->decrypt(key, padding, cipherText, cipherTextLen,
-                                       plainText, plainTextLen);
-    return errSecUnsupportedOperation;
-}
-
-size_t SecKeyGetBlockSize(SecKeyRef key) {
-    if (key->key_class->blockSize)
-        return key->key_class->blockSize(key);
-    return 0;
-}
-
-/* Private API functions. */
-
-CFDictionaryRef SecKeyCopyAttributeDictionary(SecKeyRef key) {
-    if (key->key_class->copyDictionary)
-        return key->key_class->copyDictionary(key);
-    return NULL;
-}
-
-SecKeyRef SecKeyCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
-       /* TODO: Support having an allocator in refAttributes. */
-       CFAllocatorRef allocator = NULL;
-       CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData);
-       CFTypeRef ktype = CFDictionaryGetValue(refAttributes, kSecAttrKeyType);
-       SInt32 algorithm;
-       SecKeyRef ref;
-    
-       /* First figure out the key type (algorithm). */
-       if (CFGetTypeID(ktype) == CFNumberGetTypeID()) {
-               CFNumberGetValue(ktype, kCFNumberSInt32Type, &algorithm);
-       } else if (isString(ktype)) {
-        algorithm = CFStringGetIntValue(ktype);
-        CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) algorithm);
-        if (!CFEqual(t, ktype)) {
-            secwarning("Unsupported key class: %@", ktype);
-            CFReleaseSafe(t);
-            return NULL;
-        }
-        CFReleaseSafe(t);
-    } else {
-               secwarning("Unsupported key type: %@", ktype);
-               return NULL;
-       }
-    
-       /* TODO: The code below won't scale well, consider moving to something
-     table driven. */
-       SInt32 class;
-       CFTypeRef kclass = CFDictionaryGetValue(refAttributes, kSecAttrKeyClass);
-       if (CFGetTypeID(kclass) == CFNumberGetTypeID()) {
-               CFNumberGetValue(kclass, kCFNumberSInt32Type, &class);
-       } else if (isString(kclass)) {
-        class = CFStringGetIntValue(kclass);
-        CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) class);
-        if (!CFEqual(t, kclass)) {
-            CFReleaseSafe(t);
-            secwarning("Unsupported key class: %@", kclass);
-            return NULL;
-        }
-        CFReleaseSafe(t);
-    } else {
-               secwarning("Unsupported key class: %@", kclass);
-               return NULL;
-       }
-    
-    switch (class) {
-        case 0: // kSecAttrKeyClassPublic
-            switch (algorithm) {
-                case 42: // kSecAlgorithmRSA
-                    ref = SecKeyCreateRSAPublicKey(allocator,
-                                                   CFDataGetBytePtr(data), CFDataGetLength(data),
-                                                   kSecKeyEncodingBytes);
-                    break;
-                case 43: // kSecAlgorithmECDSA
-                case 73: // kSecAlgorithmEC
-                    ref = SecKeyCreateECPublicKey(allocator,
-                                                  CFDataGetBytePtr(data), CFDataGetLength(data),
-                                                  kSecKeyEncodingBytes);
-                    break;
-                default:
-                    secwarning("Unsupported public key type: %@", ktype);
-                    ref = NULL;
-                    break;
-            };
-            break;
-        case 1: // kSecAttrKeyClassPrivate
-            switch (algorithm) {
-                case 42: // kSecAlgorithmRSA
-                    ref = SecKeyCreateRSAPrivateKey(allocator,
-                                                    CFDataGetBytePtr(data), CFDataGetLength(data),
-                                                    kSecKeyEncodingBytes);
-                    break;
-                case 43: // kSecAlgorithmECDSA
-                case 73: // kSecAlgorithmEC
-                    ref = SecKeyCreateECPrivateKey(allocator,
-                                                   CFDataGetBytePtr(data), CFDataGetLength(data),
-                                                   kSecKeyEncodingBytes);
-                    break;
-                default:
-                    secwarning("Unsupported private key type: %@", ktype);
-                    ref = NULL;
-                    break;
-            };
-            break;
-        case 2: // kSecAttrKeyClassSymmetric
-            secwarning("Unsupported symmetric key type: %@", ktype);
-            ref = NULL;
-            break;
-        default:
-            secwarning("Unsupported key class: %@", kclass);
-            ref = NULL;
-    }
-    
-       return ref;
-}
-
-/* TODO: This function should ensure that this keys algorithm matches the
- signature algorithm. */
-static OSStatus SecKeyGetDigestInfo(SecKeyRef this, 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) */
-    if (keyAlgID == kSecNullAlgorithmID)
-        keyAlgID = SecKeyGetAlgorithmID(this);
-    else if (keyAlgID != SecKeyGetAlgorithmID(this))
-        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 SecKeyDigestAndVerify(
-                               SecKeyRef           this,            /* Private key */
-                               const SecAsn1AlgId  *algId,         /* algorithm oid/params */
-                               const uint8_t       *dataToDigest,      /* signature over this data */
-                               size_t              dataToDigestLen,/* 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;
-    
-    if (this == NULL)
-        return errSecParam;
-    
-    status = SecKeyGetDigestInfo(this, algId, dataToDigest, dataToDigestLen, true,
-                                 digestInfo, &digestInfoLength);
-    if (status)
-        return status;
-    return SecKeyRawVerify(this, kSecPaddingPKCS1,
-                           digestInfo, digestInfoLength, sig, sigLen);
-}
-
-OSStatus SecKeyDigestAndSign(
-                             SecKeyRef           this,            /* Private key */
-                             const SecAsn1AlgId  *algId,         /* algorithm oid/params */
-                             const uint8_t       *dataToDigest,        /* signature over this data */
-                             size_t              dataToDigestLen,/* length of dataToDigest */
-                             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(this, algId, dataToDigest, dataToDigestLen, true /* digest data */,
-                                 digestInfo, &digestInfoLength);
-    if (status)
-        return status;
-    return SecKeyRawSign(this, kSecPaddingPKCS1,
-                         digestInfo, digestInfoLength, sig, sigLen);
-}
-
-OSStatus SecKeyVerifyDigest(
-                            SecKeyRef           this,            /* 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(this, algId, digestData, digestDataLen, false /* data is digest */,
-                                 digestInfo, &digestInfoLength);
-    if (status)
-        return status;
-    return SecKeyRawVerify(this, kSecPaddingPKCS1,
-                           digestInfo, digestInfoLength, sig, sigLen);
-}
-
-OSStatus SecKeySignDigest(
-                          SecKeyRef           this,            /* 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(this, algId, digestData, digestDataLen, false,
-                                 digestInfo, &digestInfoLength);
-    if (status)
-        return status;
-    return SecKeyRawSign(this, kSecPaddingPKCS1,
-                         digestInfo, digestInfoLength, sig, sigLen);
-}
-
-CFIndex SecKeyGetAlgorithmID(SecKeyRef key) {
-    /* This method was added to version 1 keys. */
-    if (key->key_class->version > 0 && key->key_class->getAlgorithmID)
-        return key->key_class->getAlgorithmID(key);
-    /* All version 0 key were RSA. */
-    return kSecRSAAlgorithmID;
-}
-
-
-OSStatus SecKeyCopyPublicBytes(SecKeyRef key, CFDataRef* serializedPublic) {
-    if (key->key_class->version > 1 && key->key_class->copyPublic)
-        return key->key_class->copyPublic(key, serializedPublic);
-    return errSecUnimplemented;
-}
-
-SecKeyRef SecKeyCreateFromPublicBytes(CFAllocatorRef allocator, CFIndex algorithmID, const uint8_t *keyData, CFIndex keyDataLength)
-{
-    switch (algorithmID)
-    {
-        case kSecRSAAlgorithmID:
-            return SecKeyCreateRSAPublicKey(allocator,
-                                            keyData, keyDataLength,
-                                            kSecKeyEncodingBytes);
-        case kSecECDSAAlgorithmID:
-            return SecKeyCreateECPublicKey(allocator,
-                                           keyData, keyDataLength,
-                                           kSecKeyEncodingBytes);
-        default:
-            return NULL;
-    }
-}
-
-SecKeyRef SecKeyCreateFromPublicData(CFAllocatorRef allocator, CFIndex algorithmID, CFDataRef serialized)
-{
-    return SecKeyCreateFromPublicBytes(allocator, algorithmID, CFDataGetBytePtr(serialized), CFDataGetLength(serialized));
-}
-
-// This is a bit icky hack to avoid changing the vtable for
-// SecKey.
-size_t SecKeyGetSize(SecKeyRef key, SecKeySize whichSize)
-{
-    size_t result = SecKeyGetBlockSize(key);
-    
-    if (kSecECDSAAlgorithmID == SecKeyGetAlgorithmID(key)) {
-        switch (whichSize) {
-            case kSecKeyEncryptedDataSize:
-                result = 0;
-                break;
-            case kSecKeySignatureSize:
-                result = (result >= 66 ? 9 : 8) + 2 * result;
-                break;
-            case kSecKeyKeySizeInBits:
-                if (result >= 66)
-                    return 521;
-        }
-    }
-    
-    if (whichSize == kSecKeyKeySizeInBits)
-        result *= 8;
-    
-    return result;
-    
-}
-
-OSStatus SecKeyFindWithPersistentRef(CFDataRef persistentRef, SecKeyRef* lookedUpData)
-{
-    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
-                                                         kSecReturnRef,             kCFBooleanTrue,
-                                                         kSecClass,                 kSecClassKey,
-                                                         kSecValuePersistentRef,    persistentRef,
-                                                         NULL);
-    CFTypeRef foundRef = NULL;
-    OSStatus status = SecItemCopyMatching(query, &foundRef);
-    
-    if (status == errSecSuccess) {
-        if (CFGetTypeID(foundRef) == SecKeyGetTypeID()) {
-            *lookedUpData = (SecKeyRef) foundRef;
-            foundRef = NULL;
-            status = errSecSuccess;
-        } else {
-            status = errSecItemNotFound;
-        }
-    }
-    
-    CFReleaseSafe(foundRef);
-    CFReleaseSafe(query);
-    
-    return status;
-}
-
-OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef)
-{
-    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
-                                                         kSecReturnPersistentRef,   kCFBooleanTrue,
-                                                         kSecValueRef,              key,
-                                                         kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
-                                                         NULL);
-    CFTypeRef foundRef = NULL;
-    OSStatus status = SecItemCopyMatching(query, &foundRef);
-    
-    if (status == errSecSuccess) {
-        if (CFGetTypeID(foundRef) == CFDataGetTypeID()) {
-            *persistentRef = foundRef;
-            foundRef = NULL;
-        } else {
-            status = errSecItemNotFound;
-        }
-    }
-    
-    CFReleaseSafe(foundRef);
-    CFReleaseSafe(query);
-    
-    return status;
-}