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> 
  41 #include <os/activity.h> 
  43 /* private function declarations */ 
  45 SecIdentityFindPreferenceItemWithNameAndKeyUsage( 
  46         CFTypeRef keychainOrArray
, 
  49         SecKeychainItemRef 
*itemRef
); 
  51 OSStatus 
SecIdentityDeletePreferenceItemWithNameAndKeyUsage( 
  52         CFTypeRef keychainOrArray
, 
  57 CSSM_KEYUSE 
ConvertArrayToKeyUsage(CFArrayRef usage
) 
  60         CSSM_KEYUSE result 
= (CSSM_KEYUSE
) 0; 
  62         if ((NULL 
== usage
) || (0 == (count 
= CFArrayGetCount(usage
)))) 
  67         for (CFIndex iCnt 
= 0; iCnt 
< count
; iCnt
++) 
  69                 CFStringRef keyUsageStr 
= NULL
; 
  70                 keyUsageStr 
= (CFStringRef
)CFArrayGetValueAtIndex(usage
,iCnt
); 
  71                 if (NULL 
!= keyUsageStr
) 
  73                         if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanEncrypt
, keyUsageStr
, 0)) 
  75                                 result 
|= CSSM_KEYUSE_ENCRYPT
; 
  77                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanDecrypt
, keyUsageStr
, 0)) 
  79                                 result 
|= CSSM_KEYUSE_DECRYPT
; 
  81                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanDerive
, keyUsageStr
, 0)) 
  83                                 result 
|= CSSM_KEYUSE_DERIVE
; 
  85                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanSign
, keyUsageStr
, 0)) 
  87                                 result 
|= CSSM_KEYUSE_SIGN
; 
  89                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanVerify
, keyUsageStr
, 0)) 
  91                                 result 
|= CSSM_KEYUSE_VERIFY
; 
  93                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanWrap
, keyUsageStr
, 0)) 
  95                                 result 
|= CSSM_KEYUSE_WRAP
; 
  97                         else if (kCFCompareEqualTo 
== CFStringCompare((CFStringRef
)kSecAttrCanUnwrap
, keyUsageStr
, 0)) 
  99                                 result 
|= CSSM_KEYUSE_UNWRAP
; 
 109 SecIdentityGetTypeID(void) 
 113         return gTypes().Identity
.typeID
; 
 115         END_SECAPI1(_kCFRuntimeNotATypeID
) 
 120 SecIdentityCopyCertificate( 
 121             SecIdentityRef identityRef
, 
 122             SecCertificateRef 
*certificateRef
) 
 125     os_activity_t activity 
= os_activity_create("SecIdentityCopyCertificate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 126     os_activity_scope(activity
); 
 127     os_release(activity
); 
 129         if (!identityRef 
|| !certificateRef
) { 
 132         CFTypeID itemType 
= CFGetTypeID(identityRef
); 
 133         if (itemType 
== SecIdentityGetTypeID()) { 
 134                 SecPointer
<Certificate
> certificatePtr(Identity::required(identityRef
)->certificate()); 
 135                 Required(certificateRef
) = certificatePtr
->handle(); 
 137                 /* convert outgoing certificate item to a unified SecCertificateRef */ 
 138                 CssmData certData 
= certificatePtr
->data(); 
 139                 CFDataRef data 
= NULL
; 
 140                 if (certData
.Data 
&& certData
.Length
) { 
 141                         data 
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
); 
 144                         *certificateRef 
= NULL
; 
 145                         syslog(LOG_ERR
, "ERROR: SecIdentityCopyCertificate failed to retrieve certificate data (length=%ld, data=0x%lX)", 
 146                                         (long)certData
.Length
, (uintptr_t)certData
.Data
); 
 147                         return errSecInternal
; 
 149                 SecCertificateRef tmpRef 
= *certificateRef
; 
 150                 *certificateRef 
= SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
); 
 158         else if (itemType 
== SecCertificateGetTypeID()) { 
 160                 // reconstituting a persistent identity reference could return the certificate 
 161                 SecCertificateRef certificate 
= (SecCertificateRef
)identityRef
; 
 163                 /* convert outgoing certificate item to a unified SecCertificateRef, if needed */ 
 164                 if (SecCertificateIsItemImplInstance(certificate
)) { 
 165                         *certificateRef 
= SecCertificateCreateFromItemImplInstance(certificate
); 
 168                         *certificateRef 
= (SecCertificateRef
) CFRetain(certificate
); 
 170                 return errSecSuccess
; 
 181 SecIdentityCopyPrivateKey( 
 182             SecIdentityRef identityRef
, 
 183             SecKeyRef 
*privateKeyRef
) 
 186     os_activity_t activity 
= os_activity_create("SecIdentityCopyPrivateKey", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 187     os_activity_scope(activity
); 
 188     os_release(activity
); 
 190         Required(privateKeyRef
) = (SecKeyRef
)CFRetain(Identity::required(identityRef
)->privateKeyRef()); 
 196 SecIdentityCreateWithCertificate( 
 197         CFTypeRef keychainOrArray
, 
 198         SecCertificateRef certificate
, 
 199         SecIdentityRef 
*identityRef
) 
 201         // This macro converts a new-style SecCertificateRef to an old-style ItemImpl 
 204         SecPointer
<Certificate
> certificatePtr(Certificate::required(__itemImplRef
)); 
 205         StorageManager::KeychainList keychains
; 
 206         globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
); 
 207         SecPointer
<Identity
> identityPtr(new Identity(keychains
, certificatePtr
)); 
 208         Required(identityRef
) = identityPtr
->handle(); 
 215         CFAllocatorRef allocator
, 
 216         SecCertificateRef certificate
, 
 217         SecKeyRef privateKey
) 
 219         SecIdentityRef identityRef 
= NULL
; 
 220         OSStatus __secapiresult
; 
 221         SecCertificateRef __itemImplRef 
= NULL
; 
 222         if (SecCertificateIsItemImplInstance(certificate
)) { 
 223                 __itemImplRef
=(SecCertificateRef
)CFRetain(certificate
); 
 225         if (!__itemImplRef 
&& certificate
) { 
 226                 __itemImplRef
=(SecCertificateRef
)SecCertificateCopyKeychainItem(certificate
); 
 228         if (!__itemImplRef 
&& certificate
) { 
 229                 __itemImplRef
=SecCertificateCreateItemImplInstance(certificate
); 
 230                 (void)SecCertificateSetKeychainItem(certificate
,__itemImplRef
); 
 233                 SecPointer
<Certificate
> certificatePtr(Certificate::required(__itemImplRef
)); 
 234                 SecPointer
<Identity
> identityPtr(new Identity(privateKey
, certificatePtr
)); 
 235                 identityRef 
= identityPtr
->handle(); 
 237                 __secapiresult
=errSecSuccess
; 
 239         catch (const MacOSError 
&err
) { __secapiresult
=err
.osStatus(); } 
 240         catch (const CommonError 
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
 241         catch (const std::bad_alloc 
&) { __secapiresult
=errSecAllocate
; } 
 242         catch (...) { __secapiresult
=errSecInternalComponent
; } 
 243         if (__itemImplRef
) { CFRelease(__itemImplRef
); } 
 249         SecIdentityRef identity1
, 
 250         SecIdentityRef identity2
, 
 251         CFOptionFlags compareOptions
) 
 253         if (!identity1 
|| !identity2
) 
 255                 if (identity1 
== identity2
) 
 256                         return kCFCompareEqualTo
; 
 257                 else if (identity1 
< identity2
) 
 258                         return kCFCompareLessThan
; 
 260                         return kCFCompareGreaterThan
; 
 264         SecPointer
<Identity
> id1(Identity::required(identity1
)); 
 265         SecPointer
<Identity
> id2(Identity::required(identity2
)); 
 268             return kCFCompareEqualTo
; 
 270             return kCFCompareLessThan
; 
 272             return kCFCompareGreaterThan
; 
 276     return kCFCompareGreaterThan
; 
 280 CFArrayRef 
_SecIdentityCopyPossiblePaths( 
 283     // utility function to build and return an array of possible paths for the given name. 
 284     // if name is not a URL, this returns a single-element array. 
 285     // if name is a URL, the array may contain 1..N elements, one for each level of the path hierarchy. 
 287     CFMutableArrayRef names 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 291     CFIndex oldLength 
= CFStringGetLength(name
); 
 292     CFArrayAppendValue(names
, name
); 
 294     CFURLRef url 
= CFURLCreateWithString(NULL
, name
, NULL
); 
 296                 if (CFURLCanBeDecomposed(url
)) { 
 297                         // first, remove the query portion of this URL, if any 
 298                         CFStringRef qs 
= CFURLCopyQueryString(url
, NULL
); 
 300                                 CFMutableStringRef newName 
= CFStringCreateMutableCopy(NULL
, oldLength
, name
); 
 302                                         CFIndex qsLength 
= CFStringGetLength(qs
) + 1; // include the '?' 
 303                                         CFStringDelete(newName
, CFRangeMake(oldLength
-qsLength
, qsLength
)); 
 305                                         url 
= CFURLCreateWithString(NULL
, newName
, NULL
); 
 306                                         CFArraySetValueAtIndex(names
, 0, newName
); 
 311                         // now add an entry for each level of the path 
 313                                 CFURLRef parent 
= CFURLCreateCopyDeletingLastPathComponent(NULL
, url
); 
 315                                         CFStringRef parentURLString 
= CFURLGetString(parent
); 
 316                                         if (parentURLString
) { 
 317                                                 CFIndex newLength 
= CFStringGetLength(parentURLString
); 
 318                                                 // check that string length has decreased as expected; for file URLs, 
 319                                                 // CFURLCreateCopyDeletingLastPathComponent can insert './' or '../' 
 320                                                 if ((newLength 
>= oldLength
) || (!CFStringHasPrefix(name
, parentURLString
))) { 
 325                                                 oldLength 
= newLength
; 
 326                                                 CFArrayAppendValue(names
, parentURLString
); 
 337         // finally, add wildcard entries for each subdomain 
 338         url 
= CFURLCreateWithString(NULL
, name
, NULL
); 
 340                 if (CFURLCanBeDecomposed(url
)) { 
 341                         CFStringRef netLocString 
= CFURLCopyNetLocation(url
); 
 343                                 // first strip off port number, if present 
 344                                 CFStringRef tmpLocString 
= netLocString
; 
 345                                 CFArrayRef hostnameArray 
= CFStringCreateArrayBySeparatingStrings(NULL
, netLocString
, CFSTR(":")); 
 346                                 tmpLocString 
= (CFStringRef
)CFRetain((CFStringRef
)CFArrayGetValueAtIndex(hostnameArray
, 0)); 
 347                                 CFRelease(netLocString
); 
 348                                 CFRelease(hostnameArray
); 
 349                                 netLocString 
= tmpLocString
; 
 350                                 // split remaining string into domain components 
 351                                 hostnameArray 
= CFStringCreateArrayBySeparatingStrings(NULL
, netLocString
, CFSTR(".")); 
 352                                 CFIndex subdomainCount 
= CFArrayGetCount(hostnameArray
); 
 354                                 while (++i 
< subdomainCount
) { 
 356                                         CFMutableStringRef wildcardString 
= CFStringCreateMutable(NULL
, 0); 
 357                                         if (wildcardString
) { 
 358                                                 CFStringAppendCString(wildcardString
, "*", kCFStringEncodingUTF8
); 
 359                                                 while (j 
< subdomainCount
) { 
 360                                                         CFStringRef domainString 
= (CFStringRef
)CFArrayGetValueAtIndex(hostnameArray
, j
++); 
 361                                                         if (CFStringGetLength(domainString
) > 0) { 
 362                                                                 CFStringAppendCString(wildcardString
, ".", kCFStringEncodingUTF8
); 
 363                                                                 CFStringAppend(wildcardString
, domainString
); 
 366                                                 if (CFStringGetLength(wildcardString
) > 1) { 
 367                                                         CFArrayAppendValue(names
, wildcardString
); 
 369                                                 CFRelease(wildcardString
); 
 372                                 CFRelease(hostnameArray
); 
 373                                 CFRelease(netLocString
); 
 383 OSStatus 
_SecIdentityCopyPreferenceMatchingName( 
 385     CSSM_KEYUSE keyUsage
, 
 386     CFArrayRef validIssuers
, 
 387     SecIdentityRef 
*identity
) 
 389     // this is NOT exported, and called only from SecIdentityCopyPreference (below), so no BEGIN/END macros here; 
 390     // caller must handle exceptions 
 392         StorageManager::KeychainList keychains
; 
 393         globals().storageManager
.getSearchList(keychains
); 
 394         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 396         char idUTF8
[MAXPATHLEN
]; 
 398     if (!CFStringGetCString(name
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
)) 
 399         idUTF8
[0] = (char)'\0'; 
 400     CssmData 
service(const_cast<char *>(idUTF8
), strlen(idUTF8
)); 
 401         FourCharCode itemType 
= 'iprf'; 
 402     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 403         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), itemType
); 
 405         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 408         if (!cursor
->next(prefItem
)) 
 409                 return errSecItemNotFound
; 
 411         // get persistent certificate reference 
 412         SecKeychainAttribute itemAttrs
[] = { { kSecGenericItemAttr
, 0, NULL 
} }; 
 413         SecKeychainAttributeList itemAttrList 
= { sizeof(itemAttrs
) / sizeof(itemAttrs
[0]), itemAttrs 
}; 
 414         prefItem
->getContent(NULL
, &itemAttrList
, NULL
, NULL
); 
 416         // find certificate, given persistent reference data 
 417         CFDataRef pItemRef 
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8 
*)itemAttrs
[0].data
, itemAttrs
[0].length
, kCFAllocatorNull
); 
 418         SecKeychainItemRef certItemRef 
= nil
; 
 419         OSStatus status 
= SecKeychainItemCopyFromPersistentReference(pItemRef
, &certItemRef
); //%%% need to make this a method of ItemImpl 
 420         prefItem
->freeContent(&itemAttrList
, NULL
); 
 426     // filter on valid issuers, if provided 
 431         // create identity reference, given certificate 
 432         status 
= SecIdentityCreateWithCertificate(NULL
, (SecCertificateRef
)certItemRef
, identity
); 
 434                 CFRelease(certItemRef
); 
 440 SecIdentityRef 
SecIdentityCopyPreferred(CFStringRef name
, CFArrayRef keyUsage
, CFArrayRef validIssuers
) 
 442         // This function will look for a matching preference in the following order: 
 443         // - matches the name and the supplied key use 
 444         // - matches the name and the special 'ANY' key use 
 445         // - matches the name with no key usage constraint 
 447         SecIdentityRef identityRef 
= NULL
; 
 448         CSSM_KEYUSE keyUse 
= ConvertArrayToKeyUsage(keyUsage
); 
 449         OSStatus status 
= SecIdentityCopyPreference(name
, keyUse
, validIssuers
, &identityRef
); 
 450         if (status 
!= errSecSuccess 
&& keyUse 
!= CSSM_KEYUSE_ANY
) 
 451                 status 
= SecIdentityCopyPreference(name
, CSSM_KEYUSE_ANY
, validIssuers
, &identityRef
); 
 452         if (status 
!= errSecSuccess 
&& keyUse 
!= 0) 
 453                 status 
= SecIdentityCopyPreference(name
, 0, validIssuers
, &identityRef
); 
 458 OSStatus 
SecIdentityCopyPreference( 
 460     CSSM_KEYUSE keyUsage
, 
 461     CFArrayRef validIssuers
, 
 462     SecIdentityRef 
*identity
) 
 464     // The original implementation of SecIdentityCopyPreference matches the exact string only. 
 465     // That implementation has been moved to _SecIdentityCopyPreferenceMatchingName (above), 
 466     // and this function is a wrapper which calls it, so that existing clients will get the 
 467     // extended behavior of server domain matching for items that specify URLs. 
 468     // (Note that behavior is unchanged if the specified name is not a URL.) 
 471     os_activity_t activity 
= os_activity_create("SecIdentityCopyPreference", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 472     os_activity_scope(activity
); 
 473     os_release(activity
); 
 475     CFTypeRef val 
= (CFTypeRef
)CFPreferencesCopyValue(CFSTR("LogIdentityPreferenceLookup"), 
 476                     CFSTR("com.apple.security"), 
 477                     kCFPreferencesCurrentUser
, 
 478                     kCFPreferencesAnyHost
); 
 479     Boolean logging 
= false; 
 481         if (CFGetTypeID(val
) == CFBooleanGetTypeID()) { 
 482             logging 
= CFBooleanGetValue((CFBooleanRef
)val
); 
 487     OSStatus status 
= errSecItemNotFound
; 
 488     CFArrayRef names 
= _SecIdentityCopyPossiblePaths(name
); 
 493     CFIndex idx
, total 
= CFArrayGetCount(names
); 
 494     for (idx 
= 0; idx 
< total
; idx
++) { 
 495         CFStringRef aName 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, idx
); 
 497             status 
= _SecIdentityCopyPreferenceMatchingName(aName
, keyUsage
, validIssuers
, identity
); 
 499         catch (...) { status 
= errSecItemNotFound
; } 
 502             // get identity label 
 503             CFStringRef labelString 
= NULL
; 
 504             if (!status 
&& identity 
&& *identity
) { 
 506                     SecPointer
<Certificate
> cert(Identity::required(*identity
)->certificate()); 
 507                     cert
->inferLabel(false, &labelString
); 
 509                 catch (...) { labelString 
= NULL
; }; 
 511             char *labelBuf 
= NULL
; 
 512             CFIndex labelBufSize 
= (labelString
) ? CFStringGetLength(labelString
) * 4 : 4; 
 513             labelBuf 
= (char *)malloc(labelBufSize
); 
 514             if (!labelString 
|| !CFStringGetCString(labelString
, labelBuf
, labelBufSize
, kCFStringEncodingUTF8
)) { 
 518                 CFRelease(labelString
); 
 522             char *serviceBuf 
= NULL
; 
 523             CFIndex serviceBufSize 
= CFStringGetLength(aName
) * 4; 
 524             serviceBuf 
= (char *)malloc(serviceBufSize
); 
 525             if (!CFStringGetCString(aName
, serviceBuf
, serviceBufSize
, kCFStringEncodingUTF8
)) { 
 529             syslog(LOG_NOTICE
, "preferred identity: \"%s\" found for \"%s\"\n", labelBuf
, serviceBuf
); 
 530             if (!status 
&& name
) { 
 531                 char *nameBuf 
= NULL
; 
 532                 CFIndex nameBufSize 
= CFStringGetLength(name
) * 4; 
 533                 nameBuf 
= (char *)malloc(nameBufSize
); 
 534                 if (!CFStringGetCString(name
, nameBuf
, nameBufSize
, kCFStringEncodingUTF8
)) { 
 537                 syslog(LOG_NOTICE
, "lookup complete; will use: \"%s\" for \"%s\"\n", labelBuf
, nameBuf
); 
 545         if (status 
== errSecSuccess
) { 
 546             break; // match found 
 556 OSStatus 
SecIdentitySetPreference( 
 557     SecIdentityRef identity
, 
 559     CSSM_KEYUSE keyUsage
) 
 565                 // treat NULL identity as a request to clear the preference 
 566                 // (note: if keyUsage is 0, this clears all key usage prefs for name) 
 567                 return SecIdentityDeletePreferenceItemWithNameAndKeyUsage(NULL
, name
, keyUsage
); 
 571     os_activity_t activity 
= os_activity_create("SecIdentitySetPreference", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 572     os_activity_scope(activity
); 
 573     os_release(activity
); 
 575     CFRef
<SecCertificateRef
>  certRef
; 
 576     OSStatus status 
= SecIdentityCopyCertificate(identity
, certRef
.take()); 
 577     if(status 
!= errSecSuccess
) { 
 578         MacOSError::throwMe(status
); 
 581         // determine the account attribute 
 583         // This attribute must be synthesized from certificate label + pref item type + key usage, 
 584         // as only the account and service attributes can make a generic keychain item unique. 
 585         // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that 
 586         // we can save a certificate preference if an identity preference already exists for the 
 587         // given service name, and vice-versa. 
 588         // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. 
 590     CFStringRef labelStr 
= nil
; 
 591     SecCertificateInferLabel(certRef
.get(), &labelStr
); 
 593         MacOSError::throwMe(errSecDataTooLarge
); // data is "in a format which cannot be displayed" 
 595         CFIndex accountUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1; 
 596         const char *templateStr 
= "%s [key usage 0x%X]"; 
 597         const int keyUsageMaxStrLen 
= 8; 
 598         accountUTF8Len 
+= strlen(templateStr
) + keyUsageMaxStrLen
; 
 599         char *accountUTF8 
= (char *)malloc(accountUTF8Len
); 
 601                 MacOSError::throwMe(errSecMemoryError
); 
 603     if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
)) 
 604                 accountUTF8
[0] = (char)'\0'; 
 606                 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
); 
 607         snprintf(accountUTF8
, accountUTF8Len
-1, "%s ", accountUTF8
); 
 608     CssmDataContainer 
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
)); 
 612         // service attribute (name provided by the caller) 
 613         CFIndex serviceUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(name
), kCFStringEncodingUTF8
) + 1;; 
 614         char *serviceUTF8 
= (char *)malloc(serviceUTF8Len
); 
 616                 MacOSError::throwMe(errSecMemoryError
); 
 618     if (!CFStringGetCString(name
, serviceUTF8
, serviceUTF8Len
-1, kCFStringEncodingUTF8
)) 
 619         serviceUTF8
[0] = (char)'\0'; 
 620     CssmDataContainer 
service(const_cast<char *>(serviceUTF8
), strlen(serviceUTF8
)); 
 623     // look for existing identity preference item, in case this is an update 
 624         StorageManager::KeychainList keychains
; 
 625         globals().storageManager
.getSearchList(keychains
); 
 626         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 627     FourCharCode itemType 
= 'iprf'; 
 628     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 629         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), itemType
); 
 631         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 634         Item 
item(kSecGenericPasswordItemClass
, 'aapl', 0, NULL
, false); 
 635     bool add 
= (!cursor
->next(item
)); 
 636         // at this point, we either have a new item to add or an existing item to update 
 638     // set item attribute values 
 639     item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 640     item
->setAttribute(Schema::attributeInfo(kSecTypeItemAttr
), itemType
); 
 641     item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 642         item
->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 643     item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
); 
 645         // generic attribute (store persistent certificate reference) 
 646         CFDataRef pItemRef 
= nil
; 
 647     SecKeychainItemCreatePersistentReference((SecKeychainItemRef
)certRef
.get(), &pItemRef
); 
 649                 MacOSError::throwMe(errSecInvalidItemRef
); 
 651         const UInt8 
*dataPtr 
= CFDataGetBytePtr(pItemRef
); 
 652         CFIndex dataLen 
= CFDataGetLength(pItemRef
); 
 653         CssmData 
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
); 
 654         item
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
); 
 658         Keychain keychain 
= nil
; 
 660             keychain 
= globals().storageManager
.defaultKeychain(); 
 661             if (!keychain
->exists()) 
 662                 MacOSError::throwMe(errSecNoSuchKeychain
);      // Might be deleted or not available at this time. 
 665             keychain 
= globals().storageManager
.defaultKeychainUI(item
); 
 671                 catch (const MacOSError 
&err
) { 
 672                         if (err
.osStatus() != errSecDuplicateItem
) 
 673                                 throw; // if item already exists, fall through to update 
 682 SecIdentitySetPreferred(SecIdentityRef identity
, CFStringRef name
, CFArrayRef keyUsage
) 
 684         CSSM_KEYUSE keyUse 
= ConvertArrayToKeyUsage(keyUsage
); 
 685         return SecIdentitySetPreference(identity
, name
, keyUse
); 
 689 SecIdentityFindPreferenceItem( 
 690         CFTypeRef keychainOrArray
, 
 691         CFStringRef idString
, 
 692         SecKeychainItemRef 
*itemRef
) 
 695     os_activity_t activity 
= os_activity_create("SecIdentityFindPreferenceItem", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 696     os_activity_scope(activity
); 
 697     os_release(activity
); 
 699         StorageManager::KeychainList keychains
; 
 700         globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
); 
 701         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 703         char idUTF8
[MAXPATHLEN
]; 
 704     idUTF8
[0] = (char)'\0'; 
 707                 if (!CFStringGetCString(idString
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
)) 
 708                         idUTF8
[0] = (char)'\0'; 
 710     size_t idUTF8Len 
= strlen(idUTF8
); 
 712         MacOSError::throwMe(errSecParam
); 
 714     CssmData 
service(const_cast<char *>(idUTF8
), idUTF8Len
); 
 715     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 716         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'iprf'); 
 719         if (!cursor
->next(item
)) 
 720                 MacOSError::throwMe(errSecItemNotFound
); 
 723                 *itemRef
=item
->handle(); 
 729 SecIdentityFindPreferenceItemWithNameAndKeyUsage( 
 730         CFTypeRef keychainOrArray
, 
 733         SecKeychainItemRef 
*itemRef
) 
 736     os_activity_t activity 
= os_activity_create("SecIdentityFindPreferenceItemWithNameAndKeyUsage", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 737     os_activity_scope(activity
); 
 738     os_release(activity
); 
 740         StorageManager::KeychainList keychains
; 
 741         globals().storageManager
.optionalSearchList(keychainOrArray
, keychains
); 
 742         KCCursor 
cursor(keychains
, kSecGenericPasswordItemClass
, NULL
); 
 744         char idUTF8
[MAXPATHLEN
]; 
 745     idUTF8
[0] = (char)'\0'; 
 748                 if (!CFStringGetCString(name
, idUTF8
, sizeof(idUTF8
)-1, kCFStringEncodingUTF8
)) 
 749                         idUTF8
[0] = (char)'\0'; 
 751     size_t idUTF8Len 
= strlen(idUTF8
); 
 753         MacOSError::throwMe(errSecParam
); 
 755     CssmData 
service(const_cast<char *>(idUTF8
), idUTF8Len
); 
 756     cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 757         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'iprf'); 
 759         cursor
->add(CSSM_DB_EQUAL
, Schema::attributeInfo(kSecScriptCodeItemAttr
), (sint32
)keyUsage
); 
 762         if (!cursor
->next(item
)) 
 763                 MacOSError::throwMe(errSecItemNotFound
); 
 766                 *itemRef
=item
->handle(); 
 771 OSStatus 
SecIdentityDeletePreferenceItemWithNameAndKeyUsage( 
 772         CFTypeRef keychainOrArray
, 
 776         // when a specific key usage is passed, we'll only match & delete that pref; 
 777         // when a key usage of 0 is passed, all matching prefs should be deleted. 
 778         // maxUsages represents the most matches there could theoretically be, so 
 779         // cut things off at that point if we're still finding items (if they can't 
 780         // be deleted for some reason, we'd never break out of the loop.) 
 782         OSStatus status 
= errSecInternalError
; 
 783         SecKeychainItemRef item 
= NULL
; 
 784         int count 
= 0, maxUsages 
= 12; 
 785         while (++count 
<= maxUsages 
&& 
 786                         (status 
= SecIdentityFindPreferenceItemWithNameAndKeyUsage(keychainOrArray
, name
, keyUsage
, &item
)) == errSecSuccess
) { 
 787                 status 
= SecKeychainItemDelete(item
); 
 792         // it's not an error if the item isn't found 
 793         return (status 
== errSecItemNotFound
) ? errSecSuccess 
: status
; 
 798 OSStatus 
_SecIdentityAddPreferenceItemWithName( 
 799         SecKeychainRef keychainRef
, 
 800         SecIdentityRef identityRef
, 
 801         CFStringRef idString
, 
 802         SecKeychainItemRef 
*itemRef
) 
 804     // this is NOT exported, and called only from SecIdentityAddPreferenceItem (below), so no BEGIN/END macros here; 
 805     // caller must handle exceptions 
 807         if (!identityRef 
|| !idString
) 
 809         SecPointer
<Certificate
> cert(Identity::required(identityRef
)->certificate()); 
 810         Item 
item(kSecGenericPasswordItemClass
, 'aapl', 0, NULL
, false); 
 813         // determine the account attribute 
 815         // This attribute must be synthesized from certificate label + pref item type + key usage, 
 816         // as only the account and service attributes can make a generic keychain item unique. 
 817         // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that 
 818         // we can save a certificate preference if an identity preference already exists for the 
 819         // given service name, and vice-versa. 
 820         // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. 
 822     CFStringRef labelStr 
= nil
; 
 823         cert
->inferLabel(false, &labelStr
); 
 825         return errSecDataTooLarge
; // data is "in a format which cannot be displayed" 
 827         CFIndex accountUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1; 
 828         const char *templateStr 
= "%s [key usage 0x%X]"; 
 829         const int keyUsageMaxStrLen 
= 8; 
 830         accountUTF8Len 
+= strlen(templateStr
) + keyUsageMaxStrLen
; 
 831         char *accountUTF8 
= (char *)malloc(accountUTF8Len
); 
 833                 MacOSError::throwMe(errSecMemoryError
); 
 835     if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
)) 
 836                 accountUTF8
[0] = (char)'\0'; 
 838                 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
); 
 839         snprintf(accountUTF8
, accountUTF8Len
-1, "%s ", accountUTF8
); 
 840     CssmDataContainer 
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
)); 
 844         // service attribute (name provided by the caller) 
 845         CFIndex serviceUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(idString
), kCFStringEncodingUTF8
) + 1;; 
 846         char *serviceUTF8 
= (char *)malloc(serviceUTF8Len
); 
 848                 MacOSError::throwMe(errSecMemoryError
); 
 850     if (!CFStringGetCString(idString
, serviceUTF8
, serviceUTF8Len
-1, kCFStringEncodingUTF8
)) 
 851         serviceUTF8
[0] = (char)'\0'; 
 852     CssmDataContainer 
service(const_cast<char *>(serviceUTF8
), strlen(serviceUTF8
)); 
 855         // set item attribute values 
 856         item
->setAttribute(Schema::attributeInfo(kSecServiceItemAttr
), service
); 
 857         item
->setAttribute(Schema::attributeInfo(kSecLabelItemAttr
), service
); 
 858         item
->setAttribute(Schema::attributeInfo(kSecTypeItemAttr
), (FourCharCode
)'iprf'); 
 859         item
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
 860         item
->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr
), keyUsage
); 
 862         // generic attribute (store persistent certificate reference) 
 863         CFDataRef pItemRef 
= nil
; 
 864         OSStatus status 
= SecKeychainItemCreatePersistentReference((SecKeychainItemRef
)cert
->handle(), &pItemRef
); 
 866                 status 
= errSecInvalidItemRef
; 
 869         const UInt8 
*dataPtr 
= CFDataGetBytePtr(pItemRef
); 
 870         CFIndex dataLen 
= CFDataGetLength(pItemRef
); 
 871         CssmData 
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
); 
 872         item
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
); 
 875         Keychain keychain 
= nil
; 
 877         keychain 
= Keychain::optional(keychainRef
); 
 878         if (!keychain
->exists()) 
 879             MacOSError::throwMe(errSecNoSuchKeychain
);  // Might be deleted or not available at this time. 
 882         keychain 
= globals().storageManager
.defaultKeychainUI(item
); 
 888         catch (const MacOSError 
&err
) { 
 889                 if (err
.osStatus() != errSecDuplicateItem
) 
 890                         throw; // if item already exists, fall through to update 
 896                 *itemRef 
= item
->handle(); 
 901 OSStatus 
SecIdentityAddPreferenceItem( 
 902         SecKeychainRef keychainRef
, 
 903         SecIdentityRef identityRef
, 
 904         CFStringRef idString
, 
 905         SecKeychainItemRef 
*itemRef
) 
 907     // The original implementation of SecIdentityAddPreferenceItem adds the exact string only. 
 908     // That implementation has been moved to _SecIdentityAddPreferenceItemWithName (above), 
 909     // and this function is a wrapper which calls it, so that existing clients will get the 
 910     // extended behavior of server domain matching for items that specify URLs. 
 911     // (Note that behavior is unchanged if the specified idString is not a URL.) 
 914     os_activity_t activity 
= os_activity_create("SecIdentityAddPreferenceItem", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 915     os_activity_scope(activity
); 
 916     os_release(activity
); 
 918     OSStatus status 
= errSecInternalComponent
; 
 919     CFArrayRef names 
= _SecIdentityCopyPossiblePaths(idString
); 
 924     CFIndex total 
= CFArrayGetCount(names
); 
 926         // add item for name (first element in array) 
 927         CFStringRef aName 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, 0); 
 929             status 
= _SecIdentityAddPreferenceItemWithName(keychainRef
, identityRef
, aName
, itemRef
); 
 931         catch (const MacOSError 
&err
)   { status
=err
.osStatus(); } 
 932         catch (const CommonError 
&err
)  { status
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
 933         catch (const std::bad_alloc 
&)  { status
=errSecAllocate
; } 
 934         catch (...)                     { status
=errSecInternalComponent
; } 
 937                 Boolean setDomainDefaultIdentity 
= FALSE
; 
 938                 CFTypeRef val 
= (CFTypeRef
)CFPreferencesCopyValue(CFSTR("SetDomainDefaultIdentity"), 
 939                                                                                                                   CFSTR("com.apple.security.identities"), 
 940                                                                                                                   kCFPreferencesCurrentUser
, 
 941                                                                                                                   kCFPreferencesAnyHost
); 
 943                         if (CFGetTypeID(val
) == CFBooleanGetTypeID()) 
 944                                 setDomainDefaultIdentity 
= CFBooleanGetValue((CFBooleanRef
)val
) ? TRUE 
: FALSE
; 
 947                 if (setDomainDefaultIdentity
) { 
 948                         // add item for domain (second-to-last element in array, e.g. "*.apple.com") 
 949                         OSStatus tmpStatus 
= errSecSuccess
; 
 950                         CFStringRef aName 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, total
-2); 
 952                                 tmpStatus 
= _SecIdentityAddPreferenceItemWithName(keychainRef
, identityRef
, aName
, itemRef
); 
 954                         catch (const MacOSError 
&err
)   { tmpStatus
=err
.osStatus(); } 
 955                         catch (const CommonError 
&err
)  { tmpStatus
=SecKeychainErrFromOSStatus(err
.osStatus()); } 
 956                         catch (const std::bad_alloc 
&)  { tmpStatus
=errSecAllocate
; } 
 957                         catch (...)                     { tmpStatus
=errSecInternalComponent
; } 
 967 /* deprecated in 10.5 */ 
 968 OSStatus 
SecIdentityUpdatePreferenceItem( 
 969                         SecKeychainItemRef itemRef
, 
 970                         SecIdentityRef identityRef
) 
 973     os_activity_t activity 
= os_activity_create("SecIdentityUpdatePreferenceItem", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
 974     os_activity_scope(activity
); 
 975     os_release(activity
); 
 977         if (!itemRef 
|| !identityRef
) 
 978                 MacOSError::throwMe(errSecParam
); 
 979         SecPointer
<Certificate
> certificate(Identity::required(identityRef
)->certificate()); 
 980         Item prefItem 
= ItemImpl::required(itemRef
); 
 982         // get the current key usage value for this item 
 985         SecKeychainAttribute attr 
= { kSecScriptCodeItemAttr
, sizeof(sint32
), &keyUsage 
}; 
 987                 prefItem
->getAttribute(attr
, &actLen
); 
 993         // set the account attribute 
 995         // This attribute must be synthesized from certificate label + pref item type + key usage, 
 996         // as only the account and service attributes can make a generic keychain item unique. 
 997         // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that 
 998         // we can save a certificate preference if an identity preference already exists for the 
 999         // given service name, and vice-versa. 
1000         // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. 
1002     CFStringRef labelStr 
= nil
; 
1003         certificate
->inferLabel(false, &labelStr
); 
1005         MacOSError::throwMe(errSecDataTooLarge
); // data is "in a format which cannot be displayed" 
1007         CFIndex accountUTF8Len 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr
), kCFStringEncodingUTF8
) + 1; 
1008         const char *templateStr 
= "%s [key usage 0x%X]"; 
1009         const int keyUsageMaxStrLen 
= 8; 
1010         accountUTF8Len 
+= strlen(templateStr
) + keyUsageMaxStrLen
; 
1011         char *accountUTF8 
= (char *)malloc(accountUTF8Len
); 
1013                 MacOSError::throwMe(errSecMemoryError
); 
1015         if (!CFStringGetCString(labelStr
, accountUTF8
, accountUTF8Len
-1, kCFStringEncodingUTF8
)) 
1016                 accountUTF8
[0] = (char)'\0'; 
1018                 snprintf(accountUTF8
, accountUTF8Len
-1, templateStr
, accountUTF8
, keyUsage
); 
1019         snprintf(accountUTF8
, accountUTF8Len
-1, "%s ", accountUTF8
); 
1020         CssmDataContainer 
account(const_cast<char *>(accountUTF8
), strlen(accountUTF8
)); 
1021         prefItem
->setAttribute(Schema::attributeInfo(kSecAccountItemAttr
), account
); 
1023         CFRelease(labelStr
); 
1025         // generic attribute (store persistent certificate reference) 
1026         CFDataRef pItemRef 
= nil
; 
1027         OSStatus status 
= SecKeychainItemCreatePersistentReference((SecKeychainItemRef
)certificate
->handle(), &pItemRef
); 
1029                 status 
= errSecInvalidItemRef
; 
1031                 MacOSError::throwMe(status
); 
1032         const UInt8 
*dataPtr 
= CFDataGetBytePtr(pItemRef
); 
1033         CFIndex dataLen 
= CFDataGetLength(pItemRef
); 
1034         CssmData 
pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr
)), dataLen
); 
1035         prefItem
->setAttribute(Schema::attributeInfo(kSecGenericItemAttr
), pref
); 
1036         CFRelease(pItemRef
); 
1043 OSStatus 
SecIdentityCopyFromPreferenceItem( 
1044                         SecKeychainItemRef itemRef
, 
1045                         SecIdentityRef 
*identityRef
) 
1048     os_activity_t activity 
= os_activity_create("SecIdentityCopyFromPreferenceItem", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
1049     os_activity_scope(activity
); 
1050     os_release(activity
); 
1052         if (!itemRef 
|| !identityRef
) 
1053                 MacOSError::throwMe(errSecParam
); 
1054         Item prefItem 
= ItemImpl::required(itemRef
); 
1056         // get persistent certificate reference 
1057         SecKeychainAttribute itemAttrs
[] = { { kSecGenericItemAttr
, 0, NULL 
} }; 
1058         SecKeychainAttributeList itemAttrList 
= { sizeof(itemAttrs
) / sizeof(itemAttrs
[0]), itemAttrs 
}; 
1059         prefItem
->getContent(NULL
, &itemAttrList
, NULL
, NULL
); 
1061         // find certificate, given persistent reference data 
1062         CFDataRef pItemRef 
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8 
*)itemAttrs
[0].data
, itemAttrs
[0].length
, kCFAllocatorNull
); 
1063         SecKeychainItemRef certItemRef 
= nil
; 
1064         OSStatus status 
= SecKeychainItemCopyFromPersistentReference(pItemRef
, &certItemRef
); //%%% need to make this a method of ItemImpl 
1065         prefItem
->freeContent(&itemAttrList
, NULL
); 
1067                 CFRelease(pItemRef
); 
1071         // create identity reference, given certificate 
1072         StorageManager::KeychainList keychains
; 
1073         globals().storageManager
.optionalSearchList((CFTypeRef
)NULL
, keychains
); 
1074         Item certItem 
= ItemImpl::required(SecKeychainItemRef(certItemRef
)); 
1075         SecPointer
<Certificate
> certificate(static_cast<Certificate 
*>(certItem
.get())); 
1076         SecPointer
<Identity
> identity(new Identity(keychains
, certificate
)); 
1078                 CFRelease(certItemRef
); 
1080         Required(identityRef
) = identity
->handle(); 
1086  * System Identity Support. 
1089 /* plist domain (in /Library/Preferences) */ 
1090 #define IDENTITY_DOMAIN         "com.apple.security.systemidentities" 
1093  * Our plist is a dictionary whose entries have the following format: 
1094  * key   = domain name as CFString 
1095  * value = public key hash as CFData 
1098 #define SYSTEM_KEYCHAIN_PATH    kSystemKeychainDir "/" kSystemKeychainName 
1101  * All accesses to system identities and its associated plist are 
1102  * protected by this lock. 
1104 ModuleNexus
<Mutex
> systemIdentityLock
; 
1106 OSStatus 
SecIdentityCopySystemIdentity( 
1108    SecIdentityRef 
*idRef
, 
1109    CFStringRef 
*actualDomain
) /* optional */ 
1112     os_activity_t activity 
= os_activity_create("SecIdentityCopySystemIdentity", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
1113     os_activity_scope(activity
); 
1114     os_release(activity
); 
1116         StLock
<Mutex
> _(systemIdentityLock()); 
1117         auto_ptr
<Dictionary
> identDict
; 
1119         /* get top-level dictionary - if not present, we're done */ 
1120         Dictionary
* d 
= Dictionary::CreateDictionary(IDENTITY_DOMAIN
, Dictionary::US_System
); 
1123                 return errSecNotAvailable
; 
1128         /* see if there's an entry for specified domain */ 
1129         CFDataRef entryValue 
= identDict
->getDataValue(domain
); 
1130         if(entryValue 
== NULL
) { 
1131                 /* try for default entry if we're not already looking for default */ 
1132                 if(!CFEqual(domain
, kSecIdentityDomainDefault
)) { 
1133                         entryValue 
= identDict
->getDataValue(kSecIdentityDomainDefault
); 
1135                 if(entryValue 
== NULL
) { 
1136                         /* no default identity */ 
1137                         MacOSError::throwMe(errSecItemNotFound
); 
1140                 /* remember that we're not fetching the requested domain */ 
1141                 domain 
= kSecIdentityDomainDefault
; 
1144         /* open system keychain - error here is fatal */ 
1145         Keychain systemKc 
= globals().storageManager
.make(SYSTEM_KEYCHAIN_PATH
, false); 
1146         CFRef
<SecKeychainRef
> systemKcRef(systemKc
->handle()); 
1147         StorageManager::KeychainList keychains
; 
1148         globals().storageManager
.optionalSearchList(systemKcRef
, keychains
); 
1150         /* search for specified cert */ 
1151         SecKeychainAttributeList        attrList
; 
1152         SecKeychainAttribute            attr
; 
1153         attr
.tag        
= kSecPublicKeyHashItemAttr
; 
1154         attr
.length     
= (UInt32
)CFDataGetLength(entryValue
); 
1155         attr
.data       
= (void *)CFDataGetBytePtr(entryValue
); 
1157         attrList
.attr   
= &attr
; 
1159         KCCursor 
cursor(keychains
, kSecCertificateItemClass
, &attrList
); 
1161         if(!cursor
->next(certItem
)) { 
1162                 MacOSError::throwMe(errSecItemNotFound
); 
1165         /* found the cert; try matching with key to cook up identity */ 
1166         SecPointer
<Certificate
> certificate(static_cast<Certificate 
*>(certItem
.get())); 
1167         SecPointer
<Identity
> identity(new Identity(keychains
, certificate
)); 
1169         Required(idRef
) = identity
->handle(); 
1171                 *actualDomain 
= domain
; 
1172                 CFRetain(*actualDomain
); 
1178 OSStatus 
SecIdentitySetSystemIdentity( 
1180    SecIdentityRef idRef
) 
1183     os_activity_t activity 
= os_activity_create("SecIdentitySetSystemIdentity", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
); 
1184     os_activity_scope(activity
); 
1185     os_release(activity
); 
1187         StLock
<Mutex
> _(systemIdentityLock()); 
1188         if(geteuid() != 0) { 
1189                 MacOSError::throwMe(errSecAuthFailed
); 
1192         auto_ptr
<MutableDictionary
> identDict
; 
1193         MutableDictionary 
*d 
= MutableDictionary::CreateMutableDictionary(IDENTITY_DOMAIN
, Dictionary::US_System
); 
1201                         /* nothing there, nothing to set - done */ 
1202                         return errSecSuccess
; 
1204                 identDict
.reset(new MutableDictionary()); 
1208                 /* Just delete the possible entry for this domain */ 
1209                 identDict
->removeValue(domain
); 
1212                 /* obtain public key hash of identity's cert */ 
1213                 SecPointer
<Identity
> identity(Identity::required(idRef
)); 
1214                 SecPointer
<Certificate
> cert 
= identity
->certificate(); 
1215                 const CssmData 
&pubKeyHash 
= cert
->publicKeyHash(); 
1216                 CFRef
<CFDataRef
> pubKeyHashData(CFDataCreate(NULL
, pubKeyHash
.Data
, 
1217                         pubKeyHash
.Length
)); 
1219                 /* add/replace to dictionary */ 
1220                 identDict
->setValue(domain
, pubKeyHashData
); 
1224         if(!identDict
->writePlistToPrefs(IDENTITY_DOMAIN
, Dictionary::US_System
)) { 
1225                 MacOSError::throwMe(errSecIO
); 
1231 const CFStringRef kSecIdentityDomainDefault 
= CFSTR("com.apple.systemdefault"); 
1232 const CFStringRef kSecIdentityDomainKerberosKDC 
= CFSTR("com.apple.kerberos.kdc");