]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_keychain/lib/SecIdentity.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_keychain / lib / SecIdentity.cpp
diff --git a/Security/libsecurity_keychain/lib/SecIdentity.cpp b/Security/libsecurity_keychain/lib/SecIdentity.cpp
deleted file mode 100644 (file)
index 5c16a1b..0000000
+++ /dev/null
@@ -1,1119 +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 <Security/SecIdentity.h>
-#include <Security/SecIdentityPriv.h>
-#include <Security/SecKeychainItemPriv.h>
-#include <Security/SecItem.h>
-#include <Security/SecIdentityPriv.h>
-
-#include "SecBridge.h"
-#include <security_keychain/Certificate.h>
-#include <security_keychain/Identity.h>
-#include <security_keychain/KeyItem.h>
-#include <security_keychain/KCCursor.h>
-#include <security_cdsa_utilities/Schema.h>
-#include <security_utilities/simpleprefs.h>
-#include <sys/param.h>
-#include <syslog.h>
-
-
-/* private function declarations */
-OSStatus
-SecIdentityFindPreferenceItemWithNameAndKeyUsage(
-       CFTypeRef keychainOrArray,
-       CFStringRef name,
-       int32_t keyUsage,
-       SecKeychainItemRef *itemRef);
-
-OSStatus SecIdentityDeletePreferenceItemWithNameAndKeyUsage(
-       CFTypeRef keychainOrArray,
-       CFStringRef name,
-       int32_t keyUsage);
-
-
-CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage)
-{
-       CFIndex count = 0;
-       CSSM_KEYUSE result = (CSSM_KEYUSE) 0;
-
-       if ((NULL == usage) || (0 == (count = CFArrayGetCount(usage))))
-       {
-               return result;
-       }
-
-       for (CFIndex iCnt = 0; iCnt < count; iCnt++)
-       {
-               CFStringRef keyUsageStr = NULL;
-               keyUsageStr = (CFStringRef)CFArrayGetValueAtIndex(usage,iCnt);
-               if (NULL != keyUsageStr)
-               {
-                       if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanEncrypt, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_ENCRYPT;
-                       }
-                       else if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanDecrypt, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_DECRYPT;
-                       }
-                       else if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanDerive, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_DERIVE;
-                       }
-                       else if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanSign, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_SIGN;
-                       }
-                       else if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanVerify, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_VERIFY;
-                       }
-                       else if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanWrap, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_WRAP;
-                       }
-                       else if (kCFCompareEqualTo == CFStringCompare((CFStringRef)kSecAttrCanUnwrap, keyUsageStr, 0))
-                       {
-                               result |= CSSM_KEYUSE_UNWRAP;
-                       }
-               }
-       }
-
-       return result;
-}
-
-
-CFTypeID
-SecIdentityGetTypeID(void)
-{
-       BEGIN_SECAPI
-
-       return gTypes().Identity.typeID;
-
-       END_SECAPI1(_kCFRuntimeNotATypeID)
-}
-
-
-OSStatus
-SecIdentityCopyCertificate(
-            SecIdentityRef identityRef,
-            SecCertificateRef *certificateRef)
-{
-    BEGIN_SECAPI
-
-       SecPointer<Certificate> certificatePtr(Identity::required(identityRef)->certificate());
-       Required(certificateRef) = certificatePtr->handle();
-
-    END_SECAPI
-}
-
-
-OSStatus
-SecIdentityCopyPrivateKey(
-            SecIdentityRef identityRef,
-            SecKeyRef *privateKeyRef)
-{
-    BEGIN_SECAPI
-
-       SecPointer<KeyItem> keyItemPtr(Identity::required(identityRef)->privateKey());
-       Required(privateKeyRef) = keyItemPtr->handle();
-
-    END_SECAPI
-}
-
-OSStatus
-SecIdentityCreateWithCertificate(
-       CFTypeRef keychainOrArray,
-       SecCertificateRef certificateRef,
-       SecIdentityRef *identityRef)
-{
-    BEGIN_SECAPI
-
-       SecPointer<Certificate> certificatePtr(Certificate::required(certificateRef));
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList(keychainOrArray, keychains);
-       SecPointer<Identity> identityPtr(new Identity(keychains, certificatePtr));
-       Required(identityRef) = identityPtr->handle();
-
-    END_SECAPI
-}
-
-SecIdentityRef
-SecIdentityCreate(
-       CFAllocatorRef allocator,
-       SecCertificateRef certificate,
-       SecKeyRef privateKey)
-{
-       SecIdentityRef identityRef = NULL;
-    OSStatus __secapiresult;
-       try {
-               SecPointer<Certificate> certificatePtr(Certificate::required(certificate));
-               SecPointer<KeyItem> keyItemPtr(KeyItem::required(privateKey));
-               SecPointer<Identity> identityPtr(new Identity(keyItemPtr, certificatePtr));
-               identityRef = identityPtr->handle();
-
-               __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 identityRef;
-}
-
-CFComparisonResult
-SecIdentityCompare(
-       SecIdentityRef identity1,
-       SecIdentityRef identity2,
-       CFOptionFlags compareOptions)
-{
-       if (!identity1 || !identity2)
-       {
-               if (identity1 == identity2)
-                       return kCFCompareEqualTo;
-               else if (identity1 < identity2)
-                       return kCFCompareLessThan;
-               else
-                       return kCFCompareGreaterThan;
-       }
-
-       BEGIN_SECAPI
-
-       SecPointer<Identity> id1(Identity::required(identity1));
-       SecPointer<Identity> id2(Identity::required(identity2));
-
-       if (id1 == id2)
-               return kCFCompareEqualTo;
-       else if (id1 < id2)
-               return kCFCompareLessThan;
-       else
-               return kCFCompareGreaterThan;
-
-       END_SECAPI1(kCFCompareGreaterThan);
-}
-
-static
-CFArrayRef _SecIdentityCopyPossiblePaths(
-    CFStringRef name)
-{
-    // utility function to build and return an array of possible paths for the given name.
-    // if name is not a URL, this returns a single-element array.
-    // if name is a URL, the array may contain 1..N elements, one for each level of the path hierarchy.
-
-    CFMutableArrayRef names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    if (!name) {
-        return names;
-    }
-    CFIndex oldLength = CFStringGetLength(name);
-    CFArrayAppendValue(names, name);
-
-    CFURLRef url = CFURLCreateWithString(NULL, name, NULL);
-    if (url) {
-               if (CFURLCanBeDecomposed(url)) {
-                       // first, remove the query portion of this URL, if any
-                       CFStringRef qs = CFURLCopyQueryString(url, NULL);
-                       if (qs) {
-                               CFMutableStringRef newName = CFStringCreateMutableCopy(NULL, oldLength, name);
-                               if (newName) {
-                                       CFIndex qsLength = CFStringGetLength(qs) + 1; // include the '?'
-                                       CFStringDelete(newName, CFRangeMake(oldLength-qsLength, qsLength));
-                                       CFRelease(url);
-                                       url = CFURLCreateWithString(NULL, newName, NULL);
-                                       CFArraySetValueAtIndex(names, 0, newName);
-                                       CFRelease(newName);
-                               }
-                               CFRelease(qs);
-                       }
-                       // now add an entry for each level of the path
-                       while (url) {
-                               CFURLRef parent = CFURLCreateCopyDeletingLastPathComponent(NULL, url);
-                               if (parent) {
-                                       CFStringRef parentURLString = CFURLGetString(parent);
-                                       if (parentURLString) {
-                                               CFIndex newLength = CFStringGetLength(parentURLString);
-                                               // check that string length has decreased as expected; for file URLs,
-                                               // CFURLCreateCopyDeletingLastPathComponent can insert './' or '../'
-                                               if ((newLength >= oldLength) || (!CFStringHasPrefix(name, parentURLString))) {
-                                                       CFRelease(parent);
-                                                       CFRelease(url);
-                                                       break;
-                                               }
-                                               oldLength = newLength;
-                                               CFArrayAppendValue(names, parentURLString);
-                                       }
-                               }
-                               CFRelease(url);
-                               url = parent;
-                       }
-               }
-               else {
-                       CFRelease(url);
-               }
-       }
-       // finally, add wildcard entries for each subdomain
-       url = CFURLCreateWithString(NULL, name, NULL);
-       if (url) {
-               if (CFURLCanBeDecomposed(url)) {
-                       CFStringRef netLocString = CFURLCopyNetLocation(url);
-                       if (netLocString) {
-                               // first strip off port number, if present
-                               CFStringRef tmpLocString = netLocString;
-                               CFArrayRef hostnameArray = CFStringCreateArrayBySeparatingStrings(NULL, netLocString, CFSTR(":"));
-                               tmpLocString = (CFStringRef)CFRetain((CFStringRef)CFArrayGetValueAtIndex(hostnameArray, 0));
-                               CFRelease(netLocString);
-                               CFRelease(hostnameArray);
-                               netLocString = tmpLocString;
-                               // split remaining string into domain components
-                               hostnameArray = CFStringCreateArrayBySeparatingStrings(NULL, netLocString, CFSTR("."));
-                               CFIndex subdomainCount = CFArrayGetCount(hostnameArray);
-                               CFIndex i = 0;
-                               while (++i < subdomainCount) {
-                                       CFIndex j = i;
-                                       CFMutableStringRef wildcardString = CFStringCreateMutable(NULL, 0);
-                                       if (wildcardString) {
-                                               CFStringAppendCString(wildcardString, "*", kCFStringEncodingUTF8);
-                                               while (j < subdomainCount) {
-                                                       CFStringRef domainString = (CFStringRef)CFArrayGetValueAtIndex(hostnameArray, j++);
-                                                       if (CFStringGetLength(domainString) > 0) {
-                                                               CFStringAppendCString(wildcardString, ".", kCFStringEncodingUTF8);
-                                                               CFStringAppend(wildcardString, domainString);
-                                                       }
-                                               }
-                                               if (CFStringGetLength(wildcardString) > 1) {
-                                                       CFArrayAppendValue(names, wildcardString);
-                                               }
-                                               CFRelease(wildcardString);
-                                       }
-                               }
-                               CFRelease(hostnameArray);
-                               CFRelease(netLocString);
-                       }
-               }
-               CFRelease(url);
-       }
-
-    return names;
-}
-
-static
-OSStatus _SecIdentityCopyPreferenceMatchingName(
-    CFStringRef name,
-    CSSM_KEYUSE keyUsage,
-    CFArrayRef validIssuers,
-    SecIdentityRef *identity)
-{
-    // this is NOT exported, and called only from SecIdentityCopyPreference (below), so no BEGIN/END macros here;
-    // caller must handle exceptions
-
-       StorageManager::KeychainList keychains;
-       globals().storageManager.getSearchList(keychains);
-       KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
-
-       char idUTF8[MAXPATHLEN];
-    Required(name);
-    if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8))
-        idUTF8[0] = (char)'\0';
-    CssmData service(const_cast<char *>(idUTF8), strlen(idUTF8));
-       FourCharCode itemType = 'iprf';
-    cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
-       cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType);
-    if (keyUsage)
-        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
-
-       Item prefItem;
-       if (!cursor->next(prefItem))
-               return errSecItemNotFound;
-
-       // get persistent certificate reference
-       SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } };
-       SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
-       prefItem->getContent(NULL, &itemAttrList, NULL, NULL);
-
-       // find certificate, given persistent reference data
-       CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull);
-       SecKeychainItemRef certItemRef = nil;
-       OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); //%%% need to make this a method of ItemImpl
-       prefItem->freeContent(&itemAttrList, NULL);
-       if (pItemRef)
-               CFRelease(pItemRef);
-       if (status)
-               return status;
-
-    // filter on valid issuers, if provided
-    if (validIssuers) {
-        //%%%TBI
-    }
-
-       // create identity reference, given certificate
-       Item certItem = ItemImpl::required(SecKeychainItemRef(certItemRef));
-       SecPointer<Certificate> certificate(static_cast<Certificate *>(certItem.get()));
-       SecPointer<Identity> identity_ptr(new Identity(keychains, certificate));
-       if (certItemRef)
-               CFRelease(certItemRef);
-
-       Required(identity) = identity_ptr->handle();
-
-    return status;
-}
-
-SecIdentityRef SecIdentityCopyPreferred(CFStringRef name, CFArrayRef keyUsage, CFArrayRef validIssuers)
-{
-       // This function will look for a matching preference in the following order:
-       // - matches the name and the supplied key use
-       // - matches the name and the special 'ANY' key use
-       // - matches the name with no key usage constraint
-
-       SecIdentityRef identityRef = NULL;
-       CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage);
-       OSStatus status = SecIdentityCopyPreference(name, keyUse, validIssuers, &identityRef);
-       if (status != errSecSuccess && keyUse != CSSM_KEYUSE_ANY)
-               status = SecIdentityCopyPreference(name, CSSM_KEYUSE_ANY, validIssuers, &identityRef);
-       if (status != errSecSuccess && keyUse != 0)
-               status = SecIdentityCopyPreference(name, 0, validIssuers, &identityRef);
-
-       return identityRef;
-}
-
-OSStatus SecIdentityCopyPreference(
-    CFStringRef name,
-    CSSM_KEYUSE keyUsage,
-    CFArrayRef validIssuers,
-    SecIdentityRef *identity)
-{
-    // The original implementation of SecIdentityCopyPreference matches the exact string only.
-    // That implementation has been moved to _SecIdentityCopyPreferenceMatchingName (above),
-    // and this function is a wrapper which calls it, so that existing clients will get the
-    // extended behavior of server domain matching for items that specify URLs.
-    // (Note that behavior is unchanged if the specified name is not a URL.)
-
-    BEGIN_SECAPI
-
-    CFTypeRef val = (CFTypeRef)CFPreferencesCopyValue(CFSTR("LogIdentityPreferenceLookup"),
-                    CFSTR("com.apple.security"),
-                    kCFPreferencesCurrentUser,
-                    kCFPreferencesAnyHost);
-    Boolean logging = false;
-    if (val && CFGetTypeID(val) == CFBooleanGetTypeID()) {
-        logging = CFBooleanGetValue((CFBooleanRef)val);
-        CFRelease(val);
-    }
-
-    OSStatus status = errSecItemNotFound;
-    CFArrayRef names = _SecIdentityCopyPossiblePaths(name);
-    if (!names) {
-        return status;
-    }
-
-    CFIndex idx, total = CFArrayGetCount(names);
-    for (idx = 0; idx < total; idx++) {
-        CFStringRef aName = (CFStringRef)CFArrayGetValueAtIndex(names, idx);
-        try {
-            status = _SecIdentityCopyPreferenceMatchingName(aName, keyUsage, validIssuers, identity);
-        }
-        catch (...) { status = errSecItemNotFound; }
-
-        if (logging) {
-            // get identity label
-            CFStringRef labelString = NULL;
-            if (!status && identity && *identity) {
-                try {
-                    SecPointer<Certificate> cert(Identity::required(*identity)->certificate());
-                    cert->inferLabel(false, &labelString);
-                }
-                catch (...) { labelString = NULL; };
-            }
-            char *labelBuf = NULL;
-            CFIndex labelBufSize = (labelString) ? CFStringGetLength(labelString) * 4 : 4;
-            labelBuf = (char *)malloc(labelBufSize);
-            if (!labelString || !CFStringGetCString(labelString, labelBuf, labelBufSize, kCFStringEncodingUTF8)) {
-                labelBuf[0] = 0;
-            }
-            if (labelString) {
-                CFRelease(labelString);
-            }
-
-            // get service name
-            char *serviceBuf = NULL;
-            CFIndex serviceBufSize = CFStringGetLength(aName) * 4;
-            serviceBuf = (char *)malloc(serviceBufSize);
-            if (!CFStringGetCString(aName, serviceBuf, serviceBufSize, kCFStringEncodingUTF8)) {
-                serviceBuf[0] = 0;
-            }
-
-            syslog(LOG_NOTICE, "preferred identity: \"%s\" found for \"%s\"\n", labelBuf, serviceBuf);
-            if (!status && name) {
-                char *nameBuf = NULL;
-                CFIndex nameBufSize = CFStringGetLength(name) * 4;
-                nameBuf = (char *)malloc(nameBufSize);
-                if (!CFStringGetCString(name, nameBuf, nameBufSize, kCFStringEncodingUTF8)) {
-                    nameBuf[0] = 0;
-                }
-                syslog(LOG_NOTICE, "lookup complete; will use: \"%s\" for \"%s\"\n", labelBuf, nameBuf);
-                free(nameBuf);
-            }
-
-            free(labelBuf);
-            free(serviceBuf);
-        }
-
-        if (status == errSecSuccess) {
-            break; // match found
-        }
-    }
-
-    CFRelease(names);
-    return status;
-
-    END_SECAPI
-}
-
-OSStatus SecIdentitySetPreference(
-    SecIdentityRef identity,
-    CFStringRef name,
-    CSSM_KEYUSE keyUsage)
-{
-       if (!name) {
-               return errSecParam;
-       }
-       if (!identity) {
-               // treat NULL identity as a request to clear the preference
-               // (note: if keyUsage is 0, this clears all key usage prefs for name)
-               return SecIdentityDeletePreferenceItemWithNameAndKeyUsage(NULL, name, keyUsage);
-       }
-
-    BEGIN_SECAPI
-
-       SecPointer<Certificate> certificate(Identity::required(identity)->certificate());
-
-       // determine the account attribute
-       //
-       // This attribute must be synthesized from certificate label + pref item type + key usage,
-       // as only the account and service attributes can make a generic keychain item unique.
-       // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that
-       // we can save a certificate preference if an identity preference already exists for the
-       // given service name, and vice-versa.
-       // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string.
-       //
-    CFStringRef labelStr = nil;
-       certificate->inferLabel(false, &labelStr);
-       if (!labelStr) {
-        MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed"
-       }
-       CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1;
-       const char *templateStr = "%s [key usage 0x%X]";
-       const int keyUsageMaxStrLen = 8;
-       accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen;
-       char accountUTF8[accountUTF8Len];
-    if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8))
-               accountUTF8[0] = (char)'\0';
-       if (keyUsage)
-               snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage);
-       snprintf(accountUTF8, accountUTF8Len-1, "%s ", accountUTF8);
-    CssmData account(const_cast<char *>(accountUTF8), strlen(accountUTF8));
-    CFRelease(labelStr);
-
-       // service attribute (name provided by the caller)
-       CFIndex serviceUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(name), kCFStringEncodingUTF8) + 1;;
-       char serviceUTF8[serviceUTF8Len];
-    if (!CFStringGetCString(name, serviceUTF8, serviceUTF8Len-1, kCFStringEncodingUTF8))
-        serviceUTF8[0] = (char)'\0';
-    CssmData service(const_cast<char *>(serviceUTF8), strlen(serviceUTF8));
-
-    // look for existing identity preference item, in case this is an update
-       StorageManager::KeychainList keychains;
-       globals().storageManager.getSearchList(keychains);
-       KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
-    FourCharCode itemType = 'iprf';
-    cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
-       cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType);
-    if (keyUsage) {
-        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
-       }
-
-       Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false);
-    bool add = (!cursor->next(item));
-       // at this point, we either have a new item to add or an existing item to update
-
-    // set item attribute values
-    item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
-    item->setAttribute(Schema::attributeInfo(kSecTypeItemAttr), itemType);
-    item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
-       item->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
-    item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
-
-       // generic attribute (store persistent certificate reference)
-       CFDataRef pItemRef = nil;
-    certificate->copyPersistentReference(pItemRef);
-       if (!pItemRef) {
-               MacOSError::throwMe(errSecInvalidItemRef);
-    }
-       const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef);
-       CFIndex dataLen = CFDataGetLength(pItemRef);
-       CssmData pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr)), dataLen);
-       item->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref);
-       CFRelease(pItemRef);
-
-    if (add) {
-        Keychain keychain = nil;
-        try {
-            keychain = globals().storageManager.defaultKeychain();
-            if (!keychain->exists())
-                MacOSError::throwMe(errSecNoSuchKeychain);     // Might be deleted or not available at this time.
-        }
-        catch(...) {
-            keychain = globals().storageManager.defaultKeychainUI(item);
-        }
-
-               try {
-                       keychain->add(item);
-               }
-               catch (const MacOSError &err) {
-                       if (err.osStatus() != errSecDuplicateItem)
-                               throw; // if item already exists, fall through to update
-               }
-    }
-       item->update();
-
-    END_SECAPI
-}
-
-OSStatus
-SecIdentitySetPreferred(SecIdentityRef identity, CFStringRef name, CFArrayRef keyUsage)
-{
-       CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage);
-       return SecIdentitySetPreference(identity, name, keyUse);
-}
-
-OSStatus
-SecIdentityFindPreferenceItem(
-       CFTypeRef keychainOrArray,
-       CFStringRef idString,
-       SecKeychainItemRef *itemRef)
-{
-    BEGIN_SECAPI
-
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList(keychainOrArray, keychains);
-       KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
-
-       char idUTF8[MAXPATHLEN];
-    idUTF8[0] = (char)'\0';
-       if (idString)
-       {
-               if (!CFStringGetCString(idString, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8))
-                       idUTF8[0] = (char)'\0';
-       }
-    size_t idUTF8Len = strlen(idUTF8);
-    if (!idUTF8Len)
-        MacOSError::throwMe(errSecParam);
-
-    CssmData service(const_cast<char *>(idUTF8), idUTF8Len);
-    cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
-       cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'iprf');
-
-       Item item;
-       if (!cursor->next(item))
-               MacOSError::throwMe(errSecItemNotFound);
-
-       if (itemRef)
-               *itemRef=item->handle();
-
-    END_SECAPI
-}
-
-OSStatus
-SecIdentityFindPreferenceItemWithNameAndKeyUsage(
-       CFTypeRef keychainOrArray,
-       CFStringRef name,
-       int32_t keyUsage,
-       SecKeychainItemRef *itemRef)
-{
-    BEGIN_SECAPI
-
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList(keychainOrArray, keychains);
-       KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
-
-       char idUTF8[MAXPATHLEN];
-    idUTF8[0] = (char)'\0';
-       if (name)
-       {
-               if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8))
-                       idUTF8[0] = (char)'\0';
-       }
-    size_t idUTF8Len = strlen(idUTF8);
-    if (!idUTF8Len)
-        MacOSError::throwMe(errSecParam);
-
-    CssmData service(const_cast<char *>(idUTF8), idUTF8Len);
-    cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
-       cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'iprf');
-    if (keyUsage)
-        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
-
-       Item item;
-       if (!cursor->next(item))
-               MacOSError::throwMe(errSecItemNotFound);
-
-       if (itemRef)
-               *itemRef=item->handle();
-
-    END_SECAPI
-}
-
-OSStatus SecIdentityDeletePreferenceItemWithNameAndKeyUsage(
-       CFTypeRef keychainOrArray,
-       CFStringRef name,
-       int32_t keyUsage)
-{
-       // when a specific key usage is passed, we'll only match & delete that pref;
-       // when a key usage of 0 is passed, all matching prefs should be deleted.
-       // maxUsages represents the most matches there could theoretically be, so
-       // cut things off at that point if we're still finding items (if they can't
-       // be deleted for some reason, we'd never break out of the loop.)
-
-       OSStatus status;
-       SecKeychainItemRef item = NULL;
-       int count = 0, maxUsages = 12;
-       while (++count <= maxUsages &&
-                       (status = SecIdentityFindPreferenceItemWithNameAndKeyUsage(keychainOrArray, name, keyUsage, &item)) == errSecSuccess) {
-               status = SecKeychainItemDelete(item);
-               CFRelease(item);
-               item = NULL;
-       }
-
-       // it's not an error if the item isn't found
-       return (status == errSecItemNotFound) ? errSecSuccess : status;
-}
-
-
-static
-OSStatus _SecIdentityAddPreferenceItemWithName(
-       SecKeychainRef keychainRef,
-       SecIdentityRef identityRef,
-       CFStringRef idString,
-       SecKeychainItemRef *itemRef)
-{
-    // this is NOT exported, and called only from SecIdentityAddPreferenceItem (below), so no BEGIN/END macros here;
-    // caller must handle exceptions
-
-       if (!identityRef || !idString)
-               return errSecParam;
-       SecPointer<Certificate> cert(Identity::required(identityRef)->certificate());
-       Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false);
-       sint32 keyUsage = 0;
-
-       // determine the account attribute
-       //
-       // This attribute must be synthesized from certificate label + pref item type + key usage,
-       // as only the account and service attributes can make a generic keychain item unique.
-       // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that
-       // we can save a certificate preference if an identity preference already exists for the
-       // given service name, and vice-versa.
-       // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string.
-       //
-    CFStringRef labelStr = nil;
-       cert->inferLabel(false, &labelStr);
-       if (!labelStr) {
-        return errSecDataTooLarge; // data is "in a format which cannot be displayed"
-       }
-       CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1;
-       const char *templateStr = "%s [key usage 0x%X]";
-       const int keyUsageMaxStrLen = 8;
-       accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen;
-       char accountUTF8[accountUTF8Len];
-    if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8))
-               accountUTF8[0] = (char)'\0';
-       if (keyUsage)
-               snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage);
-       snprintf(accountUTF8, accountUTF8Len-1, "%s ", accountUTF8);
-    CssmData account(const_cast<char *>(accountUTF8), strlen(accountUTF8));
-    CFRelease(labelStr);
-
-       // service attribute (name provided by the caller)
-       CFIndex serviceUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(idString), kCFStringEncodingUTF8) + 1;;
-       char serviceUTF8[serviceUTF8Len];
-    if (!CFStringGetCString(idString, serviceUTF8, serviceUTF8Len-1, kCFStringEncodingUTF8))
-        serviceUTF8[0] = (char)'\0';
-    CssmData service(const_cast<char *>(serviceUTF8), strlen(serviceUTF8));
-
-       // set item attribute values
-       item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
-       item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
-       item->setAttribute(Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'iprf');
-       item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
-       item->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr), keyUsage);
-
-       // generic attribute (store persistent certificate reference)
-       CFDataRef pItemRef = nil;
-       OSStatus status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)cert->handle(), &pItemRef);
-       if (!pItemRef)
-               status = errSecInvalidItemRef;
-       if (status)
-                return status;
-       const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef);
-       CFIndex dataLen = CFDataGetLength(pItemRef);
-       CssmData pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr)), dataLen);
-       item->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref);
-       CFRelease(pItemRef);
-
-       Keychain keychain = nil;
-       try {
-        keychain = Keychain::optional(keychainRef);
-        if (!keychain->exists())
-            MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
-    }
-    catch(...) {
-        keychain = globals().storageManager.defaultKeychainUI(item);
-    }
-
-       try {
-               keychain->add(item);
-       }
-       catch (const MacOSError &err) {
-               if (err.osStatus() != errSecDuplicateItem)
-                       throw; // if item already exists, fall through to update
-       }
-
-       item->update();
-
-    if (itemRef)
-               *itemRef = item->handle();
-
-    return status;
-}
-
-OSStatus SecIdentityAddPreferenceItem(
-       SecKeychainRef keychainRef,
-       SecIdentityRef identityRef,
-       CFStringRef idString,
-       SecKeychainItemRef *itemRef)
-{
-    // The original implementation of SecIdentityAddPreferenceItem adds the exact string only.
-    // That implementation has been moved to _SecIdentityAddPreferenceItemWithName (above),
-    // and this function is a wrapper which calls it, so that existing clients will get the
-    // extended behavior of server domain matching for items that specify URLs.
-    // (Note that behavior is unchanged if the specified idString is not a URL.)
-
-    BEGIN_SECAPI
-
-    OSStatus status = errSecInternalComponent;
-    CFArrayRef names = _SecIdentityCopyPossiblePaths(idString);
-    if (!names) {
-        return status;
-    }
-
-    CFIndex total = CFArrayGetCount(names);
-    if (total > 0) {
-        // add item for name (first element in array)
-        CFStringRef aName = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
-        try {
-            status = _SecIdentityAddPreferenceItemWithName(keychainRef, identityRef, aName, itemRef);
-        }
-        catch (const MacOSError &err)   { status=err.osStatus(); }
-        catch (const CommonError &err)  { status=SecKeychainErrFromOSStatus(err.osStatus()); }
-        catch (const std::bad_alloc &)  { status=errSecAllocate; }
-        catch (...)                     { status=errSecInternalComponent; }
-    }
-    if (total > 2) {
-               Boolean setDomainDefaultIdentity = FALSE;
-               CFTypeRef val = (CFTypeRef)CFPreferencesCopyValue(CFSTR("SetDomainDefaultIdentity"),
-                                                                                                                 CFSTR("com.apple.security.identities"),
-                                                                                                                 kCFPreferencesCurrentUser,
-                                                                                                                 kCFPreferencesAnyHost);
-               if (val) {
-                       if (CFGetTypeID(val) == CFBooleanGetTypeID())
-                               setDomainDefaultIdentity = CFBooleanGetValue((CFBooleanRef)val) ? TRUE : FALSE;
-                       CFRelease(val);
-               }
-               if (setDomainDefaultIdentity) {
-                       // add item for domain (second-to-last element in array, e.g. "*.apple.com")
-                       OSStatus tmpStatus = errSecSuccess;
-                       CFStringRef aName = (CFStringRef)CFArrayGetValueAtIndex(names, total-2);
-                       try {
-                               tmpStatus = _SecIdentityAddPreferenceItemWithName(keychainRef, identityRef, aName, itemRef);
-                       }
-                       catch (const MacOSError &err)   { tmpStatus=err.osStatus(); }
-                       catch (const CommonError &err)  { tmpStatus=SecKeychainErrFromOSStatus(err.osStatus()); }
-                       catch (const std::bad_alloc &)  { tmpStatus=errSecAllocate; }
-                       catch (...)                     { tmpStatus=errSecInternalComponent; }
-               }
-    }
-
-    CFRelease(names);
-    return status;
-
-    END_SECAPI
-}
-
-/* deprecated in 10.5 */
-OSStatus SecIdentityUpdatePreferenceItem(
-                       SecKeychainItemRef itemRef,
-                       SecIdentityRef identityRef)
-{
-    BEGIN_SECAPI
-
-       if (!itemRef || !identityRef)
-               MacOSError::throwMe(errSecParam);
-       SecPointer<Certificate> certificate(Identity::required(identityRef)->certificate());
-       Item prefItem = ItemImpl::required(itemRef);
-
-       // get the current key usage value for this item
-       sint32 keyUsage = 0;
-       UInt32 actLen = 0;
-       SecKeychainAttribute attr = { kSecScriptCodeItemAttr, sizeof(sint32), &keyUsage };
-       try {
-               prefItem->getAttribute(attr, &actLen);
-       }
-       catch(...) {
-               keyUsage = 0;
-       };
-
-       // set the account attribute
-       //
-       // This attribute must be synthesized from certificate label + pref item type + key usage,
-       // as only the account and service attributes can make a generic keychain item unique.
-       // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that
-       // we can save a certificate preference if an identity preference already exists for the
-       // given service name, and vice-versa.
-       // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string.
-       //
-    CFStringRef labelStr = nil;
-       certificate->inferLabel(false, &labelStr);
-       if (!labelStr) {
-        MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed"
-       }
-       CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1;
-       const char *templateStr = "%s [key usage 0x%X]";
-       const int keyUsageMaxStrLen = 8;
-       accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen;
-       char accountUTF8[accountUTF8Len];
-    if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8))
-               accountUTF8[0] = (char)'\0';
-       if (keyUsage)
-               snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage);
-       snprintf(accountUTF8, accountUTF8Len-1, "%s ", accountUTF8);
-    CssmData account(const_cast<char *>(accountUTF8), strlen(accountUTF8));
-       prefItem->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
-    CFRelease(labelStr);
-
-       // generic attribute (store persistent certificate reference)
-       CFDataRef pItemRef = nil;
-       OSStatus status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)certificate->handle(), &pItemRef);
-       if (!pItemRef)
-               status = errSecInvalidItemRef;
-       if (status)
-               MacOSError::throwMe(status);
-       const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef);
-       CFIndex dataLen = CFDataGetLength(pItemRef);
-       CssmData pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr)), dataLen);
-       prefItem->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref);
-       CFRelease(pItemRef);
-
-       prefItem->update();
-
-    END_SECAPI
-}
-
-OSStatus SecIdentityCopyFromPreferenceItem(
-                       SecKeychainItemRef itemRef,
-                       SecIdentityRef *identityRef)
-{
-    BEGIN_SECAPI
-
-       if (!itemRef || !identityRef)
-               MacOSError::throwMe(errSecParam);
-       Item prefItem = ItemImpl::required(itemRef);
-
-       // get persistent certificate reference
-       SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } };
-       SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
-       prefItem->getContent(NULL, &itemAttrList, NULL, NULL);
-
-       // find certificate, given persistent reference data
-       CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull);
-       SecKeychainItemRef certItemRef = nil;
-       OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); //%%% need to make this a method of ItemImpl
-       prefItem->freeContent(&itemAttrList, NULL);
-       if (pItemRef)
-               CFRelease(pItemRef);
-       if (status)
-               return status;
-
-       // create identity reference, given certificate
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList((CFTypeRef)NULL, keychains);
-       Item certItem = ItemImpl::required(SecKeychainItemRef(certItemRef));
-       SecPointer<Certificate> certificate(static_cast<Certificate *>(certItem.get()));
-       SecPointer<Identity> identity(new Identity(keychains, certificate));
-       if (certItemRef)
-               CFRelease(certItemRef);
-
-       Required(identityRef) = identity->handle();
-
-    END_SECAPI
-}
-
-/*
- * System Identity Support.
- */
-
-/* plist domain (in /Library/Preferences) */
-#define IDENTITY_DOMAIN                "com.apple.security.systemidentities"
-
-/*
- * Our plist is a dictionary whose entries have the following format:
- * key   = domain name as CFString
- * value = public key hash as CFData
- */
-
-#define SYSTEM_KEYCHAIN_PATH   kSystemKeychainDir "/" kSystemKeychainName
-
-/*
- * All accesses to system identities and its associated plist are
- * protected by this lock.
- */
-ModuleNexus<Mutex> systemIdentityLock;
-
-OSStatus SecIdentityCopySystemIdentity(
-   CFStringRef domain,
-   SecIdentityRef *idRef,
-   CFStringRef *actualDomain) /* optional */
-{
-    BEGIN_SECAPI
-
-       StLock<Mutex> _(systemIdentityLock());
-       auto_ptr<Dictionary> identDict;
-
-       /* get top-level dictionary - if not present, we're done */
-       Dictionary* d = Dictionary::CreateDictionary(IDENTITY_DOMAIN, Dictionary::US_System);
-       if (d == NULL)
-       {
-               return errSecNotAvailable;
-       }
-
-       identDict.reset(d);
-
-       /* see if there's an entry for specified domain */
-       CFDataRef entryValue = identDict->getDataValue(domain);
-       if(entryValue == NULL) {
-               /* try for default entry if we're not already looking for default */
-               if(!CFEqual(domain, kSecIdentityDomainDefault)) {
-                       entryValue = identDict->getDataValue(kSecIdentityDomainDefault);
-               }
-               if(entryValue == NULL) {
-                       /* no default identity */
-                       MacOSError::throwMe(errSecItemNotFound);
-               }
-
-               /* remember that we're not fetching the requested domain */
-               domain = kSecIdentityDomainDefault;
-       }
-
-       /* open system keychain - error here is fatal */
-       Keychain systemKc = globals().storageManager.make(SYSTEM_KEYCHAIN_PATH, false);
-       CFRef<SecKeychainRef> systemKcRef(systemKc->handle());
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList(systemKcRef, keychains);
-
-       /* search for specified cert */
-       SecKeychainAttributeList        attrList;
-       SecKeychainAttribute            attr;
-       attr.tag        = kSecPublicKeyHashItemAttr;
-       attr.length     = (UInt32)CFDataGetLength(entryValue);
-       attr.data       = (void *)CFDataGetBytePtr(entryValue);
-       attrList.count  = 1;
-       attrList.attr   = &attr;
-
-       KCCursor cursor(keychains, kSecCertificateItemClass, &attrList);
-       Item certItem;
-       if(!cursor->next(certItem)) {
-               MacOSError::throwMe(errSecItemNotFound);
-       }
-
-       /* found the cert; try matching with key to cook up identity */
-       SecPointer<Certificate> certificate(static_cast<Certificate *>(certItem.get()));
-       SecPointer<Identity> identity(new Identity(keychains, certificate));
-
-       Required(idRef) = identity->handle();
-       if(actualDomain) {
-               *actualDomain = domain;
-               CFRetain(*actualDomain);
-       }
-
-    END_SECAPI
-}
-
-OSStatus SecIdentitySetSystemIdentity(
-   CFStringRef domain,
-   SecIdentityRef idRef)
-{
-    BEGIN_SECAPI
-
-       StLock<Mutex> _(systemIdentityLock());
-       if(geteuid() != 0) {
-               MacOSError::throwMe(errSecAuthFailed);
-       }
-
-       auto_ptr<MutableDictionary> identDict;
-       MutableDictionary *d = MutableDictionary::CreateMutableDictionary(IDENTITY_DOMAIN, Dictionary::US_System);
-       if (d)
-       {
-               identDict.reset(d);
-       }
-       else
-       {
-               if(idRef == NULL) {
-                       /* nothing there, nothing to set - done */
-                       return errSecSuccess;
-               }
-               identDict.reset(new MutableDictionary());
-       }
-
-       if(idRef == NULL) {
-               /* Just delete the possible entry for this domain */
-               identDict->removeValue(domain);
-       }
-       else {
-               /* obtain public key hash of identity's cert */
-               SecPointer<Identity> identity(Identity::required(idRef));
-               SecPointer<Certificate> cert = identity->certificate();
-               const CssmData &pubKeyHash = cert->publicKeyHash();
-               CFRef<CFDataRef> pubKeyHashData(CFDataCreate(NULL, pubKeyHash.Data,
-                       pubKeyHash.Length));
-
-               /* add/replace to dictionary */
-               identDict->setValue(domain, pubKeyHashData);
-       }
-
-       /* flush to disk */
-       if(!identDict->writePlistToPrefs(IDENTITY_DOMAIN, Dictionary::US_System)) {
-               MacOSError::throwMe(errSecIO);
-       }
-
-    END_SECAPI
-}
-
-const CFStringRef kSecIdentityDomainDefault = CFSTR("com.apple.systemdefault");
-const CFStringRef kSecIdentityDomainKerberosKDC = CFSTR("com.apple.kerberos.kdc");
-