2  * Copyright (c) 2002-2015 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 #include <Security/SecIdentity.h> 
  25 #include <Security/SecIdentityPriv.h> 
  26 #include <Security/SecKeychainItemPriv.h> 
  27 #include <Security/SecItem.h> 
  28 #include <Security/SecIdentityPriv.h> 
  29 #include <Security/SecCertificatePriv.h> 
  31 #include "SecBridge.h" 
  32 #include <security_keychain/Certificate.h> 
  33 #include <security_keychain/Identity.h> 
  34 #include <security_keychain/KeyItem.h> 
  35 #include <security_keychain/KCCursor.h> 
  36 #include <security_cdsa_utilities/Schema.h> 
  37 #include <security_utilities/simpleprefs.h> 
  38 #include <utilities/SecCFRelease.h> 
  39 #include <sys/param.h> 
  42 /* private function declarations */ 
  44 SecIdentityFindPreferenceItemWithNameAndKeyUsage( 
  45         CFTypeRef keychainOrArray
, 
  48         SecKeychainItemRef 
*itemRef
); 
  50 OSStatus 
SecIdentityDeletePreferenceItemWithNameAndKeyUsage( 
  51         CFTypeRef keychainOrArray
, 
  56 CSSM_KEYUSE 
ConvertArrayToKeyUsage(CFArrayRef usage
) 
  59         CSSM_KEYUSE result 
= (CSSM_KEYUSE
) 0; 
  61         if ((NULL 
== usage
) || (0 == (count 
= CFArrayGetCount(usage
)))) 
  66         for (CFIndex iCnt 
= 0; iCnt 
< count
; iCnt
++) 
  68                 CFStringRef keyUsageStr 
= NULL
; 
  69                 keyUsageStr 
= (CFStringRef
)CFArrayGetValueAtIndex(usage
,iCnt
); 
  70                 if (NULL 
!= keyUsageStr
) 
  72                         if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanEncrypt
, keyUsageStr
, 0)) 
  74                                 result 
|= CSSM_KEYUSE_ENCRYPT
; 
  76                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanDecrypt
, keyUsageStr
, 0)) 
  78                                 result 
|= CSSM_KEYUSE_DECRYPT
; 
  80                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanDerive
, keyUsageStr
, 0)) 
  82                                 result 
|= CSSM_KEYUSE_DERIVE
; 
  84                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanSign
, keyUsageStr
, 0)) 
  86                                 result 
|= CSSM_KEYUSE_SIGN
; 
  88                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanVerify
, keyUsageStr
, 0)) 
  90                                 result 
|= CSSM_KEYUSE_VERIFY
; 
  92                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanWrap
, keyUsageStr
, 0)) 
  94                                 result 
|= CSSM_KEYUSE_WRAP
; 
  96                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanUnwrap
, keyUsageStr
, 0)) 
  98                                 result 
|= CSSM_KEYUSE_UNWRAP
; 
 108 SecIdentityGetTypeID(void) 
 112         return gTypes().Identity
.typeID
; 
 114         END_SECAPI1(_kCFRuntimeNotATypeID
) 
 119 SecIdentityCopyCertificate( 
 120             SecIdentityRef identityRef
, 
 121             SecCertificateRef 
*certificateRef
) 
 125         if (!identityRef 
|| !certificateRef
) { 
 128         CFTypeID itemType 
= CFGetTypeID(identityRef
); 
 129         if (itemType 
== SecIdentityGetTypeID()) { 
 130                 SecPointer
<Certificate
> certificatePtr(Identity::required(identityRef
)->certificate()); 
 131                 Required(certificateRef
) = certificatePtr
->handle(); 
 133                 /* convert outgoing certificate item to a unified SecCertificateRef */ 
 134                 CssmData certData 
= certificatePtr
->data(); 
 135                 CFDataRef data 
= NULL
; 
 136                 if (certData
.Data 
&& certData
.Length
) { 
 137                         data 
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
); 
 140                         *certificateRef 
= NULL
; 
 141                         syslog(LOG_ERR
, "ERROR: SecIdentityCopyCertificate failed to retrieve certificate data (length=%ld, data=0x%lX)", 
 142                                         (long)certData
.Length
, (uintptr_t)certData
.Data
); 
 143                         return errSecInternal
; 
 145                 SecCertificateRef tmpRef 
= *certificateRef
; 
 146                 *certificateRef 
= SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
); 
 154         else if (itemType 
== SecCertificateGetTypeID()) { 
 156                 // reconstituting a persistent identity reference could return the certificate 
 157                 SecCertificateRef certificate 
= (SecCertificateRef
)identityRef
; 
 159                 /* convert outgoing certificate item to a unified SecCertificateRef, if needed */ 
 160                 if (SecCertificateIsItemImplInstance(certificate
)) { 
 161                         *certificateRef 
= SecCertificateCreateFromItemImplInstance(certificate
); 
 164                         *certificateRef 
= (SecCertificateRef
) CFRetain(certificate
); 
 166                 return errSecSuccess
; 
 177 SecIdentityCopyPrivateKey( 
 178             SecIdentityRef identityRef
, 
 179             SecKeyRef 
*privateKeyRef
) 
 183         Required(privateKeyRef
) = (SecKeyRef
)CFRetain(Identity::required(identityRef
)->privateKeyRef()); 
 189 SecIdentityCreateWithCertificate( 
 190         CFTypeRef keychainOrArray
, 
 191         SecCertificateRef certificate
, 
 192         SecIdentityRef 
*identityRef
) 
 194         // This macro converts a new-style SecCertificateRef to an old-style ItemImpl 
 197         SecPointer
<Certificate
> certificatePtr(Certificate::required(__itemImplRef
)); 
 198         StorageManager::KeychainList keychains
; 
 199         globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
); 
 200         SecPointer
<Identity
> identityPtr(new Identity(keychains
, certificatePtr
)); 
 201         Required(identityRef
) = identityPtr
->handle(); 
 208         CFAllocatorRef allocator
, 
 209         SecCertificateRef certificate
, 
 210         SecKeyRef privateKey
) 
 212         SecIdentityRef identityRef 
= NULL
; 
 213         OSStatus __secapiresult
; 
 214         SecCertificateRef __itemImplRef 
= NULL
; 
 215         if (SecCertificateIsItemImplInstance(certificate
)) { 
 216                 __itemImplRef
=(SecCertificateRef
)CFRetain(certificate
); 
 218         if (!__itemImplRef 
&& certificate
) { 
 219                 __itemImplRef
=(SecCertificateRef
)SecCertificateCopyKeychainItem(certificate
); 
 221         if (!__itemImplRef 
&& certificate
) { 
 222                 __itemImplRef
=SecCertificateCreateItemImplInstance(certificate
); 
 223                 (void)SecCertificateSetKeychainItem(certificate
,__itemImplRef
); 
 226                 SecPointer
<Certificate
> certificatePtr(Certificate::required(__itemImplRef
)); 
 227                 SecPointer
<Identity
> identityPtr(new Identity(privateKey
, certificatePtr
)); 
 228                 identityRef 
= identityPtr
->handle(); 
 230                 __secapiresult
=errSecSuccess
; 
 232         catch (const MacOSError 
&err
) { __secapiresult
=err
.osStatus(); } 
 233         catch (const CommonError 
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
 234         catch (const std::bad_alloc 
&) { __secapiresult
=errSecAllocate
; } 
 235         catch (...) { __secapiresult
=errSecInternalComponent
; } 
 236         if (__itemImplRef
) { CFRelease(__itemImplRef
); } 
 242         SecIdentityRef identity1
, 
 243         SecIdentityRef identity2
, 
 244         CFOptionFlags compareOptions
) 
 246         if (!identity1 
|| !identity2
) 
 248                 if (identity1 
== identity2
) 
 249                         return kCFCompareEqualTo
; 
 250                 else if (identity1 
< identity2
) 
 251                         return kCFCompareLessThan
; 
 253                         return kCFCompareGreaterThan
; 
 257         SecPointer
<Identity
> id1(Identity::required(identity1
)); 
 258         SecPointer
<Identity
> id2(Identity::required(identity2
)); 
 261             return kCFCompareEqualTo
; 
 263             return kCFCompareLessThan
; 
 265             return kCFCompareGreaterThan
; 
 269     return kCFCompareGreaterThan
; 
 273 CFArrayRef 
_SecIdentityCopyPossiblePaths( 
 276     // utility function to build and return an array of possible paths for the given name. 
 277     // if name is not a URL, this returns a single-element array. 
 278     // if name is a URL, the array may contain 1..N elements, one for each level of the path hierarchy. 
 280     CFMutableArrayRef names 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 284     CFIndex oldLength 
= CFStringGetLength(name
); 
 285     CFArrayAppendValue(names
, name
); 
 287     CFURLRef url 
= CFURLCreateWithString(NULL
, name
, NULL
); 
 289                 if (CFURLCanBeDecomposed(url
)) { 
 290                         // first, remove the query portion of this URL, if any 
 291                         CFStringRef qs 
= CFURLCopyQueryString(url
, NULL
); 
 293                                 CFMutableStringRef newName 
= CFStringCreateMutableCopy(NULL
, oldLength
, name
); 
 295                                         CFIndex qsLength 
= CFStringGetLength(qs
) + 1; // include the '?' 
 296                                         CFStringDelete(newName
, CFRangeMake(oldLength
-qsLength
, qsLength
)); 
 298                                         url 
= CFURLCreateWithString(NULL
, newName
, NULL
); 
 299                                         CFArraySetValueAtIndex(names
, 0, newName
); 
 304                         // now add an entry for each level of the path 
 306                                 CFURLRef parent 
= CFURLCreateCopyDeletingLastPathComponent(NULL
, url
); 
 308                                         CFStringRef parentURLString 
= CFURLGetString(parent
); 
 309                                         if (parentURLString
) { 
 310                                                 CFIndex newLength 
= CFStringGetLength(parentURLString
); 
 311                                                 // check that string length has decreased as expected; for file URLs, 
 312                                                 // CFURLCreateCopyDeletingLastPathComponent can insert './' or '../' 
 313                                                 if ((newLength 
>= oldLength
) || (!CFStringHasPrefix(name
, parentURLString
))) { 
 318                                                 oldLength 
= newLength
; 
 319                                                 CFArrayAppendValue(names
, parentURLString
); 
 330         // finally, add wildcard entries for each subdomain 
 331         url 
= CFURLCreateWithString(NULL
, name
, NULL
); 
 333                 if (CFURLCanBeDecomposed(url
)) { 
 334                         CFStringRef netLocString 
= CFURLCopyNetLocation(url
); 
 336                                 // first strip off port number, if present 
 337                                 CFStringRef tmpLocString 
= netLocString
; 
 338                                 CFArrayRef hostnameArray 
= CFStringCreateArrayBySeparatingStrings(NULL
, netLocString
, CFSTR(":")); 
 339                                 tmpLocString 
= (CFStringRef
)CFRetain((CFStringRef
)CFArrayGetValueAtIndex(hostnameArray
, 0)); 
 340                                 CFRelease(netLocString
); 
 341                                 CFRelease(hostnameArray
); 
 342                                 netLocString 
= tmpLocString
; 
 343                                 // split remaining string into domain components 
 344                                 hostnameArray 
= CFStringCreateArrayBySeparatingStrings(NULL
, netLocString
, CFSTR(".")); 
 345                                 CFIndex subdomainCount 
= CFArrayGetCount(hostnameArray
); 
 347                                 while (++i 
< subdomainCount
) { 
 349                                         CFMutableStringRef wildcardString 
= CFStringCreateMutable(NULL
, 0); 
 350                                         if (wildcardString
) { 
 351                                                 CFStringAppendCString(wildcardString
, "*", kCFStringEncodingUTF8
); 
 352                                                 while (j 
< subdomainCount
) { 
 353                                                         CFStringRef domainString 
= (CFStringRef
)CFArrayGetValueAtIndex(hostnameArray
, j
++); 
 354                                                         if (CFStringGetLength(domainString
) > 0) { 
 355                                                                 CFStringAppendCString(wildcardString
, ".", kCFStringEncodingUTF8
); 
 356                                                                 CFStringAppend(wildcardString
, domainString
); 
 359                                                 if (CFStringGetLength(wildcardString
) > 1) { 
 360                                                         CFArrayAppendValue(names
, wildcardString
); 
 362                                                 CFRelease(wildcardString
); 
 365                                 CFRelease(hostnameArray
); 
 366                                 CFRelease(netLocString
); 
 376 OSStatus 
_SecIdentityCopyPreferenceMatchingName( 
 378     CSSM_KEYUSE keyUsage
, 
 379     CFArrayRef validIssuers
, 
 380     SecIdentityRef 
*identity
) 
 382     // this is NOT exported, and called only from SecIdentityCopyPreference (below), so no BEGIN/END macros here; 
 383     // caller must handle exceptions 
 385         StorageManager::KeychainList keychains
; 
 386         globals().storageManager
.getSearchList(keychains
); 
 387         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 389         char idUTF8
[MAXPATHLEN
]; 
 391     if (!CFStringGetCString(name
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
)) 
 392         idUTF8
[0] = (char)'\0'; 
 393     CssmData 
service(const_cast<char *>(idUTF8
), strlen(idUTF8
)); 
 394         FourCharCode itemType 
= 'iprf'; 
 395     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 396         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), itemType
); 
 398         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 401         if (!cursor
->next(prefItem
)) 
 402                 return errSecItemNotFound
; 
 404         // get persistent certificate reference 
 405         SecKeychainAttribute itemAttrs
[] = { { kSecGenericItemAttr
, 0, NULL 
} }; 
 406         SecKeychainAttributeList itemAttrList 
= { sizeof(itemAttrs
) / sizeof(itemAttrs
[0]), itemAttrs 
}; 
 407         prefItem
->getContent(NULL
, &itemAttrList
, NULL
, NULL
); 
 409         // find certificate, given persistent reference data 
 410         CFDataRef pItemRef 
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8 
*)itemAttrs
[0].data
, itemAttrs
[0].length
, kCFAllocatorNull
); 
 411         SecKeychainItemRef certItemRef 
= nil
; 
 412         OSStatus status 
= SecKeychainItemCopyFromPersistentReference(pItemRef
, &certItemRef
); //%%% need to make this a method of ItemImpl 
 413         prefItem
->freeContent(&itemAttrList
, NULL
); 
 419     // filter on valid issuers, if provided 
 424         // create identity reference, given certificate 
 425         status 
= SecIdentityCreateWithCertificate(NULL
, (SecCertificateRef
)certItemRef
, identity
); 
 427                 CFRelease(certItemRef
); 
 433 SecIdentityRef 
SecIdentityCopyPreferred(CFStringRef name
, CFArrayRef keyUsage
, CFArrayRef validIssuers
) 
 435         // This function will look for a matching preference in the following order: 
 436         // - matches the name and the supplied key use 
 437         // - matches the name and the special 'ANY' key use 
 438         // - matches the name with no key usage constraint 
 440         SecIdentityRef identityRef 
= NULL
; 
 441         CSSM_KEYUSE keyUse 
= ConvertArrayToKeyUsage(keyUsage
); 
 442         OSStatus status 
= SecIdentityCopyPreference(name
, keyUse
, validIssuers
, &identityRef
); 
 443         if (status 
!= errSecSuccess 
&& keyUse 
!= CSSM_KEYUSE_ANY
) 
 444                 status 
= SecIdentityCopyPreference(name
, CSSM_KEYUSE_ANY
, validIssuers
, &identityRef
); 
 445         if (status 
!= errSecSuccess 
&& keyUse 
!= 0) 
 446                 status 
= SecIdentityCopyPreference(name
, 0, validIssuers
, &identityRef
); 
 451 OSStatus 
SecIdentityCopyPreference( 
 453     CSSM_KEYUSE keyUsage
, 
 454     CFArrayRef validIssuers
, 
 455     SecIdentityRef 
*identity
) 
 457     // The original implementation of SecIdentityCopyPreference matches the exact string only. 
 458     // That implementation has been moved to _SecIdentityCopyPreferenceMatchingName (above), 
 459     // and this function is a wrapper which calls it, so that existing clients will get the 
 460     // extended behavior of server domain matching for items that specify URLs. 
 461     // (Note that behavior is unchanged if the specified name is not a URL.) 
 465     CFTypeRef val 
= (CFTypeRef
)CFPreferencesCopyValue(CFSTR("LogIdentityPreferenceLookup"), 
 466                     CFSTR("com.apple.security"), 
 467                     kCFPreferencesCurrentUser
, 
 468                     kCFPreferencesAnyHost
); 
 469     Boolean logging 
= false; 
 470     if (val 
&& CFGetTypeID(val
) == CFBooleanGetTypeID()) { 
 471         logging 
= CFBooleanGetValue((CFBooleanRef
)val
); 
 475     OSStatus status 
= errSecItemNotFound
; 
 476     CFArrayRef names 
= _SecIdentityCopyPossiblePaths(name
); 
 481     CFIndex idx
, total 
= CFArrayGetCount(names
); 
 482     for (idx 
= 0; idx 
< total
; idx
++) { 
 483         CFStringRef aName 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, idx
); 
 485             status 
= _SecIdentityCopyPreferenceMatchingName(aName
, keyUsage
, validIssuers
, identity
); 
 487         catch (...) { status 
= errSecItemNotFound
; } 
 490             // get identity label 
 491             CFStringRef labelString 
= NULL
; 
 492             if (!status 
&& identity 
&& *identity
) { 
 494                     SecPointer
<Certificate
> cert(Identity::required(*identity
)->certificate()); 
 495                     cert
->inferLabel(false, &labelString
); 
 497                 catch (...) { labelString 
= NULL
; }; 
 499             char *labelBuf 
= NULL
; 
 500             CFIndex labelBufSize 
= (labelString
) ? CFStringGetLength(labelString
) * 4 : 4; 
 501             labelBuf 
= (char *)malloc(labelBufSize
); 
 502             if (!labelString 
|| !CFStringGetCString(labelString
, labelBuf
, labelBufSize
, kCFStringEncodingUTF8
)) { 
 506                 CFRelease(labelString
); 
 510             char *serviceBuf 
= NULL
; 
 511             CFIndex serviceBufSize 
= CFStringGetLength(aName
) * 4; 
 512             serviceBuf 
= (char *)malloc(serviceBufSize
); 
 513             if (!CFStringGetCString(aName
, serviceBuf
, serviceBufSize
, kCFStringEncodingUTF8
)) { 
 517             syslog(LOG_NOTICE
, "preferred identity: \"%s\" found for \"%s\"\n", labelBuf
, serviceBuf
); 
 518             if (!status 
&& name
) { 
 519                 char *nameBuf 
= NULL
; 
 520                 CFIndex nameBufSize 
= CFStringGetLength(name
) * 4; 
 521                 nameBuf 
= (char *)malloc(nameBufSize
); 
 522                 if (!CFStringGetCString(name
, nameBuf
, nameBufSize
, kCFStringEncodingUTF8
)) { 
 525                 syslog(LOG_NOTICE
, "lookup complete; will use: \"%s\" for \"%s\"\n", labelBuf
, nameBuf
); 
 533         if (status 
== errSecSuccess
) { 
 534             break; // match found 
 544 OSStatus 
SecIdentitySetPreference( 
 545     SecIdentityRef identity
, 
 547     CSSM_KEYUSE keyUsage
) 
 553                 // treat NULL identity as a request to clear the preference 
 554                 // (note: if keyUsage is 0, this clears all key usage prefs for name) 
 555                 return SecIdentityDeletePreferenceItemWithNameAndKeyUsage(NULL
, name
, keyUsage
); 
 560         SecPointer
<Certificate
> certificate(Identity::required(identity
)->certificate()); 
 562         // determine the account attribute 
 564         // This attribute must be synthesized from certificate label + pref item type + key usage, 
 565         // as only the account and service attributes can make a generic keychain item unique. 
 566         // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that 
 567         // we can save a certificate preference if an identity preference already exists for the 
 568         // given service name, and vice-versa. 
 569         // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. 
 571     CFStringRef labelStr 
= nil
; 
 572         certificate
->inferLabel(false, &labelStr
); 
 574         MacOSError::throwMe(errSecDataTooLarge
); // data is "in a format which cannot be displayed" 
 576         CFIndex accountUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1; 
 577         const char *templateStr 
= "%s [key usage 0x%X]"; 
 578         const int keyUsageMaxStrLen 
= 8; 
 579         accountUTF8Len 
+= strlen(templateStr
) + keyUsageMaxStrLen
; 
 580         char accountUTF8
[accountUTF8Len
]; 
 581     if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
)) 
 582                 accountUTF8
[0] = (char)'\0'; 
 584                 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
); 
 585         snprintf(accountUTF8
, accountUTF8Len
-1, "%s ", accountUTF8
); 
 586     CssmData 
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
)); 
 589         // service attribute (name provided by the caller) 
 590         CFIndex serviceUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(name
), kCFStringEncodingUTF8
) + 1;; 
 591         char serviceUTF8
[serviceUTF8Len
]; 
 592     if (!CFStringGetCString(name
, serviceUTF8
, serviceUTF8Len
-1, kCFStringEncodingUTF8
)) 
 593         serviceUTF8
[0] = (char)'\0'; 
 594     CssmData 
service(const_cast<char *>(serviceUTF8
), strlen(serviceUTF8
)); 
 596     // look for existing identity preference item, in case this is an update 
 597         StorageManager::KeychainList keychains
; 
 598         globals().storageManager
.getSearchList(keychains
); 
 599         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 600     FourCharCode itemType 
= 'iprf'; 
 601     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 602         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), itemType
); 
 604         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 607         Item 
item(kSecGenericPasswordItemClass
, 'aapl', 0, NULL
, false); 
 608     bool add 
= (!cursor
->next(item
)); 
 609         // at this point, we either have a new item to add or an existing item to update 
 611     // set item attribute values 
 612     item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 613     item
->setAttribute(Schema::attributeInfo(kSecTypeItemAttr
), itemType
); 
 614     item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 615         item
->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 616     item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
); 
 618         // generic attribute (store persistent certificate reference) 
 619         CFDataRef pItemRef 
= nil
; 
 620     certificate
->copyPersistentReference(pItemRef
); 
 622                 MacOSError::throwMe(errSecInvalidItemRef
); 
 624         const UInt8 
*dataPtr 
= CFDataGetBytePtr(pItemRef
); 
 625         CFIndex dataLen 
= CFDataGetLength(pItemRef
); 
 626         CssmData 
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
); 
 627         item
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
); 
 631         Keychain keychain 
= nil
; 
 633             keychain 
= globals().storageManager
.defaultKeychain(); 
 634             if (!keychain
->exists()) 
 635                 MacOSError::throwMe(errSecNoSuchKeychain
);      // Might be deleted or not available at this time. 
 638             keychain 
= globals().storageManager
.defaultKeychainUI(item
); 
 644                 catch (const MacOSError 
&err
) { 
 645                         if (err
.osStatus() != errSecDuplicateItem
) 
 646                                 throw; // if item already exists, fall through to update 
 655 SecIdentitySetPreferred(SecIdentityRef identity
, CFStringRef name
, CFArrayRef keyUsage
) 
 657         CSSM_KEYUSE keyUse 
= ConvertArrayToKeyUsage(keyUsage
); 
 658         return SecIdentitySetPreference(identity
, name
, keyUse
); 
 662 SecIdentityFindPreferenceItem( 
 663         CFTypeRef keychainOrArray
, 
 664         CFStringRef idString
, 
 665         SecKeychainItemRef 
*itemRef
) 
 669         StorageManager::KeychainList keychains
; 
 670         globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
); 
 671         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 673         char idUTF8
[MAXPATHLEN
]; 
 674     idUTF8
[0] = (char)'\0'; 
 677                 if (!CFStringGetCString(idString
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
)) 
 678                         idUTF8
[0] = (char)'\0'; 
 680     size_t idUTF8Len 
= strlen(idUTF8
); 
 682         MacOSError::throwMe(errSecParam
); 
 684     CssmData 
service(const_cast<char *>(idUTF8
), idUTF8Len
); 
 685     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 686         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'iprf'); 
 689         if (!cursor
->next(item
)) 
 690                 MacOSError::throwMe(errSecItemNotFound
); 
 693                 *itemRef
=item
->handle(); 
 699 SecIdentityFindPreferenceItemWithNameAndKeyUsage( 
 700         CFTypeRef keychainOrArray
, 
 703         SecKeychainItemRef 
*itemRef
) 
 707         StorageManager::KeychainList keychains
; 
 708         globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
); 
 709         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 711         char idUTF8
[MAXPATHLEN
]; 
 712     idUTF8
[0] = (char)'\0'; 
 715                 if (!CFStringGetCString(name
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
)) 
 716                         idUTF8
[0] = (char)'\0'; 
 718     size_t idUTF8Len 
= strlen(idUTF8
); 
 720         MacOSError::throwMe(errSecParam
); 
 722     CssmData 
service(const_cast<char *>(idUTF8
), idUTF8Len
); 
 723     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 724         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'iprf'); 
 726         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 729         if (!cursor
->next(item
)) 
 730                 MacOSError::throwMe(errSecItemNotFound
); 
 733                 *itemRef
=item
->handle(); 
 738 OSStatus 
SecIdentityDeletePreferenceItemWithNameAndKeyUsage( 
 739         CFTypeRef keychainOrArray
, 
 743         // when a specific key usage is passed, we'll only match & delete that pref; 
 744         // when a key usage of 0 is passed, all matching prefs should be deleted. 
 745         // maxUsages represents the most matches there could theoretically be, so 
 746         // cut things off at that point if we're still finding items (if they can't 
 747         // be deleted for some reason, we'd never break out of the loop.) 
 749         OSStatus status 
= errSecInternalError
; 
 750         SecKeychainItemRef item 
= NULL
; 
 751         int count 
= 0, maxUsages 
= 12; 
 752         while (++count 
<= maxUsages 
&& 
 753                         (status 
= SecIdentityFindPreferenceItemWithNameAndKeyUsage(keychainOrArray
, name
, keyUsage
, &item
)) == errSecSuccess
) { 
 754                 status 
= SecKeychainItemDelete(item
); 
 759         // it's not an error if the item isn't found 
 760         return (status 
== errSecItemNotFound
) ? errSecSuccess 
: status
; 
 765 OSStatus 
_SecIdentityAddPreferenceItemWithName( 
 766         SecKeychainRef keychainRef
, 
 767         SecIdentityRef identityRef
, 
 768         CFStringRef idString
, 
 769         SecKeychainItemRef 
*itemRef
) 
 771     // this is NOT exported, and called only from SecIdentityAddPreferenceItem (below), so no BEGIN/END macros here; 
 772     // caller must handle exceptions 
 774         if (!identityRef 
|| !idString
) 
 776         SecPointer
<Certificate
> cert(Identity::required(identityRef
)->certificate()); 
 777         Item 
item(kSecGenericPasswordItemClass
, 'aapl', 0, NULL
, false); 
 780         // determine the account attribute 
 782         // This attribute must be synthesized from certificate label + pref item type + key usage, 
 783         // as only the account and service attributes can make a generic keychain item unique. 
 784         // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that 
 785         // we can save a certificate preference if an identity preference already exists for the 
 786         // given service name, and vice-versa. 
 787         // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. 
 789     CFStringRef labelStr 
= nil
; 
 790         cert
->inferLabel(false, &labelStr
); 
 792         return errSecDataTooLarge
; // data is "in a format which cannot be displayed" 
 794         CFIndex accountUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1; 
 795         const char *templateStr 
= "%s [key usage 0x%X]"; 
 796         const int keyUsageMaxStrLen 
= 8; 
 797         accountUTF8Len 
+= strlen(templateStr
) + keyUsageMaxStrLen
; 
 798         char accountUTF8
[accountUTF8Len
]; 
 799     if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
)) 
 800                 accountUTF8
[0] = (char)'\0'; 
 802                 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
); 
 803         snprintf(accountUTF8
, accountUTF8Len
-1, "%s ", accountUTF8
); 
 804     CssmData 
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
)); 
 807         // service attribute (name provided by the caller) 
 808         CFIndex serviceUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(idString
), kCFStringEncodingUTF8
) + 1;; 
 809         char serviceUTF8
[serviceUTF8Len
]; 
 810     if (!CFStringGetCString(idString
, serviceUTF8
, serviceUTF8Len
-1, kCFStringEncodingUTF8
)) 
 811         serviceUTF8
[0] = (char)'\0'; 
 812     CssmData 
service(const_cast<char *>(serviceUTF8
), strlen(serviceUTF8
)); 
 814         // set item attribute values 
 815         item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 816         item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
); 
 817         item
->setAttribute(Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'iprf'); 
 818         item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 819         item
->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr
), keyUsage
); 
 821         // generic attribute (store persistent certificate reference) 
 822         CFDataRef pItemRef 
= nil
; 
 823         OSStatus status 
= SecKeychainItemCreatePersistentReference((SecKeychainItemRef
)cert
->handle(), &pItemRef
); 
 825                 status 
= errSecInvalidItemRef
; 
 828         const UInt8 
*dataPtr 
= CFDataGetBytePtr(pItemRef
); 
 829         CFIndex dataLen 
= CFDataGetLength(pItemRef
); 
 830         CssmData 
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
); 
 831         item
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
); 
 834         Keychain keychain 
= nil
; 
 836         keychain 
= Keychain::optional(keychainRef
); 
 837         if (!keychain
->exists()) 
 838             MacOSError::throwMe(errSecNoSuchKeychain
);  // Might be deleted or not available at this time. 
 841         keychain 
= globals().storageManager
.defaultKeychainUI(item
); 
 847         catch (const MacOSError 
&err
) { 
 848                 if (err
.osStatus() != errSecDuplicateItem
) 
 849                         throw; // if item already exists, fall through to update 
 855                 *itemRef 
= item
->handle(); 
 860 OSStatus 
SecIdentityAddPreferenceItem( 
 861         SecKeychainRef keychainRef
, 
 862         SecIdentityRef identityRef
, 
 863         CFStringRef idString
, 
 864         SecKeychainItemRef 
*itemRef
) 
 866     // The original implementation of SecIdentityAddPreferenceItem adds the exact string only. 
 867     // That implementation has been moved to _SecIdentityAddPreferenceItemWithName (above), 
 868     // and this function is a wrapper which calls it, so that existing clients will get the 
 869     // extended behavior of server domain matching for items that specify URLs. 
 870     // (Note that behavior is unchanged if the specified idString is not a URL.) 
 874     OSStatus status 
= errSecInternalComponent
; 
 875     CFArrayRef names 
= _SecIdentityCopyPossiblePaths(idString
); 
 880     CFIndex total 
= CFArrayGetCount(names
); 
 882         // add item for name (first element in array) 
 883         CFStringRef aName 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, 0); 
 885             status 
= _SecIdentityAddPreferenceItemWithName(keychainRef
, identityRef
, aName
, itemRef
); 
 887         catch (const MacOSError 
&err
)   { status
=err
.osStatus(); } 
 888         catch (const CommonError 
&err
)  { status
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
 889         catch (const std::bad_alloc 
&)  { status
=errSecAllocate
; } 
 890         catch (...)                     { status
=errSecInternalComponent
; } 
 893                 Boolean setDomainDefaultIdentity 
= FALSE
; 
 894                 CFTypeRef val 
= (CFTypeRef
)CFPreferencesCopyValue(CFSTR("SetDomainDefaultIdentity"), 
 895                                                                                                                   CFSTR("com.apple.security.identities"), 
 896                                                                                                                   kCFPreferencesCurrentUser
, 
 897                                                                                                                   kCFPreferencesAnyHost
); 
 899                         if (CFGetTypeID(val
) == CFBooleanGetTypeID()) 
 900                                 setDomainDefaultIdentity 
= CFBooleanGetValue((CFBooleanRef
)val
) ? TRUE 
: FALSE
; 
 903                 if (setDomainDefaultIdentity
) { 
 904                         // add item for domain (second-to-last element in array, e.g. "*.apple.com") 
 905                         OSStatus tmpStatus 
= errSecSuccess
; 
 906                         CFStringRef aName 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, total
-2); 
 908                                 tmpStatus 
= _SecIdentityAddPreferenceItemWithName(keychainRef
, identityRef
, aName
, itemRef
); 
 910                         catch (const MacOSError 
&err
)   { tmpStatus
=err
.osStatus(); } 
 911                         catch (const CommonError 
&err
)  { tmpStatus
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
 912                         catch (const std::bad_alloc 
&)  { tmpStatus
=errSecAllocate
; } 
 913                         catch (...)                     { tmpStatus
=errSecInternalComponent
; } 
 923 /* deprecated in 10.5 */ 
 924 OSStatus 
SecIdentityUpdatePreferenceItem( 
 925                         SecKeychainItemRef itemRef
, 
 926                         SecIdentityRef identityRef
) 
 930         if (!itemRef 
|| !identityRef
) 
 931                 MacOSError::throwMe(errSecParam
); 
 932         SecPointer
<Certificate
> certificate(Identity::required(identityRef
)->certificate()); 
 933         Item prefItem 
= ItemImpl::required(itemRef
); 
 935         // get the current key usage value for this item 
 938         SecKeychainAttribute attr 
= { kSecScriptCodeItemAttr
, sizeof(sint32
), &keyUsage 
}; 
 940                 prefItem
->getAttribute(attr
, &actLen
); 
 946         // set the account attribute 
 948         // This attribute must be synthesized from certificate label + pref item type + key usage, 
 949         // as only the account and service attributes can make a generic keychain item unique. 
 950         // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that 
 951         // we can save a certificate preference if an identity preference already exists for the 
 952         // given service name, and vice-versa. 
 953         // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. 
 955     CFStringRef labelStr 
= nil
; 
 956         certificate
->inferLabel(false, &labelStr
); 
 958         MacOSError::throwMe(errSecDataTooLarge
); // data is "in a format which cannot be displayed" 
 960         CFIndex accountUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1; 
 961         const char *templateStr 
= "%s [key usage 0x%X]"; 
 962         const int keyUsageMaxStrLen 
= 8; 
 963         accountUTF8Len 
+= strlen(templateStr
) + keyUsageMaxStrLen
; 
 964         char accountUTF8
[accountUTF8Len
]; 
 965     if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
)) 
 966                 accountUTF8
[0] = (char)'\0'; 
 968                 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
); 
 969         snprintf(accountUTF8
, accountUTF8Len
-1, "%s ", accountUTF8
); 
 970     CssmData 
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
)); 
 971         prefItem
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 974         // generic attribute (store persistent certificate reference) 
 975         CFDataRef pItemRef 
= nil
; 
 976         OSStatus status 
= SecKeychainItemCreatePersistentReference((SecKeychainItemRef
)certificate
->handle(), &pItemRef
); 
 978                 status 
= errSecInvalidItemRef
; 
 980                 MacOSError::throwMe(status
); 
 981         const UInt8 
*dataPtr 
= CFDataGetBytePtr(pItemRef
); 
 982         CFIndex dataLen 
= CFDataGetLength(pItemRef
); 
 983         CssmData 
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
); 
 984         prefItem
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
); 
 992 OSStatus 
SecIdentityCopyFromPreferenceItem( 
 993                         SecKeychainItemRef itemRef
, 
 994                         SecIdentityRef 
*identityRef
) 
 998         if (!itemRef 
|| !identityRef
) 
 999                 MacOSError::throwMe(errSecParam
); 
1000         Item prefItem 
= ItemImpl::required(itemRef
); 
1002         // get persistent certificate reference 
1003         SecKeychainAttribute itemAttrs
[] = { { kSecGenericItemAttr
, 0, NULL 
} }; 
1004         SecKeychainAttributeList itemAttrList 
= { sizeof(itemAttrs
) / sizeof(itemAttrs
[0]), itemAttrs 
}; 
1005         prefItem
->getContent(NULL
, &itemAttrList
, NULL
, NULL
); 
1007         // find certificate, given persistent reference data 
1008         CFDataRef pItemRef 
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8 
*)itemAttrs
[0].data
, itemAttrs
[0].length
, kCFAllocatorNull
); 
1009         SecKeychainItemRef certItemRef 
= nil
; 
1010         OSStatus status 
= SecKeychainItemCopyFromPersistentReference(pItemRef
, &certItemRef
); //%%% need to make this a method of ItemImpl 
1011         prefItem
->freeContent(&itemAttrList
, NULL
); 
1013                 CFRelease(pItemRef
); 
1017         // create identity reference, given certificate 
1018         StorageManager::KeychainList keychains
; 
1019         globals().storageManager
.optionalSearchList((CFTypeRef
)NULL
, keychains
); 
1020         Item certItem 
= ItemImpl::required(SecKeychainItemRef(certItemRef
)); 
1021         SecPointer
<Certificate
> certificate(static_cast<Certificate 
*>(certItem
.get())); 
1022         SecPointer
<Identity
> identity(new Identity(keychains
, certificate
)); 
1024                 CFRelease(certItemRef
); 
1026         Required(identityRef
) = identity
->handle(); 
1032  * System Identity Support. 
1035 /* plist domain (in /Library/Preferences) */ 
1036 #define IDENTITY_DOMAIN         "com.apple.security.systemidentities" 
1039  * Our plist is a dictionary whose entries have the following format: 
1040  * key   = domain name as CFString 
1041  * value = public key hash as CFData 
1044 #define SYSTEM_KEYCHAIN_PATH    kSystemKeychainDir "/" kSystemKeychainName 
1047  * All accesses to system identities and its associated plist are 
1048  * protected by this lock. 
1050 ModuleNexus
<Mutex
> systemIdentityLock
; 
1052 OSStatus 
SecIdentityCopySystemIdentity( 
1054    SecIdentityRef 
*idRef
, 
1055    CFStringRef 
*actualDomain
) /* optional */ 
1059         StLock
<Mutex
> _(systemIdentityLock()); 
1060         auto_ptr
<Dictionary
> identDict
; 
1062         /* get top-level dictionary - if not present, we're done */ 
1063         Dictionary
* d 
= Dictionary::CreateDictionary(IDENTITY_DOMAIN
, Dictionary::US_System
); 
1066                 return errSecNotAvailable
; 
1071         /* see if there's an entry for specified domain */ 
1072         CFDataRef entryValue 
= identDict
->getDataValue(domain
); 
1073         if(entryValue 
== NULL
) { 
1074                 /* try for default entry if we're not already looking for default */ 
1075                 if(!CFEqual(domain
, kSecIdentityDomainDefault
)) { 
1076                         entryValue 
= identDict
->getDataValue(kSecIdentityDomainDefault
); 
1078                 if(entryValue 
== NULL
) { 
1079                         /* no default identity */ 
1080                         MacOSError::throwMe(errSecItemNotFound
); 
1083                 /* remember that we're not fetching the requested domain */ 
1084                 domain 
= kSecIdentityDomainDefault
; 
1087         /* open system keychain - error here is fatal */ 
1088         Keychain systemKc 
= globals().storageManager
.make(SYSTEM_KEYCHAIN_PATH
, false); 
1089         CFRef
<SecKeychainRef
> systemKcRef(systemKc
->handle()); 
1090         StorageManager::KeychainList keychains
; 
1091         globals().storageManager
.optionalSearchList(systemKcRef
, keychains
); 
1093         /* search for specified cert */ 
1094         SecKeychainAttributeList        attrList
; 
1095         SecKeychainAttribute            attr
; 
1096         attr
.tag        
= kSecPublicKeyHashItemAttr
; 
1097         attr
.length     
= (UInt32
)CFDataGetLength(entryValue
); 
1098         attr
.data       
= (void *)CFDataGetBytePtr(entryValue
); 
1100         attrList
.attr   
= &attr
; 
1102         KCCursor 
cursor(keychains
, kSecCertificateItemClass
, &attrList
); 
1104         if(!cursor
->next(certItem
)) { 
1105                 MacOSError::throwMe(errSecItemNotFound
); 
1108         /* found the cert; try matching with key to cook up identity */ 
1109         SecPointer
<Certificate
> certificate(static_cast<Certificate 
*>(certItem
.get())); 
1110         SecPointer
<Identity
> identity(new Identity(keychains
, certificate
)); 
1112         Required(idRef
) = identity
->handle(); 
1114                 *actualDomain 
= domain
; 
1115                 CFRetain(*actualDomain
); 
1121 OSStatus 
SecIdentitySetSystemIdentity( 
1123    SecIdentityRef idRef
) 
1127         StLock
<Mutex
> _(systemIdentityLock()); 
1128         if(geteuid() != 0) { 
1129                 MacOSError::throwMe(errSecAuthFailed
); 
1132         auto_ptr
<MutableDictionary
> identDict
; 
1133         MutableDictionary 
*d 
= MutableDictionary::CreateMutableDictionary(IDENTITY_DOMAIN
, Dictionary::US_System
); 
1141                         /* nothing there, nothing to set - done */ 
1142                         return errSecSuccess
; 
1144                 identDict
.reset(new MutableDictionary()); 
1148                 /* Just delete the possible entry for this domain */ 
1149                 identDict
->removeValue(domain
); 
1152                 /* obtain public key hash of identity's cert */ 
1153                 SecPointer
<Identity
> identity(Identity::required(idRef
)); 
1154                 SecPointer
<Certificate
> cert 
= identity
->certificate(); 
1155                 const CssmData 
&pubKeyHash 
= cert
->publicKeyHash(); 
1156                 CFRef
<CFDataRef
> pubKeyHashData(CFDataCreate(NULL
, pubKeyHash
.Data
, 
1157                         pubKeyHash
.Length
)); 
1159                 /* add/replace to dictionary */ 
1160                 identDict
->setValue(domain
, pubKeyHashData
); 
1164         if(!identDict
->writePlistToPrefs(IDENTITY_DOMAIN
, Dictionary::US_System
)) { 
1165                 MacOSError::throwMe(errSecIO
); 
1171 const CFStringRef kSecIdentityDomainDefault 
= CFSTR("com.apple.systemdefault"); 
1172 const CFStringRef kSecIdentityDomainKerberosKDC 
= CFSTR("com.apple.kerberos.kdc");