2  * Copyright (c) 2006-2019 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 "SecBridge.h" 
  25 #include <Security/SecInternal.h> 
  26 #include <CoreFoundation/CoreFoundation.h> 
  27 #include <security_utilities/cfutilities.h> 
  28 #include <Security/SecBase.h> 
  29 #include <Security/SecKeychainItem.h> 
  30 #include <Security/SecCertificate.h> 
  31 #include <Security/SecCertificatePriv.h> 
  32 #include <sys/param.h> 
  33 #include "cssmdatetime.h" 
  34 #include <Security/SecItem.h> 
  35 #include <Security/SecItemPriv.h> 
  36 #include <Security/SecIdentitySearchPriv.h> 
  37 #include <Security/SecKeychainPriv.h> 
  38 #include <Security/SecCertificatePriv.h> 
  39 #include <Security/SecPolicyPriv.h> 
  40 #include "TrustAdditions.h" 
  41 #include "TrustSettingsSchema.h" 
  42 #include <Security/SecTrustPriv.h> 
  43 #include "utilities/array_size.h" 
  44 #include "utilities/SecCFWrappers.h" 
  46 #include <AssertMacros.h> 
  50 #include <Security/SecTrustedApplication.h> 
  51 #include <Security/SecTrustedApplicationPriv.h> 
  52 #include <Security/SecCode.h> 
  53 #include <Security/SecCodePriv.h> 
  54 #include <Security/SecRequirement.h> 
  56 #include <login/SessionAgentCom.h> 
  57 #include <login/SessionAgentStatusCom.h> 
  58 #include <os/activity.h> 
  59 #include <CoreFoundation/CFPriv.h> 
  62 const uint8_t kUUIDStringLength 
= 36; 
  64 OSStatus 
SecItemAdd_osx(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  65 OSStatus 
SecItemCopyMatching_osx(CFDictionaryRef query
, CFTypeRef 
*result
); 
  66 OSStatus 
SecItemUpdate_osx(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  67 OSStatus 
SecItemDelete_osx(CFDictionaryRef query
); 
  70 OSStatus 
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  71 OSStatus 
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef 
*result
); 
  72 OSStatus 
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  73 OSStatus 
SecItemDelete_ios(CFDictionaryRef query
); 
  74 OSStatus 
SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
); 
  77 OSStatus 
SecItemValidateAppleApplicationGroupAccess(CFStringRef group
); 
  78 CFDictionaryRef 
SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
  79         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
); 
  81 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef 
*return_class
, 
  82                                 long long int *return_rowid
, CFDictionaryRef 
*return_token_attrs
); 
  85 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
); 
  86 static CFArrayRef 
_CopyMatchingIssuers(CFArrayRef issuers
); 
  88 static void secitemlog(int priority
, const char *format
, ...) 
  93         if (priority 
< LOG_NOTICE
) // log warnings and errors 
  97                 va_start(list
, format
); 
  98                 vsyslog(priority
, format
, list
); 
 103 static void secitemshow(CFTypeRef obj
, const char *context
) 
 106         CFStringRef desc 
= CFCopyDescription(obj
); 
 109         CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1; 
 110         char* buffer 
= (char*) malloc(length
); 
 112                 Boolean converted 
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
); 
 114                         const char *prefix 
= (context
) ? context 
: ""; 
 115                         const char *separator 
= (context
) ? " " : ""; 
 116                         secitemlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
); 
 125 #define CFDataGetBytePtrVoid CFDataGetBytePtr 
 127 #pragma mark SecItem private utility functions 
 129 /******************************************************************************/ 
 131 struct ProtocolAttributeInfo 
{ 
 132         const CFStringRef 
*protocolValue
; 
 133         SecProtocolType protocolType
; 
 136 static ProtocolAttributeInfo gProtocolTypes
[] = { 
 137         { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP 
}, 
 138         { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount 
}, 
 139         { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP 
}, 
 140         { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC 
}, 
 141         { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP 
}, 
 142         { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3 
}, 
 143         { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP 
}, 
 144         { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS 
}, 
 145         { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP 
}, 
 146         { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP 
}, 
 147         { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk 
}, 
 148         { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP 
}, 
 149         { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet 
}, 
 150         { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH 
}, 
 151         { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS 
}, 
 152         { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS 
}, 
 153         { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy 
}, 
 154         { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy 
}, 
 155         { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy 
}, 
 156         { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB 
}, 
 157         { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP 
}, 
 158         { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy 
}, 
 159         { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP 
}, 
 160         { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC 
}, 
 161         { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP 
}, 
 162         { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS 
}, 
 163         { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS 
}, 
 164         { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS 
}, 
 165         { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS 
}, 
 166         { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS 
}, 
 167         { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S 
} 
 170 static const int kNumberOfProtocolTypes 
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
); 
 173  * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType. 
 175 static SecProtocolType
 
 176 _SecProtocolTypeForSecAttrProtocol( 
 179         SecProtocolType result 
= kSecProtocolTypeAny
; 
 181         if (protocol 
!= NULL
) { 
 183                 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 184                         if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) { 
 185                                 result 
= gProtocolTypes
[count
].protocolType
; 
 195  * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol. 
 198 _SecAttrProtocolForSecProtocolType( 
 199         SecProtocolType protocolType
) 
 201         CFTypeRef result 
= NULL
; 
 203         for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 204                 if (gProtocolTypes
[count
].protocolType 
== protocolType
) { 
 205                         result 
= *(gProtocolTypes
[count
].protocolValue
); 
 214 /******************************************************************************/ 
 216 struct AuthenticationAttributeInfo 
{ 
 217         const CFStringRef 
*authValue
; 
 218         SecAuthenticationType authType
; 
 221 static AuthenticationAttributeInfo gAuthTypes
[] = { 
 222         { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM 
}, 
 223         { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN 
}, 
 224         { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA 
}, 
 225         { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA 
}, 
 226         { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic 
}, 
 227         { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest 
}, 
 228         { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm 
}, 
 229         { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault 
} 
 232 static const int kNumberOfAuthenticationTypes 
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
); 
 235  * _SecAuthenticationTypeForSecAttrAuthenticationType converts a 
 236  * SecAttrAuthenticationType to a SecAuthenticationType. 
 238 static SecAuthenticationType
 
 239 _SecAuthenticationTypeForSecAttrAuthenticationType( 
 240         CFTypeRef authenticationType
) 
 242         SecAuthenticationType result 
= kSecAuthenticationTypeAny
; 
 244         if (authenticationType 
!= NULL
) { 
 246                 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 247                         if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) { 
 248                                 result 
= gAuthTypes
[count
].authType
; 
 258  * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType 
 259  * to a SecAttrAuthenticationType. 
 262 _SecAttrAuthenticationTypeForSecAuthenticationType( 
 263         SecAuthenticationType authenticationType
) 
 265         CFTypeRef result 
= NULL
; 
 267         for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 268                 if (gAuthTypes
[count
].authType 
== authenticationType
) { 
 269                         result 
= *(gAuthTypes
[count
].authValue
); 
 278 /******************************************************************************/ 
 280 struct KeyAlgorithmInfo 
{ 
 281         const CFStringRef 
*keyType
; 
 285 static KeyAlgorithmInfo gKeyTypes
[] = { 
 286         { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA 
}, 
 287         { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA 
}, 
 288         { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES 
}, 
 289         { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES 
}, 
 290         { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES 
}, 
 291         { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4 
}, 
 292         { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2 
}, 
 293         { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST 
}, 
 294         { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA 
}, 
 295         { &kSecAttrKeyTypeEC
, CSSM_ALGID_ECDSA 
} 
 298 static const int kNumberOfKeyTypes 
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
); 
 301 static UInt32 
_SecAlgorithmTypeFromSecAttrKeyType( 
 302         CFTypeRef keyTypeRef
) 
 304         UInt32 keyAlgValue 
= 0; 
 305         if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
)) 
 309         for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) { 
 310                 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) { 
 311                         keyAlgValue 
= gKeyTypes
[ix
].keyValue
; 
 316         //%%%TODO try to convert the input string to a number here 
 322 enum ItemRepresentation
 
 324         kStringRepresentation
, 
 326         kNumberRepresentation
, 
 327         kBooleanRepresentation
, 
 332 struct InternalAttributeListInfo
 
 335         const CFStringRef 
*newItemType
; 
 336         ItemRepresentation itemRepresentation
; 
 340 static InternalAttributeListInfo gGenericPasswordAttributes
[] = 
 342         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 343         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 344         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 345         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 346         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 347         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 348         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 349         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 350         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 351         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 352         { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation 
}, 
 353         { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation 
} 
 356 static const int kNumberOfGenericPasswordAttributes 
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 359 static InternalAttributeListInfo gInternetPasswordAttributes
[] = 
 361         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 362         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 363         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 364         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 365         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 366         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 367         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 368         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 369         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 370         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 371         { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation 
}, 
 372         { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation 
}, 
 373         { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation 
}, // maps from UInt32 value to string constant 
 374         { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation 
}, 
 375         { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation 
} 
 378 static const int kNumberOfInternetPasswordAttributes 
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 381 static InternalAttributeListInfo gCertificateAttributes
[] = 
 383         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 384         { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation 
}, 
 385         { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation 
}, 
 386         { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation 
}, 
 387         { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation 
}, 
 388         { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation 
}, 
 389         { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation 
}, 
 390         { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation 
} 
 393 static const int kNumberOfCertificateAttributes 
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
); 
 396 static InternalAttributeListInfo gKeyAttributes
[] = 
 398     { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation 
}, // key class maps from UInt32 value to string constant 
 399     { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation 
}, // note that "print name" maps to the user-visible label 
 400 //  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation }, 
 401     { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation 
}, 
 402 //  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 403 //  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 404     { kSecKeyLabel
, &kSecAttrApplicationLabel
, kDataRepresentation 
}, // this contains the hash of the key (or the public key hash, if asymmetric) as a CFData. Legacy keys may contain a UUID as a CFString 
 405     { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation 
}, 
 406 //  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key 
 407     { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation 
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES) 
 408     { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation 
}, 
 409     { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation 
}, 
 410 //  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 411 //  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 412 //  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 413 //  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 414 //  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 415 //  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 416     { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation 
}, 
 417     { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation 
}, 
 418     { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation 
}, 
 419     { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation 
}, 
 420     { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation 
}, 
 421 //  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 422 //  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 423     { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation 
}, 
 424     { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation 
} 
 427 static const int kNumberOfKeyAttributes 
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
); 
 430 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
) 
 434                 case kStringRepresentation
: 
 436                         if (CFStringGetTypeID() != CFGetTypeID(value
)) { 
 440                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 441                         char* buffer 
= (char*) malloc(maxLength
); 
 442                         Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 444                                 length 
= (UInt32
)strlen(buffer
); 
 454                 case kDataRepresentation
: 
 456                         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 457                 // We may have a string here, since the key label may be a GUID for the symmetric keys 
 458                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 459                 char* buffer 
= (char*) malloc(maxLength
); 
 460                 Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 462                     length 
= (UInt32
)strlen(buffer
); 
 472                         if (CFDataGetTypeID() != CFGetTypeID(value
)) { 
 476                         length 
= (UInt32
)CFDataGetLength((CFDataRef
) value
); 
 477                         uint8_t* buffer 
= (uint8_t*) malloc(length
); 
 478                         CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
); 
 482                 case kNumberRepresentation
: 
 484                         if (CFNumberGetTypeID() != CFGetTypeID(value
)) { 
 488                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 489                         Boolean converted 
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
); 
 491                                 length 
= sizeof(uint32_t); 
 501                 case kBooleanRepresentation
: 
 503                         if (CFBooleanGetTypeID() != CFGetTypeID(value
)) { 
 507                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 508                         *buffer 
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
 509                         length 
= sizeof(uint32_t); 
 513                 case kDateRepresentation
: 
 515                         if (CFDateGetTypeID() != CFGetTypeID(value
)) { 
 519                         char* buffer 
= (char*) calloc(1, 32); // max length of a CSSM date string 
 520                         CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
); 
 521                         length 
= (UInt32
)strlen(buffer
); 
 535 _ConvertNewFormatToOldFormat( 
 536         CFAllocatorRef allocator
, 
 537         const InternalAttributeListInfo
* info
, 
 539         CFDictionaryRef dictionaryRef
, 
 540         SecKeychainAttributeList
* &attrList
 
 543     // make storage to extract the dictionary items 
 544     CFIndex itemsInDictionary 
= CFDictionaryGetCount(dictionaryRef
); 
 545     if (itemsInDictionary 
> 10000) { 
 549         // get the keychain attributes array from the data item 
 550         // here's the problem.  On the one hand, we have a dictionary that is purported to contain 
 551         // attributes for our type.  On the other hand, the dictionary may contain items we don't support, 
 552         // and we therefore don't know how many attributes we will have unless we count them first 
 555         attrList 
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
)); 
 557         std::vector
<CFTypeRef
> keys(itemsInDictionary
); 
 558         std::vector
<CFTypeRef
> values(itemsInDictionary
); 
 560         CFDictionaryGetKeysAndValues(dictionaryRef
, keys
.data(), values
.data()); 
 562         // count the number of items we are interested in 
 566         // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that 
 567         // we don't pay the price for this twice 
 568         std::vector
<SecKeychainAttrType
> tags(itemsInDictionary
); 
 569         std::vector
<ItemRepresentation
> types(itemsInDictionary
); 
 571         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 573                 CFTypeRef key 
= keys
[i
]; 
 576                 for (j 
= 0; j 
< infoNumItems
; ++j
) 
 578                         if (CFEqual(*(info
[j
].newItemType
), key
)) 
 580                                 tags
[i
] = info
[j
].oldItemType
; 
 581                                 types
[i
] = info
[j
].itemRepresentation
; 
 587                 if (j 
>= infoNumItems
) 
 589                         // if we got here, we aren't interested in this item. 
 594         // now we can make the result array 
 595         attrList
->count 
= (UInt32
)count
; 
 598         attrList
->attr 
= NULL
; 
 600         attrList
->attr 
= (SecKeychainAttribute
*) calloc(count
, sizeof(SecKeychainAttribute
)); 
 602         // fill out the array 
 603         int resultPointer 
= 0; 
 604         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 606             if (values
[i
] != NULL
) 
 608                 attrList
->attr
[resultPointer
].tag 
= tags
[i
]; 
 610                 // we have to clone the data pointer.  The caller will need to make sure to throw these away 
 611                 // with _FreeAttrList when it is done... 
 612                 attrList
->attr
[resultPointer
].data 
= CloneDataByType(types
[i
], values
[i
], attrList
->attr
[resultPointer
].length
); 
 618         return errSecSuccess
; 
 624 _ConvertOldFormatToNewFormat( 
 625         CFAllocatorRef allocator
, 
 626         const InternalAttributeListInfo
* info
, 
 628         SecKeychainItemRef itemRef
, 
 629         CFMutableDictionaryRef
& dictionaryRef
) 
 631         SecKeychainAttributeList list
; 
 632         list
.count 
= infoNumItems
; 
 633         list
.attr 
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
)); 
 635         // fill out the array.  We only need to fill in the tags, since calloc zeros what it returns 
 637         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 639                 list
.attr
[i
].tag 
= info
[i
].oldItemType
; 
 642         OSStatus result 
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
); 
 643         if (result 
!= errSecSuccess
) 
 645                 dictionaryRef 
= NULL
; 
 650         // create the dictionary 
 651         dictionaryRef 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 654         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 656                 if (list
.attr
[i
].data 
== NULL
) 
 659                 switch (info
[i
].itemRepresentation
) 
 661                         case kStringRepresentation
: 
 663                                 CFStringRef stringRef
; 
 664                                 if (info
[i
].oldItemType 
== kSecKeyKeyClass
) { 
 665                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 666                                         uint32_t keyRecordValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 667                                         bool retainString 
= true; 
 668                                         switch (keyRecordValue
) { 
 669                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 670                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 672                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 673                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 675                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 676                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 679                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
); 
 680                             retainString 
= false; 
 684                                                 if (retainString
) CFRetain(stringRef
); 
 685                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 686                                                 CFRelease(stringRef
); 
 689                                 else if (info
[i
].oldItemType 
== kSecKeyKeyType
) { 
 690                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 691                                         uint32_t keyAlgValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 692                                         bool retainString 
= true; 
 693                                         switch (keyAlgValue
) { 
 694                                                 case CSSM_ALGID_RSA 
: 
 695                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 697                                                 case CSSM_ALGID_DSA 
: 
 698                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 700                                                 case CSSM_ALGID_AES 
: 
 701                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 703                                                 case CSSM_ALGID_DES 
: 
 704                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 706                                                 case CSSM_ALGID_3DES 
: 
 707                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 709                                                 case CSSM_ALGID_RC4 
: 
 710                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 712                                                 case CSSM_ALGID_RC2 
: 
 713                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 715                                                 case CSSM_ALGID_CAST 
: 
 716                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 718                                                 case CSSM_ALGID_ECDSA 
: 
 719                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 722                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
); 
 723                                                         retainString 
= false; 
 727                                                 if (retainString
) CFRetain(stringRef
); 
 728                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 729                                                 CFRelease(stringRef
); 
 733                                         // normal case: attribute contains a string 
 734                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 735                                         if (stringRef 
== NULL
) 
 736                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 737                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 738                                         CFRelease(stringRef
); 
 743                         case kDataRepresentation
: 
 745                 if ((info
[i
].oldItemType 
== kSecKeyLabel
) && (list
.attr
[i
].length 
== kUUIDStringLength
)) { 
 746                                         // It's possible that there could be a string here because the key label may have a UUID 
 747                                         CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 748                                         if (stringRef 
== NULL
) 
 749                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 750                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 751                                         CFRelease(stringRef
); 
 754                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
); 
 756                     dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
 757                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
); 
 762                         case kNumberRepresentation
: 
 764                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
); 
 765                                 if (numberRef 
== NULL
) 
 766                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
 767                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
); 
 768                                 CFRelease(numberRef
); 
 772                         case kBooleanRepresentation
: 
 774                                 uint32_t value 
= *((uint32_t*)list
.attr
[i
].data
); 
 775                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
 776                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
); 
 780                         case kDateRepresentation
: 
 782                                 CFDateRef dateRef 
= NULL
; 
 783                                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
); 
 785                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
 786                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
); 
 794         SecKeychainItemFreeContent(&list
, NULL
); 
 804  * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the 
 805  * attributes of item. 
 808 _CreateAttributesDictionaryFromGenericPasswordItem( 
 809         CFAllocatorRef allocator
, 
 810         SecKeychainItemRef item
, 
 811         CFDictionaryRef 
*dictionary
) 
 813         // do the basic allocations 
 814         CFMutableDictionaryRef dict 
= NULL
; 
 815         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
); 
 816         if (result 
== errSecSuccess
) // did we complete OK 
 818                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
); 
 829  * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the 
 830  * attributes of item. 
 833 _CreateAttributesDictionaryFromCertificateItem( 
 834         CFAllocatorRef allocator
, 
 835         SecKeychainItemRef item
, 
 836         CFDictionaryRef 
*dictionary
) 
 838         // do the basic allocations 
 839         CFMutableDictionaryRef dict 
= NULL
; 
 840         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
); 
 841         if (result 
== errSecSuccess
) // did we complete OK 
 843                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
); 
 848         return errSecSuccess
; 
 852  * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the 
 853  * attributes of item. 
 856 _CreateAttributesDictionaryFromKeyItem( 
 857         CFAllocatorRef allocator
, 
 858         SecKeychainItemRef item
, 
 859         CFDictionaryRef 
*dictionary
) 
 862 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails. 
 863 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and 
 864 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent. 
 867                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 870         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 872         // do the basic allocations 
 873         CFMutableDictionaryRef dict 
= NULL
; 
 874         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
); 
 875         if (result 
== errSecSuccess
) // did we complete OK 
 877                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
 882         return errSecSuccess
; 
 885         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 887         SecItemClass itemClass 
= (SecItemClass
) 0; 
 889         SecKeychainAttributeList 
*attrList 
= NULL
; 
 890         SecKeychainAttributeInfo 
*info 
= NULL
; 
 891         SecKeychainRef keychain 
= NULL
; 
 893         OSStatus status 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
 895                 goto error_exit
; // item must have an itemClass 
 900     case kSecInternetPasswordItemClass
: 
 901                 itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
 903     case kSecGenericPasswordItemClass
: 
 904                 itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
 906     case 'ashp': /* kSecAppleSharePasswordItemClass */ 
 907                 itemID 
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
; 
 914         status 
= SecKeychainItemCopyKeychain(item
, &keychain
); 
 916                 goto error_exit
; // item must have a keychain, so we can get the attribute info for it 
 919         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
 921                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 924         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 926                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 929         for (ix 
= 0; ix 
< info
->count
; ++ix
) 
 931                 SecKeychainAttribute 
*attribute 
= &attrList
->attr
[ix
]; 
 932                 if (!attribute
->length 
&& !attribute
->data
) 
 935                 UInt32 j
, count 
= kNumberOfKeyAttributes
; 
 936                 InternalAttributeListInfo 
*intInfo 
= NULL
; 
 937                 for (j
=0; j
<count
; j
++) { 
 938                         if (gKeyAttributes
[j
].oldItemType 
== info
->tag
[ix
]) { 
 939                                 intInfo 
= &gKeyAttributes
[j
]; 
 946                 switch (intInfo
->itemRepresentation
) 
 948                         case kStringRepresentation
: 
 950                                 CFStringRef stringRef
; 
 951                                 if (intInfo
->oldItemType 
== kSecKeyKeyClass
) { 
 952                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 953                                         UInt32 keyRecordValue 
= *((UInt32
*)attribute
->data
); 
 954                                         bool retainString 
= true; 
 955                                         switch (keyRecordValue
) { 
 956                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 957                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 959                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 960                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 962                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 963                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 966                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyRecordValue
); 
 967                             retainString 
= false; 
 971                                                 if (retainString
) CFRetain(stringRef
); 
 972                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 973                                                 CFRelease(stringRef
); 
 976                                 else if (intInfo
->oldItemType 
== kSecKeyKeyType
) { 
 977                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 978                                         UInt32 keyAlgValue 
= *((UInt32
*)attribute
->data
); 
 979                                         bool retainString 
= true; 
 980                                         switch (keyAlgValue
) { 
 981                                                 case CSSM_ALGID_RSA 
: 
 982                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 984                                                 case CSSM_ALGID_DSA 
: 
 985                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 987                                                 case CSSM_ALGID_AES 
: 
 988                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 990                                                 case CSSM_ALGID_DES 
: 
 991                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 993                                                 case CSSM_ALGID_3DES 
: 
 994                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 996                                                 case CSSM_ALGID_RC4 
: 
 997                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 999                                                 case CSSM_ALGID_RC2 
: 
1000                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
1002                                                 case CSSM_ALGID_CAST 
: 
1003                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
1005                                                 case CSSM_ALGID_ECDSA 
: 
1006                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
1009                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyAlgValue
); 
1010                                                         retainString 
= false; 
1014                                                 if (retainString
) CFRetain(stringRef
); 
1015                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1016                                                 CFRelease(stringRef
); 
1020                                         // normal case: attribute contains a string 
1021                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1022                                         if (stringRef 
== NULL
) 
1023                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1024                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1025                                         CFRelease(stringRef
); 
1030                         case kDataRepresentation
: 
1032                 if ((intInfo
->oldItemType 
== kSecKeyLabel
) && (attribute
->length 
== kUUIDStringLength
)) { 
1033                                         // It's possible that there could be a string here because the key label may have a UUID 
1034                     CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1035                                         if (stringRef 
== NULL
) 
1036                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1037                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1038                                         CFRelease(stringRef
); 
1042                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
); 
1043                                 if (dataRef 
== NULL
) 
1044                                         dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
1045                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
); 
1050                         case kNumberRepresentation
: 
1052                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
); 
1053                                 if (numberRef 
== NULL
) 
1054                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
1055                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
); 
1056                                 CFRelease(numberRef
); 
1060                         case kBooleanRepresentation
: 
1062                                 UInt32 value 
= *((UInt32
*)attribute
->data
); 
1063                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1064                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
); 
1068                         case kDateRepresentation
: 
1070                                 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here 
1071                                 CFDateRef dateRef 
= NULL
; 
1072                                 if (dateRef 
== NULL
) 
1073                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
1074                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
); 
1081         CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
1086                 SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
1089                 SecKeychainFreeAttributeInfo(info
); 
1092                 CFRelease(keychain
); 
1101  * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the 
1102  * attributes of item. 
1105 _CreateAttributesDictionaryFromInternetPasswordItem( 
1106         CFAllocatorRef allocator
, 
1107         SecKeychainItemRef item
, 
1108         CFDictionaryRef 
*dictionary
) 
1111         SecKeychainAttribute attr
[] = { 
1112                 { kSecServerItemAttr
, 0, NULL 
},                /* [0] server */ 
1113                 { kSecSecurityDomainItemAttr
, 0, NULL 
},        /* [1] securityDomain */ 
1114                 { kSecAccountItemAttr
, 0, NULL 
},               /* [2] account */ 
1115                 { kSecPathItemAttr
, 0, NULL 
},                  /* [3] path */ 
1116                 { kSecPortItemAttr
, 0, NULL 
},                  /* [4] port */ 
1117                 { kSecProtocolItemAttr
, 0, NULL 
},              /* [5] protocol */ 
1118                 { kSecAuthenticationTypeItemAttr
, 0, NULL 
},    /* [6] authenticationType */ 
1119                 { kSecCommentItemAttr
, 0, NULL 
},               /* [7] comment */ 
1120                 { kSecDescriptionItemAttr
, 0, NULL 
},           /* [8] description */ 
1121                 { kSecLabelItemAttr
, 0, NULL 
},                 /* [9] label */ 
1122                 { kSecCreationDateItemAttr
, 0, NULL 
},  /* [10] creation date */ 
1123                 { kSecModDateItemAttr
, 0, NULL 
},               /* [11] modification date */ 
1124                 { kSecCreatorItemAttr
, 0, NULL 
},               /* [12] creator */ 
1125                 { kSecTypeItemAttr
, 0, NULL 
},                  /* [13] type */ 
1126                 { kSecInvisibleItemAttr
, 0, NULL 
},             /* [14] invisible */ 
1127                 { kSecNegativeItemAttr
, 0, NULL 
},              /* [15] negative */ 
1129         SecKeychainAttributeList attrList 
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr 
}; 
1132         CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1133         CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1137         // copy the item's attributes 
1138         status 
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
); 
1139         require_noerr(status
, SecKeychainItemCopyContent_failed
); 
1144         keys
[numValues
] = kSecClass
; 
1145         values
[numValues
] = kSecClassInternetPassword
; 
1148         // add kSecAttrServer 
1149         if ( attrList
.attr
[0].length 
> 0 ) { 
1150                 keys
[numValues
] = kSecAttrServer
; 
1151                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
); 
1152                 if ( values
[numValues
] != NULL 
) { 
1157         // add kSecAttrSecurityDomain 
1158         if ( attrList
.attr
[1].length 
> 0 ) { 
1159                 keys
[numValues
] = kSecAttrSecurityDomain
; 
1160                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
); 
1161                 if ( values
[numValues
] != NULL 
) { 
1166         // add kSecAttrAccount 
1167         if ( attrList
.attr
[2].length 
> 0 ) { 
1168                 keys
[numValues
] = kSecAttrAccount
; 
1169                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
); 
1170                 if ( values
[numValues
] != NULL 
) { 
1176         if ( attrList
.attr
[3].length 
> 0 ) { 
1177                 keys
[numValues
] = kSecAttrPath
; 
1178                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
); 
1179                 if ( values
[numValues
] != NULL 
) { 
1185         if ( attrList
.attr
[4].length 
> 0 ) { 
1186                 keys
[numValues
] = kSecAttrPort
; 
1187                 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
); 
1188                 if ( values
[numValues
] != NULL 
) { 
1193         // add kSecAttrProtocol 
1194         if ( attrList
.attr
[5].length 
> 0 ) { 
1195                 keys
[numValues
] = kSecAttrProtocol
; 
1196                 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
); 
1197                 if ( values
[numValues
] != NULL 
) { 
1198                         CFRetain(values
[numValues
]); 
1203         // add kSecAttrAuthenticationType 
1204         if ( attrList
.attr
[6].length 
> 0 ) { 
1205                 keys
[numValues
] = kSecAttrAuthenticationType
; 
1206                 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType( (SecAuthenticationType
) (*(SecProtocolType
*)attrList
.attr
[6].data
)); 
1207                 if ( values
[numValues
] != NULL 
) { 
1208                         CFRetain(values
[numValues
]); 
1213         // add kSecAttrComment 
1214         if ( attrList
.attr
[7].length 
> 0 ) { 
1215                 keys
[numValues
] = kSecAttrComment
; 
1216                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
); 
1217                 if ( values
[numValues
] != NULL 
) { 
1222         // add kSecAttrDescription 
1223         if ( attrList
.attr
[8].length 
> 0 ) { 
1224                 keys
[numValues
] = kSecAttrDescription
; 
1225                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
); 
1226                 if ( values
[numValues
] != NULL 
) { 
1231         // add kSecAttrLabel 
1232         if ( attrList
.attr
[9].length 
> 0 ) { 
1233                 keys
[numValues
] = kSecAttrLabel
; 
1234                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
); 
1235                 if ( values
[numValues
] != NULL 
) { 
1240         // add kSecAttrCreationDate 
1241         if ( attrList
.attr
[10].length 
> 0 ) { 
1242                 CFDateRef creationDate 
= NULL
; 
1243                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
); 
1244                 keys
[numValues
] = kSecAttrCreationDate
; 
1245                 values
[numValues
] = creationDate
; 
1246                 if ( values
[numValues
] != NULL 
) { 
1251         // add kSecAttrModificationDate 
1252         if ( attrList
.attr
[11].length 
> 0 ) { 
1253                 CFDateRef modDate 
= NULL
; 
1254                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
); 
1255                 keys
[numValues
] = kSecAttrModificationDate
; 
1256                 values
[numValues
] = modDate
; 
1257                 if ( values
[numValues
] != NULL 
) { 
1262         // add kSecCreatorItemAttr 
1263         if ( attrList
.attr
[12].length 
> 0 ) { 
1264                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
); 
1265                 keys
[numValues
] = kSecAttrCreator
; 
1266                 values
[numValues
] = numberRef
; 
1267                 if ( values
[numValues
] != NULL 
) { 
1268                         CFRetain(values
[numValues
]); 
1273         // add kSecTypeItemAttr 
1274         if ( attrList
.attr
[13].length 
> 0 ) { 
1275                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
); 
1276                 keys
[numValues
] = kSecAttrType
; 
1277                 values
[numValues
] = numberRef
; 
1278                 if ( values
[numValues
] != NULL 
) { 
1279                         CFRetain(values
[numValues
]); 
1284         // add kSecInvisibleItemAttr 
1285         if ( attrList
.attr
[14].length 
> 0 ) { 
1286                 uint32_t value 
= *((uint32_t*)attrList
.attr
[14].data
); 
1287                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1288                 keys
[numValues
] = kSecAttrIsInvisible
; 
1289                 values
[numValues
] = boolRef
; 
1290                 if ( values
[numValues
] != NULL 
) { 
1291                         CFRetain(values
[numValues
]); 
1296         // add kSecNegativeItemAttr 
1297         if ( attrList
.attr
[15].length 
> 0 ) { 
1298                 uint32_t value 
= *((uint32_t*)attrList
.attr
[15].data
); 
1299                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1300                 keys
[numValues
] = kSecAttrIsNegative
; 
1301                 values
[numValues
] = boolRef
; 
1302                 if ( values
[numValues
] != NULL 
) { 
1303                         CFRetain(values
[numValues
]); 
1308         // create the dictionary 
1309         *dictionary 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1311         // release the values added to the dictionary 
1312         for ( index 
= 0; index 
< numValues
; ++index 
) 
1314                 CFRelease(values
[index
]); 
1317         // and free the attributes 
1318         (void) SecKeychainItemFreeContent(&attrList
, NULL
); 
1320 SecKeychainItemCopyContent_failed
: 
1327  * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the 
1328  * attributes of the specified item class and item. 
1331 _CreateAttributesDictionaryFromItem( 
1332         CFAllocatorRef allocator
, 
1333         SecItemClass itemClass
, 
1334         SecKeychainItemRef item
, 
1335         CFDictionaryRef 
*dictionary
) 
1339                 case kSecInternetPasswordItemClass
: 
1340                         return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
); 
1342                 case kSecGenericPasswordItemClass
: 
1343                         return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
); 
1345                 case kSecCertificateItemClass
: 
1346                         return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
); 
1348                 case kSecPublicKeyItemClass
: 
1349                 case kSecPrivateKeyItemClass
: 
1350                 case kSecSymmetricKeyItemClass
: 
1351                         return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
); 
1362  * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList 
1363  * by the _CreateSecKeychainAttributeListFromDictionary function. 
1367         SecKeychainAttributeList 
*attrListPtr
) 
1371         if ( attrListPtr 
!= NULL 
) { 
1372                 if ( attrListPtr
->attr 
!= NULL 
) { 
1373                         // free any attribute data 
1374                         for ( index 
= 0; index 
< attrListPtr
->count
; ++index 
) { 
1375                                 free(attrListPtr
->attr
[index
].data
); 
1377                         // free the attribute array 
1378                         free(attrListPtr
->attr
); 
1380                 // free the attribute list 
1386  * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by 
1387  * attr using the data and tag parameters. 
1389  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1390  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1393 _CFDataCreateAttribute( 
1395         SecKeychainAttrType tag
, 
1396         SecKeychainAttributePtr attr
) 
1398         OSStatus status 
= errSecSuccess
; 
1401         // set the attribute tag 
1404         // determine the attribute length 
1405         attr
->length 
= (UInt32
) CFDataGetLength(data
); 
1406         range 
= CFRangeMake(0, (CFIndex
)attr
->length
); 
1408         // allocate memory for the attribute bytes 
1409         attr
->data 
= malloc(attr
->length
); 
1410         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1412         // get the attribute bytes 
1413         CFDataGetBytes(data
, range
, (UInt8 
*)attr
->data
); 
1421  * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by 
1422  * attr using the string and tag parameters. 
1424  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1425  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1428 _CFStringCreateAttribute( 
1430         SecKeychainAttrType tag
, 
1431         SecKeychainAttributePtr attr
) 
1433         OSStatus status 
= errSecSuccess
; 
1436         // set the attribute tag 
1439         // determine the attribute length 
1440         range 
= CFRangeMake(0, CFStringGetLength(string
)); 
1441         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex 
*)&attr
->length
); 
1443         // allocate memory for the attribute bytes 
1444         attr
->data 
= malloc(attr
->length
); 
1445         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1447         // get the attribute bytes 
1448         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8 
*)attr
->data
, attr
->length
, NULL
); 
1457  * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1458  * from the attribute key/values in attrDictionary. 
1460  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1461  * must be freed by the caller with _FreeAttrList() 
1464 _CreateSecKeychainGenericPasswordAttributeListFromDictionary( 
1465         CFDictionaryRef attrDictionary
, 
1466         SecKeychainAttributeList 
**attrList
) 
1468         return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
); 
1473  * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList 
1474  * from the attribute key/values in attrDictionary. 
1476  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1477  * must be freed by the caller with _FreeAttrList() 
1480 _CreateSecKeychainCertificateAttributeListFromDictionary( 
1481         CFDictionaryRef attrDictionary
, 
1482         SecKeychainAttributeList 
**attrList
) 
1484         return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
); 
1489  * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList 
1490  * from the attribute key/values in attrDictionary. 
1492  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1493  * must be freed by the caller with _FreeAttrList() 
1496 _CreateSecKeychainKeyAttributeListFromDictionary( 
1497         CFDictionaryRef attrDictionary
, 
1498         SecKeychainAttributeList 
**attrList
) 
1501         //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug 
1502         return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
); 
1504         // explicitly build attribute list for supported key attributes 
1505         // NOTE: this code supports only MaxSecKeyAttributes (15) attributes 
1506         const int MaxSecKeyAttributes 
= 15; 
1510         SecKeychainAttributeList 
*attrListPtr
; 
1512         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1513         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1515         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
)); 
1516         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1518         // [0] get the kSecKeyKeyClass value 
1519         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) { 
1520                 UInt32 keyRecordValue 
= 0; 
1521                 if (CFEqual(kSecAttrKeyClassPublic
, value
)) 
1522                         keyRecordValue 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
1523                 else if (CFEqual(kSecAttrKeyClassPrivate
, value
)) 
1524                         keyRecordValue 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
1525                 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
)) 
1526                         keyRecordValue 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
1528                 // only use this attribute if we recognize the value! 
1529                 if (keyRecordValue 
!= 0) { 
1530                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1531                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1533                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyClass
; 
1534                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1535                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
; 
1537                         ++attrListPtr
->count
; 
1541         // [1] get the kSecKeyPrintName string 
1542         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) { 
1543                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1544                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1546                 ++attrListPtr
->count
; 
1549         // [2] get the kSecKeyPermanent boolean 
1550         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) { 
1551                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1552                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1554                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyPermanent
; 
1555                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1556                 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1558                 ++attrListPtr
->count
; 
1561         // [3] get the kSecKeyLabel string 
1562         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) { 
1563         if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1564             status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1565         else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1566             status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1568             status 
= errSecParam
; 
1570                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1572                 ++attrListPtr
->count
; 
1575         // [4] get the kSecKeyApplicationTag data 
1576         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) { 
1577                 if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1578                         status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1579                 else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1580                         status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1582                         status 
= errSecParam
; 
1584                 require_noerr_quiet(status
, CFDataCreateAttribute_failed
); 
1585                 ++attrListPtr
->count
; 
1588         // [5] get the kSecKeyKeyType number 
1589         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) { 
1590                 UInt32 keyAlgValue 
= _SecAlgorithmTypeFromSecAttrKeyType(value
); 
1591                 if (keyAlgValue 
!= 0) { 
1592                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1593                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1595                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyType
; 
1596                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1597                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
; 
1599                         ++attrListPtr
->count
; 
1603         // [6] get the kSecKeyKeySizeInBits number 
1604         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) { 
1605                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1606                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1607                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1609                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeySizeInBits
; 
1610                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1611                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1613                         ++attrListPtr
->count
; 
1617         // [7] get the kSecKeyEffectiveKeySize number 
1618         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) { 
1619                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1620                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1621                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1623                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEffectiveKeySize
; 
1624                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1625                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1627                         ++attrListPtr
->count
; 
1631         // [8] get the kSecKeyEncrypt boolean 
1632         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) { 
1633                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1634                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1635                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1637                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEncrypt
; 
1638                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1639                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1641                         ++attrListPtr
->count
; 
1645         // [9] get the kSecKeyDecrypt boolean 
1646         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) { 
1647                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1648                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1649                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1651                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDecrypt
; 
1652                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1653                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1655                         ++attrListPtr
->count
; 
1659         // [10] get the kSecKeyDerive boolean 
1660         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) { 
1661                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1662                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1663                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1665                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDerive
; 
1666                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1667                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1669                         ++attrListPtr
->count
; 
1673         // [11] get the kSecKeySign boolean 
1674         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) { 
1675                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1676                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1677                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1679                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeySign
; 
1680                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1681                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1683                         ++attrListPtr
->count
; 
1687         // [12] get the kSecKeyVerify boolean 
1688         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) { 
1689                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1690                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1691                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1693                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyVerify
; 
1694                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1695                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1697                         ++attrListPtr
->count
; 
1701         // [13] get the kSecKeyWrap boolean 
1702         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) { 
1703                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1704                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1705                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1707                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyWrap
; 
1708                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1709                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1711                         ++attrListPtr
->count
; 
1715         // [14] get the kSecKeyUnwrap boolean 
1716         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) { 
1717                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1718                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1719                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1721                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyUnwrap
; 
1722                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1723                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1725                         ++attrListPtr
->count
; 
1729         // return the pointer to the attrList 
1730         *attrList 
= attrListPtr
; 
1732         return ( errSecSuccess 
); 
1736 malloc_number_failed
: 
1737 CFDataCreateAttribute_failed
: 
1738 CFStringCreateAttribute_failed
: 
1739 malloc_attrPtr_failed
: 
1741         // free any attributes 
1742         _FreeAttrList(attrListPtr
); 
1744 calloc_attrListPtr_failed
: 
1746         return ( errSecBufferTooSmall 
); 
1751 static CFTypeRef 
copyNumber(CFTypeRef obj
) 
1756     CFTypeID tid 
= CFGetTypeID(obj
); 
1757     if (tid 
== CFNumberGetTypeID()) 
1763     if (tid 
== CFBooleanGetTypeID()) 
1765         SInt32 value 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
1766         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1769     if (tid 
== CFStringGetTypeID()) 
1771         SInt32 value 
= CFStringGetIntValue((CFStringRef
)obj
); 
1772         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value
); 
1773         /* If a string converted to an int isn't equal to the int printed as 
1774          a string, return a NULL instead. */ 
1775         if (!CFEqual(t
, obj
)) 
1781         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1787  * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1788  * from the attribute key/values in attrDictionary. 
1790  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1791  * must be freed by the caller with _FreeAttrList() 
1794 _CreateSecKeychainInternetPasswordAttributeListFromDictionary( 
1795         CFDictionaryRef attrDictionary
, 
1796         SecKeychainAttributeList 
**attrList
) 
1798         // explicitly build attribute list for supported key attributes 
1799         // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes 
1800         const int MaxSecKeychainAttributes 
= 14; 
1804         SecKeychainAttributeList 
*attrListPtr
; 
1806         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1807         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1809         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
)); 
1810         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1813         // [0] get the serverName string 
1814         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) { 
1815                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1816                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1818                 ++attrListPtr
->count
; 
1821         // [1] get the securityDomain string 
1822         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) { 
1823                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1824                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1826                 ++attrListPtr
->count
; 
1829         // [2] get the accountName string 
1830         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) { 
1831                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1832                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1834                 ++attrListPtr
->count
; 
1837         // [3] get the path string 
1838         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) { 
1839                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1840                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1842                 ++attrListPtr
->count
; 
1845         // [4] get the port number 
1846         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) { 
1847                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt16
)); 
1848                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1850         CFTypeRef num 
= copyNumber(value
); 
1851                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1852                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecPortItemAttr
; 
1853                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt16
); 
1854                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1857                 ++attrListPtr
->count
; 
1860         // [5] get the protocol 
1861         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) { 
1862                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecProtocolType
)); 
1863                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_protocol_failed
, status 
= errSecBufferTooSmall
); 
1865                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecProtocolItemAttr
; 
1866                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecProtocolType
); 
1867                 *(SecProtocolType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
); 
1869                 ++attrListPtr
->count
; 
1872         // [6] get the authenticationType 
1873         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) { 
1874                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecAuthenticationType
)); 
1875                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_authenticationType_failed
, status 
= errSecBufferTooSmall
); 
1877                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecAuthenticationTypeItemAttr
; 
1878                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecAuthenticationType
); 
1879                 *(SecAuthenticationType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
); 
1881                 ++attrListPtr
->count
; 
1884         // [7] get the comment string 
1885         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) { 
1886                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1887                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1889                 ++attrListPtr
->count
; 
1892         // [8] get the description string 
1893         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) { 
1894                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1895                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1897                 ++attrListPtr
->count
; 
1900         // [9] get the label string 
1901         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) { 
1902                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1903                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1905                 ++attrListPtr
->count
; 
1908         // [10] get the creator code 
1909         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) { 
1910                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1911                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1913         CFTypeRef num 
= copyNumber(value
); 
1914                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1915                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecCreatorItemAttr
; 
1916                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1917                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1920                 ++attrListPtr
->count
; 
1923         // [11] get the type code 
1924         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) { 
1925                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1926                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1928         CFTypeRef num 
= copyNumber(value
); 
1929                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1930                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecTypeItemAttr
; 
1931                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1932                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1935                 ++attrListPtr
->count
; 
1938         // [12] get the invisible flag 
1939         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) { 
1940                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1941                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1943                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecInvisibleItemAttr
; 
1944                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1945                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1947                 ++attrListPtr
->count
; 
1950         // [13] get the negative flag 
1951         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) { 
1952                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1953                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1955                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecNegativeItemAttr
; 
1956                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1957                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1959                 ++attrListPtr
->count
; 
1962         // return the pointer to the attrList 
1963         *attrList 
= attrListPtr
; 
1965         return ( errSecSuccess 
); 
1969 malloc_authenticationType_failed
: 
1970 malloc_protocol_failed
: 
1972 CFStringCreateAttribute_failed
: 
1973 malloc_attrPtr_failed
: 
1975         // free any attributes 
1976         _FreeAttrList(attrListPtr
); 
1978 calloc_attrListPtr_failed
: 
1980         return ( errSecBufferTooSmall 
); 
1985  * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList 
1986  * from the attribute key/values in attrDictionary for the specified item class. 
1988  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1989  * must be freed by the caller with _FreeAttrList() 
1992 _CreateSecKeychainAttributeListFromDictionary( 
1993         CFDictionaryRef attrDictionary
, 
1994         SecItemClass itemClass
, 
1995         SecKeychainAttributeList 
**attrList
) 
1999                 case kSecInternetPasswordItemClass
: 
2000                         return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
2002                 case kSecGenericPasswordItemClass
: 
2003                         return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
2005                 case kSecCertificateItemClass
: 
2006                         return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
); 
2008                 case kSecPublicKeyItemClass
: 
2009                 case kSecPrivateKeyItemClass
: 
2010                 case kSecSymmetricKeyItemClass
: 
2011                         return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
); 
2021  * _AppNameFromSecTrustedApplication attempts to pull the name of the 
2022  * application/tool from the SecTrustedApplicationRef. 
2024 static CFStringRef CF_RETURNS_RETAINED
 
2025 _AppNameFromSecTrustedApplication( 
2026         CFAllocatorRef alloc
, 
2027         SecTrustedApplicationRef appRef
) 
2031         CFDataRef appDataRef
; 
2035         // get the data for item's application/tool 
2036         status 
= SecTrustedApplicationCopyData(appRef
, &appDataRef
); 
2037         if ( status 
== errSecSuccess 
) { 
2040                 // convert it to a CFString potentially containing the path 
2041                 path 
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
); 
2042                 if ( path 
!= NULL 
) { 
2043                         // the path has to start with a "/" and cannot contain "://" 
2044                         if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location 
== kCFNotFound
) ) { 
2045                                 CFRange nameRange
, compRg
; 
2047                                 nameRange 
= CFRangeMake(0, CFStringGetLength(path
)); 
2049                                 // remove the trailing slashes (if any) 
2050                                 while ( (nameRange
.length 
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length 
- 1) == '/') ) { 
2051                                         nameRange
.length 
--; 
2054                                 if ( nameRange
.length 
> 0 ) { 
2055                                         // find last slash and adjust nameRange to be everything after it 
2056                                         if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) { 
2057                                                 nameRange
.length 
= nameRange
.location 
+ nameRange
.length 
- (compRg
.location 
+ 1); 
2058                                                 nameRange
.location 
= compRg
.location 
+ 1; 
2061                                         result 
= CFStringCreateWithSubstring(alloc
, path
, nameRange
); 
2066                 CFRelease(appDataRef
); 
2072 /* (This function really belongs in SecIdentity.cpp!) 
2074  * Returns the public key item corresponding to the identity, if it exists in 
2075  * the same keychain as the private key. Note that the public key might not 
2076  * exist in the same keychain (e.g. if the identity was imported via PKCS12), 
2077  * in which case it will not be found. 
2080 _SecIdentityCopyPublicKey( 
2081         SecIdentityRef identityRef
, 
2082         SecKeyRef 
*publicKeyRef
) 
2086         SecKeychainAttribute attr 
= { kSecKeyLabel
, 0, NULL 
}; 
2087         SecKeychainAttributeList attrList 
= { 1, &attr 
}; 
2088         SecKeychainAttributeList 
*keyAttrList 
= NULL
; 
2089         SecKeychainAttributeInfo 
*info 
= NULL
; 
2090         SecKeychainSearchRef search 
= NULL
; 
2091         SecKeychainRef keychain 
= NULL
; 
2092         SecKeychainItemRef privateKey 
= NULL
; 
2093         SecKeychainItemRef publicKey 
= NULL
; 
2095         status 
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef 
*)&privateKey
); 
2097                 goto error_exit
; // identity must have a private key 
2099         status 
= SecKeychainItemCopyKeychain(privateKey
, &keychain
); 
2101                 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it 
2103         status 
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
); 
2105                 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys 
2107         status 
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
); 
2109                 goto error_exit
; // unable to get the key label attribute for the private key 
2112         // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching 
2113         for (count 
= 0; count 
< keyAttrList
->count
; count
++) { 
2114                 if (keyAttrList
->attr
[count
].tag 
== kSecKeyLabel
) { 
2115                         attr
.length 
= keyAttrList
->attr
[count
].length
; 
2116                         attr
.data 
= keyAttrList
->attr
[count
].data
; 
2120         if (!attr
.length 
|| !attr
.data
) { 
2121                 status 
= errSecNoSuchAttr
; 
2122                 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel 
2124         status 
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
); 
2126                 goto error_exit
; // unable to create the search reference 
2128         status 
= SecKeychainSearchCopyNext(search
, &publicKey
); 
2130                 goto error_exit
; // unable to find the public key 
2134                 *publicKeyRef 
= (SecKeyRef
)publicKey
; 
2136                 CFRelease(publicKey
); 
2139         if (status 
!= errSecSuccess
) { 
2141                         *publicKeyRef 
= NULL
; 
2143                         CFRelease(publicKey
); 
2149                 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
); 
2152                 SecKeychainFreeAttributeInfo(info
); 
2155                 CFRelease(keychain
); 
2158                 CFRelease(privateKey
); 
2165  * Deletes a keychain item if the current application/tool is the only application/tool 
2166  * with decrypt access to that keychain item. If more than one application/tool 
2167  * has decrypt access to the keychain item, the item is left on the keychain. 
2169  * TBD: If more than one app/tool has access to the keychain item, we should remove 
2170  * the current app/tool's decrypt access. There's no easy way to do that with 
2171  * current keychain APIs without bringing up the security UI. 
2174 _SafeSecKeychainItemDelete( 
2175         SecKeychainItemRef itemRef
) 
2178         SecAccessRef access 
= NULL
; 
2179         CFArrayRef aclList 
= NULL
; 
2180         SecACLRef acl 
= NULL
; 
2181         CFArrayRef appList 
= NULL
; 
2182         CFStringRef description 
= NULL
; 
2183         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
2184         CFIndex idx
, count 
= 0; 
2185         SecTrustedApplicationRef currentAppRef 
= NULL
; 
2186         CFStringRef itemAppName 
= NULL
, currentAppName 
= NULL
; 
2188         SecItemClass itemClass 
= (SecItemClass
)0; 
2189         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2190         if (!(itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2191                 // only perform the access control safety check on deletion of password credentials; 
2192                 // if the item is of some other type, delete it normally. 
2193                 return SecKeychainItemDelete(itemRef
); 
2196         // skip access control checking for web form passwords: <rdar://10957301> 
2197         // This permits Safari to manage the removal of all web form passwords, 
2198         // regardless of whether they are shared by multiple applications. 
2199         if (itemClass 
== kSecInternetPasswordItemClass
) { 
2200                 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr 
}; 
2201                 SecKeychainAttributeInfo attrInfo 
= { 1, tags
, NULL 
}; 
2202                 SecKeychainAttributeList 
*attrs 
= NULL
; 
2203                 status 
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
); 
2204                 if (!status 
&& attrs
) { 
2205                         bool webFormPassword 
= (attrs
->attr
[0].length 
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4))); 
2206                         SecKeychainItemFreeAttributesAndData(attrs
, NULL
); 
2207                         if (webFormPassword
) { 
2208                                 return SecKeychainItemDelete(itemRef
); 
2213         // copy the access of the keychain item 
2214         status 
= SecKeychainItemCopyAccess(itemRef
, &access
); 
2215         require_noerr(status
, finish
); 
2216         require_quiet(access 
!= NULL
, finish
); 
2218         // copy the decrypt access control lists -- this is what has access to the keychain item 
2219         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
2220         require_noerr(status
, finish
); 
2221         require_quiet(aclList 
!= NULL
, finish
); 
2223         // get the access control list 
2224         acl 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
2225         require_quiet(acl 
!= NULL
, finish
); 
2227         // copy the application list, description, and CSSM prompt selector for a given access control list entry 
2228         status 
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
); 
2229         require_noerr(status
, finish
); 
2230         require_quiet(appList 
!= NULL
, finish
); 
2232         // does the calling application/tool have decrypt access to this item? 
2233         count 
= CFArrayGetCount(appList
); 
2234         for ( idx 
= 0; idx 
< count
; idx
++ ) { 
2235                 // get SecTrustedApplicationRef for this entry 
2236                 SecTrustedApplicationRef itemAppRef 
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, idx
); 
2237                 require_quiet(itemAppRef 
!= NULL
, finish
); 
2239                 // copy the name out 
2240                 CFReleaseSafe(itemAppName
); 
2241                 itemAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
); 
2242                 if (itemAppName 
== NULL
) { 
2244                          * If there is no app name, it's probably because it's not an appname 
2245                          * in the ACE but an entitlement/info.plist based rule instead; 
2246                          * just let the caller have it. */ 
2251                 // create SecTrustedApplicationRef for current application/tool 
2252                 CFReleaseNull(currentAppRef
); 
2253                 status 
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
); 
2254                 require_noerr(status
, finish
); 
2255                 require_quiet(currentAppRef 
!= NULL
, finish
); 
2257                 // copy the name out 
2258                 CFReleaseSafe(currentAppName
); 
2259                 currentAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
); 
2260                 require_quiet(currentAppName 
!= NULL
, finish
); 
2262                 // compare the names to see if we own the decrypt access 
2263                 // TBD: validation of membership in an application group 
2264                 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo 
) { 
2272         CFReleaseSafe(currentAppName
); 
2273         CFReleaseSafe(itemAppName
); 
2274         CFReleaseSafe(currentAppRef
); 
2275         CFReleaseSafe(description
); 
2276         CFReleaseSafe(appList
); 
2277         CFReleaseSafe(aclList
); 
2278         CFReleaseSafe(access
); 
2280         if ((count 
== 0) || (status 
== errSecVerifyFailed
)) { 
2281                 // no "owners" remain in the ACL list (or unable to get ACL) 
2282                 status 
= SecKeychainItemDelete(itemRef
); 
2284                 // caller is not the "owner" of the item 
2285                 status 
= errSecInvalidOwnerEdit
; 
2292 _ReplaceKeychainItem( 
2293         SecKeychainItemRef itemToUpdate
, 
2294         SecKeychainAttributeList 
*changeAttrList
, 
2299         SecItemClass itemClass
; 
2300         SecKeychainAttributeInfo 
*info 
= NULL
; 
2301         SecKeychainAttributeList 
*attrList 
= NULL
; 
2302         SecKeychainAttributeList newAttrList 
= { 0, NULL
}; 
2303         SecKeychainRef keychain 
= NULL
; 
2304         SecKeychainItemRef newItem 
= NULL
; 
2306         int priority 
= LOG_DEBUG
; 
2307         const char *format 
= "ReplaceKeychainItem (%d) error %d"; 
2309         // get existing item's keychain 
2310         status 
= SecKeychainItemCopyKeychain(itemToUpdate
, &keychain
); 
2311         if (status
) { secitemlog(priority
, format
, 1, (int)status
); } 
2312         require_noerr(status
, replace_failed
); 
2314         // get attribute info (i.e. database schema) for the item class 
2315         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2316         if (status
) { secitemlog(priority
, format
, 2, (int)status
); } 
2317         require_noerr(status
, replace_failed
); 
2321                 case kSecInternetPasswordItemClass
: 
2322                         itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
2324                 case kSecGenericPasswordItemClass
: 
2325                         itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
2331         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
2332         if (status
) { secitemlog(priority
, format
, 3, (int)status
); } 
2334         // get item's existing attributes (but not data!) 
2335         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
2336         if (status
) { secitemlog(priority
, format
, 4, (int)status
); } 
2337         require(attrList 
!= NULL
, replace_failed
); 
2339         // move aside the item by changing a primary attribute 
2340     // (currently only for passwords) 
2341         if (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
) { 
2342                 CFUUIDRef uuid 
= CFUUIDCreate(kCFAllocatorDefault
); 
2343                 CFStringRef uuidStr 
= (uuid
) ? CFUUIDCreateString(kCFAllocatorDefault
, uuid
) : CFSTR("MOVED"); 
2344                 CFReleaseSafe(uuid
); 
2346                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr
), kCFStringEncodingUTF8
) + 1; 
2347                         char* buffer 
= (char*) malloc(maxLength
); 
2349                                 if (CFStringGetCString(uuidStr
, buffer
, maxLength
, kCFStringEncodingUTF8
)) { 
2350                                         UInt32 length 
= (UInt32
)strlen(buffer
); 
2351                                         SecKeychainAttribute attrs
[] = { { kSecAccountItemAttr
, length
, (char*)buffer 
}, }; 
2352                                         SecKeychainAttributeList updateAttrList 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
2353                                         status 
= SecKeychainItemModifyAttributesAndData(itemToUpdate
, &updateAttrList
, 0, NULL
); 
2354                                         if (status
) { secitemlog(priority
, format
, 5, (int)status
); } 
2355                                         if (status 
== errSecVerifyFailed
) { 
2356                                                 // still unable to change attrs? delete unconditionally here 
2357                                                 status 
= SecKeychainItemDelete(itemToUpdate
); 
2358                                                 if (status
) { secitemlog(priority
, format
, 6, (int)status
); } 
2363                         CFReleaseSafe(uuidStr
); 
2366         require_noerr(status
, replace_failed
); 
2368         // make attribute list for new item (the data is still owned by attrList) 
2369         newAttrList
.count 
= attrList
->count
; 
2370         newAttrList
.attr 
= (SecKeychainAttribute 
*) calloc(attrList
->count
, sizeof(SecKeychainAttribute
)); 
2372         for (i
=0, newCount
=0; i 
< attrList
->count
; i
++) { 
2373                 if (attrList
->attr
[i
].length 
> 0) { 
2374                         newAttrList
.attr
[newCount
++] = attrList
->attr
[i
]; 
2377         newAttrList
.count 
= newCount
; 
2379         // create new item in the same keychain 
2380         status 
= SecKeychainItemCreateFromContent(itemClass
, &newAttrList
, 
2381                 (UInt32
)((itemData
) ? CFDataGetLength(itemData
) : 0), 
2382                 (const void *)((itemData
) ? CFDataGetBytePtr(itemData
) : NULL
), 
2383                 keychain
, NULL
, &newItem
); 
2384         if (status
) { secitemlog(priority
, format
, 7, (int)status
); } 
2385         require_noerr(status
, replace_failed
); 
2387         // delete the old item unconditionally once new item exists 
2388         status 
= SecKeychainItemDelete(itemToUpdate
); 
2390         // update the new item with changed attributes, if any 
2391         status 
= (changeAttrList
) ? SecKeychainItemModifyContent(newItem
, changeAttrList
, 0, NULL
) : errSecSuccess
; 
2392         if (status
) { secitemlog(priority
, format
, 8, (int)status
); } 
2393         if (status 
== errSecSuccess
) { 
2394                 // say the item already exists, because it does now. <rdar://19063674> 
2395                 status 
= errSecDuplicateItem
; 
2399         if (newAttrList
.attr
) { 
2400                 free(newAttrList
.attr
); 
2403         SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
2406         SecKeychainFreeAttributeInfo(info
); 
2408         CFReleaseSafe(newItem
); 
2409         CFReleaseSafe(keychain
); 
2415 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
) 
2417         // This function updates a single keychain item, which may be specified as 
2418         // a reference, persistent reference or attribute dictionary, with the 
2419         // attributes provided. 
2421         OSStatus status 
= errSecSuccess
; 
2426         SecItemClass itemClass 
= (SecItemClass
) 0; 
2427         SecAccessRef access 
= NULL
; 
2428         SecKeychainAttributeList 
*changeAttrList 
= NULL
; 
2429         SecKeychainItemRef itemToUpdate 
= NULL
; 
2430         CFDataRef theData 
= NULL
; 
2431         CFTypeID itemType 
= CFGetTypeID(item
); 
2433         // validate input item (must be convertible to a SecKeychainItemRef) 
2434         if (SecKeychainItemGetTypeID() == itemType 
|| 
2435                 SecCertificateGetTypeID() == itemType 
|| 
2436                 SecKeyGetTypeID() == itemType
) { 
2437                 // item is already a reference, retain it 
2438                 itemToUpdate 
= (SecKeychainItemRef
) CFRetain(item
); 
2440         else if (CFDataGetTypeID() == itemType
) { 
2441                 // item is a persistent reference, must convert it 
2442                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
); 
2444         else if (CFDictionaryGetTypeID() == itemType
) { 
2445                 // item is a dictionary 
2446                 CFTypeRef value 
= NULL
; 
2447                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2448                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2449                         itemToUpdate 
= (SecKeychainItemRef
) CFRetain(value
); 
2451                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2452                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2453                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
); 
2456         else if (SecIdentityGetTypeID() == itemType
) { 
2457                 // item is a certificate + private key; since we can't really change the 
2458                 // certificate's attributes, assume we want to update the private key 
2459                 status 
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
); 
2461         require_action(itemToUpdate 
!= NULL
, update_failed
, status 
= errSecInvalidItemRef
); 
2462         require_noerr(status
, update_failed
); 
2464         status 
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
); 
2465         require_noerr(status
, update_failed
); 
2467         // build changeAttrList from changedAttributes dictionary 
2470                 case kSecInternetPasswordItemClass
: 
2472                         status 
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2473                         require_noerr(status
, update_failed
); 
2477                 case kSecGenericPasswordItemClass
: 
2479                         status 
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2480                         require_noerr(status
, update_failed
); 
2484                 case kSecCertificateItemClass
: 
2486                         status 
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2487                         require_noerr(status
, update_failed
); 
2491                 case kSecPublicKeyItemClass
: 
2492                 case kSecPrivateKeyItemClass
: 
2493                 case kSecSymmetricKeyItemClass
: 
2495                         status 
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2496                         require_noerr(status
, update_failed
); 
2499                 case kSecAppleSharePasswordItemClass
: 
2501                         // do nothing (legacy behavior). 
2508         // (if the caller is not updating the password, this value will be NULL) 
2509         theData 
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
); 
2510         if (theData 
!= NULL
) { 
2511                 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status 
= errSecParam
); 
2514         status 
= SecKeychainItemModifyContent(itemToUpdate
, 
2515                                 (!changeAttrList 
|| changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2516                                 (theData 
!= NULL
) ? (UInt32
)CFDataGetLength(theData
) : 0, 
2517                                 (theData 
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
); 
2518         require_noerr(status
, update_failed
); 
2520         // one more thing... update access? 
2521         if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) { 
2522                 status 
= SecKeychainItemSetAccess(itemToUpdate
, access
); 
2526         if (status 
== errSecVerifyFailed 
&& 
2527                 (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2528                 // if we got a cryptographic failure updating a password item, it needs to be replaced 
2529                 status 
= _ReplaceKeychainItem(itemToUpdate
, 
2530                                         (!changeAttrList 
||  changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2534                 CFRelease(itemToUpdate
); 
2535         _FreeAttrList(changeAttrList
); 
2540 _DeleteKeychainItem(CFTypeRef item
) 
2542         // This function deletes a single keychain item, which may be specified as 
2543         // a reference, persistent reference or attribute dictionary. It will not 
2544         // delete non-keychain items or aggregate items (such as a SecIdentityRef); 
2545         // it is assumed that the caller will pass identity components separately. 
2547         OSStatus status 
= errSecSuccess
; 
2552         SecKeychainItemRef itemToDelete 
= NULL
; 
2553         CFTypeID itemType 
= CFGetTypeID(item
); 
2554         if (SecKeychainItemGetTypeID() == itemType 
|| 
2555                 SecCertificateGetTypeID() == itemType 
|| 
2556                 SecKeyGetTypeID() == itemType
) { 
2557                 // item is already a reference, retain it 
2558                 itemToDelete 
= (SecKeychainItemRef
) CFRetain(item
); 
2560         else if (CFDataGetTypeID() == itemType
) { 
2561                 // item is a persistent reference, must convert it 
2562                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
); 
2564         else if (CFDictionaryGetTypeID() == itemType
) { 
2565                 // item is a dictionary 
2566                 CFTypeRef value 
= NULL
; 
2567                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2568                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2569                         itemToDelete 
= (SecKeychainItemRef
) CFRetain(value
); 
2571                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2572                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2573                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
); 
2579                         status 
= _SafeSecKeychainItemDelete(itemToDelete
); 
2581                 CFRelease(itemToDelete
); 
2588 _DeleteIdentity(SecIdentityRef identity
) 
2590         OSStatus status
, result 
= errSecSuccess
; 
2591         SecKeyRef privateKey 
= NULL
; 
2592         SecCertificateRef certificate 
= NULL
; 
2594         status 
= SecIdentityCopyPrivateKey(identity
, &privateKey
); 
2596                 SecKeyRef publicKey 
= NULL
; 
2597                 status 
= _SecIdentityCopyPublicKey(identity
, &publicKey
); 
2599                         status 
= _DeleteKeychainItem(publicKey
); 
2600                         CFRelease(publicKey
); 
2602                 status 
= _DeleteKeychainItem(privateKey
); 
2605         if (privateKey
) CFRelease(privateKey
); 
2606         if (status
) result 
= status
; 
2608         status 
= SecIdentityCopyCertificate(identity
, &certificate
); 
2610                 status 
= _DeleteKeychainItem(certificate
); 
2613         if (certificate
) CFRelease(certificate
); 
2614         if (status
) result 
= status
; 
2620 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
) 
2622         // This function is used when atomically processing multiple items, 
2623         // where an overall error result must be returned for the entire operation. 
2624         // When newStatus is something other than errSecSuccess, we want to keep the "most 
2625         // interesting" status (which usually will be newStatus, unless curStatus is 
2626         // already set; in that case, newStatus can trump curStatus only by being 
2627         // something different than baseStatus.) 
2629         OSStatus result 
= curStatus
; 
2631         if (newStatus 
!= errSecSuccess
) { 
2633                 if (curStatus 
!= errSecSuccess
) { 
2634                         result 
= (newStatus 
!= baseStatus
) ? newStatus 
: curStatus
; 
2641 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
) 
2643         // CFDictionaryApplierFunction 
2644         // This function just takes the given key/value pair, 
2645         // and adds it to another dictionary supplied in the context argument. 
2647         CFMutableDictionaryRef dict 
= *((CFMutableDictionaryRef
*) context
); 
2649                 CFDictionaryAddValue(dict
, key
, value
); 
2653 static CFStringCompareFlags
 
2654 _StringCompareFlagsFromQuery(CFDictionaryRef query
) 
2657         CFStringCompareFlags flags 
= 0; 
2658         if (!query
) return flags
; 
2660         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) || 
2661                 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2662                 flags 
|= kCFCompareAnchored
; 
2664         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2665                 flags 
|= kCFCompareBackwards
; 
2667         if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2668                 flags 
|= kCFCompareCaseInsensitive
; 
2670         if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2671                 flags 
|= kCFCompareDiacriticInsensitive
; 
2673         if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2674                 flags 
|= kCFCompareWidthInsensitive
; 
2680 _CssmKeyUsageFromQuery(CFDictionaryRef query
) 
2683         uint32 keyUsage 
= 0; 
2684         if (!query
) return keyUsage
; 
2686         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2687                 keyUsage 
|= CSSM_KEYUSE_ENCRYPT
; 
2689         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2690                 keyUsage 
|= CSSM_KEYUSE_DECRYPT
; 
2692         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2693                 keyUsage 
|= CSSM_KEYUSE_SIGN
; 
2695         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2696                 keyUsage 
|= CSSM_KEYUSE_VERIFY
; 
2698         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2699                 keyUsage 
|= CSSM_KEYUSE_WRAP
; 
2701         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2702                 keyUsage 
|= CSSM_KEYUSE_UNWRAP
; 
2704         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2705                 keyUsage 
|= CSSM_KEYUSE_DERIVE
; 
2711 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean 
*isIdentity
) 
2713         SecItemClass itemClass 
= (SecItemClass
) 0; 
2714         if (isIdentity
) *isIdentity 
= false; 
2716         if (CFEqual(item
, kSecClassGenericPassword
)) { 
2717                 itemClass 
= kSecGenericPasswordItemClass
; 
2719         else if (CFEqual(item
, kSecClassInternetPassword
)) { 
2720                 itemClass 
= kSecInternetPasswordItemClass
; 
2722         else if (CFEqual(item
, kSecClassCertificate
)) { 
2723                 itemClass 
= kSecCertificateItemClass
; 
2725         else if (CFEqual(item
, kSecClassIdentity
)) { 
2726                 // will perform a certificate lookup 
2727                 itemClass 
= kSecCertificateItemClass
; 
2728                 if (isIdentity
) *isIdentity 
= true; 
2730         else if (CFEqual(item
, kSecClassKey
)) { 
2731                 // examine second parameter to determine type of key 
2732                 if (!keyClass 
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) { 
2733                         itemClass 
= kSecSymmetricKeyItemClass
; 
2735                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) { 
2736                         itemClass 
= kSecPublicKeyItemClass
; 
2738                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) { 
2739                         itemClass 
= kSecPrivateKeyItemClass
; 
2747 _ItemClassFromItemList(CFArrayRef itemList
) 
2749         // Given a list of items (standard or persistent references), 
2750         // determine whether they all have the same item class. Returns 
2751         // the item class, or 0 if multiple classes in list. 
2752         SecItemClass result 
= (SecItemClass
) 0; 
2753         CFIndex index
, count 
= (itemList
) ? CFArrayGetCount(itemList
) : 0; 
2754         for (index
=0; index 
< count
; index
++) { 
2755                 CFTypeRef item 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemList
, index
); 
2757                         SecKeychainItemRef itemRef 
= NULL
; 
2759                         if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
2760                                 // persistent reference, resolve first 
2761                                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemRef
); 
2764                                 itemRef 
= (SecKeychainItemRef
) CFRetain(item
); 
2767                                 SecItemClass itemClass 
= (SecItemClass
) 0; 
2768                                 CFTypeID itemTypeID 
= CFGetTypeID(itemRef
); 
2769                                 if (itemTypeID 
== SecIdentityGetTypeID() || itemTypeID 
== SecCertificateGetTypeID()) { 
2770                                         // Identities and certificates have the same underlying item class 
2771                                         itemClass 
= kSecCertificateItemClass
; 
2773                                 else if (itemTypeID 
== SecKeychainItemGetTypeID()) { 
2774                                         // Reference to item in a keychain 
2775                                         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2777                                 else if (itemTypeID 
== SecKeyGetTypeID()) { 
2778                                         // SecKey that isn't stored in a keychain 
2779                                         // %%% will need to change this code when SecKey is no longer CSSM-based %%% 
2780                                         const CSSM_KEY 
*cssmKey
; 
2781                                         status 
= SecKeyGetCSSMKey((SecKeyRef
)itemRef
, &cssmKey
); 
2782                                         if (status 
== errSecSuccess
) { 
2783                                                 if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) 
2784                                                         itemClass 
= kSecPublicKeyItemClass
; 
2785                                                 else if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY
) 
2786                                                         itemClass 
= kSecPrivateKeyItemClass
; 
2788                                                         itemClass 
= kSecSymmetricKeyItemClass
; 
2792                                 if (itemClass 
!= 0) { 
2793                                         if (result 
!= 0 && result 
!= itemClass
) { 
2794                                                 return (SecItemClass
) 0; // different item classes in list; bail out 
2804 // SecItemParams contains a validated set of input parameters, as well as a 
2805 // search reference and attribute list built from those parameters. It is 
2806 // designed to be allocated with _CreateSecItemParamsFromDictionary, and 
2807 // freed with _FreeSecItemParams. 
2809 struct SecItemParams 
{ 
2810         CFDictionaryRef query
;                          // caller-supplied query 
2811         int numResultTypes
;                                     // number of result types requested 
2812         int maxMatches
;                                         // max number of matches to return 
2813         uint32 keyUsage
;                                        // key usage(s) requested 
2814         Boolean returningAttributes
;            // true if returning attributes dictionary 
2815         Boolean returningData
;                          // true if returning item's data 
2816         Boolean returningRef
;                           // true if returning item reference 
2817         Boolean returningPersistentRef
;         // true if returing a persistent reference 
2818         Boolean returnAllMatches
;                       // true if we should return all matches 
2819         Boolean returnIdentity
;                         // true if we are returning a SecIdentityRef 
2820         Boolean trustedOnly
;                            // true if we only return trusted certs 
2821         Boolean issuerAndSNToMatch
;                     // true if both issuer and SN were provided 
2822         SecItemClass itemClass
;                         // item class for this query 
2823         SecPolicyRef policy
;                            // value for kSecMatchPolicy (may be NULL) 
2824         SecKeychainRef keychain
;                        // value for kSecUseKeychain (may be NULL) 
2825         CFArrayRef useItems
;                            // value for kSecUseItemList (may be NULL) 
2826         CFArrayRef itemList
;                            // value for kSecMatchItemList (may be NULL) 
2827         CFTypeRef searchList
;                           // value for kSecMatchSearchList (may be NULL) 
2828         CFTypeRef matchLimit
;                           // value for kSecMatchLimit (may be NULL) 
2829         CFTypeRef emailAddrToMatch
;                     // value for kSecMatchEmailAddressIfPresent (may be NULL) 
2830         CFTypeRef validOnDate
;                          // value for kSecMatchValidOnDate (may be NULL) 
2831         CFTypeRef keyClass
;                                     // value for kSecAttrKeyClass (may be NULL) 
2832         CFTypeRef service
;                                      // value for kSecAttrService (may be NULL) 
2833         CFTypeRef issuer
;                                       // value for kSecAttrIssuer (may be NULL) 
2834         CFTypeRef matchIssuers
;                                 // value for kSecMatchIssuers (may be NULL) 
2835         CFTypeRef serialNumber
;                         // value for kSecAttrSerialNumber (may be NULL) 
2836         CFTypeRef search
;                                       // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) 
2837         CFTypeRef assumedKeyClass
;                      // if no kSecAttrKeyClass provided, holds the current class we're searching for 
2838         CFIndex itemListIndex
;                          // if no search reference but we have itemList, holds index of next item to return 
2839         SecKeychainAttributeList 
*attrList
;     // attribute list for this query 
2840         SecAccessRef access
;                            // access reference (for SecItemAdd only, not used to find items) 
2841         CFDataRef itemData
;                                     // item data (for SecItemAdd only, not used to find items) 
2842         CFTypeRef itemRef
;                                      // item reference (to find, add, update or delete, depending on context) 
2843         SecIdentityRef identityRef
;                     // identity reference (input as kSecValueRef) 
2844         CFDataRef itemPersistentRef
;            // item persistent reference (to find, add, update or delete, depending on context) 
2845         Boolean isPCSItem
;                                      // true if this query is for a Protected Cloud Storage item 
2849 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
) 
2851         if (!dict 
|| !key 
|| !value 
|| !expectedTypeID
) 
2854         if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) { 
2855                 // value was not provided for this key (not an error!) 
2858         else if (!(*value
)) { 
2859                 // provided value is NULL (also not an error!) 
2860                 return errSecSuccess
; 
2863                 CFTypeID actualTypeID 
= CFGetTypeID(*value
); 
2864                 if (!((expectedTypeID 
== actualTypeID
) || (altTypeID 
&& altTypeID 
== actualTypeID
))) { 
2865                         // provided value does not have the expected (or alternate) CF type ID 
2866                         if ((expectedTypeID 
== SecKeychainItemGetTypeID()) && 
2867                                 (actualTypeID 
== SecKeyGetTypeID() || actualTypeID 
== SecCertificateGetTypeID())) { 
2868                                 // provided value is a "floating" reference which is not yet in a keychain 
2870                                 return errSecSuccess
; 
2872                         return errSecItemInvalidValue
; 
2875                         // provided value is OK; retain it 
2879         return errSecSuccess
; 
2883 _EnsureUserDefaultKeychainIsSearched(SecItemParams 
*itemParams
) 
2886         CFArrayRef tmpList 
= (CFArrayRef
) itemParams
->searchList
; 
2888                 // search list exists; make it mutable 
2889                 itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2892                 // no search list; start with default list 
2893                 status 
= SecKeychainCopySearchList(&tmpList
); 
2894                 if (!status 
&& tmpList
) { 
2895                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2899                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2903         SecKeychainRef userKeychain 
= NULL
; 
2904         status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2905         if (!status 
&& userKeychain
) { 
2906                 if (!CFArrayContainsValue((CFArrayRef
)itemParams
->searchList
, 
2907                         CFRangeMake(0, CFArrayGetCount((CFArrayRef
)itemParams
->searchList
)), userKeychain
)) { 
2908                         // user's default keychain isn't currently in the search list, so append it 
2909                         CFArrayAppendValue((CFMutableArrayRef
)itemParams
->searchList
, userKeychain
); 
2911                 CFRelease(userKeychain
); 
2916 _EnsureUserDefaultKeychainIsTargeted(SecItemParams 
*itemParams
) 
2918         if (itemParams
->keychain
) { 
2919                 return; // keychain is already explicitly specified, assume it's correct 
2921         SecKeychainRef userKeychain 
= NULL
; 
2922         OSStatus status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2923         if (!status 
&& userKeychain
) { 
2924                 itemParams
->keychain 
= userKeychain
; 
2929 _FreeSecItemParams(SecItemParams 
*itemParams
) 
2934         if (itemParams
->query
) CFRelease(itemParams
->query
); 
2935         if (itemParams
->policy
) CFRelease(itemParams
->policy
); 
2936         if (itemParams
->keychain
) CFRelease(itemParams
->keychain
); 
2937         if (itemParams
->useItems
) CFRelease(itemParams
->useItems
); 
2938         if (itemParams
->itemList
) CFRelease(itemParams
->itemList
); 
2939         if (itemParams
->searchList
) CFRelease(itemParams
->searchList
); 
2940         if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
); 
2941         if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
); 
2942         if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
); 
2943         if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
); 
2944         if (itemParams
->service
) CFRelease(itemParams
->service
); 
2945         if (itemParams
->issuer
) CFRelease(itemParams
->issuer
); 
2946         if (itemParams
->matchIssuers
) CFRelease(itemParams
->matchIssuers
); 
2947         if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
); 
2948         if (itemParams
->search
) CFRelease(itemParams
->search
); 
2949         if (itemParams
->access
) CFRelease(itemParams
->access
); 
2950         if (itemParams
->itemData
) CFRelease(itemParams
->itemData
); 
2951         if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
); 
2952         if (itemParams
->identityRef
) CFRelease(itemParams
->identityRef
); 
2953         if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
); 
2955         _FreeAttrList(itemParams
->attrList
); 
2960 static SecItemParams
* 
2961 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus 
*error
) 
2964         CFTypeRef value 
= NULL
; 
2965     CFDictionaryRef policyDict 
= NULL
; 
2966         SecItemParams 
*itemParams 
= (SecItemParams 
*)calloc(1, sizeof(struct SecItemParams
)); 
2968         require_action(itemParams 
!= NULL
, error_exit
, status 
= errSecAllocate
); 
2969         require_action(dict 
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status 
= errSecParam
); 
2971         itemParams
->query 
= (CFDictionaryRef
) CFRetain(dict
); 
2973         // validate input search parameters 
2974         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
); 
2975         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2976         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2977         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
2978         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
); 
2979         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
); 
2981         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
); 
2982         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
); 
2984         // validate a subset of input attributes (used to create an appropriate search reference) 
2985         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
); 
2986         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
); 
2987         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
); 
2988         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
); 
2990         if (itemParams
->service 
&& CFStringHasPrefix((CFStringRef
)itemParams
->service
, CFSTR("ProtectedCloudStorage"))) { 
2991                 itemParams
->isPCSItem 
= true; 
2992                 if (!SecItemSynchronizable(dict
)) { 
2993                         _EnsureUserDefaultKeychainIsSearched(itemParams
); // for SecItemCopyMatching, SecItemUpdate, SecItemDelete 
2994                         _EnsureUserDefaultKeychainIsTargeted(itemParams
); // for SecItemAdd 
2998         // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items 
2999         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
); 
3000         if (itemParams
->itemData 
&& CFGetTypeID(itemParams
->itemData
) == CFStringGetTypeID()) { 
3001                 /* If we got a string, convert it into a data object */ 
3002                 CFStringRef string 
= (CFStringRef
)itemParams
->itemData
; 
3003                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(string
), kCFStringEncodingUTF8
) + 1; 
3004                 CFMutableDataRef data 
= CFDataCreateMutable(NULL
, maxLength
); 
3005                 require_action(data
, error_exit
, status 
= errSecAllocate
); 
3007                 CFDataSetLength(data
, maxLength
); 
3009                 if (!CFStringGetCString(string
, (char *)CFDataGetMutableBytePtr(data
), maxLength
, kCFStringEncodingUTF8
)) { 
3011                         status 
= errSecAllocate
; 
3015                 CFDataSetLength(data
, strlen((const char *)CFDataGetBytePtr(data
))); /* dont include NUL in string */ 
3016                 itemParams
->itemData 
= data
; 
3020         // validate item references 
3021         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit
); 
3022         if (itemParams
->itemRef 
&& (CFGetTypeID(itemParams
->itemRef
) == SecIdentityGetTypeID())) { 
3023                 itemParams
->identityRef 
= (SecIdentityRef
)itemParams
->itemRef
; 
3024                 itemParams
->itemRef 
= NULL
; 
3025                 SecIdentityCopyCertificate(itemParams
->identityRef
, (SecCertificateRef 
*)&itemParams
->itemRef
); 
3027         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
); 
3028         if (itemParams
->itemRef 
|| itemParams
->itemPersistentRef
) { 
3029                 // Caller is trying to add or find an item by reference. 
3030                 // The supported method for doing that is to provide a kSecUseItemList array 
3031                 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al, 
3032                 // so add the item reference to those arrays here. 
3033                 if (itemParams
->useItems
) { 
3034                         CFArrayRef tmpItems 
= itemParams
->useItems
; 
3035                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3036                         CFRelease(tmpItems
); 
3038                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3040                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
); 
3041                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
); 
3043                 if (itemParams
->itemList
) { 
3044                         CFArrayRef tmpItems 
= itemParams
->itemList
; 
3045                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3046                         CFRelease(tmpItems
); 
3048                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3050                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
); 
3051                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
); 
3054         // must have an explicit item class, unless one of the following is true: 
3055         //   - we have an item list to add or search (kSecUseItemList) 
3056         //   - we have an item reference or persistent reference for the thing we want to look up 
3057         // Note that both of these cases will set itemParams->useItems. 
3058         // If we have an item list to match (kSecMatchItemList), that still requires an item class, 
3059         // so we can perform a search and see if the results match items in the list. 
3061         if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
) { 
3062                 require_action(false, error_exit
, status 
= errSecItemClassMissing
); 
3065                 itemParams
->itemClass 
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
); 
3066                 if (itemParams
->itemClass 
== kSecSymmetricKeyItemClass 
&& !itemParams
->keyClass
) { 
3067             // no key class specified, so start with symmetric key class; will search the others later in UpdateKeychainSearchAndCopyNext 
3068             itemParams
->itemClass 
= kSecSymmetricKeyItemClass
; 
3069             itemParams
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3071                 require_action(!(itemParams
->itemClass 
== 0 && !itemParams
->useItems
), error_exit
, status 
= errSecItemClassMissing
); 
3074     // kSecMatchIssuers is only permitted with identities or certificates. 
3075     // Convert the input issuers to normalized form. 
3076     require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchIssuers
, (const void **)&itemParams
->matchIssuers
, CFArrayGetTypeID(), NULL
), error_exit
); 
3077     if (itemParams
->matchIssuers
) { 
3078         CFTypeRef allowCerts 
= CFDictionaryGetValue(itemParams
->query
, kSecUseCertificatesWithMatchIssuers
); 
3079         require_action(itemParams
->returnIdentity 
|| (allowCerts 
&& CFEqual(allowCerts
, kCFBooleanTrue
)), error_exit
, status 
= errSecParam
); 
3080         CFMutableArrayRef canonical_issuers 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3081         CFArrayRef issuers 
= (CFArrayRef
)itemParams
->matchIssuers
; 
3082         if (canonical_issuers
) { 
3083             CFIndex i
, count 
= CFArrayGetCount(issuers
); 
3084             for (i 
= 0; i 
< count
; i
++) { 
3085                 CFTypeRef issuer_data 
= CFArrayGetValueAtIndex(issuers
, i
); 
3086                 CFDataRef issuer_canonical 
= NULL
; 
3087                 if (CFDataGetTypeID() == CFGetTypeID(issuer_data
)) 
3088                     issuer_canonical 
= SecDistinguishedNameCopyNormalizedSequence((CFDataRef
)issuer_data
); 
3089                 if (issuer_canonical
) { 
3090                     CFArrayAppendValue(canonical_issuers
, issuer_canonical
); 
3091                     CFRelease(issuer_canonical
); 
3094             if (CFArrayGetCount(canonical_issuers
) > 0) { 
3095                 CFAssignRetained(itemParams
->matchIssuers
, canonical_issuers
); 
3097                 CFRelease(canonical_issuers
); 
3101         itemParams
->keyUsage 
= _CssmKeyUsageFromQuery(dict
); 
3102         itemParams
->trustedOnly 
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3103         itemParams
->issuerAndSNToMatch 
= (itemParams
->issuer 
!= NULL 
&& itemParams
->serialNumber 
!= NULL
); 
3105         // other input attributes, used for SecItemAdd but not for finding items 
3106         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3107         if (itemParams
->access 
== NULL
) { 
3108                 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>) 
3109                 require_noerr(status 
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3112         // determine how to return the result 
3113         itemParams
->numResultTypes 
= 0; 
3114         itemParams
->returningRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3115         if (itemParams
->returningRef
) ++itemParams
->numResultTypes
; 
3116         itemParams
->returningPersistentRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3117         if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
; 
3118         itemParams
->returningAttributes 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3119         if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
; 
3120         itemParams
->returningData 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3121         if (itemParams
->returningData
) ++itemParams
->numResultTypes
; 
3123         // default is kSecReturnRef if no result types were specified 
3124         if (!itemParams
->numResultTypes
) { 
3125                 itemParams
->returningRef 
= TRUE
; 
3126                 itemParams
->numResultTypes 
= 1; 
3129         // determine if one, some or all matches should be returned (default is kSecMatchLimitOne) 
3130         itemParams
->maxMatches 
= 1; 
3131         itemParams
->returnAllMatches 
= FALSE
; 
3132         if (itemParams
->matchLimit
) { 
3133                 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3134                         itemParams
->returnAllMatches 
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
); 
3136                 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3137                         CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
); 
3138                         require_action(!(itemParams
->maxMatches 
< 0), error_exit
, status 
= errSecMatchLimitUnsupported
); 
3141         if (itemParams
->returnAllMatches
) { 
3142                 itemParams
->maxMatches 
= INT32_MAX
; 
3143                 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each) 
3144                 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass 
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
) 
3145                         status 
= errSecReturnDataUnsupported
; 
3146                 require_noerr(status
, error_exit
); 
3149     // if we already have an item list (to add or find items in), we don't need a search reference 
3150         if (itemParams
->useItems
) { 
3151                 if (itemParams
->itemClass 
== 0) { 
3152                         itemParams
->itemClass 
= _ItemClassFromItemList(itemParams
->useItems
); 
3155         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3156         if (itemParams
->itemClass 
!= 0) { 
3157             status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
); 
3159             status 
= errSecSuccess
; 
3161                 goto error_exit
; // all done here 
3164         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3165         require_noerr(status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
); 
3167     // if policy is a SMIME policy, copy email address in policy into emailAddrToMatch parameter 
3168     if(itemParams
->policy
) { 
3169         policyDict 
= SecPolicyCopyProperties(itemParams
->policy
); 
3170         CFStringRef oidStr 
= (CFStringRef
) CFDictionaryGetValue(policyDict
, kSecPolicyOid
); 
3171         if(oidStr 
&& CFStringCompare(kSecPolicyAppleSMIME
,oidStr
,0) == 0) { 
3172             require_noerr(status 
= _ValidateDictionaryEntry(policyDict
, kSecPolicyName
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
3174         CFReleaseNull(policyDict
); 
3177         // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) 
3178         if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) { 
3179                 // searching for certificates by email address 
3180                 char *nameBuf 
= (char*)malloc(MAXPATHLEN
); 
3182                         status 
= errSecAllocate
; 
3184                 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) { 
3185                         status 
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
); 
3188                         status 
= errSecItemInvalidValue
; 
3190                 if (nameBuf
) free(nameBuf
); 
3192         else if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) { 
3193                 // searching for certificates by issuer and serial number 
3194                 status 
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
, 
3195                                 (CFDataRef
)itemParams
->issuer
, 
3196                                 (CFDataRef
)itemParams
->serialNumber
, 
3197                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3199         else if (itemParams
->returnIdentity 
&& itemParams
->policy
) { 
3200                 // searching for identities by policy 
3201                 status 
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
, 
3202                                 (CFStringRef
)itemParams
->service
, 
3203                                 itemParams
->keyUsage
, 
3204                                 itemParams
->searchList
, 
3205                                 itemParams
->trustedOnly
, 
3206                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3208         else if (itemParams
->returnIdentity
) { 
3209                 // searching for identities 
3210                 status 
= SecIdentitySearchCreate(itemParams
->searchList
, 
3211                                 itemParams
->keyUsage
, 
3212                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3215                 // normal keychain item search 
3216                 status 
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
, 
3217                                 itemParams
->itemClass
, 
3218                                 (itemParams
->attrList
->count 
== 0) ? NULL 
: itemParams
->attrList
, 
3219                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3223     CFReleaseNull(policyDict
); 
3225                 _FreeSecItemParams(itemParams
); 
3238         SecKeychainRef keychainRef
, 
3239         SecAccessRef accessRef
, 
3240         SecKeychainAttributeList 
*attrList
, 
3241         SecKeychainItemRef 
*outItemRef
) 
3245                 // We must specify the access, since a free-floating key won't have one yet by default 
3246                 SecPointer
<Access
> access
; 
3248                         access 
= Access::required(accessRef
); 
3251                         CFStringRef descriptor 
= NULL
; 
3253                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
3254                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
3255                                         if (attr
.tag 
== kSecKeyPrintName
) { 
3256                                                 descriptor 
= CFStringCreateWithBytes(NULL
, (const UInt8 
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
); 
3261                         if (descriptor 
== NULL
) { 
3262                                 descriptor 
= (CFStringRef
) CFRetain(CFSTR("<unknown>")); 
3264                         access 
= new Access(cfString(descriptor
)); 
3265                         CFRelease(descriptor
); 
3268                 KeyItem 
*key 
= KeyItem::required(keyRef
); 
3269                 Item item 
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
); 
3271                         *outItemRef 
= item
->handle(); 
3277 _FilterWithPolicy(SecPolicyRef policy
, CFDateRef date
, SecCertificateRef cert
) 
3279         CFDictionaryRef props 
= NULL
; 
3280         CFArrayRef keychains 
= NULL
; 
3281         CFArrayRef anchors 
= NULL
; 
3282         CFArrayRef certs 
= NULL
; 
3283         CFArrayRef chain 
= NULL
; 
3284         SecTrustRef trust 
= NULL
; 
3286         SecTrustResultType      trustResult
; 
3287         Boolean needChain 
= false; 
3288         Boolean needCSEKU 
= false; 
3290         if (!policy 
|| !cert
) return errSecParam
; 
3292         certs 
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
); 
3293         status 
= SecTrustCreateWithCertificates(certs
, policy
, &trust
); 
3294         if(status
) goto cleanup
; 
3296         /* Set evaluation date, if specified (otherwise current date is implied) */ 
3297         if (date 
&& (CFGetTypeID(date
) == CFDateGetTypeID())) { 
3298                 status 
= SecTrustSetVerifyDate(trust
, date
); 
3299                 if(status
) goto cleanup
; 
3302         /* Check whether we can avoid full chain evaluation, based on policy */ 
3303         props 
= SecPolicyCopyProperties(policy
); 
3305                 CFTypeRef oid 
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
); 
3306                 if (oid 
&& (CFEqual(oid
, kSecPolicyAppleX509Basic
) || 
3307                             CFEqual(oid
, kSecPolicyAppleRevocation
))) { 
3309                 } else if (oid 
&& (CFEqual(oid
, kSecPolicyAppleCodeSigning
))) { 
3314         /* If a code signing EKU purpose is needed, filter out certs without it here 
3315            to reduce log noise associated with evaluation failures. */ 
3317                 CFDataRef eku 
= CFDataCreate(kCFAllocatorDefault
, 
3318                                              oidExtendedKeyUsageCodeSigning
.data
, 
3319                                              oidExtendedKeyUsageCodeSigning
.length
); 
3321                         if (!SecPolicyCheckCertExtendedKeyUsage(cert
, eku
)) { 
3327                         status 
= errSecCertificateCannotOperate
; 
3333                 status 
= SecTrustEvaluateLeafOnly(trust
, &trustResult
); 
3335                 status 
= SecTrustEvaluate(trust
, &trustResult
); 
3338         if (!(trustResult 
== kSecTrustResultProceed 
|| 
3339                   trustResult 
== kSecTrustResultUnspecified 
|| 
3340                   trustResult 
== kSecTrustResultRecoverableTrustFailure
)) { 
3341                 /* The evaluation failed in a non-recoverable way */ 
3342                 status 
= errSecCertificateCannotOperate
; 
3346         /* If there are no per-cert policy status codes, 
3347          * and the cert has not expired, consider it valid for the policy. 
3350                 (void)SecTrustGetCssmResultCode(trust
, &status
); 
3354         if(props
) CFRelease(props
); 
3355         if(chain
) CFRelease(chain
); 
3356         if(anchors
) CFRelease(anchors
); 
3357         if(keychains
) CFRelease(keychains
); 
3358         if(certs
) CFRelease(certs
); 
3359         if(trust
) CFRelease(trust
); 
3365 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
) 
3367         if (!validOnDate 
|| !cert
) return errSecParam
; 
3369         CFAbsoluteTime at
, nb
, na
; 
3370         if (CFGetTypeID(validOnDate
) == CFDateGetTypeID()) 
3371                 at 
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
); 
3373                 at 
= CFAbsoluteTimeGetCurrent(); 
3375         OSStatus status 
= errSecSuccess
; 
3376         nb 
= SecCertificateNotValidBefore(cert
); 
3377         na 
= SecCertificateNotValidAfter(cert
); 
3379         if (nb 
== 0 || na 
== 0 || nb 
== na
) 
3380                 status 
= errSecCertificateCannotOperate
; 
3382                 status 
= errSecCertificateNotValidYet
; 
3384                 status 
= errSecCertificateExpired
; 
3390 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
) 
3392         if (!cert
) return errSecParam
; 
3393         if (!trustedOnly
) return errSecSuccess
; 
3395         CFArrayRef certArray 
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
); 
3396         SecPolicyRef policy 
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
); 
3397         OSStatus status 
= (policy 
== NULL
) ? errSecPolicyNotFound 
: errSecSuccess
; 
3400                 SecTrustRef trust 
= NULL
; 
3401                 status 
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
); 
3403                         SecTrustResultType trustResult
; 
3404                         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3406                                 if (!(trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
)) { 
3407                                         status 
= (trustResult 
== kSecTrustResultDeny
) ? errSecTrustSettingDeny 
: errSecNotTrusted
; 
3415                 CFRelease(certArray
); 
3421 static bool items_matching_issuer_parent(CFDataRef issuer
, CFArrayRef issuers
, int recurse
) { 
3422     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) { return false; } 
3424     /* We found a match, we're done. */ 
3425     if (CFArrayContainsValue(issuers
, CFRangeMake(0, CFArrayGetCount(issuers
)), issuer
)) { return true; } 
3427     /* Prevent infinite recursion */ 
3428     if (recurse 
<= 0) { return false; } 
3431     /* Query for parents */ 
3432     CFMutableDictionaryRef query 
= NULL
; 
3433     CFTypeRef parents 
= NULL
; 
3436     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 4, &kCFTypeDictionaryKeyCallBacks
, 
3437                                       &kCFTypeDictionaryValueCallBacks
), out
); 
3438     CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
3439     CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
); 
3440     CFDictionaryAddValue(query
, kSecAttrSubject
, issuer
); 
3441     CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
3442     require_noerr_quiet(SecItemCopyMatching(query
, &parents
), out
); 
3444     if (parents 
&& CFArrayGetTypeID() == CFGetTypeID(parents
)) { 
3445         CFIndex i
, count 
= CFArrayGetCount((CFArrayRef
)parents
); 
3446         for (i 
= 0; i 
< count
; i
++) { 
3447             SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)parents
, i
); 
3448             CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3449             if (CFEqual(cert_issuer
, issuer
)) { 
3450                 // Self-issued cert, don't look for parents. 
3451                 CFReleaseNull(cert_issuer
); 
3454             found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3455             CFReleaseNull(cert_issuer
); 
3456             if (found
) { break; } 
3458     } else if (parents 
&& SecCertificateGetTypeID() == CFGetTypeID(parents
)) { 
3459         SecCertificateRef cert 
= (SecCertificateRef
)parents
; 
3460         CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3461         require_action_quiet(!CFEqual(cert_issuer
, issuer
), out
, CFReleaseNull(cert_issuer
)); 
3462         found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3463         CFReleaseNull(cert_issuer
); 
3467     CFReleaseNull(query
); 
3468     CFReleaseNull(parents
); 
3473 _FilterWithIssuers(CFArrayRef issuers
, SecCertificateRef cert
) 
3475     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) return errSecParam
; 
3476     if (!cert
) return errSecParam
; 
3478     OSStatus status 
= errSecInternalError
; 
3480     /* kSecMatchIssuers matches certificates where ANY certificate in the chain has this issuer. 
3481      * So we now need to recursively query the keychain for this cert's parents to determine if 
3482      * they match. (This is why we limited the use of this key in _CreateSecItemParamsFromDictionary.) */ 
3483     CFDataRef issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3484     if (items_matching_issuer_parent(issuer
, issuers
, 10)) { 
3485         status 
= errSecSuccess
; 
3488     CFReleaseNull(issuer
); 
3492 static SecKeychainItemRef
 
3493 CopyResolvedKeychainItem(CFTypeRef item
) 
3495         SecKeychainItemRef kcItem 
= NULL
; 
3496         OSStatus status 
= errSecSuccess
; 
3498                 if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
3499                         // persistent reference, resolve first 
3500                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &kcItem
); 
3504                         kcItem 
= (SecKeychainItemRef
) CFRetain(item
); 
3507                         // ask for the item's class: 
3508                         // will return an error if the item has been deleted 
3509                         SecItemClass itemClass
; 
3510                         SecCertificateRef certRef 
= NULL
; 
3511                         CFTypeID itemTypeID 
= CFGetTypeID(kcItem
); 
3512                         if (itemTypeID 
== SecIdentityGetTypeID()) { 
3513                                 status 
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
, &certRef
); 
3515                         else if (itemTypeID 
== SecCertificateGetTypeID()) { 
3516                                 certRef 
= (SecCertificateRef
) CFRetain(kcItem
); 
3519                                 // can't call SecKeychainItemCopyAttributesAndData on a SecCertificateRef 
3520                                 itemClass 
= kSecCertificateItemClass
; 
3523                                 status 
= SecKeychainItemCopyAttributesAndData(kcItem
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3538 UpdateKeychainSearchAndCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3540         // This function refreshes the search parameters in the specific case where 
3541         // the caller is searching for kSecClassKey items but did not provide the 
3542         // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and 
3543         // we must perform separate searches to obtain all results. 
3545         OSStatus status 
= errSecItemNotFound
; 
3546         if (!params 
|| !params
->assumedKeyClass 
|| !params
->query 
|| !item
) 
3549         // Free the previous search reference and attribute list. 
3551                 CFRelease(params
->search
); 
3552         params
->search 
= NULL
; 
3553         _FreeAttrList(params
->attrList
); 
3554         params
->attrList 
= NULL
; 
3556         // Make a copy of the query dictionary so we can set the key class parameter. 
3557         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
); 
3558         CFRelease(params
->query
); 
3559         params
->query 
= dict
; 
3560         CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
); 
3562         // Determine the current item class for this search, and the next assumed key class. 
3563         if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) { 
3564                 params
->itemClass 
= kSecSymmetricKeyItemClass
; 
3565                 params
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3566         } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) { 
3567                 params
->itemClass 
= kSecPublicKeyItemClass
; 
3568                 params
->assumedKeyClass 
= kSecAttrKeyClassPrivate
; 
3570                 params
->itemClass 
= kSecPrivateKeyItemClass
; 
3571                 params
->assumedKeyClass 
= NULL
; 
3574         // Rebuild the attribute list for the new key class. 
3575         if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == errSecSuccess
) { 
3576                 // Create a new search reference for the new attribute list. 
3577                 if (SecKeychainSearchCreateFromAttributes(params
->searchList
, 
3579                         (params
->attrList
->count 
== 0) ? NULL 
: params
->attrList
, 
3580                         (SecKeychainSearchRef
*)¶ms
->search
) == errSecSuccess
) { 
3581                         // Return the first matching item from the new search. 
3582                         // We won't come back here again until there are no more matching items for this search. 
3583                         status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
); 
3591 SecItemSearchCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3593         // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef. 
3594         // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter, 
3595         // depending on the type of search reference. 
3598         CFTypeRef search 
= (params
) ? params
->search 
: NULL
; 
3599         CFTypeID typeID 
= (search
) ? CFGetTypeID(search
) : 0; 
3601         if (search 
&& typeID 
== SecIdentitySearchGetTypeID()) { 
3602                 status 
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
); 
3604         else if (search 
&& typeID 
== SecKeychainSearchGetTypeID()) { 
3605                 status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
); 
3606                 // Check if we need to refresh the search for the next key class 
3607                 while (status 
== errSecItemNotFound 
&& params
->assumedKeyClass 
!= NULL
) 
3608                         status 
= UpdateKeychainSearchAndCopyNext(params
, item
); 
3610         else if (typeID 
== 0 && params 
&& (params
->useItems 
|| params
->itemList
)) { 
3611                 // No search available, but there is an item list available. 
3612                 // Return the next candidate item from the caller's item list 
3613                 CFArrayRef itemList 
= (params
->useItems
) ? params
->useItems 
: params
->itemList
; 
3614                 CFIndex count 
= CFArrayGetCount(itemList
); 
3615                 *item 
= (CFTypeRef
) NULL
; 
3616                 if (params
->itemListIndex 
< count
) { 
3617                         *item 
= (CFTypeRef
)CFArrayGetValueAtIndex(itemList
, params
->itemListIndex
++); 
3619                                 // Potentially resolve persistent item references here, and 
3620                                 // verify the item reference we're about to hand back is still 
3621                                 // valid (it could have been deleted from the keychain while 
3622                                 // our query was holding onto the itemList). 
3623                                 *item 
= CopyResolvedKeychainItem(*item
); 
3624                                 if (*item 
&& (CFGetTypeID(*item
) == SecIdentityGetTypeID())) { 
3625                                         // Persistent reference resolved to an identity, so return that type. 
3626                                         params
->returnIdentity 
= true; 
3630                 status 
= (*item
) ? errSecSuccess 
: errSecItemNotFound
; 
3633                 status 
= errSecItemNotFound
; 
3639 FilterCandidateItem(CFTypeRef 
*item
, SecItemParams 
*itemParams
, SecIdentityRef 
*identity
) 
3641         if (!item 
|| *item 
== NULL 
|| !itemParams
) 
3642                 return errSecItemNotFound
; 
3645         CFStringRef commonName 
= NULL
; 
3646         SecIdentityRef foundIdentity 
= NULL
; 
3647         if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) { 
3648                 // we found a SecIdentityRef, rather than a SecKeychainItemRef; 
3649                 // replace the found "item" with its associated certificate (which is the 
3650                 // item we actually want for purposes of getting attributes, data, or a 
3651                 // persistent data reference), and return the identity separately. 
3652                 SecCertificateRef certificate
; 
3653                 status 
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
); 
3654                 if (itemParams
->returnIdentity
) { 
3655                         foundIdentity 
= (SecIdentityRef
) *item
; 
3657                                 *identity 
= foundIdentity
; 
3663                 *item 
= (CFTypeRef
)certificate
; 
3666         CFDictionaryRef query 
= itemParams
->query
; 
3668         if (itemParams
->itemClass 
== kSecCertificateItemClass
) { 
3669                 // perform string comparisons first 
3670                 CFStringCompareFlags flags 
= _StringCompareFlagsFromQuery(query
); 
3671                 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
; 
3672                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
)) 
3673                         nameContains 
= NULL
; 
3674                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
)) 
3676                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
)) 
3678                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
)) 
3680                 if (nameContains 
|| nameStarts 
|| nameEnds 
|| nameExact
) { 
3681                         status 
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
); 
3682                         if (status 
|| !commonName
) goto filterOut
; 
3685                         CFRange range 
= CFStringFind(commonName
, nameContains
, flags
); 
3686                         if (range
.length 
< 1) 
3688                         // certificate item contains string; proceed to next check 
3691                         CFRange range 
= CFStringFind(commonName
, nameStarts
, flags
); 
3692                         if (range
.length 
< 1 || range
.location 
> 1) 
3694                         // certificate item starts with string; proceed to next check 
3697                         CFRange range 
= CFStringFind(commonName
, nameEnds
, flags
); 
3698                         if (range
.length 
< 1 || range
.location 
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
))) 
3700                         // certificate item ends with string; proceed to next check 
3703                         CFRange range 
= CFStringFind(commonName
, nameExact
, flags
); 
3704                         if (range
.length 
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
))) 
3706                         // certificate item exactly matches string; proceed to next check 
3708                 if (itemParams
->returnIdentity
) { 
3709                         // if we already found and returned the identity, we can skip this 
3710                         if (!foundIdentity
) { 
3711                                 status 
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
); 
3712                                 if (status
) goto filterOut
; 
3714                         // certificate item is part of an identity; proceed to next check 
3716                 if (itemParams
->policy
) { 
3717                         status 
= _FilterWithPolicy(itemParams
->policy
, (CFDateRef
)itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3718                         if (status
) goto filterOut
; 
3719                         // certificate item is valid for specified policy (and optionally specified date) 
3721                 if (itemParams
->validOnDate
) { 
3722                         status 
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3723                         if (status
) goto filterOut
; 
3724                         // certificate item is valid for specified date 
3726                 if (itemParams
->trustedOnly
) { 
3727                         // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search, 
3728                         // their trust has already been validated and we can skip this part. 
3729                         if (!(foundIdentity 
&& itemParams
->returnIdentity 
&& itemParams
->policy
)) { 
3730                                 status 
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
); 
3731                                 if (status
) goto filterOut
; 
3733                         // certificate item is trusted on this system 
3735         if (itemParams
->matchIssuers
) { 
3736             status 
= _FilterWithIssuers((CFArrayRef
)itemParams
->matchIssuers
, (SecCertificateRef
) *item
); 
3737             if (status
) goto filterOut
; 
3738             // certificate item has one of the issuers 
3741         if (itemParams
->itemList
) { 
3742                 Boolean foundMatch 
= FALSE
; 
3743                 CFIndex idx
, count 
= CFArrayGetCount(itemParams
->itemList
); 
3744                 for (idx
=0; idx
<count
; idx
++) { 
3745                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
); 
3746                         SecKeychainItemRef realItem 
= NULL
; 
3747                         SecCertificateRef aCert 
= NULL
; 
3748                         if (anItem 
== NULL
) { 
3751                         if (CFDataGetTypeID() == CFGetTypeID(anItem
) && 
3752                                 errSecSuccess 
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) { 
3755                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) && 
3756                                 errSecSuccess 
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) { 
3759                         if (CFEqual(anItem
, (CFTypeRef
) *item
)) { 
3766                                 CFRelease(realItem
); 
3772                 if (!foundMatch
) goto filterOut
; 
3773                 // item was found on provided list 
3776         if (foundIdentity 
&& !identity
) { 
3777                 CFRelease(foundIdentity
); 
3780                 CFRelease(commonName
); 
3783         // if we get here, consider the item a match 
3784         return errSecSuccess
; 
3788                 CFRelease(commonName
); 
3792         if (foundIdentity
) { 
3793                 CFRelease(foundIdentity
); 
3798         return errSecItemNotFound
; 
3802 AddItemResults(SecKeychainItemRef item
, 
3803         SecIdentityRef identity
, 
3804         SecItemParams 
*itemParams
, 
3805         CFAllocatorRef allocator
, 
3806         CFMutableArrayRef 
*items
, 
3809         // Given a found item (which may also be an identity), this function adds 
3810         // the requested result types (specified in itemParams) to the appropriate 
3811         // container as follows: 
3813         // 1. If there is only one result type (numResultTypes == 1) and only one 
3814         //    match requested (maxMatches == 1), set *result directly. 
3816         // 2. If there are multiple result types (numResultTypes > 1), and only one 
3817         //    match requested (maxMatches == 1), add each result type to itemDict 
3818         //    and set itemDict as the value of *result. 
3820         // 3. If there is only one result type (numResultTypes == 1) and multiple 
3821         //    possible matches (maxMatches > 1), add the result type to *items 
3822         //    and set *items as the value of *result. 
3824         // 4. If there are multiple result types (numResultTypes > 1) and multiple 
3825         //    possible matches (maxMatches > 1), add each result type to itemDict, 
3826         //    add itemDict to *items, and set *items as the value of *result. 
3828         // Note that we allocate *items if needed. 
3830         if (!item 
|| !itemParams 
|| !result
) 
3833         if (itemParams
->maxMatches 
> 1) { 
3834                 // if we can return more than one item, we must have an array 
3837                 else if (*items 
== NULL
) 
3838                         *items 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
3841         OSStatus tmpStatus
, status 
= errSecSuccess
; 
3842         CFMutableArrayRef itemArray 
= (items
) ? *items 
: NULL
; 
3843         CFMutableDictionaryRef itemDict 
= NULL
; 
3844         if (itemParams
->numResultTypes 
> 1) { 
3845                 // if we're returning more than one result type, each item we return must be a dictionary 
3846                 itemDict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
3849         if (itemParams
->returningRef
) { 
3850                 const void* itemRef 
= (identity
) ? (const void*)identity 
: (const void*)item
; 
3852                         CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
); 
3854                 else if (itemArray
) { 
3855                         CFArrayAppendValue(itemArray
, itemRef
); 
3858                         *result 
= CFRetain((CFTypeRef
)itemRef
); 
3862         if (itemParams
->returningPersistentRef
) { 
3863                 CFDataRef persistentRef
; 
3864                 SecKeychainItemRef tmpItem 
= item
; 
3865                 if (itemParams
->identityRef
) { 
3866                         tmpItem 
= (SecKeychainItemRef
)itemParams
->identityRef
; 
3868                 tmpStatus 
= SecKeychainItemCreatePersistentReference(tmpItem
, &persistentRef
); 
3869                 if (tmpStatus 
== errSecSuccess
) { 
3871                                 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
); 
3873                         else if (itemArray
) { 
3874                                 CFArrayAppendValue(itemArray
, persistentRef
); 
3877                                 *result 
= CFRetain(persistentRef
); 
3879                         CFRelease(persistentRef
); 
3881                 else if (status 
== errSecSuccess
) { 
3886         if (itemParams
->returningData
) { 
3887                 // Use SecCertificateCopyData if we have a SecCertificateRef item. 
3888                 // Note that a SecCertificateRef may not actually be a SecKeychainItem, 
3889                 // in which case SecKeychainItemCopyContent will not obtain its data. 
3891                 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) { 
3892                         CFDataRef dataRef 
= SecCertificateCopyData((SecCertificateRef
)item
); 
3895                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3897                                 else if (itemArray
) { 
3898                                         CFArrayAppendValue(itemArray
, dataRef
); 
3901                                         *result 
= CFRetain(dataRef
); 
3904                                 status 
= errSecSuccess
; 
3907                                 status 
= errSecAllocate
; 
3913                         tmpStatus 
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
); 
3914                         if (tmpStatus 
== errSecSuccess
) { 
3915                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8 
*)data
, length
); 
3917                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3919                                 else if (itemArray
) { 
3920                                         CFArrayAppendValue(itemArray
, dataRef
); 
3923                                         *result 
= CFRetain(dataRef
); 
3926                                 (void) SecKeychainItemFreeContent(NULL
, data
); 
3928                         else if (status 
== errSecSuccess
) { 
3934         if (itemParams
->returningAttributes
) { 
3935                 CFDictionaryRef attrsDict 
= NULL
; 
3936                 SecItemClass itemClass
; 
3937                 // since we have an item, allow its actual class to override the query-specified item class 
3938                 tmpStatus 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3940                         itemClass 
= itemParams
->itemClass
; 
3942                 tmpStatus 
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
); 
3945                                 // add all keys and values from attrsDict to the item dictionary 
3946                                 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
); 
3948                         else if (itemArray
) { 
3949                                 CFArrayAppendValue(itemArray
, attrsDict
); 
3952                                 *result 
= CFRetain(attrsDict
); 
3954                         CFRelease(attrsDict
); 
3956                 if (tmpStatus 
&& (status 
== errSecSuccess
)) { 
3963                         CFArrayAppendValue(itemArray
, itemDict
); 
3964                         CFRelease(itemDict
); 
3965                         *result 
= itemArray
; 
3971         else if (itemArray
) { 
3972                 *result 
= itemArray
; 
3978 CFDataRef 
_SecItemGetPersistentReference(CFTypeRef raw_item
) 
3981                 Item item 
= ItemImpl::required((SecKeychainItemRef
)raw_item
); 
3982                 return item
->getPersistentRef(); 
3988 /******************************************************************************/ 
3989 #pragma mark SecItem API functions 
3990 /******************************************************************************/ 
3993 // Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error. 
3995 static SInt32 
readNumber(CFTypeRef obj
) { 
3996     CFTypeID tid 
= CFGetTypeID(obj
); 
3998     if (tid 
== CFNumberGetTypeID()) { 
3999         CFNumberGetValue((CFNumberRef
)obj
, kCFNumberSInt32Type
, &v
); 
4001     } else if (tid 
== CFBooleanGetTypeID()) { 
4002         v 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
4004     } else if (tid 
== CFStringGetTypeID()) { 
4005         v 
= CFStringGetIntValue((CFStringRef
)obj
); 
4006         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v
); 
4007         /* If a string converted to an int isn't equal to the int printed as 
4008          a string, return a CFStringRef instead. */ 
4009         if (!CFEqual(t
, obj
)) { 
4020 // Function to check whether the kSecAttrSynchronizable flag is set in the query. 
4022 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
) 
4024         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
4025         Boolean result 
= (value 
&& readNumber(value
)); 
4031 // Function to check whether a synchronizable persistent reference was provided. 
4033 static Boolean 
SecItemIsIOSPersistentReference(CFTypeRef value
) 
4036         return ::_SecItemParsePersistentRef((CFDataRef
)value
, NULL
, NULL
, NULL
); 
4041 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
4044 // Function to find out which keychains are targetted by the query. 
4046 static OSStatus 
SecItemCategorizeQuery(CFDictionaryRef query
, bool &can_target_ios
, bool &can_target_osx
, bool &useDataProtectionKeychainFlag
) 
4048         // By default, target both keychain. 
4049         can_target_osx 
= can_target_ios 
= true; 
4050     useDataProtectionKeychainFlag 
= false; 
4052         // Check no-legacy flag. 
4053     // it's iOS or bust if we're on MZ! 
4054     CFTypeRef useDataProtection 
= NULL
; 
4055     if (_CFMZEnabled()) { 
4056         useDataProtection 
= kCFBooleanTrue
; 
4059         // In case your CFDict is dumb and compares by pointer equality we check both versions of the symbol 
4060         if (!CFDictionaryGetValueIfPresent(query
, kSecUseDataProtectionKeychain
, &useDataProtection
)) { 
4061             // Ah the irony of ignoring deprecation while checking for a legacy-avoiding attribute 
4062 #pragma clang diagnostic push 
4063 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
4064             useDataProtection 
= CFDictionaryGetValue(query
, kSecAttrNoLegacy
); 
4065 #pragma clang diagnostic pop 
4069         if (useDataProtection 
!= NULL
) { 
4070         useDataProtectionKeychainFlag 
= readNumber(useDataProtection
); 
4071                 can_target_ios 
= useDataProtectionKeychainFlag
; 
4072                 can_target_osx 
= !can_target_ios
; 
4073                 return errSecSuccess
; 
4076         // Check whether the query contains kSecValueRef and modify can_ flags according to the kind and type of the value. 
4077         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecValueRef
); 
4078         if (value 
!= NULL
) { 
4079                 CFTypeID typeID 
= CFGetTypeID(value
); 
4080                 if (typeID 
== SecKeyGetTypeID()) { 
4081                         can_target_osx 
= SecKeyIsCDSAKey((SecKeyRef
)value
); 
4082                         can_target_ios 
= !can_target_osx
; 
4083                 } else if (typeID 
== SecCertificateGetTypeID()) { 
4084                         // All types of certificates can target OSX keychains, but OSX certificates won't work on iOS 
4085                         can_target_ios 
&= !SecCertificateIsItemImplInstance((SecCertificateRef
)value
); 
4086                 } else if (typeID 
== SecKeychainItemGetTypeID()) { 
4087                         // SecKeychainItemRef can target iOS keychain only when it has attached iOS-style persistent reference. 
4088                         if (_SecItemGetPersistentReference(value
) == NULL
) { 
4089                                 can_target_ios 
= false; 
4094         // Check presence of kSecAttrTokenID and kSecAttrAccessControl; they are not defined for CDSA keychain. 
4095         if (CFDictionaryContainsKey(query
, kSecAttrTokenID
) || CFDictionaryContainsKey(query
, kSecAttrAccessControl
)) { 
4096                 can_target_osx 
= false; 
4099         // Check for special token access groups.  If present, redirect query to iOS keychain. 
4100         value 
= CFDictionaryGetValue(query
, kSecAttrAccessGroup
); 
4101         if (value 
!= NULL 
&& CFEqual(value
, kSecAttrAccessGroupToken
)) { 
4102                 can_target_osx 
= false; 
4105         // Synchronizable items should go to iOS keychain only. 
4106         if (SecItemSynchronizable(query
)) { 
4107                 can_target_osx 
= false; 
4110         value 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
4111         if (value 
!= NULL
) { 
4112                 if (SecItemIsIOSPersistentReference(value
)) { 
4113                         can_target_osx 
= false; 
4115                         // Non-iOS-style persistent references should not be fed to iOS keychain queries. 
4116                         can_target_ios 
= false; 
4120         // Presence of following atributes means that query is OSX-only. 
4121         static const CFStringRef 
*osx_only_items
[] = { 
4123                 &kSecMatchSearchList
, 
4124                 &kSecMatchSubjectStartsWith
, 
4125                 &kSecMatchSubjectEndsWith
, 
4126                 &kSecMatchSubjectWholeString
, 
4127                 &kSecMatchDiacriticInsensitive
, 
4128                 &kSecMatchWidthInsensitive
, 
4137         for (CFIndex i 
= 0; i 
< array_size(osx_only_items
); i
++) { 
4138                 can_target_ios 
= can_target_ios 
&& !CFDictionaryContainsKey(query
, *osx_only_items
[i
]); 
4141     // Absence of all of kSecItemClass, kSecValuePersistentRef, and kSecValueRef means that the query can't target iOS 
4142     if(CFDictionaryGetValue(query
, kSecClass
) == NULL 
&& 
4143        CFDictionaryGetValue(query
, kSecValuePersistentRef
) == NULL 
&& 
4144        CFDictionaryGetValue(query
, kSecValueRef
) == NULL
) { 
4145         can_target_ios 
= false; 
4148         return (can_target_ios 
|| can_target_osx
) ? errSecSuccess 
: errSecParam
; 
4152 // Function to check whether the kSecAttrSynchronizable attribute is being updated. 
4154 static Boolean 
SecItemHasSynchronizableUpdate(Boolean synchronizable
, CFDictionaryRef changes
) 
4156         CFTypeRef newValue 
= CFDictionaryGetValue(changes
, kSecAttrSynchronizable
); 
4160         Boolean new_sync 
= readNumber(newValue
); 
4161         Boolean old_sync 
= synchronizable
; 
4163         return (old_sync 
!= new_sync
); 
4167 // Function to apply changes to a mutable dictionary. 
4168 // (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction) 
4170 static void SecItemApplyChanges(const void *key
, const void *value
, void *context
) 
4172         CFMutableDictionaryRef dict 
= (CFMutableDictionaryRef
) context
; 
4175         CFDictionarySetValue(dict
, key
, value
); 
4179 // Function to change matching items from non-syncable to syncable 
4180 // (if toSyncable is true), otherwise from syncable to non-syncable. 
4181 // This currently moves items between keychain containers. 
4183 static OSStatus 
SecItemChangeSynchronizability(CFDictionaryRef query
, CFDictionaryRef changes
, Boolean toSyncable
) 
4185         // Note: the input query dictionary is a mutable copy of the query originally 
4186         // provided by the caller as the first parameter to SecItemUpdate. It may not 
4187         // specify returning attributes or data, but we will need both to make a copy. 
4189         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnRef
); 
4190         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnPersistentRef
); 
4191         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnData
); 
4192         CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4193         if (NULL 
== CFDictionaryGetValue(changes
, kSecValueData
)) 
4194                 CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnData
, kCFBooleanTrue
); 
4199                 status 
= SecItemCopyMatching_osx(query
, &result
); 
4201                 status 
= SecItemCopyMatching_ios(query
, &result
); 
4206                 return errSecItemNotFound
; 
4208         CFMutableArrayRef items
; 
4209         if (CFGetTypeID(result
) != CFArrayGetTypeID()) { 
4210                 items 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4211                 CFArrayAppendValue(items
, result
); 
4215                 items 
= (CFMutableArrayRef
)result
; 
4218         CFIndex idx
, count 
= (items
) ? CFArrayGetCount(items
) : 0; 
4219         int priority 
= LOG_DEBUG
; 
4221         for (idx 
= 0; idx 
< count
; idx
++) { 
4222                 CFDictionaryRef dict 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(items
, idx
); 
4223                 CFMutableDictionaryRef item 
= (CFMutableDictionaryRef
) 
4224                         SecItemCopyTranslatedAttributes(dict
, 
4225                                 CFDictionaryGetValue(query
, kSecClass
), 
4226                                 (toSyncable
) ? true : false /*iOSOut*/, 
4227                                 true /*pruneMatch*/, 
4229                                 true /*pruneReturn*/, 
4230                                 false /*pruneData*/, 
4231                                 (toSyncable
) ? true : false /*pruneAccess*/); 
4232                 // hold onto the query before applying changes, in case the item already exists. 
4233                 // note that we cannot include the creation or modification dates from our 
4234                 // found item in this query, as they may not match the item in the other keychain. 
4235                 CFMutableDictionaryRef itemQuery 
= CFDictionaryCreateMutableCopy(NULL
, 0, item
); 
4236                 CFDictionaryRemoveValue(itemQuery
, kSecAttrCreationDate
); 
4237                 CFDictionaryRemoveValue(itemQuery
, kSecAttrModificationDate
); 
4238                 // apply changes to the item dictionary that we will pass to SecItemAdd 
4239                 CFDictionaryApplyFunction(changes
, SecItemApplyChanges
, item
); 
4241                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4242                         status 
= SecItemAdd_ios(item
, NULL
); 
4243                         secitemlog(priority
, "ChangeSync: SecItemAdd_ios=%d", status
); 
4244                         if (errSecDuplicateItem 
== status
) { 
4245                                 // find and apply changes to the existing syncable item. 
4246                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4247                                 status 
= SecItemUpdate_ios(itemQuery
, changes
); 
4248                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_ios=%d", status
); 
4250                         if (errSecSuccess 
== status
) { 
4251                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4252                                 status 
= SecItemDelete_osx(itemQuery
); 
4253                                 secitemlog(priority
, "ChangeSync: SecItemDelete_osx=%d", status
); 
4257                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4258                         status 
= SecItemAdd_osx(item
, NULL
); 
4259                         secitemlog(priority
, "ChangeSync: SecItemAdd_osx=%d", status
); 
4260                         if (errSecDuplicateItem 
== status
) { 
4261                                 // find and apply changes to the existing non-syncable item. 
4262                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4263                                 status 
= SecItemUpdate_osx(itemQuery
, changes
); 
4264                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_osx=%d", status
); 
4266                         if (errSecSuccess 
== status
) { 
4267                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4268                                 status 
= SecItemDelete_ios(itemQuery
); 
4269                                 secitemlog(priority
, "ChangeSync: SecItemDelete_ios=%d", status
); 
4272                 CFReleaseSafe(item
); 
4273                 CFReleaseSafe(itemQuery
); 
4277         CFReleaseSafe(items
); 
4286 SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
) { 
4287         CFTypeRef ref 
= NULL
; 
4288         CFStringRef item_class_string 
= (CFStringRef
)CFDictionaryGetValue(refAttributes
, kSecClass
); 
4289         SecItemClass item_class 
= (SecItemClass
) 0; 
4291         if (CFEqual(item_class_string
, kSecClassGenericPassword
)) { 
4292                 item_class 
= kSecGenericPasswordItemClass
; 
4293         } else if (CFEqual(item_class_string
, kSecClassInternetPassword
)) { 
4294                 item_class 
= kSecInternetPasswordItemClass
; 
4297         if (item_class 
!= 0) { 
4298                 // we carry v_Data around here so the *_ios calls can find it and locate 
4299                 // their own data.   Putting things in the attribute list doesn't help as 
4300                 // the osx keychainitem and item calls bail when they don't see a keychain 
4301                 // object.   If we need to make them work we either have to bridge them, or 
4302                 // find a way to craft a workable keychain object.   #if'ed code left below 
4303                 // in case we need to go down that path. 
4305     SecKeychainAttributeList attrs 
= {}; 
4306     SecKeychainAttribute attr 
= {}; 
4312     Item item 
= Item(item_class
, &attrs
, 0, ""); 
4313                 v 
= CFCast(CFData
, CFDictionaryGetValue(refAttributes
, kSecValuePersistentRef
)); 
4315                         item
->setPersistentRef((CFDataRef
)v
); 
4317                 ref 
= item
->handle(); 
4324  * SecItemValidateAppleApplicationGroupAccess determines if the caller 
4325  * is a member of the specified application group, and is signed by Apple. 
4328 SecItemValidateAppleApplicationGroupAccess(CFStringRef group
) 
4330         SecTrustedApplicationRef app 
= NULL
; 
4331         SecRequirementRef requirement 
= NULL
; 
4332         SecCodeRef code 
= NULL
; 
4333         OSStatus status 
= errSecParam
; 
4336                 CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(group
), kCFStringEncodingUTF8
) + 1; 
4337                 char* buffer 
= (char*) malloc(length
); 
4339                         if (CFStringGetCString(group
, buffer
, length
, kCFStringEncodingUTF8
)) { 
4340                                 status 
= SecTrustedApplicationCreateApplicationGroup(buffer
, NULL
, &app
); 
4344                         status 
= errSecMemoryError
; 
4348                 status 
= SecTrustedApplicationCopyRequirement(app
, &requirement
); 
4351                 status 
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
); 
4354                 status 
= SecCodeCheckValidity(code
, kSecCSDefaultFlags
, requirement
); 
4357         CFReleaseSafe(code
); 
4358         CFReleaseSafe(requirement
); 
4363 static Mutex
& gParentCertCacheLock() { 
4364     static Mutex fParentCertCacheLock
; 
4365     return fParentCertCacheLock
; 
4367 static CFMutableDictionaryRef gParentCertCache
; 
4368 static CFMutableArrayRef gParentCertCacheList
; 
4369 #define PARENT_CACHE_SIZE 100 
4371 void SecItemParentCachePurge() { 
4372     StLock
<Mutex
> _(gParentCertCacheLock()); 
4373     CFReleaseNull(gParentCertCache
); 
4374     CFReleaseNull(gParentCertCacheList
); 
4377 static CFArrayRef CF_RETURNS_RETAINED 
parentCacheRead(SecCertificateRef certificate
) { 
4378     CFArrayRef parents 
= NULL
; 
4380     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4381     if (!digest
) return NULL
; 
4383     StLock
<Mutex
> _(gParentCertCacheLock()); 
4384     if (gParentCertCache 
&& gParentCertCacheList
) { 
4385         if (0 <= (ix 
= CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4386                                                    CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4388             // Cache hit. Get value and move entry to the top of the list. 
4389             parents 
= (CFArrayRef
)CFDictionaryGetValue(gParentCertCache
, digest
); 
4390             CFArrayRemoveValueAtIndex(gParentCertCacheList
, ix
); 
4391             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4394     CFRetainSafe(parents
); 
4398 static void parentCacheWrite(SecCertificateRef certificate
, CFArrayRef parents
) { 
4399     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4400     if (!digest
) return; 
4402     StLock
<Mutex
> _(gParentCertCacheLock()); 
4403     if (!gParentCertCache 
|| !gParentCertCacheList
) { 
4404         CFReleaseNull(gParentCertCache
); 
4405         gParentCertCache 
= makeCFMutableDictionary(); 
4406         CFReleaseNull(gParentCertCacheList
); 
4407         gParentCertCacheList 
= makeCFMutableArray(0); 
4410     if (gParentCertCache 
&& gParentCertCacheList
) { 
4411         // check to make sure another thread didn't add this entry to the cache already 
4412         if (0 > CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4413                                             CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4415             CFDictionaryAddValue(gParentCertCache
, digest
, parents
); 
4416             if (PARENT_CACHE_SIZE 
<= CFArrayGetCount(gParentCertCacheList
)) { 
4417                 // Remove least recently used cache entry. 
4418                 CFDictionaryRemoveValue(gParentCertCache
, CFArrayGetValueAtIndex(gParentCertCacheList
, 0)); 
4419                 CFArrayRemoveValueAtIndex(gParentCertCacheList
, 0); 
4421             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4427  * SecItemCopyParentCertificates_osx returns an array of zero of more possible 
4428  * issuer certificates for the provided certificate. No cryptographic validation 
4429  * of the signature is performed in this function; its purpose is only to 
4430  * provide a list of candidate certificates. 
4433 SecItemCopyParentCertificates_osx(SecCertificateRef certificate
, void *context
) 
4435 #pragma unused (context) /* for now; in future this can reference a container object */ 
4436         /* Check for parents in keychain cache */ 
4437         CFArrayRef parents 
= parentCacheRead(certificate
); 
4442         /* Cache miss. Query for parents. */ 
4444         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4446         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4447         CFRetainSafe(normalizedIssuer
); 
4450         CFMutableArrayRef combinedSearchList 
= NULL
; 
4452         /* Define the array of keychains which will be searched for parents. */ 
4453         CFArrayRef searchList 
= NULL
; 
4454         status 
= SecKeychainCopySearchList(&searchList
); 
4456                 combinedSearchList 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, searchList
); 
4457                 CFRelease(searchList
); 
4459                 combinedSearchList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4461         SecKeychainRef rootStoreKeychain 
= NULL
; 
4462         status 
= SecKeychainOpen(SYSTEM_ROOT_STORE_PATH
, &rootStoreKeychain
); 
4463         if (rootStoreKeychain
) { 
4464                 if (combinedSearchList
) { 
4465                         CFArrayAppendValue(combinedSearchList
, rootStoreKeychain
); 
4467                 CFRelease(rootStoreKeychain
); 
4470         /* Create and populate a fixed-size query dictionary. */ 
4471         CFMutableDictionaryRef query 
= CFDictionaryCreateMutable(NULL
, 5, 
4472                         &kCFTypeDictionaryKeyCallBacks
, 
4473                         &kCFTypeDictionaryValueCallBacks
); 
4474         CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
4475         CFDictionaryAddValue(query
, kSecReturnData
, kCFBooleanTrue
); 
4476         CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4477         if (combinedSearchList
) { 
4478                 CFDictionaryAddValue(query
, kSecMatchSearchList
, combinedSearchList
); 
4479                 CFRelease(combinedSearchList
); 
4482         CFTypeRef results 
= NULL
; 
4483         if (normalizedIssuer
) { 
4484                 /* Look up certs whose subject is the same as this cert's issuer. */ 
4485                 CFDictionaryAddValue(query
, kSecAttrSubject
, normalizedIssuer
); 
4486                 status 
= SecItemCopyMatching_osx(query
, &results
); 
4489                 /* Cannot match anything without an issuer! */ 
4490                 status 
= errSecItemNotFound
; 
4493         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4494                 secitemlog(LOG_WARNING
, "SecItemCopyParentCertificates_osx: %d", (int)status
); 
4498         CFMutableArrayRef result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4499         CFTypeID resultType 
= (results
) ? CFGetTypeID(results
) : 0; 
4500         if (resultType 
== CFArrayGetTypeID()) { 
4501                 CFIndex index
, count 
= CFArrayGetCount((CFArrayRef
)results
); 
4502                 for (index 
= 0; index 
< count
; index
++) { 
4503                         CFDataRef data 
= (CFDataRef
) CFArrayGetValueAtIndex((CFArrayRef
)results
, index
); 
4505                                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
4507                                         CFArrayAppendValue(result
, cert
); 
4512         } else if (results 
&& resultType 
== CFDataGetTypeID()) { 
4513                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)results
); 
4515                         CFArrayAppendValue(result
, cert
); 
4519         CFReleaseSafe(results
); 
4520         CFReleaseSafe(normalizedIssuer
); 
4523         parentCacheWrite(certificate
, result
); 
4528 SecCertificateRef 
SecItemCopyStoredCertificate(SecCertificateRef certificate
, void *context
) 
4530 #pragma unused (context) /* for now; in future this can reference a container object */ 
4532         /* Certificates are unique by issuer and serial number. */ 
4533         CFDataRef serialNumber 
= SecCertificateCopySerialNumberData(certificate
, NULL
); 
4535         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4537         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4538         CFRetainSafe(normalizedIssuer
); 
4541         const void *keys
[] = { 
4545                 kSecAttrSerialNumber
, 
4549                 kSecClassCertificate
, 
4555         CFDictionaryRef query 
= CFDictionaryCreate(NULL
, keys
, values
, 5,       NULL
, NULL
); 
4556         CFTypeRef result 
= NULL
; 
4558         OSStatus status 
= SecItemCopyMatching_osx(query
, &result
); 
4559         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4560                 secitemlog(LOG_WARNING
, "SecItemCopyStoredCertificate: %d", (int)status
); 
4561                 CFReleaseNull(result
); 
4563         CFReleaseSafe(query
); 
4564         CFReleaseSafe(serialNumber
); 
4565         CFReleaseSafe(normalizedIssuer
); 
4567         return (SecCertificateRef
)result
; 
4571  * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary 
4572  * and attempts to return a sanitized copy for passing to the underlying 
4573  * platform-specific implementation code. 
4575  * If iOSOut is true, one or more translations may apply: 
4576  *   - SecKeychain refs are removed, since there aren't multiple keychains 
4577  *   - SecPolicy refs are removed, since they can't be externalized 
4578  *   - SecAccess refs are removed, and potentially translated to entitlements 
4580  * If pruneMatch is true, kSecMatch* attributes are removed; this avoids 
4581  * parameter errors due to strict input checks in secd, which only permits 
4582  * these constants for calls to SecItemCopyMatching. 
4584  * If pruneSync is true, the kSecAttrSynchronizable attribute is removed. 
4585  * This permits a query to be reused for non-synchronizable items, or to 
4586  * resolve a search based on a persistent item reference for iOS. 
4588  * If pruneReturn is true, kSecReturn* attributes are removed; this avoids 
4589  * parameter errors due to strict input checks in secd, which do not permit 
4590  * these constants for calls to SecItemUpdate. 
4593 SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
4594         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
) 
4596         CFMutableDictionaryRef result 
= CFDictionaryCreateMutableCopy(NULL
, 0, inOSXDict
); 
4597         if (result 
== NULL
) { 
4602                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4606                 /* Match constants are only supported on iOS for SecItemCopyMatching, 
4607                  * and will generate an error if passed to other SecItem API functions; 
4608                  * on OS X, they're just ignored if not applicable for the context. 
4610                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4611                 CFDictionaryRemoveValue(result
, kSecMatchItemList
); 
4612                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4613                 CFDictionaryRemoveValue(result
, kSecMatchIssuers
); 
4614                 CFDictionaryRemoveValue(result
, kSecMatchEmailAddressIfPresent
); 
4615                 CFDictionaryRemoveValue(result
, kSecMatchSubjectContains
); 
4616                 CFDictionaryRemoveValue(result
, kSecMatchCaseInsensitive
); 
4617                 CFDictionaryRemoveValue(result
, kSecMatchTrustedOnly
); 
4618                 CFDictionaryRemoveValue(result
, kSecMatchValidOnDate
); 
4619                 CFDictionaryRemoveValue(result
, kSecMatchLimit
); 
4620                 CFDictionaryRemoveValue(result
, kSecMatchLimitOne
); 
4621                 CFDictionaryRemoveValue(result
, kSecMatchLimitAll
); 
4625                 /* Return constants are not supported on iOS for SecItemUpdate, 
4626                  * where they will generate an error; on OS X, they're just ignored 
4627                  * if not applicable for the context. 
4629                 CFDictionaryRemoveValue(result
, kSecReturnData
); 
4630                 CFDictionaryRemoveValue(result
, kSecReturnAttributes
); 
4631                 CFDictionaryRemoveValue(result
, kSecReturnRef
); 
4632                 CFDictionaryRemoveValue(result
, kSecReturnPersistentRef
); 
4636                 /* Searching on data is not supported. */ 
4637                 CFDictionaryRemoveValue(result
, kSecValueData
); 
4641         /* Searching on access lists is not supported */ 
4642         CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4646                 /* Remove kSecMatchSearchList (value is array of SecKeychainRef); 
4647                  * cannot specify a keychain search list on iOS 
4649                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4651                 /* Remove kSecUseKeychain (value is a SecKeychainRef); 
4652                  * cannot specify a keychain on iOS 
4654                 CFDictionaryRemoveValue(result
, kSecUseKeychain
); 
4656                 /* Potentially translate kSecAttrAccess (value is a SecAccessRef), 
4657                  * unless kSecAttrAccessGroup has already been specified. 
4659                 SecAccessRef access 
= (SecAccessRef
) CFDictionaryGetValue(result
, kSecAttrAccess
); 
4660                 CFStringRef accessGroup 
= (CFStringRef
) CFDictionaryGetValue(result
, kSecAttrAccessGroup
); 
4661                 if (access 
!= NULL 
&& accessGroup 
== NULL
) { 
4662                         /* Translate "InternetAccounts" application group to an access group */ 
4663                         if (errSecSuccess 
== SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) { 
4664                                 /* The caller is a valid member of the application group. */ 
4665                                 CFStringRef groupName 
= CFSTR("appleaccount"); 
4666                                 CFTypeRef value 
= CFDictionaryGetValue(result
, kSecAttrAuthenticationType
); 
4667                                 if (value 
&& CFEqual(value
, kSecAttrAuthenticationTypeHTMLForm
)) { 
4668                                         groupName 
= CFSTR("com.apple.cfnetwork"); 
4670                                 CFDictionarySetValue(result
, kSecAttrAccessGroup
, groupName
); 
4673                 CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4675                 /* If item is specified by direct reference, and this is an iOS search, 
4676                  * replace it with a persistent reference, if it was recorded inside ItemImpl. 
4678                 CFTypeRef directRef 
= CFDictionaryGetValue(result
, kSecValueRef
); 
4679                 if (directRef 
!= NULL
) { 
4680                         CFTypeID typeID 
= CFGetTypeID(directRef
); 
4681                         if ((typeID 
!= SecKeyGetTypeID() || SecKeyIsCDSAKey((SecKeyRef
)directRef
)) && 
4682                                 (typeID 
!= SecCertificateGetTypeID() || SecCertificateIsItemImplInstance((SecCertificateRef
)directRef
)) && 
4683                                 (typeID 
!= SecIdentityGetTypeID())) { 
4684                                 CFDataRef persistentRef 
= _SecItemGetPersistentReference(directRef
); 
4685                                 if (persistentRef
) { 
4686                                         CFDictionarySetValue(result
, kSecValuePersistentRef
, persistentRef
); 
4687                                         CFDictionaryRemoveValue(result
, kSecValueRef
); 
4692                 /* If item is specified by persistent reference, and this is an iOS search, 
4693                  * remove the synchronizable attribute as it will be rejected by secd. 
4695                 CFTypeRef persistentRef 
= CFDictionaryGetValue(result
, kSecValuePersistentRef
); 
4696                 if (persistentRef
) { 
4697                         CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4700                 /* Remove kSecAttrModificationDate; this should never be used as criteria 
4701                  * for a search, or to add/modify an item. (If we are cloning an item 
4702                  * and want to keep its modification date, we don't call this function.) 
4703                  * It turns out that some clients are using the full attributes dictionary 
4704                  * returned by SecItemCopyMatching as a query to find the same item later, 
4705                  * which won't work once the item is updated. 
4707                 CFDictionaryRemoveValue(result
, kSecAttrModificationDate
); 
4709         /* Find all intermediate certificates in OSX keychain and append them in to the kSecMatchIssuers. 
4710          * This is required because secd cannot do query in to the OSX keychain 
4712         CFTypeRef matchIssuers 
= CFDictionaryGetValue(result
, kSecMatchIssuers
); 
4713         if (matchIssuers 
&& CFGetTypeID(matchIssuers
) == CFArrayGetTypeID()) { 
4714             CFArrayRef newMatchIssuers 
= _CopyMatchingIssuers((CFArrayRef
)matchIssuers
); 
4715             if (newMatchIssuers
) { 
4716                 CFDictionarySetValue(result
, kSecMatchIssuers
, newMatchIssuers
); 
4717                 CFRelease(newMatchIssuers
); 
4722                 /* iOS doesn't add the class attribute, so we must do it here. */ 
4724                         CFDictionarySetValue(result
, kSecClass
, itemClass
); 
4726                 /* Remove attributes which are not part of the OS X database schema. */ 
4727                 CFDictionaryRemoveValue(result
, kSecAttrAccessible
); 
4728                 CFDictionaryRemoveValue(result
, kSecAttrAccessControl
); 
4729                 CFDictionaryRemoveValue(result
, kSecAttrAccessGroup
); 
4730                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4731                 CFDictionaryRemoveValue(result
, kSecAttrTombstone
); 
4734     /* This attribute is consumed by the bridge itself. */ 
4735     CFDictionaryRemoveValue(result
, kSecUseDataProtectionKeychain
); 
4736 #pragma clang diagnostic push 
4737 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
4738     // Also remove deprecated symbol in case your CFDict is derpy 
4739     CFDictionaryRemoveValue(result
, kSecAttrNoLegacy
); 
4740 #pragma clang diagnostic pop 
4748 _CopyMatchingIssuers(CFArrayRef matchIssuers
) { 
4749     CFMutableArrayRef result 
= NULL
; 
4750     CFMutableDictionaryRef query 
= NULL
; 
4751     CFMutableDictionaryRef policyProperties 
= NULL
; 
4752     SecPolicyRef policy 
= NULL
; 
4753     CFTypeRef matchedCertificates 
= NULL
; 
4755     require_quiet(policyProperties 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), out
); 
4756     CFDictionarySetValue(policyProperties
, kSecPolicyKU_KeyCertSign
, kCFBooleanTrue
); 
4757     require_quiet(policy 
= SecPolicyCreateWithProperties(kSecPolicyAppleX509Basic
, policyProperties
), out
); 
4759     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), out
); 
4760     CFDictionarySetValue(query
, kSecClass
, kSecClassCertificate
); 
4761     CFDictionarySetValue(query
, kSecMatchIssuers
, matchIssuers
); 
4762     CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4763     CFDictionarySetValue(query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4764     CFDictionarySetValue(query
, kSecUseCertificatesWithMatchIssuers
, kCFBooleanTrue
); 
4765     CFDictionarySetValue(query
, kSecMatchPolicy
, policy
); 
4767     if (SecItemCopyMatching_osx(query
, &matchedCertificates
) == errSecSuccess 
&& CFGetTypeID(matchedCertificates
) == CFArrayGetTypeID()) { 
4768         require_quiet(result 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, (CFArrayRef
)matchedCertificates
), out
); 
4769         for(CFIndex i 
= 0; i 
< CFArrayGetCount((CFArrayRef
)matchedCertificates
); ++i
) { 
4770             CFDictionaryRef attributes 
= (CFDictionaryRef
)CFArrayGetValueAtIndex((CFArrayRef
)matchedCertificates
, i
); 
4771             CFTypeRef subject 
= CFDictionaryGetValue(attributes
, kSecAttrSubject
); 
4772             if (!CFArrayContainsValue(result
, CFRangeMake(0, CFArrayGetCount(result
)), subject
)) { 
4773                 CFArrayAppendValue(result
, subject
); 
4779     CFReleaseSafe(query
); 
4780     CFReleaseSafe(policyProperties
); 
4781     CFReleaseSafe(policy
); 
4782     CFReleaseSafe(matchedCertificates
); 
4788 SecItemMergeResults(bool can_target_ios
, OSStatus status_ios
, CFTypeRef result_ios
, 
4789                                         bool can_target_osx
, OSStatus status_osx
, CFTypeRef result_osx
, 
4790                                         CFTypeRef 
*result
) { 
4791         // When querying both keychains and iOS keychain fails because of missing 
4792         // entitlements, completely ignore iOS keychain result.  This is to keep 
4793         // backward compatibility with applications which know nothing about iOS keychain 
4794         // and use SecItem API to access OSX keychain which does not need any entitlements. 
4795         if (can_target_osx 
&& can_target_ios 
&& status_ios 
== errSecMissingEntitlement
) { 
4796                 can_target_ios 
= false; 
4799         if (can_target_osx 
&& can_target_ios
) { 
4800                 // If both keychains were targetted, examine returning statuses and decide what to do. 
4801                 if (status_ios 
!= errSecSuccess
) { 
4802                         // iOS keychain failed to produce results because of some error, go with results from OSX keychain. 
4803             // Since iOS keychain queries will fail without a keychain-access-group or proper entitlements, SecItemCopyMatching 
4804             // calls against the OSX keychain API that should return errSecItemNotFound will return nonsense from the iOS keychain. 
4805                         AssignOrReleaseResult(result_osx
, result
); 
4807                 } else if (status_osx 
!= errSecSuccess
) { 
4808                         if (status_osx 
!= errSecItemNotFound
) { 
4809                                 // OSX failed to produce results with some failure mode (else than not_found), but iOS produced results. 
4810                                 // We have to either return OSX failure result and discard iOS results, or vice versa.  For now, we just 
4811                                 // ignore OSX error and return just iOS results. 
4812                                 secitemlog(LOG_NOTICE
, "SecItemMergeResults: osx_result=%d, ignoring it, iOS succeeded fine", status_osx
); 
4815                         // OSX failed to produce results, but we have success from iOS keychain; go with results from iOS keychain. 
4816                         AssignOrReleaseResult(result_ios
, result
); 
4817                         return errSecSuccess
; 
4819                         // Both searches succeeded, merge results. 
4820                         if (result 
!= NULL
) { 
4821                                 CFTypeID id_osx 
= (result_osx
) ? CFGetTypeID(result_osx
) : 0; 
4822                                 CFTypeID id_ios 
= (result_ios
) ? CFGetTypeID(result_ios
) : 0; 
4823                                 CFTypeID id_array 
= CFArrayGetTypeID(); 
4824                                 if ((id_osx 
== id_array
) && (id_ios 
== id_array
)) { 
4825                                         // Fold the arrays into one. 
4826                                         *result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4827                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_ios
, 
4828                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_ios
))); 
4829                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_osx
, 
4830                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_osx
))); 
4832                                         // Result type is not an array, so only one match can be returned. 
4833                                         *result 
= (id_ios
) ? result_ios 
: result_osx
; 
4834                                         CFRetainSafe(*result
); 
4837                         CFReleaseSafe(result_osx
); 
4838                         CFReleaseSafe(result_ios
); 
4839                         return errSecSuccess
; 
4841         } else if (can_target_ios
) { 
4842                 // Only iOS keychain was targetted. 
4843                 AssignOrReleaseResult(result_ios
, result
); 
4845         } else if (can_target_osx
) { 
4846                 // Only OSX keychain was targetted. 
4847                 AssignOrReleaseResult(result_osx
, result
); 
4850                 // Query could not run at all? 
4856 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef 
*result
) 
4858     os_activity_t activity 
= os_activity_create("SecItemCopyMatching", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4859     os_activity_scope(activity
); 
4860     os_release(activity
); 
4865         secitemshow(query
, "SecItemCopyMatching query:"); 
4867         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4868         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4869         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
4870         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
4871         if (status 
!= errSecSuccess
) { 
4875         if (can_target_ios
) { 
4876                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4877                         CFDictionaryGetValue(query
, kSecClass
), true, false, false, false, true, true); 
4879                         status_ios 
= errSecParam
; 
4882                         status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4883                         CFRelease(attrs_ios
); 
4885                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_ios result: %d", status_ios
); 
4888         if (can_target_osx
) { 
4889                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4890                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, false, true, true); 
4892                         status_osx 
= errSecParam
; 
4895                         status_osx 
= SecItemCopyMatching_osx(attrs_osx
, &result_osx
); 
4896                         CFRelease(attrs_osx
); 
4898                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_osx result: %d", status_osx
); 
4901         status 
= SecItemMergeResults(can_target_ios
, status_ios
, result_ios
, 
4902                                                                  can_target_osx
, status_osx
, result_osx
, result
); 
4903         secitemlog(LOG_NOTICE
, "SecItemCopyMatching result: %d", status
); 
4908 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
4910     os_activity_t activity 
= os_activity_create("SecItemAdd", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4911     os_activity_scope(activity
); 
4912     os_release(activity
); 
4920         secitemshow(attributes
, "SecItemAdd attrs:"); 
4922         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4923         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
4924         OSStatus status 
= SecItemCategorizeQuery(attributes
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
4925         if (status 
!= errSecSuccess
) { 
4929         // SecItemAdd cannot be really done on both keychains.  In order to keep backward compatibility 
4930         // with existing applications, we prefer to add items into legacy keychain and fallback 
4931         // into iOS (modern) keychain only when the query is not suitable for legacy keychain. 
4932         if (!can_target_osx
) { 
4933                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(attributes
, 
4934                         NULL
, true, true, false, false, false, false); 
4936                         status 
= errSecParam
; 
4938             status 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4939                         CFRelease(attrs_ios
); 
4941                 secitemlog(LOG_NOTICE
, "SecItemAdd_ios result: %d", status
); 
4942                 AssignOrReleaseResult(result_ios
, result
); 
4945                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(attributes
, 
4946                     NULL
, false, false, true, false, false, false); 
4948                         status 
= errSecParam
; 
4950                         status 
= SecItemAdd_osx(attrs_osx
, &result_osx
); 
4951                         CFRelease(attrs_osx
); 
4953                 secitemlog(LOG_NOTICE
, "SecItemAdd_osx result: %d", status
); 
4954                 AssignOrReleaseResult(result_osx
, result
); 
4960 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
4962     os_activity_t activity 
= os_activity_create("SecItemUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4963     os_activity_scope(activity
); 
4964     os_release(activity
); 
4966         if (!query 
|| !attributesToUpdate
) { 
4969         secitemshow(query
, "SecItemUpdate query:"); 
4970         secitemshow(attributesToUpdate
, "SecItemUpdate attrs:"); 
4972         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4973         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
4974         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
4975         if (status 
!= errSecSuccess
) { 
4980      * If the user have explicity opted in to UseDataProtectionKeychain, then don't touch the legacy keychain at all 
4981      * ie don't move the item back to legacy keychain if you remove sync=1 or the inverse. 
4983     if (useDataProtectionKeychainFlag
) { 
4984         CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4985             CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4987             status_ios 
= errSecParam
; 
4989             status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4990             CFRelease(attrs_ios
); 
4992         secitemlog(LOG_NOTICE
, "SecItemUpdate(ios only) result: %d", status_ios
); 
4996         if (can_target_ios
) { 
4997                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4998                         CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
5000                         status_ios 
= errSecParam
; 
5003             if (SecItemHasSynchronizableUpdate(true, attributesToUpdate
)) { 
5004                 status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
5006                 status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
5008                         CFRelease(attrs_ios
); 
5010                 secitemlog(LOG_NOTICE
, "SecItemUpdate_ios result: %d", status_ios
); 
5013         if (can_target_osx
) { 
5014                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
5015                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, true, true, true); 
5017                         status_osx 
= errSecParam
; 
5020                         if (SecItemHasSynchronizableUpdate(false, attributesToUpdate
)) 
5021                                 status_osx 
= SecItemChangeSynchronizability(attrs_osx
, attributesToUpdate
, true); 
5023                                 status_osx 
= SecItemUpdate_osx(attrs_osx
, attributesToUpdate
); 
5025                         CFRelease(attrs_osx
); 
5027                 secitemlog(LOG_NOTICE
, "SecItemUpdate_osx result: %d", status_osx
); 
5030         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
5031                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
5032         secitemlog(LOG_NOTICE
, "SecItemUpdate result: %d", status
); 
5037 SecItemDelete(CFDictionaryRef query
) 
5039     os_activity_t activity 
= os_activity_create("SecItemDelete", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
5040     os_activity_scope(activity
); 
5041     os_release(activity
); 
5046         secitemshow(query
, "SecItemDelete query:"); 
5048         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
5049         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
5050         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
5051         if (status 
!= errSecSuccess
) { 
5055         if (can_target_ios
) { 
5056                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
5057                         NULL
, true, true, false, true, true, true); 
5059                         status_ios 
= errSecParam
; 
5061             status_ios 
= SecItemDelete_ios(attrs_ios
); 
5062                         CFRelease(attrs_ios
); 
5064                 secitemlog(LOG_NOTICE
, "SecItemDelete_ios result: %d", status_ios
); 
5067         if (can_target_osx
) { 
5068                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
5069                     NULL
, false, false, true, true, true, true); 
5071                         status_osx 
= errSecParam
; 
5073                         status_osx 
= SecItemDelete_osx(attrs_osx
); 
5074                         CFRelease(attrs_osx
); 
5076                 secitemlog(LOG_NOTICE
, "SecItemDelete_osx result: %d", status_osx
); 
5079         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
5080                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
5081         secitemlog(LOG_NOTICE
, "SecItemCopyDelete result: %d", status
); 
5086 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
) 
5088         OSStatus status 
= SecItemUpdateTokenItems_ios(tokenID
, tokenItemsAttributes
); 
5089         secitemlog(LOG_NOTICE
, "SecItemUpdateTokenItems_ios result: %d", status
); 
5094 SecItemCopyMatching_osx( 
5095         CFDictionaryRef query
, 
5098         if (!query 
|| !result
) 
5103         CFAllocatorRef allocator 
= CFGetAllocator(query
); 
5104         CFIndex matchCount 
= 0; 
5105         CFMutableArrayRef itemArray 
= NULL
; 
5106         SecKeychainItemRef item 
= NULL
; 
5107         SecIdentityRef identity 
= NULL
; 
5108         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5110         // validate input query parameters and create the search reference 
5111         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(query
, &status
); 
5112         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5114         // find the next match until we hit maxMatches, or no more matches found 
5115         while ( !(!itemParams
->returnAllMatches 
&& matchCount 
>= itemParams
->maxMatches
) && 
5116                         SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == errSecSuccess
) { 
5118                 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
)) 
5119                         continue; // move on to next item 
5121                 ++matchCount
; // we have a match 
5123                 tmpStatus 
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
); 
5124                 if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5132                         CFRelease(identity
); 
5137         if (status 
== errSecSuccess
) 
5138                 status 
= (matchCount 
> 0) ? errSecSuccess 
: errSecItemNotFound
; 
5141         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5145         _FreeSecItemParams(itemParams
); 
5151 SecItemCopyDisplayNames( 
5153         CFArrayRef 
*displayNames
) 
5157         Required(displayNames
); 
5159     return errSecUnimplemented
; 
5165         CFDictionaryRef attributes
, 
5173         CFAllocatorRef allocator 
= CFGetAllocator(attributes
); 
5174         CFMutableArrayRef itemArray 
= NULL
; 
5175         SecKeychainItemRef item 
= NULL
; 
5176         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5178         // validate input attribute parameters 
5179         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(attributes
, &status
); 
5180         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5182         // currently, we don't support adding SecIdentityRef items (an aggregate item class), 
5183         // since the private key should already be in a keychain by definition. We could support 
5184         // this as a copy operation for the private key if a different keychain is specified, 
5185         // but in any case it should try to add the certificate. See <rdar://8317887>. 
5186         require_action(!itemParams
->returnIdentity
, error_exit
, status 
= errSecItemInvalidValue
); 
5188         if (itemParams
->useItems 
== NULL
) { 
5190                 require_action(itemParams
->itemData 
== NULL 
|| CFGetTypeID(itemParams
->itemData
) == CFDataGetTypeID(), 
5191                                            error_exit
, status 
= errSecItemInvalidValue
); 
5193                 // create a single keychain item specified by the input attributes 
5194                 status 
= SecKeychainItemCreateFromContent(itemParams
->itemClass
, 
5195                         itemParams
->attrList
, 
5196                         (itemParams
->itemData
) ? (UInt32
)CFDataGetLength(itemParams
->itemData
) : 0, 
5197                         (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
, 
5198                         itemParams
->keychain
, 
5201                 require_noerr(status
, error_exit
); 
5203                 // return results (if requested) 
5205                         itemParams
->maxMatches 
= 1; // in case kSecMatchLimit was set to > 1 
5206                         tmpStatus 
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5207                         if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5213                 // add multiple items which are specified in the itemParams->useItems array. 
5214                 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain. 
5215                 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain. 
5216                 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain. 
5218                 OSStatus aggregateStatus 
= errSecSuccess
; 
5219                 CFIndex ix
, count 
= CFArrayGetCount(itemParams
->useItems
); 
5220                 itemParams
->maxMatches 
= (count 
> 1) ? (int)count 
: 2; // force results to always be returned as an array 
5221                 for (ix
=0; ix 
< count
; ix
++) { 
5222                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
); 
5224                                 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) { 
5225                                         // SecCertificateRef item 
5226                                         tmpStatus 
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
); 
5227                                         if (!tmpStatus 
&& result
) { 
5228                                                 tmpStatus 
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5230                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5232                                 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) { 
5234                                         SecKeychainRef itemKeychain 
= NULL
; 
5235                                         tmpStatus 
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
); 
5236                                         if (tmpStatus 
== errSecSuccess
) { 
5237                                                 // key was in a keychain, so we can attempt to copy it 
5238                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5239                                                 tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5240                                                 if (!tmpStatus 
&& result
) { 
5241                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5244                                                         CFRelease(itemCopy
); 
5248                                                 // key was not in any keychain, so must be imported 
5249                                                 SecKeychainItemRef keyItem 
= NULL
; 
5250                                                 tmpStatus 
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
); 
5251                                                 if (!tmpStatus 
&& result
) { 
5252                                                         tmpStatus 
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5259                                                 CFRelease(itemKeychain
); 
5261                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5263                                 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) { 
5264                                         // SecKeychainItemRef item 
5265                                         SecKeychainItemRef itemCopy 
= NULL
; 
5266                                         tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5267                                         if (!tmpStatus 
&& result
) { 
5268                                                 tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5271                                                 CFRelease(itemCopy
); 
5273                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5275                                 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) { 
5276                                         // CFDataRef item (persistent reference) 
5277                                         SecKeychainItemRef realItem 
= NULL
; 
5278                                         tmpStatus 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
); 
5279                                         if (tmpStatus 
== errSecSuccess
) { 
5280                                                 // persistent reference resolved to a keychain item, so we can attempt to copy it 
5281                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5282                                                 tmpStatus 
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5283                                                 if (!tmpStatus 
&& result
) { 
5284                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5287                                                         CFRelease(itemCopy
); 
5291                                                 CFRelease(realItem
); 
5293                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5296                 } // end of itemList array loop 
5297                 status 
= aggregateStatus
; 
5298         } // end processing multiple items 
5301         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5305         _FreeSecItemParams(itemParams
); 
5312         CFDictionaryRef query
, 
5313         CFDictionaryRef attributesToUpdate
) 
5315         if (!query 
|| !attributesToUpdate
) 
5318         // run the provided query to get a list of items to update 
5319         CFTypeRef results 
= NULL
; 
5320         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5321         if (status 
!= errSecSuccess
) 
5322                 return status
; // nothing was matched, or the query was bad 
5324         CFArrayRef items 
= NULL
; 
5325         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5326                 items 
= (CFArrayRef
) results
; 
5329                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5333         OSStatus result 
= errSecSuccess
; 
5334         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5335         for (ix
=0; ix 
< count
; ix
++) { 
5336                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5338                         status 
= _UpdateKeychainItem(anItem
, attributesToUpdate
); 
5339                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
); 
5351         CFDictionaryRef query
) 
5356         // run the provided query to get a list of items to delete 
5357         CFTypeRef results 
= NULL
; 
5358         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5359         if (status 
!= errSecSuccess
) 
5360                 return status
; // nothing was matched, or the query was bad 
5362         CFArrayRef items 
= NULL
; 
5363         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5364                 items 
= (CFArrayRef
) results
; 
5367                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5371         OSStatus result 
= errSecSuccess
; 
5372         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5373         for (ix
=0; ix 
< count
; ix
++) { 
5374                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5376                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) { 
5377                                 status 
= _DeleteIdentity((SecIdentityRef
)anItem
); 
5380                                 status 
= _DeleteKeychainItem(anItem
); 
5382                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
);