2  * Copyright (c) 2006-2017 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 "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" 
  35 #include "SecItemPriv.h" 
  36 #include "SecIdentitySearchPriv.h" 
  37 #include "SecKeychainPriv.h" 
  38 #include "SecCertificatePriv.h" 
  39 #include "TrustAdditions.h" 
  40 #include "TrustSettingsSchema.h" 
  41 #include <Security/SecTrustPriv.h> 
  42 #include "utilities/array_size.h" 
  44 #include <AssertMacros.h> 
  48 #include <Security/SecTrustedApplication.h> 
  49 #include <Security/SecTrustedApplicationPriv.h> 
  50 #include <Security/SecCode.h> 
  51 #include <Security/SecCodePriv.h> 
  52 #include <Security/SecRequirement.h> 
  54 #include <login/SessionAgentCom.h> 
  55 #include <login/SessionAgentStatusCom.h> 
  56 #include <os/activity.h> 
  57 #include <CoreFoundation/CFPriv.h> 
  60 const uint8_t kUUIDStringLength 
= 36; 
  62 OSStatus 
SecItemAdd_osx(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  63 OSStatus 
SecItemCopyMatching_osx(CFDictionaryRef query
, CFTypeRef 
*result
); 
  64 OSStatus 
SecItemUpdate_osx(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  65 OSStatus 
SecItemDelete_osx(CFDictionaryRef query
); 
  68 OSStatus 
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  69 OSStatus 
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef 
*result
); 
  70 OSStatus 
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  71 OSStatus 
SecItemDelete_ios(CFDictionaryRef query
); 
  72 OSStatus 
SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
); 
  75 OSStatus 
SecItemValidateAppleApplicationGroupAccess(CFStringRef group
); 
  76 CFDictionaryRef 
SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
  77         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
); 
  79 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef 
*return_class
, 
  80                                 long long int *return_rowid
, CFDictionaryRef 
*return_token_attrs
); 
  83 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
); 
  84 static CFArrayRef 
_CopyMatchingIssuers(CFArrayRef issuers
); 
  86 static void secitemlog(int priority
, const char *format
, ...) 
  91         if (priority 
< LOG_NOTICE
) // log warnings and errors 
  95                 va_start(list
, format
); 
  96                 vsyslog(priority
, format
, list
); 
 101 static void secitemshow(CFTypeRef obj
, const char *context
) 
 104         CFStringRef desc 
= CFCopyDescription(obj
); 
 107         CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1; 
 108         char* buffer 
= (char*) malloc(length
); 
 110                 Boolean converted 
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
); 
 112                         const char *prefix 
= (context
) ? context 
: ""; 
 113                         const char *separator 
= (context
) ? " " : ""; 
 114                         secitemlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
); 
 123 #define CFDataGetBytePtrVoid CFDataGetBytePtr 
 125 #pragma mark SecItem private utility functions 
 127 /******************************************************************************/ 
 129 struct ProtocolAttributeInfo 
{ 
 130         const CFStringRef 
*protocolValue
; 
 131         SecProtocolType protocolType
; 
 134 static ProtocolAttributeInfo gProtocolTypes
[] = { 
 135         { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP 
}, 
 136         { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount 
}, 
 137         { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP 
}, 
 138         { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC 
}, 
 139         { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP 
}, 
 140         { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3 
}, 
 141         { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP 
}, 
 142         { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS 
}, 
 143         { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP 
}, 
 144         { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP 
}, 
 145         { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk 
}, 
 146         { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP 
}, 
 147         { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet 
}, 
 148         { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH 
}, 
 149         { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS 
}, 
 150         { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS 
}, 
 151         { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy 
}, 
 152         { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy 
}, 
 153         { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy 
}, 
 154         { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB 
}, 
 155         { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP 
}, 
 156         { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy 
}, 
 157         { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP 
}, 
 158         { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC 
}, 
 159         { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP 
}, 
 160         { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS 
}, 
 161         { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS 
}, 
 162         { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS 
}, 
 163         { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS 
}, 
 164         { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS 
}, 
 165         { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S 
} 
 168 static const int kNumberOfProtocolTypes 
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
); 
 171  * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType. 
 173 static SecProtocolType
 
 174 _SecProtocolTypeForSecAttrProtocol( 
 177         SecProtocolType result 
= kSecProtocolTypeAny
; 
 179         if (protocol 
!= NULL
) { 
 181                 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 182                         if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) { 
 183                                 result 
= gProtocolTypes
[count
].protocolType
; 
 193  * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol. 
 196 _SecAttrProtocolForSecProtocolType( 
 197         SecProtocolType protocolType
) 
 199         CFTypeRef result 
= NULL
; 
 201         for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 202                 if (gProtocolTypes
[count
].protocolType 
== protocolType
) { 
 203                         result 
= *(gProtocolTypes
[count
].protocolValue
); 
 212 /******************************************************************************/ 
 214 struct AuthenticationAttributeInfo 
{ 
 215         const CFStringRef 
*authValue
; 
 216         SecAuthenticationType authType
; 
 219 static AuthenticationAttributeInfo gAuthTypes
[] = { 
 220         { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM 
}, 
 221         { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN 
}, 
 222         { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA 
}, 
 223         { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA 
}, 
 224         { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic 
}, 
 225         { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest 
}, 
 226         { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm 
}, 
 227         { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault 
} 
 230 static const int kNumberOfAuthenticationTypes 
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
); 
 233  * _SecAuthenticationTypeForSecAttrAuthenticationType converts a 
 234  * SecAttrAuthenticationType to a SecAuthenticationType. 
 236 static SecAuthenticationType
 
 237 _SecAuthenticationTypeForSecAttrAuthenticationType( 
 238         CFTypeRef authenticationType
) 
 240         SecAuthenticationType result 
= kSecAuthenticationTypeAny
; 
 242         if (authenticationType 
!= NULL
) { 
 244                 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 245                         if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) { 
 246                                 result 
= gAuthTypes
[count
].authType
; 
 256  * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType 
 257  * to a SecAttrAuthenticationType. 
 260 _SecAttrAuthenticationTypeForSecAuthenticationType( 
 261         SecAuthenticationType authenticationType
) 
 263         CFTypeRef result 
= NULL
; 
 265         for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 266                 if (gAuthTypes
[count
].authType 
== authenticationType
) { 
 267                         result 
= *(gAuthTypes
[count
].authValue
); 
 276 /******************************************************************************/ 
 278 struct KeyAlgorithmInfo 
{ 
 279         const CFStringRef 
*keyType
; 
 283 static KeyAlgorithmInfo gKeyTypes
[] = { 
 284         { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA 
}, 
 285         { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA 
}, 
 286         { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES 
}, 
 287         { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES 
}, 
 288         { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES 
}, 
 289         { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4 
}, 
 290         { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2 
}, 
 291         { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST 
}, 
 292         { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA 
}, 
 293         { &kSecAttrKeyTypeEC
, CSSM_ALGID_ECDSA 
} 
 296 static const int kNumberOfKeyTypes 
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
); 
 299 static UInt32 
_SecAlgorithmTypeFromSecAttrKeyType( 
 300         CFTypeRef keyTypeRef
) 
 302         UInt32 keyAlgValue 
= 0; 
 303         if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
)) 
 307         for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) { 
 308                 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) { 
 309                         keyAlgValue 
= gKeyTypes
[ix
].keyValue
; 
 314         //%%%TODO try to convert the input string to a number here 
 320 enum ItemRepresentation
 
 322         kStringRepresentation
, 
 324         kNumberRepresentation
, 
 325         kBooleanRepresentation
, 
 330 struct InternalAttributeListInfo
 
 333         const CFStringRef 
*newItemType
; 
 334         ItemRepresentation itemRepresentation
; 
 338 static InternalAttributeListInfo gGenericPasswordAttributes
[] = 
 340         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 341         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 342         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 343         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 344         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 345         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 346         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 347         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 348         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 349         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 350         { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation 
}, 
 351         { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation 
} 
 354 static const int kNumberOfGenericPasswordAttributes 
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 357 static InternalAttributeListInfo gInternetPasswordAttributes
[] = 
 359         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 360         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 361         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 362         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 363         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 364         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 365         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 366         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 367         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 368         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 369         { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation 
}, 
 370         { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation 
}, 
 371         { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation 
}, // maps from UInt32 value to string constant 
 372         { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation 
}, 
 373         { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation 
} 
 376 static const int kNumberOfInternetPasswordAttributes 
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 379 static InternalAttributeListInfo gCertificateAttributes
[] = 
 381         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 382         { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation 
}, 
 383         { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation 
}, 
 384         { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation 
}, 
 385         { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation 
}, 
 386         { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation 
}, 
 387         { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation 
}, 
 388         { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation 
} 
 391 static const int kNumberOfCertificateAttributes 
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
); 
 394 static InternalAttributeListInfo gKeyAttributes
[] = 
 396     { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation 
}, // key class maps from UInt32 value to string constant 
 397     { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation 
}, // note that "print name" maps to the user-visible label 
 398 //  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation }, 
 399     { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation 
}, 
 400 //  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 401 //  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 402     { 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 
 403     { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation 
}, 
 404 //  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key 
 405     { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation 
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES) 
 406     { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation 
}, 
 407     { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation 
}, 
 408 //  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 409 //  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 410 //  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 411 //  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 412 //  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 413 //  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 414     { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation 
}, 
 415     { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation 
}, 
 416     { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation 
}, 
 417     { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation 
}, 
 418     { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation 
}, 
 419 //  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 420 //  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 421     { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation 
}, 
 422     { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation 
} 
 425 static const int kNumberOfKeyAttributes 
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
); 
 428 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
) 
 432                 case kStringRepresentation
: 
 434                         if (CFStringGetTypeID() != CFGetTypeID(value
)) { 
 438                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 439                         char* buffer 
= (char*) malloc(maxLength
); 
 440                         Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 442                                 length 
= (UInt32
)strlen(buffer
); 
 452                 case kDataRepresentation
: 
 454                         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 455                 // We may have a string here, since the key label may be a GUID for the symmetric keys 
 456                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 457                 char* buffer 
= (char*) malloc(maxLength
); 
 458                 Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 460                     length 
= (UInt32
)strlen(buffer
); 
 470                         if (CFDataGetTypeID() != CFGetTypeID(value
)) { 
 474                         length 
= (UInt32
)CFDataGetLength((CFDataRef
) value
); 
 475                         uint8_t* buffer 
= (uint8_t*) malloc(length
); 
 476                         CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
); 
 480                 case kNumberRepresentation
: 
 482                         if (CFNumberGetTypeID() != CFGetTypeID(value
)) { 
 486                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 487                         Boolean converted 
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
); 
 489                                 length 
= sizeof(uint32_t); 
 499                 case kBooleanRepresentation
: 
 501                         if (CFBooleanGetTypeID() != CFGetTypeID(value
)) { 
 505                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 506                         *buffer 
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
 507                         length 
= sizeof(uint32_t); 
 511                 case kDateRepresentation
: 
 513                         if (CFDateGetTypeID() != CFGetTypeID(value
)) { 
 517                         char* buffer 
= (char*) calloc(1, 32); // max length of a CSSM date string 
 518                         CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
); 
 519                         length 
= (UInt32
)strlen(buffer
); 
 533 _ConvertNewFormatToOldFormat( 
 534         CFAllocatorRef allocator
, 
 535         const InternalAttributeListInfo
* info
, 
 537         CFDictionaryRef dictionaryRef
, 
 538         SecKeychainAttributeList
* &attrList
 
 541         // get the keychain attributes array from the data item 
 542         // here's the problem.  On the one hand, we have a dictionary that is purported to contain 
 543         // attributes for our type.  On the other hand, the dictionary may contain items we don't support, 
 544         // and we therefore don't know how many attributes we will have unless we count them first 
 547         attrList 
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
)); 
 549         // make storage to extract the dictionary items 
 550         CFIndex itemsInDictionary 
= CFDictionaryGetCount(dictionaryRef
); 
 551         std::vector
<CFTypeRef
> keys(itemsInDictionary
); 
 552         std::vector
<CFTypeRef
> values(itemsInDictionary
); 
 554         CFDictionaryGetKeysAndValues(dictionaryRef
, keys
.data(), values
.data()); 
 556         // count the number of items we are interested in 
 560         // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that 
 561         // we don't pay the price for this twice 
 562         std::vector
<SecKeychainAttrType
> tags(itemsInDictionary
); 
 563         std::vector
<ItemRepresentation
> types(itemsInDictionary
); 
 565         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 567                 CFTypeRef key 
= keys
[i
]; 
 570                 for (j 
= 0; j 
< infoNumItems
; ++j
) 
 572                         if (CFEqual(*(info
[j
].newItemType
), key
)) 
 574                                 tags
[i
] = info
[j
].oldItemType
; 
 575                                 types
[i
] = info
[j
].itemRepresentation
; 
 581                 if (j 
>= infoNumItems
) 
 583                         // if we got here, we aren't interested in this item. 
 588         // now we can make the result array 
 589         attrList
->count 
= (UInt32
)count
; 
 590     attrList
->attr 
= (count 
> 0) ? (SecKeychainAttribute
*) malloc(sizeof(SecKeychainAttribute
) * count
) : NULL
; 
 592         // fill out the array 
 593         int resultPointer 
= 0; 
 594         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 596                 if (values
[i
] != NULL
) 
 598                         attrList
->attr
[resultPointer
].tag 
= tags
[i
]; 
 600                         // we have to clone the data pointer.  The caller will need to make sure to throw these away 
 601                         // with _FreeAttrList when it is done... 
 602                         attrList
->attr
[resultPointer
].data 
= CloneDataByType(types
[i
], values
[i
], attrList
->attr
[resultPointer
].length
); 
 607         return errSecSuccess
; 
 613 _ConvertOldFormatToNewFormat( 
 614         CFAllocatorRef allocator
, 
 615         const InternalAttributeListInfo
* info
, 
 617         SecKeychainItemRef itemRef
, 
 618         CFMutableDictionaryRef
& dictionaryRef
) 
 620         SecKeychainAttributeList list
; 
 621         list
.count 
= infoNumItems
; 
 622         list
.attr 
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
)); 
 624         // fill out the array.  We only need to fill in the tags, since calloc zeros what it returns 
 626         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 628                 list
.attr
[i
].tag 
= info
[i
].oldItemType
; 
 631         OSStatus result 
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
); 
 632         if (result 
!= errSecSuccess
) 
 634                 dictionaryRef 
= NULL
; 
 639         // create the dictionary 
 640         dictionaryRef 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 643         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 645                 if (list
.attr
[i
].data 
== NULL
) 
 648                 switch (info
[i
].itemRepresentation
) 
 650                         case kStringRepresentation
: 
 652                                 CFStringRef stringRef
; 
 653                                 if (info
[i
].oldItemType 
== kSecKeyKeyClass
) { 
 654                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 655                                         uint32_t keyRecordValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 656                                         bool retainString 
= true; 
 657                                         switch (keyRecordValue
) { 
 658                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 659                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 661                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 662                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 664                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 665                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 668                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
); 
 669                             retainString 
= false; 
 673                                                 if (retainString
) CFRetain(stringRef
); 
 674                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 675                                                 CFRelease(stringRef
); 
 678                                 else if (info
[i
].oldItemType 
== kSecKeyKeyType
) { 
 679                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 680                                         uint32_t keyAlgValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 681                                         bool retainString 
= true; 
 682                                         switch (keyAlgValue
) { 
 683                                                 case CSSM_ALGID_RSA 
: 
 684                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 686                                                 case CSSM_ALGID_DSA 
: 
 687                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 689                                                 case CSSM_ALGID_AES 
: 
 690                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 692                                                 case CSSM_ALGID_DES 
: 
 693                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 695                                                 case CSSM_ALGID_3DES 
: 
 696                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 698                                                 case CSSM_ALGID_RC4 
: 
 699                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 701                                                 case CSSM_ALGID_RC2 
: 
 702                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 704                                                 case CSSM_ALGID_CAST 
: 
 705                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 707                                                 case CSSM_ALGID_ECDSA 
: 
 708                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 711                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
); 
 712                                                         retainString 
= false; 
 716                                                 if (retainString
) CFRetain(stringRef
); 
 717                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 718                                                 CFRelease(stringRef
); 
 722                                         // normal case: attribute contains a string 
 723                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 724                                         if (stringRef 
== NULL
) 
 725                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 726                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 727                                         CFRelease(stringRef
); 
 732                         case kDataRepresentation
: 
 734                 if ((info
[i
].oldItemType 
== kSecKeyLabel
) && (list
.attr
[i
].length 
== kUUIDStringLength
)) { 
 735                                         // It's possible that there could be a string here because the key label may have a UUID 
 736                                         CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 737                                         if (stringRef 
== NULL
) 
 738                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 739                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 740                                         CFRelease(stringRef
); 
 743                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
); 
 745                     dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
 746                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
); 
 751                         case kNumberRepresentation
: 
 753                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
); 
 754                                 if (numberRef 
== NULL
) 
 755                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
 756                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
); 
 757                                 CFRelease(numberRef
); 
 761                         case kBooleanRepresentation
: 
 763                                 uint32_t value 
= *((uint32_t*)list
.attr
[i
].data
); 
 764                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
 765                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
); 
 769                         case kDateRepresentation
: 
 771                                 CFDateRef dateRef 
= NULL
; 
 772                                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
); 
 774                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
 775                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
); 
 783         SecKeychainItemFreeContent(&list
, NULL
); 
 793  * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the 
 794  * attributes of item. 
 797 _CreateAttributesDictionaryFromGenericPasswordItem( 
 798         CFAllocatorRef allocator
, 
 799         SecKeychainItemRef item
, 
 800         CFDictionaryRef 
*dictionary
) 
 802         // do the basic allocations 
 803         CFMutableDictionaryRef dict 
= NULL
; 
 804         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
); 
 805         if (result 
== errSecSuccess
) // did we complete OK 
 807                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
); 
 818  * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the 
 819  * attributes of item. 
 822 _CreateAttributesDictionaryFromCertificateItem( 
 823         CFAllocatorRef allocator
, 
 824         SecKeychainItemRef item
, 
 825         CFDictionaryRef 
*dictionary
) 
 827         // do the basic allocations 
 828         CFMutableDictionaryRef dict 
= NULL
; 
 829         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
); 
 830         if (result 
== errSecSuccess
) // did we complete OK 
 832                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
); 
 837         return errSecSuccess
; 
 841  * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the 
 842  * attributes of item. 
 845 _CreateAttributesDictionaryFromKeyItem( 
 846         CFAllocatorRef allocator
, 
 847         SecKeychainItemRef item
, 
 848         CFDictionaryRef 
*dictionary
) 
 851 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails. 
 852 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and 
 853 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent. 
 856                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 859         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 861         // do the basic allocations 
 862         CFMutableDictionaryRef dict 
= NULL
; 
 863         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
); 
 864         if (result 
== errSecSuccess
) // did we complete OK 
 866                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
 871         return errSecSuccess
; 
 874         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 876         SecItemClass itemClass 
= (SecItemClass
) 0; 
 878         SecKeychainAttributeList 
*attrList 
= NULL
; 
 879         SecKeychainAttributeInfo 
*info 
= NULL
; 
 880         SecKeychainRef keychain 
= NULL
; 
 882         OSStatus status 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
 884                 goto error_exit
; // item must have an itemClass 
 889     case kSecInternetPasswordItemClass
: 
 890                 itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
 892     case kSecGenericPasswordItemClass
: 
 893                 itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
 895     case 'ashp': /* kSecAppleSharePasswordItemClass */ 
 896                 itemID 
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
; 
 903         status 
= SecKeychainItemCopyKeychain(item
, &keychain
); 
 905                 goto error_exit
; // item must have a keychain, so we can get the attribute info for it 
 908         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
 910                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 913         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 915                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 918         for (ix 
= 0; ix 
< info
->count
; ++ix
) 
 920                 SecKeychainAttribute 
*attribute 
= &attrList
->attr
[ix
]; 
 921                 if (!attribute
->length 
&& !attribute
->data
) 
 924                 UInt32 j
, count 
= kNumberOfKeyAttributes
; 
 925                 InternalAttributeListInfo 
*intInfo 
= NULL
; 
 926                 for (j
=0; j
<count
; j
++) { 
 927                         if (gKeyAttributes
[j
].oldItemType 
== info
->tag
[ix
]) { 
 928                                 intInfo 
= &gKeyAttributes
[j
]; 
 935                 switch (intInfo
->itemRepresentation
) 
 937                         case kStringRepresentation
: 
 939                                 CFStringRef stringRef
; 
 940                                 if (intInfo
->oldItemType 
== kSecKeyKeyClass
) { 
 941                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 942                                         UInt32 keyRecordValue 
= *((UInt32
*)attribute
->data
); 
 943                                         bool retainString 
= true; 
 944                                         switch (keyRecordValue
) { 
 945                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 946                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 948                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 949                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 951                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 952                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 955                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyRecordValue
); 
 956                             retainString 
= false; 
 960                                                 if (retainString
) CFRetain(stringRef
); 
 961                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 962                                                 CFRelease(stringRef
); 
 965                                 else if (intInfo
->oldItemType 
== kSecKeyKeyType
) { 
 966                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 967                                         UInt32 keyAlgValue 
= *((UInt32
*)attribute
->data
); 
 968                                         bool retainString 
= true; 
 969                                         switch (keyAlgValue
) { 
 970                                                 case CSSM_ALGID_RSA 
: 
 971                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 973                                                 case CSSM_ALGID_DSA 
: 
 974                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 976                                                 case CSSM_ALGID_AES 
: 
 977                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 979                                                 case CSSM_ALGID_DES 
: 
 980                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 982                                                 case CSSM_ALGID_3DES 
: 
 983                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 985                                                 case CSSM_ALGID_RC4 
: 
 986                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 988                                                 case CSSM_ALGID_RC2 
: 
 989                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 991                                                 case CSSM_ALGID_CAST 
: 
 992                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 994                                                 case CSSM_ALGID_ECDSA 
: 
 995                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 998                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyAlgValue
); 
 999                                                         retainString 
= false; 
1003                                                 if (retainString
) CFRetain(stringRef
); 
1004                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1005                                                 CFRelease(stringRef
); 
1009                                         // normal case: attribute contains a string 
1010                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1011                                         if (stringRef 
== NULL
) 
1012                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1013                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1014                                         CFRelease(stringRef
); 
1019                         case kDataRepresentation
: 
1021                 if ((intInfo
->oldItemType 
== kSecKeyLabel
) && (attribute
->length 
== kUUIDStringLength
)) { 
1022                                         // It's possible that there could be a string here because the key label may have a UUID 
1023                     CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1024                                         if (stringRef 
== NULL
) 
1025                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1026                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1027                                         CFRelease(stringRef
); 
1031                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
); 
1032                                 if (dataRef 
== NULL
) 
1033                                         dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
1034                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
); 
1039                         case kNumberRepresentation
: 
1041                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
); 
1042                                 if (numberRef 
== NULL
) 
1043                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
1044                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
); 
1045                                 CFRelease(numberRef
); 
1049                         case kBooleanRepresentation
: 
1051                                 UInt32 value 
= *((UInt32
*)attribute
->data
); 
1052                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1053                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
); 
1057                         case kDateRepresentation
: 
1059                                 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here 
1060                                 CFDateRef dateRef 
= NULL
; 
1061                                 if (dateRef 
== NULL
) 
1062                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
1063                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
); 
1070         CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
1075                 SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
1078                 SecKeychainFreeAttributeInfo(info
); 
1081                 CFRelease(keychain
); 
1090  * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the 
1091  * attributes of item. 
1094 _CreateAttributesDictionaryFromInternetPasswordItem( 
1095         CFAllocatorRef allocator
, 
1096         SecKeychainItemRef item
, 
1097         CFDictionaryRef 
*dictionary
) 
1100         SecKeychainAttribute attr
[] = { 
1101                 { kSecServerItemAttr
, 0, NULL 
},                /* [0] server */ 
1102                 { kSecSecurityDomainItemAttr
, 0, NULL 
},        /* [1] securityDomain */ 
1103                 { kSecAccountItemAttr
, 0, NULL 
},               /* [2] account */ 
1104                 { kSecPathItemAttr
, 0, NULL 
},                  /* [3] path */ 
1105                 { kSecPortItemAttr
, 0, NULL 
},                  /* [4] port */ 
1106                 { kSecProtocolItemAttr
, 0, NULL 
},              /* [5] protocol */ 
1107                 { kSecAuthenticationTypeItemAttr
, 0, NULL 
},    /* [6] authenticationType */ 
1108                 { kSecCommentItemAttr
, 0, NULL 
},               /* [7] comment */ 
1109                 { kSecDescriptionItemAttr
, 0, NULL 
},           /* [8] description */ 
1110                 { kSecLabelItemAttr
, 0, NULL 
},                 /* [9] label */ 
1111                 { kSecCreationDateItemAttr
, 0, NULL 
},  /* [10] creation date */ 
1112                 { kSecModDateItemAttr
, 0, NULL 
},               /* [11] modification date */ 
1113                 { kSecCreatorItemAttr
, 0, NULL 
},               /* [12] creator */ 
1114                 { kSecTypeItemAttr
, 0, NULL 
},                  /* [13] type */ 
1115                 { kSecInvisibleItemAttr
, 0, NULL 
},             /* [14] invisible */ 
1116                 { kSecNegativeItemAttr
, 0, NULL 
},              /* [15] negative */ 
1118         SecKeychainAttributeList attrList 
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr 
}; 
1121         CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1122         CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1126         // copy the item's attributes 
1127         status 
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
); 
1128         require_noerr(status
, SecKeychainItemCopyContent_failed
); 
1133         keys
[numValues
] = kSecClass
; 
1134         values
[numValues
] = kSecClassInternetPassword
; 
1137         // add kSecAttrServer 
1138         if ( attrList
.attr
[0].length 
> 0 ) { 
1139                 keys
[numValues
] = kSecAttrServer
; 
1140                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
); 
1141                 if ( values
[numValues
] != NULL 
) { 
1146         // add kSecAttrSecurityDomain 
1147         if ( attrList
.attr
[1].length 
> 0 ) { 
1148                 keys
[numValues
] = kSecAttrSecurityDomain
; 
1149                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
); 
1150                 if ( values
[numValues
] != NULL 
) { 
1155         // add kSecAttrAccount 
1156         if ( attrList
.attr
[2].length 
> 0 ) { 
1157                 keys
[numValues
] = kSecAttrAccount
; 
1158                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
); 
1159                 if ( values
[numValues
] != NULL 
) { 
1165         if ( attrList
.attr
[3].length 
> 0 ) { 
1166                 keys
[numValues
] = kSecAttrPath
; 
1167                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
); 
1168                 if ( values
[numValues
] != NULL 
) { 
1174         if ( attrList
.attr
[4].length 
> 0 ) { 
1175                 keys
[numValues
] = kSecAttrPort
; 
1176                 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
); 
1177                 if ( values
[numValues
] != NULL 
) { 
1182         // add kSecAttrProtocol 
1183         if ( attrList
.attr
[5].length 
> 0 ) { 
1184                 keys
[numValues
] = kSecAttrProtocol
; 
1185                 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
); 
1186                 if ( values
[numValues
] != NULL 
) { 
1187                         CFRetain(values
[numValues
]); 
1192         // add kSecAttrAuthenticationType 
1193         if ( attrList
.attr
[6].length 
> 0 ) { 
1194                 keys
[numValues
] = kSecAttrAuthenticationType
; 
1195                 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType( (SecAuthenticationType
) (*(SecProtocolType
*)attrList
.attr
[6].data
)); 
1196                 if ( values
[numValues
] != NULL 
) { 
1197                         CFRetain(values
[numValues
]); 
1202         // add kSecAttrComment 
1203         if ( attrList
.attr
[7].length 
> 0 ) { 
1204                 keys
[numValues
] = kSecAttrComment
; 
1205                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
); 
1206                 if ( values
[numValues
] != NULL 
) { 
1211         // add kSecAttrDescription 
1212         if ( attrList
.attr
[8].length 
> 0 ) { 
1213                 keys
[numValues
] = kSecAttrDescription
; 
1214                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
); 
1215                 if ( values
[numValues
] != NULL 
) { 
1220         // add kSecAttrLabel 
1221         if ( attrList
.attr
[9].length 
> 0 ) { 
1222                 keys
[numValues
] = kSecAttrLabel
; 
1223                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
); 
1224                 if ( values
[numValues
] != NULL 
) { 
1229         // add kSecAttrCreationDate 
1230         if ( attrList
.attr
[10].length 
> 0 ) { 
1231                 CFDateRef creationDate 
= NULL
; 
1232                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
); 
1233                 keys
[numValues
] = kSecAttrCreationDate
; 
1234                 values
[numValues
] = creationDate
; 
1235                 if ( values
[numValues
] != NULL 
) { 
1240         // add kSecAttrModificationDate 
1241         if ( attrList
.attr
[11].length 
> 0 ) { 
1242                 CFDateRef modDate 
= NULL
; 
1243                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
); 
1244                 keys
[numValues
] = kSecAttrModificationDate
; 
1245                 values
[numValues
] = modDate
; 
1246                 if ( values
[numValues
] != NULL 
) { 
1251         // add kSecCreatorItemAttr 
1252         if ( attrList
.attr
[12].length 
> 0 ) { 
1253                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
); 
1254                 keys
[numValues
] = kSecAttrCreator
; 
1255                 values
[numValues
] = numberRef
; 
1256                 if ( values
[numValues
] != NULL 
) { 
1257                         CFRetain(values
[numValues
]); 
1262         // add kSecTypeItemAttr 
1263         if ( attrList
.attr
[13].length 
> 0 ) { 
1264                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
); 
1265                 keys
[numValues
] = kSecAttrType
; 
1266                 values
[numValues
] = numberRef
; 
1267                 if ( values
[numValues
] != NULL 
) { 
1268                         CFRetain(values
[numValues
]); 
1273         // add kSecInvisibleItemAttr 
1274         if ( attrList
.attr
[14].length 
> 0 ) { 
1275                 uint32_t value 
= *((uint32_t*)attrList
.attr
[14].data
); 
1276                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1277                 keys
[numValues
] = kSecAttrIsInvisible
; 
1278                 values
[numValues
] = boolRef
; 
1279                 if ( values
[numValues
] != NULL 
) { 
1280                         CFRetain(values
[numValues
]); 
1285         // add kSecNegativeItemAttr 
1286         if ( attrList
.attr
[15].length 
> 0 ) { 
1287                 uint32_t value 
= *((uint32_t*)attrList
.attr
[15].data
); 
1288                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1289                 keys
[numValues
] = kSecAttrIsNegative
; 
1290                 values
[numValues
] = boolRef
; 
1291                 if ( values
[numValues
] != NULL 
) { 
1292                         CFRetain(values
[numValues
]); 
1297         // create the dictionary 
1298         *dictionary 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1300         // release the values added to the dictionary 
1301         for ( index 
= 0; index 
< numValues
; ++index 
) 
1303                 CFRelease(values
[index
]); 
1306         // and free the attributes 
1307         (void) SecKeychainItemFreeContent(&attrList
, NULL
); 
1309 SecKeychainItemCopyContent_failed
: 
1316  * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the 
1317  * attributes of the specified item class and item. 
1320 _CreateAttributesDictionaryFromItem( 
1321         CFAllocatorRef allocator
, 
1322         SecItemClass itemClass
, 
1323         SecKeychainItemRef item
, 
1324         CFDictionaryRef 
*dictionary
) 
1328                 case kSecInternetPasswordItemClass
: 
1329                         return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
); 
1331                 case kSecGenericPasswordItemClass
: 
1332                         return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
); 
1334                 case kSecCertificateItemClass
: 
1335                         return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
); 
1337                 case kSecPublicKeyItemClass
: 
1338                 case kSecPrivateKeyItemClass
: 
1339                 case kSecSymmetricKeyItemClass
: 
1340                         return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
); 
1351  * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList 
1352  * by the _CreateSecKeychainAttributeListFromDictionary function. 
1356         SecKeychainAttributeList 
*attrListPtr
) 
1360         if ( attrListPtr 
!= NULL 
) { 
1361                 if ( attrListPtr
->attr 
!= NULL 
) { 
1362                         // free any attribute data 
1363                         for ( index 
= 0; index 
< attrListPtr
->count
; ++index 
) { 
1364                                 free(attrListPtr
->attr
[index
].data
); 
1366                         // free the attribute array 
1367                         free(attrListPtr
->attr
); 
1369                 // free the attribute list 
1375  * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by 
1376  * attr using the data and tag parameters. 
1378  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1379  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1382 _CFDataCreateAttribute( 
1384         SecKeychainAttrType tag
, 
1385         SecKeychainAttributePtr attr
) 
1387         OSStatus status 
= errSecSuccess
; 
1390         // set the attribute tag 
1393         // determine the attribute length 
1394         attr
->length 
= (UInt32
) CFDataGetLength(data
); 
1395         range 
= CFRangeMake(0, (CFIndex
)attr
->length
); 
1397         // allocate memory for the attribute bytes 
1398         attr
->data 
= malloc(attr
->length
); 
1399         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1401         // get the attribute bytes 
1402         CFDataGetBytes(data
, range
, (UInt8 
*)attr
->data
); 
1410  * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by 
1411  * attr using the string and tag parameters. 
1413  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1414  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1417 _CFStringCreateAttribute( 
1419         SecKeychainAttrType tag
, 
1420         SecKeychainAttributePtr attr
) 
1422         OSStatus status 
= errSecSuccess
; 
1425         // set the attribute tag 
1428         // determine the attribute length 
1429         range 
= CFRangeMake(0, CFStringGetLength(string
)); 
1430         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex 
*)&attr
->length
); 
1432         // allocate memory for the attribute bytes 
1433         attr
->data 
= malloc(attr
->length
); 
1434         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1436         // get the attribute bytes 
1437         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8 
*)attr
->data
, attr
->length
, NULL
); 
1446  * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1447  * from the attribute key/values in attrDictionary. 
1449  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1450  * must be freed by the caller with _FreeAttrList() 
1453 _CreateSecKeychainGenericPasswordAttributeListFromDictionary( 
1454         CFDictionaryRef attrDictionary
, 
1455         SecKeychainAttributeList 
**attrList
) 
1457         return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
); 
1462  * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList 
1463  * from the attribute key/values in attrDictionary. 
1465  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1466  * must be freed by the caller with _FreeAttrList() 
1469 _CreateSecKeychainCertificateAttributeListFromDictionary( 
1470         CFDictionaryRef attrDictionary
, 
1471         SecKeychainAttributeList 
**attrList
) 
1473         return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
); 
1478  * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList 
1479  * from the attribute key/values in attrDictionary. 
1481  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1482  * must be freed by the caller with _FreeAttrList() 
1485 _CreateSecKeychainKeyAttributeListFromDictionary( 
1486         CFDictionaryRef attrDictionary
, 
1487         SecKeychainAttributeList 
**attrList
) 
1490         //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug 
1491         return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
); 
1493         // explicitly build attribute list for supported key attributes 
1494         // NOTE: this code supports only MaxSecKeyAttributes (15) attributes 
1495         const int MaxSecKeyAttributes 
= 15; 
1499         SecKeychainAttributeList 
*attrListPtr
; 
1501         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1502         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1504         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
)); 
1505         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1507         // [0] get the kSecKeyKeyClass value 
1508         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) { 
1509                 UInt32 keyRecordValue 
= 0; 
1510                 if (CFEqual(kSecAttrKeyClassPublic
, value
)) 
1511                         keyRecordValue 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
1512                 else if (CFEqual(kSecAttrKeyClassPrivate
, value
)) 
1513                         keyRecordValue 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
1514                 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
)) 
1515                         keyRecordValue 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
1517                 // only use this attribute if we recognize the value! 
1518                 if (keyRecordValue 
!= 0) { 
1519                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1520                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1522                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyClass
; 
1523                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1524                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
; 
1526                         ++attrListPtr
->count
; 
1530         // [1] get the kSecKeyPrintName string 
1531         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) { 
1532                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1533                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1535                 ++attrListPtr
->count
; 
1538         // [2] get the kSecKeyPermanent boolean 
1539         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) { 
1540                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1541                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1543                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyPermanent
; 
1544                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1545                 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1547                 ++attrListPtr
->count
; 
1550         // [3] get the kSecKeyLabel string 
1551         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) { 
1552         if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1553             status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1554         else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1555             status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1557             status 
= errSecParam
; 
1559                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1561                 ++attrListPtr
->count
; 
1564         // [4] get the kSecKeyApplicationTag data 
1565         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) { 
1566                 if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1567                         status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1568                 else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1569                         status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1571                         status 
= errSecParam
; 
1573                 require_noerr_quiet(status
, CFDataCreateAttribute_failed
); 
1574                 ++attrListPtr
->count
; 
1577         // [5] get the kSecKeyKeyType number 
1578         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) { 
1579                 UInt32 keyAlgValue 
= _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType
); 
1580                 if (keyAlgValue 
!= 0) { 
1581                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1582                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1584                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyType
; 
1585                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1586                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
; 
1588                         ++attrListPtr
->count
; 
1592         // [6] get the kSecKeyKeySizeInBits number 
1593         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) { 
1594                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1595                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1596                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1598                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeySizeInBits
; 
1599                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1600                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1602                         ++attrListPtr
->count
; 
1606         // [7] get the kSecKeyEffectiveKeySize number 
1607         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) { 
1608                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1609                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1610                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1612                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEffectiveKeySize
; 
1613                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1614                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1616                         ++attrListPtr
->count
; 
1620         // [8] get the kSecKeyEncrypt boolean 
1621         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) { 
1622                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1623                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1624                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1626                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEncrypt
; 
1627                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1628                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1630                         ++attrListPtr
->count
; 
1634         // [9] get the kSecKeyDecrypt boolean 
1635         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) { 
1636                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1637                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1638                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1640                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDecrypt
; 
1641                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1642                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1644                         ++attrListPtr
->count
; 
1648         // [10] get the kSecKeyDerive boolean 
1649         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) { 
1650                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1651                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1652                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1654                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDerive
; 
1655                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1656                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1658                         ++attrListPtr
->count
; 
1662         // [11] get the kSecKeySign boolean 
1663         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) { 
1664                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1665                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1666                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1668                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeySign
; 
1669                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1670                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1672                         ++attrListPtr
->count
; 
1676         // [12] get the kSecKeyVerify boolean 
1677         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) { 
1678                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1679                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1680                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1682                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyVerify
; 
1683                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1684                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1686                         ++attrListPtr
->count
; 
1690         // [13] get the kSecKeyWrap boolean 
1691         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) { 
1692                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1693                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1694                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1696                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyWrap
; 
1697                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1698                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1700                         ++attrListPtr
->count
; 
1704         // [14] get the kSecKeyUnwrap boolean 
1705         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) { 
1706                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1707                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1708                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1710                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyUnwrap
; 
1711                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1712                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1714                         ++attrListPtr
->count
; 
1718         // return the pointer to the attrList 
1719         *attrList 
= attrListPtr
; 
1721         return ( errSecSuccess 
); 
1725 malloc_number_failed
: 
1726 CFDataCreateAttribute_failed
: 
1727 CFStringCreateAttribute_failed
: 
1728 malloc_attrPtr_failed
: 
1730         // free any attributes 
1731         _FreeAttrList(attrListPtr
); 
1733 calloc_attrListPtr_failed
: 
1735         return ( errSecBufferTooSmall 
); 
1740 static CFTypeRef 
copyNumber(CFTypeRef obj
) 
1745     CFTypeID tid 
= CFGetTypeID(obj
); 
1746     if (tid 
== CFNumberGetTypeID()) 
1752     if (tid 
== CFBooleanGetTypeID()) 
1754         SInt32 value 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
1755         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1758     if (tid 
== CFStringGetTypeID()) 
1760         SInt32 value 
= CFStringGetIntValue((CFStringRef
)obj
); 
1761         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value
); 
1762         /* If a string converted to an int isn't equal to the int printed as 
1763          a string, return a NULL instead. */ 
1764         if (!CFEqual(t
, obj
)) 
1770         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1776  * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1777  * from the attribute key/values in attrDictionary. 
1779  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1780  * must be freed by the caller with _FreeAttrList() 
1783 _CreateSecKeychainInternetPasswordAttributeListFromDictionary( 
1784         CFDictionaryRef attrDictionary
, 
1785         SecKeychainAttributeList 
**attrList
) 
1787         // explicitly build attribute list for supported key attributes 
1788         // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes 
1789         const int MaxSecKeychainAttributes 
= 14; 
1793         SecKeychainAttributeList 
*attrListPtr
; 
1795         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1796         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1798         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
)); 
1799         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1802         // [0] get the serverName string 
1803         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) { 
1804                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1805                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1807                 ++attrListPtr
->count
; 
1810         // [1] get the securityDomain string 
1811         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) { 
1812                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1813                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1815                 ++attrListPtr
->count
; 
1818         // [2] get the accountName string 
1819         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) { 
1820                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1821                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1823                 ++attrListPtr
->count
; 
1826         // [3] get the path string 
1827         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) { 
1828                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1829                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1831                 ++attrListPtr
->count
; 
1834         // [4] get the port number 
1835         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) { 
1836                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt16
)); 
1837                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1839         CFTypeRef num 
= copyNumber(value
); 
1840                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1841                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecPortItemAttr
; 
1842                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt16
); 
1843                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1846                 ++attrListPtr
->count
; 
1849         // [5] get the protocol 
1850         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) { 
1851                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecProtocolType
)); 
1852                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_protocol_failed
, status 
= errSecBufferTooSmall
); 
1854                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecProtocolItemAttr
; 
1855                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecProtocolType
); 
1856                 *(SecProtocolType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
); 
1858                 ++attrListPtr
->count
; 
1861         // [6] get the authenticationType 
1862         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) { 
1863                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecAuthenticationType
)); 
1864                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_authenticationType_failed
, status 
= errSecBufferTooSmall
); 
1866                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecAuthenticationTypeItemAttr
; 
1867                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecAuthenticationType
); 
1868                 *(SecAuthenticationType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
); 
1870                 ++attrListPtr
->count
; 
1873         // [7] get the comment string 
1874         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) { 
1875                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1876                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1878                 ++attrListPtr
->count
; 
1881         // [8] get the description string 
1882         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) { 
1883                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1884                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1886                 ++attrListPtr
->count
; 
1889         // [9] get the label string 
1890         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) { 
1891                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1892                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1894                 ++attrListPtr
->count
; 
1897         // [10] get the creator code 
1898         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) { 
1899                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1900                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1902         CFTypeRef num 
= copyNumber(value
); 
1903                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1904                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecCreatorItemAttr
; 
1905                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1906                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1909                 ++attrListPtr
->count
; 
1912         // [11] get the type code 
1913         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) { 
1914                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1915                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1917         CFTypeRef num 
= copyNumber(value
); 
1918                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1919                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecTypeItemAttr
; 
1920                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1921                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1924                 ++attrListPtr
->count
; 
1927         // [12] get the invisible flag 
1928         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) { 
1929                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1930                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1932                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecInvisibleItemAttr
; 
1933                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1934                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1936                 ++attrListPtr
->count
; 
1939         // [13] get the negative flag 
1940         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) { 
1941                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1942                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1944                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecNegativeItemAttr
; 
1945                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1946                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1948                 ++attrListPtr
->count
; 
1951         // return the pointer to the attrList 
1952         *attrList 
= attrListPtr
; 
1954         return ( errSecSuccess 
); 
1958 malloc_authenticationType_failed
: 
1959 malloc_protocol_failed
: 
1961 CFStringCreateAttribute_failed
: 
1962 malloc_attrPtr_failed
: 
1964         // free any attributes 
1965         _FreeAttrList(attrListPtr
); 
1967 calloc_attrListPtr_failed
: 
1969         return ( errSecBufferTooSmall 
); 
1974  * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList 
1975  * from the attribute key/values in attrDictionary for the specified item class. 
1977  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1978  * must be freed by the caller with _FreeAttrList() 
1981 _CreateSecKeychainAttributeListFromDictionary( 
1982         CFDictionaryRef attrDictionary
, 
1983         SecItemClass itemClass
, 
1984         SecKeychainAttributeList 
**attrList
) 
1988                 case kSecInternetPasswordItemClass
: 
1989                         return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1991                 case kSecGenericPasswordItemClass
: 
1992                         return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1994                 case kSecCertificateItemClass
: 
1995                         return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
); 
1997                 case kSecPublicKeyItemClass
: 
1998                 case kSecPrivateKeyItemClass
: 
1999                 case kSecSymmetricKeyItemClass
: 
2000                         return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
); 
2010  * _AppNameFromSecTrustedApplication attempts to pull the name of the 
2011  * application/tool from the SecTrustedApplicationRef. 
2013 static CFStringRef CF_RETURNS_RETAINED
 
2014 _AppNameFromSecTrustedApplication( 
2015         CFAllocatorRef alloc
, 
2016         SecTrustedApplicationRef appRef
) 
2020         CFDataRef appDataRef
; 
2024         // get the data for item's application/tool 
2025         status 
= SecTrustedApplicationCopyData(appRef
, &appDataRef
); 
2026         if ( status 
== errSecSuccess 
) { 
2029                 // convert it to a CFString potentially containing the path 
2030                 path 
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
); 
2031                 if ( path 
!= NULL 
) { 
2032                         // the path has to start with a "/" and cannot contain "://" 
2033                         if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location 
== kCFNotFound
) ) { 
2034                                 CFRange nameRange
, compRg
; 
2036                                 nameRange 
= CFRangeMake(0, CFStringGetLength(path
)); 
2038                                 // remove the trailing slashes (if any) 
2039                                 while ( (nameRange
.length 
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length 
- 1) == '/') ) { 
2040                                         nameRange
.length 
--; 
2043                                 if ( nameRange
.length 
> 0 ) { 
2044                                         // find last slash and adjust nameRange to be everything after it 
2045                                         if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) { 
2046                                                 nameRange
.length 
= nameRange
.location 
+ nameRange
.length 
- (compRg
.location 
+ 1); 
2047                                                 nameRange
.location 
= compRg
.location 
+ 1; 
2050                                         result 
= CFStringCreateWithSubstring(alloc
, path
, nameRange
); 
2055                 CFRelease(appDataRef
); 
2061 /* (This function really belongs in SecIdentity.cpp!) 
2063  * Returns the public key item corresponding to the identity, if it exists in 
2064  * the same keychain as the private key. Note that the public key might not 
2065  * exist in the same keychain (e.g. if the identity was imported via PKCS12), 
2066  * in which case it will not be found. 
2069 _SecIdentityCopyPublicKey( 
2070         SecIdentityRef identityRef
, 
2071         SecKeyRef 
*publicKeyRef
) 
2075         SecKeychainAttribute attr 
= { kSecKeyLabel
, 0, NULL 
}; 
2076         SecKeychainAttributeList attrList 
= { 1, &attr 
}; 
2077         SecKeychainAttributeList 
*keyAttrList 
= NULL
; 
2078         SecKeychainAttributeInfo 
*info 
= NULL
; 
2079         SecKeychainSearchRef search 
= NULL
; 
2080         SecKeychainRef keychain 
= NULL
; 
2081         SecKeychainItemRef privateKey 
= NULL
; 
2082         SecKeychainItemRef publicKey 
= NULL
; 
2084         status 
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef 
*)&privateKey
); 
2086                 goto error_exit
; // identity must have a private key 
2088         status 
= SecKeychainItemCopyKeychain(privateKey
, &keychain
); 
2090                 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it 
2092         status 
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
); 
2094                 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys 
2096         status 
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
); 
2098                 goto error_exit
; // unable to get the key label attribute for the private key 
2101         // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching 
2102         for (count 
= 0; count 
< keyAttrList
->count
; count
++) { 
2103                 if (keyAttrList
->attr
[count
].tag 
== kSecKeyLabel
) { 
2104                         attr
.length 
= keyAttrList
->attr
[count
].length
; 
2105                         attr
.data 
= keyAttrList
->attr
[count
].data
; 
2109         if (!attr
.length 
|| !attr
.data
) { 
2110                 status 
= errSecNoSuchAttr
; 
2111                 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel 
2113         status 
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
); 
2115                 goto error_exit
; // unable to create the search reference 
2117         status 
= SecKeychainSearchCopyNext(search
, &publicKey
); 
2119                 goto error_exit
; // unable to find the public key 
2123                 *publicKeyRef 
= (SecKeyRef
)publicKey
; 
2125                 CFRelease(publicKey
); 
2128         if (status 
!= errSecSuccess
) { 
2130                         *publicKeyRef 
= NULL
; 
2132                         CFRelease(publicKey
); 
2138                 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
); 
2141                 SecKeychainFreeAttributeInfo(info
); 
2144                 CFRelease(keychain
); 
2147                 CFRelease(privateKey
); 
2154  * Deletes a keychain item if the current application/tool is the only application/tool 
2155  * with decrypt access to that keychain item. If more than one application/tool 
2156  * has decrypt access to the keychain item, the item is left on the keychain. 
2158  * TBD: If more than one app/tool has access to the keychain item, we should remove 
2159  * the current app/tool's decrypt access. There's no easy way to do that with 
2160  * current keychain APIs without bringing up the security UI. 
2163 _SafeSecKeychainItemDelete( 
2164         SecKeychainItemRef itemRef
) 
2167         SecAccessRef access 
= NULL
; 
2168         CFArrayRef aclList 
= NULL
; 
2169         SecACLRef acl 
= NULL
; 
2170         CFArrayRef appList 
= NULL
; 
2171         CFStringRef description 
= NULL
; 
2172         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
2173         CFIndex idx
, count 
= 0; 
2174         SecTrustedApplicationRef currentAppRef 
= NULL
; 
2175         CFStringRef itemAppName 
= NULL
, currentAppName 
= NULL
; 
2177         SecItemClass itemClass 
= (SecItemClass
)0; 
2178         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2179         if (!(itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2180                 // only perform the access control safety check on deletion of password credentials; 
2181                 // if the item is of some other type, delete it normally. 
2182                 return SecKeychainItemDelete(itemRef
); 
2185         // skip access control checking for web form passwords: <rdar://10957301> 
2186         // This permits Safari to manage the removal of all web form passwords, 
2187         // regardless of whether they are shared by multiple applications. 
2188         if (itemClass 
== kSecInternetPasswordItemClass
) { 
2189                 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr 
}; 
2190                 SecKeychainAttributeInfo attrInfo 
= { 1, tags
, NULL 
}; 
2191                 SecKeychainAttributeList 
*attrs 
= NULL
; 
2192                 status 
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
); 
2193                 if (!status 
&& attrs
) { 
2194                         bool webFormPassword 
= (attrs
->attr
[0].length 
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4))); 
2195                         SecKeychainItemFreeAttributesAndData(attrs
, NULL
); 
2196                         if (webFormPassword
) { 
2197                                 return SecKeychainItemDelete(itemRef
); 
2202         // copy the access of the keychain item 
2203         status 
= SecKeychainItemCopyAccess(itemRef
, &access
); 
2204         require_noerr(status
, finish
); 
2205         require_quiet(access 
!= NULL
, finish
); 
2207         // copy the decrypt access control lists -- this is what has access to the keychain item 
2208         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
2209         require_noerr(status
, finish
); 
2210         require_quiet(aclList 
!= NULL
, finish
); 
2212         // get the access control list 
2213         acl 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
2214         require_quiet(acl 
!= NULL
, finish
); 
2216         // copy the application list, description, and CSSM prompt selector for a given access control list entry 
2217         status 
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
); 
2218         require_noerr(status
, finish
); 
2219         require_quiet(appList 
!= NULL
, finish
); 
2221         // does the calling application/tool have decrypt access to this item? 
2222         count 
= CFArrayGetCount(appList
); 
2223         for ( idx 
= 0; idx 
< count
; idx
++ ) { 
2224                 // get SecTrustedApplicationRef for this entry 
2225                 SecTrustedApplicationRef itemAppRef 
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, idx
); 
2226                 require_quiet(itemAppRef 
!= NULL
, finish
); 
2228                 // copy the name out 
2229                 CFReleaseSafe(itemAppName
); 
2230                 itemAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
); 
2231                 if (itemAppName 
== NULL
) { 
2233                          * If there is no app name, it's probably because it's not an appname 
2234                          * in the ACE but an entitlement/info.plist based rule instead; 
2235                          * just let the caller have it. */ 
2240                 // create SecTrustedApplicationRef for current application/tool 
2241                 CFReleaseNull(currentAppRef
); 
2242                 status 
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
); 
2243                 require_noerr(status
, finish
); 
2244                 require_quiet(currentAppRef 
!= NULL
, finish
); 
2246                 // copy the name out 
2247                 CFReleaseSafe(currentAppName
); 
2248                 currentAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
); 
2249                 require_quiet(currentAppName 
!= NULL
, finish
); 
2251                 // compare the names to see if we own the decrypt access 
2252                 // TBD: validation of membership in an application group 
2253                 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo 
) { 
2261         CFReleaseSafe(currentAppName
); 
2262         CFReleaseSafe(itemAppName
); 
2263         CFReleaseSafe(currentAppRef
); 
2264         CFReleaseSafe(description
); 
2265         CFReleaseSafe(appList
); 
2266         CFReleaseSafe(aclList
); 
2267         CFReleaseSafe(access
); 
2269         if ((count 
== 0) || (status 
== errSecVerifyFailed
)) { 
2270                 // no "owners" remain in the ACL list (or unable to get ACL) 
2271                 status 
= SecKeychainItemDelete(itemRef
); 
2273                 // caller is not the "owner" of the item 
2274                 status 
= errSecInvalidOwnerEdit
; 
2281 _ReplaceKeychainItem( 
2282         SecKeychainItemRef itemToUpdate
, 
2283         SecKeychainAttributeList 
*changeAttrList
, 
2288         SecItemClass itemClass
; 
2289         SecKeychainAttributeInfo 
*info 
= NULL
; 
2290         SecKeychainAttributeList 
*attrList 
= NULL
; 
2291         SecKeychainAttributeList newAttrList 
= { 0, NULL
}; 
2292         SecKeychainRef keychain 
= NULL
; 
2293         SecKeychainItemRef newItem 
= NULL
; 
2295         int priority 
= LOG_DEBUG
; 
2296         const char *format 
= "ReplaceKeychainItem (%d) error %d"; 
2298         // get existing item's keychain 
2299         status 
= SecKeychainItemCopyKeychain(itemToUpdate
, &keychain
); 
2300         if (status
) { secitemlog(priority
, format
, 1, (int)status
); } 
2301         require_noerr(status
, replace_failed
); 
2303         // get attribute info (i.e. database schema) for the item class 
2304         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2305         if (status
) { secitemlog(priority
, format
, 2, (int)status
); } 
2306         require_noerr(status
, replace_failed
); 
2310                 case kSecInternetPasswordItemClass
: 
2311                         itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
2313                 case kSecGenericPasswordItemClass
: 
2314                         itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
2320         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
2321         if (status
) { secitemlog(priority
, format
, 3, (int)status
); } 
2323         // get item's existing attributes (but not data!) 
2324         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
2325         if (status
) { secitemlog(priority
, format
, 4, (int)status
); } 
2326         require(attrList 
!= NULL
, replace_failed
); 
2328         // move aside the item by changing a primary attribute 
2329     // (currently only for passwords) 
2330         if (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
) { 
2331                 CFUUIDRef uuid 
= CFUUIDCreate(kCFAllocatorDefault
); 
2332                 CFStringRef uuidStr 
= (uuid
) ? CFUUIDCreateString(kCFAllocatorDefault
, uuid
) : CFSTR("MOVED"); 
2333                 CFReleaseSafe(uuid
); 
2335                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr
), kCFStringEncodingUTF8
) + 1; 
2336                         char* buffer 
= (char*) malloc(maxLength
); 
2338                                 if (CFStringGetCString(uuidStr
, buffer
, maxLength
, kCFStringEncodingUTF8
)) { 
2339                                         UInt32 length 
= (UInt32
)strlen(buffer
); 
2340                                         SecKeychainAttribute attrs
[] = { { kSecAccountItemAttr
, length
, (char*)buffer 
}, }; 
2341                                         SecKeychainAttributeList updateAttrList 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
2342                                         status 
= SecKeychainItemModifyAttributesAndData(itemToUpdate
, &updateAttrList
, 0, NULL
); 
2343                                         if (status
) { secitemlog(priority
, format
, 5, (int)status
); } 
2344                                         if (status 
== errSecVerifyFailed
) { 
2345                                                 // still unable to change attrs? delete unconditionally here 
2346                                                 status 
= SecKeychainItemDelete(itemToUpdate
); 
2347                                                 if (status
) { secitemlog(priority
, format
, 6, (int)status
); } 
2352                         CFReleaseSafe(uuidStr
); 
2355         require_noerr(status
, replace_failed
); 
2357         // make attribute list for new item (the data is still owned by attrList) 
2358         newAttrList
.count 
= attrList
->count
; 
2359         newAttrList
.attr 
= (SecKeychainAttribute 
*) malloc(sizeof(SecKeychainAttribute
) * attrList
->count
); 
2361         for (i
=0, newCount
=0; i 
< attrList
->count
; i
++) { 
2362                 if (attrList
->attr
[i
].length 
> 0) { 
2363                         newAttrList
.attr
[newCount
++] = attrList
->attr
[i
]; 
2366         newAttrList
.count 
= newCount
; 
2368         // create new item in the same keychain 
2369         status 
= SecKeychainItemCreateFromContent(itemClass
, &newAttrList
, 
2370                 (UInt32
)((itemData
) ? CFDataGetLength(itemData
) : 0), 
2371                 (const void *)((itemData
) ? CFDataGetBytePtr(itemData
) : NULL
), 
2372                 keychain
, NULL
, &newItem
); 
2373         if (status
) { secitemlog(priority
, format
, 7, (int)status
); } 
2374         require_noerr(status
, replace_failed
); 
2376         // delete the old item unconditionally once new item exists 
2377         status 
= SecKeychainItemDelete(itemToUpdate
); 
2379         // update the new item with changed attributes, if any 
2380         status 
= (changeAttrList
) ? SecKeychainItemModifyContent(newItem
, changeAttrList
, 0, NULL
) : errSecSuccess
; 
2381         if (status
) { secitemlog(priority
, format
, 8, (int)status
); } 
2382         if (status 
== errSecSuccess
) { 
2383                 // say the item already exists, because it does now. <rdar://19063674> 
2384                 status 
= errSecDuplicateItem
; 
2388         if (newAttrList
.attr
) { 
2389                 free(newAttrList
.attr
); 
2392         SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
2395         SecKeychainFreeAttributeInfo(info
); 
2397         CFReleaseSafe(newItem
); 
2398         CFReleaseSafe(keychain
); 
2404 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
) 
2406         // This function updates a single keychain item, which may be specified as 
2407         // a reference, persistent reference or attribute dictionary, with the 
2408         // attributes provided. 
2410         OSStatus status 
= errSecSuccess
; 
2415         SecItemClass itemClass 
= (SecItemClass
) 0; 
2416         SecAccessRef access 
= NULL
; 
2417         SecKeychainAttributeList 
*changeAttrList 
= NULL
; 
2418         SecKeychainItemRef itemToUpdate 
= NULL
; 
2419         CFDataRef theData 
= NULL
; 
2420         CFTypeID itemType 
= CFGetTypeID(item
); 
2422         // validate input item (must be convertible to a SecKeychainItemRef) 
2423         if (SecKeychainItemGetTypeID() == itemType 
|| 
2424                 SecCertificateGetTypeID() == itemType 
|| 
2425                 SecKeyGetTypeID() == itemType
) { 
2426                 // item is already a reference, retain it 
2427                 itemToUpdate 
= (SecKeychainItemRef
) CFRetain(item
); 
2429         else if (CFDataGetTypeID() == itemType
) { 
2430                 // item is a persistent reference, must convert it 
2431                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
); 
2433         else if (CFDictionaryGetTypeID() == itemType
) { 
2434                 // item is a dictionary 
2435                 CFTypeRef value 
= NULL
; 
2436                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2437                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2438                         itemToUpdate 
= (SecKeychainItemRef
) CFRetain(value
); 
2440                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2441                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2442                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
); 
2445         else if (SecIdentityGetTypeID() == itemType
) { 
2446                 // item is a certificate + private key; since we can't really change the 
2447                 // certificate's attributes, assume we want to update the private key 
2448                 status 
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
); 
2450         require_action(itemToUpdate 
!= NULL
, update_failed
, status 
= errSecInvalidItemRef
); 
2451         require_noerr(status
, update_failed
); 
2453         status 
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
); 
2454         require_noerr(status
, update_failed
); 
2456         // build changeAttrList from changedAttributes dictionary 
2459                 case kSecInternetPasswordItemClass
: 
2461                         status 
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2462                         require_noerr(status
, update_failed
); 
2466                 case kSecGenericPasswordItemClass
: 
2468                         status 
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2469                         require_noerr(status
, update_failed
); 
2473                 case kSecCertificateItemClass
: 
2475                         status 
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2476                         require_noerr(status
, update_failed
); 
2480                 case kSecPublicKeyItemClass
: 
2481                 case kSecPrivateKeyItemClass
: 
2482                 case kSecSymmetricKeyItemClass
: 
2484                         status 
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2485                         require_noerr(status
, update_failed
); 
2488                 case kSecAppleSharePasswordItemClass
: 
2490                         // do nothing (legacy behavior). 
2497         // (if the caller is not updating the password, this value will be NULL) 
2498         theData 
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
); 
2499         if (theData 
!= NULL
) { 
2500                 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status 
= errSecParam
); 
2503         status 
= SecKeychainItemModifyContent(itemToUpdate
, 
2504                                 (!changeAttrList 
|| changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2505                                 (theData 
!= NULL
) ? (UInt32
)CFDataGetLength(theData
) : 0, 
2506                                 (theData 
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
); 
2507         require_noerr(status
, update_failed
); 
2509         // one more thing... update access? 
2510         if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) { 
2511                 status 
= SecKeychainItemSetAccess(itemToUpdate
, access
); 
2515         if (status 
== errSecVerifyFailed 
&& 
2516                 (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2517                 // if we got a cryptographic failure updating a password item, it needs to be replaced 
2518                 status 
= _ReplaceKeychainItem(itemToUpdate
, 
2519                                         (!changeAttrList 
||  changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2523                 CFRelease(itemToUpdate
); 
2524         _FreeAttrList(changeAttrList
); 
2529 _DeleteKeychainItem(CFTypeRef item
) 
2531         // This function deletes a single keychain item, which may be specified as 
2532         // a reference, persistent reference or attribute dictionary. It will not 
2533         // delete non-keychain items or aggregate items (such as a SecIdentityRef); 
2534         // it is assumed that the caller will pass identity components separately. 
2536         OSStatus status 
= errSecSuccess
; 
2541         SecKeychainItemRef itemToDelete 
= NULL
; 
2542         CFTypeID itemType 
= CFGetTypeID(item
); 
2543         if (SecKeychainItemGetTypeID() == itemType 
|| 
2544                 SecCertificateGetTypeID() == itemType 
|| 
2545                 SecKeyGetTypeID() == itemType
) { 
2546                 // item is already a reference, retain it 
2547                 itemToDelete 
= (SecKeychainItemRef
) CFRetain(item
); 
2549         else if (CFDataGetTypeID() == itemType
) { 
2550                 // item is a persistent reference, must convert it 
2551                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
); 
2553         else if (CFDictionaryGetTypeID() == itemType
) { 
2554                 // item is a dictionary 
2555                 CFTypeRef value 
= NULL
; 
2556                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2557                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2558                         itemToDelete 
= (SecKeychainItemRef
) CFRetain(value
); 
2560                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2561                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2562                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
); 
2568                         status 
= _SafeSecKeychainItemDelete(itemToDelete
); 
2570                 CFRelease(itemToDelete
); 
2577 _DeleteIdentity(SecIdentityRef identity
) 
2579         OSStatus status
, result 
= errSecSuccess
; 
2580         SecKeyRef privateKey 
= NULL
; 
2581         SecCertificateRef certificate 
= NULL
; 
2583         status 
= SecIdentityCopyPrivateKey(identity
, &privateKey
); 
2585                 SecKeyRef publicKey 
= NULL
; 
2586                 status 
= _SecIdentityCopyPublicKey(identity
, &publicKey
); 
2588                         status 
= _DeleteKeychainItem(publicKey
); 
2589                         CFRelease(publicKey
); 
2591                 status 
= _DeleteKeychainItem(privateKey
); 
2594         if (privateKey
) CFRelease(privateKey
); 
2595         if (status
) result 
= status
; 
2597         status 
= SecIdentityCopyCertificate(identity
, &certificate
); 
2599                 status 
= _DeleteKeychainItem(certificate
); 
2602         if (certificate
) CFRelease(certificate
); 
2603         if (status
) result 
= status
; 
2609 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
) 
2611         // This function is used when atomically processing multiple items, 
2612         // where an overall error result must be returned for the entire operation. 
2613         // When newStatus is something other than errSecSuccess, we want to keep the "most 
2614         // interesting" status (which usually will be newStatus, unless curStatus is 
2615         // already set; in that case, newStatus can trump curStatus only by being 
2616         // something different than baseStatus.) 
2618         OSStatus result 
= curStatus
; 
2620         if (newStatus 
!= errSecSuccess
) { 
2622                 if (curStatus 
!= errSecSuccess
) { 
2623                         result 
= (newStatus 
!= baseStatus
) ? newStatus 
: curStatus
; 
2630 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
) 
2632         // CFDictionaryApplierFunction 
2633         // This function just takes the given key/value pair, 
2634         // and adds it to another dictionary supplied in the context argument. 
2636         CFMutableDictionaryRef dict 
= *((CFMutableDictionaryRef
*) context
); 
2638                 CFDictionaryAddValue(dict
, key
, value
); 
2642 static CFStringCompareFlags
 
2643 _StringCompareFlagsFromQuery(CFDictionaryRef query
) 
2646         CFStringCompareFlags flags 
= 0; 
2647         if (!query
) return flags
; 
2649         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) || 
2650                 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2651                 flags 
|= kCFCompareAnchored
; 
2653         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2654                 flags 
|= kCFCompareBackwards
; 
2656         if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2657                 flags 
|= kCFCompareCaseInsensitive
; 
2659         if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2660                 flags 
|= kCFCompareDiacriticInsensitive
; 
2662         if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2663                 flags 
|= kCFCompareWidthInsensitive
; 
2669 _CssmKeyUsageFromQuery(CFDictionaryRef query
) 
2672         uint32 keyUsage 
= 0; 
2673         if (!query
) return keyUsage
; 
2675         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2676                 keyUsage 
|= CSSM_KEYUSE_ENCRYPT
; 
2678         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2679                 keyUsage 
|= CSSM_KEYUSE_DECRYPT
; 
2681         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2682                 keyUsage 
|= CSSM_KEYUSE_SIGN
; 
2684         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2685                 keyUsage 
|= CSSM_KEYUSE_VERIFY
; 
2687         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2688                 keyUsage 
|= CSSM_KEYUSE_WRAP
; 
2690         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2691                 keyUsage 
|= CSSM_KEYUSE_UNWRAP
; 
2693         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2694                 keyUsage 
|= CSSM_KEYUSE_DERIVE
; 
2700 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean 
*isIdentity
) 
2702         SecItemClass itemClass 
= (SecItemClass
) 0; 
2703         if (isIdentity
) *isIdentity 
= false; 
2705         if (CFEqual(item
, kSecClassGenericPassword
)) { 
2706                 itemClass 
= kSecGenericPasswordItemClass
; 
2708         else if (CFEqual(item
, kSecClassInternetPassword
)) { 
2709                 itemClass 
= kSecInternetPasswordItemClass
; 
2711         else if (CFEqual(item
, kSecClassCertificate
)) { 
2712                 itemClass 
= kSecCertificateItemClass
; 
2714         else if (CFEqual(item
, kSecClassIdentity
)) { 
2715                 // will perform a certificate lookup 
2716                 itemClass 
= kSecCertificateItemClass
; 
2717                 if (isIdentity
) *isIdentity 
= true; 
2719         else if (CFEqual(item
, kSecClassKey
)) { 
2720                 // examine second parameter to determine type of key 
2721                 if (!keyClass 
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) { 
2722                         itemClass 
= kSecSymmetricKeyItemClass
; 
2724                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) { 
2725                         itemClass 
= kSecPublicKeyItemClass
; 
2727                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) { 
2728                         itemClass 
= kSecPrivateKeyItemClass
; 
2736 _ItemClassFromItemList(CFArrayRef itemList
) 
2738         // Given a list of items (standard or persistent references), 
2739         // determine whether they all have the same item class. Returns 
2740         // the item class, or 0 if multiple classes in list. 
2741         SecItemClass result 
= (SecItemClass
) 0; 
2742         CFIndex index
, count 
= (itemList
) ? CFArrayGetCount(itemList
) : 0; 
2743         for (index
=0; index 
< count
; index
++) { 
2744                 CFTypeRef item 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemList
, index
); 
2746                         SecKeychainItemRef itemRef 
= NULL
; 
2748                         if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
2749                                 // persistent reference, resolve first 
2750                                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemRef
); 
2753                                 itemRef 
= (SecKeychainItemRef
) CFRetain(item
); 
2756                                 SecItemClass itemClass 
= (SecItemClass
) 0; 
2757                                 CFTypeID itemTypeID 
= CFGetTypeID(itemRef
); 
2758                                 if (itemTypeID 
== SecIdentityGetTypeID() || itemTypeID 
== SecCertificateGetTypeID()) { 
2759                                         // Identities and certificates have the same underlying item class 
2760                                         itemClass 
= kSecCertificateItemClass
; 
2762                                 else if (itemTypeID 
== SecKeychainItemGetTypeID()) { 
2763                                         // Reference to item in a keychain 
2764                                         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2766                                 else if (itemTypeID 
== SecKeyGetTypeID()) { 
2767                                         // SecKey that isn't stored in a keychain 
2768                                         // %%% will need to change this code when SecKey is no longer CSSM-based %%% 
2769                                         const CSSM_KEY 
*cssmKey
; 
2770                                         status 
= SecKeyGetCSSMKey((SecKeyRef
)itemRef
, &cssmKey
); 
2771                                         if (status 
== errSecSuccess
) { 
2772                                                 if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) 
2773                                                         itemClass 
= kSecPublicKeyItemClass
; 
2774                                                 else if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY
) 
2775                                                         itemClass 
= kSecPrivateKeyItemClass
; 
2777                                                         itemClass 
= kSecSymmetricKeyItemClass
; 
2781                                 if (itemClass 
!= 0) { 
2782                                         if (result 
!= 0 && result 
!= itemClass
) { 
2783                                                 return (SecItemClass
) 0; // different item classes in list; bail out 
2793 // SecItemParams contains a validated set of input parameters, as well as a 
2794 // search reference and attribute list built from those parameters. It is 
2795 // designed to be allocated with _CreateSecItemParamsFromDictionary, and 
2796 // freed with _FreeSecItemParams. 
2798 struct SecItemParams 
{ 
2799         CFDictionaryRef query
;                          // caller-supplied query 
2800         int numResultTypes
;                                     // number of result types requested 
2801         int maxMatches
;                                         // max number of matches to return 
2802         uint32 keyUsage
;                                        // key usage(s) requested 
2803         Boolean returningAttributes
;            // true if returning attributes dictionary 
2804         Boolean returningData
;                          // true if returning item's data 
2805         Boolean returningRef
;                           // true if returning item reference 
2806         Boolean returningPersistentRef
;         // true if returing a persistent reference 
2807         Boolean returnAllMatches
;                       // true if we should return all matches 
2808         Boolean returnIdentity
;                         // true if we are returning a SecIdentityRef 
2809         Boolean trustedOnly
;                            // true if we only return trusted certs 
2810         Boolean issuerAndSNToMatch
;                     // true if both issuer and SN were provided 
2811         SecItemClass itemClass
;                         // item class for this query 
2812         SecPolicyRef policy
;                            // value for kSecMatchPolicy (may be NULL) 
2813         SecKeychainRef keychain
;                        // value for kSecUseKeychain (may be NULL) 
2814         CFArrayRef useItems
;                            // value for kSecUseItemList (may be NULL) 
2815         CFArrayRef itemList
;                            // value for kSecMatchItemList (may be NULL) 
2816         CFTypeRef searchList
;                           // value for kSecMatchSearchList (may be NULL) 
2817         CFTypeRef matchLimit
;                           // value for kSecMatchLimit (may be NULL) 
2818         CFTypeRef emailAddrToMatch
;                     // value for kSecMatchEmailAddressIfPresent (may be NULL) 
2819         CFTypeRef validOnDate
;                          // value for kSecMatchValidOnDate (may be NULL) 
2820         CFTypeRef keyClass
;                                     // value for kSecAttrKeyClass (may be NULL) 
2821         CFTypeRef service
;                                      // value for kSecAttrService (may be NULL) 
2822         CFTypeRef issuer
;                                       // value for kSecAttrIssuer (may be NULL) 
2823         CFTypeRef matchIssuers
;                                 // value for kSecMatchIssuers (may be NULL) 
2824         CFTypeRef serialNumber
;                         // value for kSecAttrSerialNumber (may be NULL) 
2825         CFTypeRef search
;                                       // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) 
2826         CFTypeRef assumedKeyClass
;                      // if no kSecAttrKeyClass provided, holds the current class we're searching for 
2827         CFIndex itemListIndex
;                          // if no search reference but we have itemList, holds index of next item to return 
2828         SecKeychainAttributeList 
*attrList
;     // attribute list for this query 
2829         SecAccessRef access
;                            // access reference (for SecItemAdd only, not used to find items) 
2830         CFDataRef itemData
;                                     // item data (for SecItemAdd only, not used to find items) 
2831         CFTypeRef itemRef
;                                      // item reference (to find, add, update or delete, depending on context) 
2832         SecIdentityRef identityRef
;                     // identity reference (input as kSecValueRef) 
2833         CFDataRef itemPersistentRef
;            // item persistent reference (to find, add, update or delete, depending on context) 
2834         Boolean isPCSItem
;                                      // true if this query is for a Protected Cloud Storage item 
2838 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
) 
2840         if (!dict 
|| !key 
|| !value 
|| !expectedTypeID
) 
2843         if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) { 
2844                 // value was not provided for this key (not an error!) 
2847         else if (!(*value
)) { 
2848                 // provided value is NULL (also not an error!) 
2849                 return errSecSuccess
; 
2852                 CFTypeID actualTypeID 
= CFGetTypeID(*value
); 
2853                 if (!((expectedTypeID 
== actualTypeID
) || (altTypeID 
&& altTypeID 
== actualTypeID
))) { 
2854                         // provided value does not have the expected (or alternate) CF type ID 
2855                         if ((expectedTypeID 
== SecKeychainItemGetTypeID()) && 
2856                                 (actualTypeID 
== SecKeyGetTypeID() || actualTypeID 
== SecCertificateGetTypeID())) { 
2857                                 // provided value is a "floating" reference which is not yet in a keychain 
2859                                 return errSecSuccess
; 
2861                         return errSecItemInvalidValue
; 
2864                         // provided value is OK; retain it 
2868         return errSecSuccess
; 
2872 _EnsureUserDefaultKeychainIsSearched(SecItemParams 
*itemParams
) 
2875         CFArrayRef tmpList 
= (CFArrayRef
) itemParams
->searchList
; 
2877                 // search list exists; make it mutable 
2878                 itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2881                 // no search list; start with default list 
2882                 status 
= SecKeychainCopySearchList(&tmpList
); 
2883                 if (!status 
&& tmpList
) { 
2884                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2888                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2892         SecKeychainRef userKeychain 
= NULL
; 
2893         status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2894         if (!status 
&& userKeychain
) { 
2895                 if (!CFArrayContainsValue((CFArrayRef
)itemParams
->searchList
, 
2896                         CFRangeMake(0, CFArrayGetCount((CFArrayRef
)itemParams
->searchList
)), userKeychain
)) { 
2897                         // user's default keychain isn't currently in the search list, so append it 
2898                         CFArrayAppendValue((CFMutableArrayRef
)itemParams
->searchList
, userKeychain
); 
2900                 CFRelease(userKeychain
); 
2905 _EnsureUserDefaultKeychainIsTargeted(SecItemParams 
*itemParams
) 
2907         if (itemParams
->keychain
) { 
2908                 return; // keychain is already explicitly specified, assume it's correct 
2910         SecKeychainRef userKeychain 
= NULL
; 
2911         OSStatus status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2912         if (!status 
&& userKeychain
) { 
2913                 itemParams
->keychain 
= userKeychain
; 
2918 _FreeSecItemParams(SecItemParams 
*itemParams
) 
2923         if (itemParams
->query
) CFRelease(itemParams
->query
); 
2924         if (itemParams
->policy
) CFRelease(itemParams
->policy
); 
2925         if (itemParams
->keychain
) CFRelease(itemParams
->keychain
); 
2926         if (itemParams
->useItems
) CFRelease(itemParams
->useItems
); 
2927         if (itemParams
->itemList
) CFRelease(itemParams
->itemList
); 
2928         if (itemParams
->searchList
) CFRelease(itemParams
->searchList
); 
2929         if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
); 
2930         if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
); 
2931         if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
); 
2932         if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
); 
2933         if (itemParams
->service
) CFRelease(itemParams
->service
); 
2934         if (itemParams
->issuer
) CFRelease(itemParams
->issuer
); 
2935         if (itemParams
->matchIssuers
) CFRelease(itemParams
->matchIssuers
); 
2936         if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
); 
2937         if (itemParams
->search
) CFRelease(itemParams
->search
); 
2938         if (itemParams
->access
) CFRelease(itemParams
->access
); 
2939         if (itemParams
->itemData
) CFRelease(itemParams
->itemData
); 
2940         if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
); 
2941         if (itemParams
->identityRef
) CFRelease(itemParams
->identityRef
); 
2942         if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
); 
2944         _FreeAttrList(itemParams
->attrList
); 
2949 static SecItemParams
* 
2950 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus 
*error
) 
2953         CFTypeRef value 
= NULL
; 
2954     CFDictionaryRef policyDict 
= NULL
; 
2955         SecItemParams 
*itemParams 
= (SecItemParams 
*)calloc(1, sizeof(struct SecItemParams
)); 
2957         require_action(itemParams 
!= NULL
, error_exit
, status 
= errSecAllocate
); 
2958         require_action(dict 
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status 
= errSecParam
); 
2960         itemParams
->query 
= (CFDictionaryRef
) CFRetain(dict
); 
2962         // validate input search parameters 
2963         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
); 
2964         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2965         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2966         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
2967         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
); 
2968         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
); 
2970         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
); 
2971         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
); 
2973         // validate a subset of input attributes (used to create an appropriate search reference) 
2974         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
); 
2975         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
); 
2976         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
); 
2977         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
); 
2979         if (itemParams
->service 
&& CFStringHasPrefix((CFStringRef
)itemParams
->service
, CFSTR("ProtectedCloudStorage"))) { 
2980                 itemParams
->isPCSItem 
= true; 
2981                 if (!SecItemSynchronizable(dict
)) { 
2982                         _EnsureUserDefaultKeychainIsSearched(itemParams
); // for SecItemCopyMatching, SecItemUpdate, SecItemDelete 
2983                         _EnsureUserDefaultKeychainIsTargeted(itemParams
); // for SecItemAdd 
2987         // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items 
2988         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
); 
2989         if (itemParams
->itemData 
&& CFGetTypeID(itemParams
->itemData
) == CFStringGetTypeID()) { 
2990                 /* If we got a string, convert it into a data object */ 
2991                 CFStringRef string 
= (CFStringRef
)itemParams
->itemData
; 
2992                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(string
), kCFStringEncodingUTF8
) + 1; 
2993                 CFMutableDataRef data 
= CFDataCreateMutable(NULL
, maxLength
); 
2994                 require_action(data
, error_exit
, status 
= errSecAllocate
); 
2996                 CFDataSetLength(data
, maxLength
); 
2998                 if (!CFStringGetCString(string
, (char *)CFDataGetMutableBytePtr(data
), maxLength
, kCFStringEncodingUTF8
)) { 
3000                         status 
= errSecAllocate
; 
3004                 CFDataSetLength(data
, strlen((const char *)CFDataGetBytePtr(data
))); /* dont include NUL in string */ 
3005                 itemParams
->itemData 
= data
; 
3009         // validate item references 
3010         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit
); 
3011         if (itemParams
->itemRef 
&& (CFGetTypeID(itemParams
->itemRef
) == SecIdentityGetTypeID())) { 
3012                 itemParams
->identityRef 
= (SecIdentityRef
)itemParams
->itemRef
; 
3013                 itemParams
->itemRef 
= NULL
; 
3014                 SecIdentityCopyCertificate(itemParams
->identityRef
, (SecCertificateRef 
*)&itemParams
->itemRef
); 
3016         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
); 
3017         if (itemParams
->itemRef 
|| itemParams
->itemPersistentRef
) { 
3018                 // Caller is trying to add or find an item by reference. 
3019                 // The supported method for doing that is to provide a kSecUseItemList array 
3020                 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al, 
3021                 // so add the item reference to those arrays here. 
3022                 if (itemParams
->useItems
) { 
3023                         CFArrayRef tmpItems 
= itemParams
->useItems
; 
3024                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3025                         CFRelease(tmpItems
); 
3027                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3029                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
); 
3030                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
); 
3032                 if (itemParams
->itemList
) { 
3033                         CFArrayRef tmpItems 
= itemParams
->itemList
; 
3034                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3035                         CFRelease(tmpItems
); 
3037                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3039                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
); 
3040                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
); 
3043         // must have an explicit item class, unless one of the following is true: 
3044         //   - we have an item list to add or search (kSecUseItemList) 
3045         //   - we have an item reference or persistent reference for the thing we want to look up 
3046         // Note that both of these cases will set itemParams->useItems. 
3047         // If we have an item list to match (kSecMatchItemList), that still requires an item class, 
3048         // so we can perform a search and see if the results match items in the list. 
3050         if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
) { 
3051                 require_action(false, error_exit
, status 
= errSecItemClassMissing
); 
3054                 itemParams
->itemClass 
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
); 
3055                 if (itemParams
->itemClass 
== kSecSymmetricKeyItemClass 
&& !itemParams
->keyClass
) { 
3056             // no key class specified, so start with symmetric key class; will search the others later in UpdateKeychainSearchAndCopyNext 
3057             itemParams
->itemClass 
= kSecSymmetricKeyItemClass
; 
3058             itemParams
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3060                 require_action(!(itemParams
->itemClass 
== 0 && !itemParams
->useItems
), error_exit
, status 
= errSecItemClassMissing
); 
3063     // kSecMatchIssuers is only permitted with identities or certificates. 
3064     // Convert the input issuers to normalized form. 
3065     require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchIssuers
, (const void **)&itemParams
->matchIssuers
, CFArrayGetTypeID(), NULL
), error_exit
); 
3066     if (itemParams
->matchIssuers
) { 
3067         CFTypeRef allowCerts 
= CFDictionaryGetValue(itemParams
->query
, kSecUseCertificatesWithMatchIssuers
); 
3068         require_action(itemParams
->returnIdentity 
|| (allowCerts 
&& CFEqual(allowCerts
, kCFBooleanTrue
)), error_exit
, status 
= errSecParam
); 
3069         CFMutableArrayRef canonical_issuers 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3070         CFArrayRef issuers 
= (CFArrayRef
)itemParams
->matchIssuers
; 
3071         if (canonical_issuers
) { 
3072             CFIndex i
, count 
= CFArrayGetCount(issuers
); 
3073             for (i 
= 0; i 
< count
; i
++) { 
3074                 CFTypeRef issuer_data 
= CFArrayGetValueAtIndex(issuers
, i
); 
3075                 CFDataRef issuer_canonical 
= NULL
; 
3076                 if (CFDataGetTypeID() == CFGetTypeID(issuer_data
)) 
3077                     issuer_canonical 
= SecDistinguishedNameCopyNormalizedSequence((CFDataRef
)issuer_data
); 
3078                 if (issuer_canonical
) { 
3079                     CFArrayAppendValue(canonical_issuers
, issuer_canonical
); 
3080                     CFRelease(issuer_canonical
); 
3083             if (CFArrayGetCount(canonical_issuers
) > 0) { 
3084                 CFAssignRetained(itemParams
->matchIssuers
, canonical_issuers
); 
3086                 CFRelease(canonical_issuers
); 
3090         itemParams
->keyUsage 
= _CssmKeyUsageFromQuery(dict
); 
3091         itemParams
->trustedOnly 
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3092         itemParams
->issuerAndSNToMatch 
= (itemParams
->issuer 
!= NULL 
&& itemParams
->serialNumber 
!= NULL
); 
3094         // other input attributes, used for SecItemAdd but not for finding items 
3095         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3096         if (itemParams
->access 
== NULL
) { 
3097                 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>) 
3098                 require_noerr(status 
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3101         // determine how to return the result 
3102         itemParams
->numResultTypes 
= 0; 
3103         itemParams
->returningRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3104         if (itemParams
->returningRef
) ++itemParams
->numResultTypes
; 
3105         itemParams
->returningPersistentRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3106         if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
; 
3107         itemParams
->returningAttributes 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3108         if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
; 
3109         itemParams
->returningData 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3110         if (itemParams
->returningData
) ++itemParams
->numResultTypes
; 
3112         // default is kSecReturnRef if no result types were specified 
3113         if (!itemParams
->numResultTypes
) { 
3114                 itemParams
->returningRef 
= TRUE
; 
3115                 itemParams
->numResultTypes 
= 1; 
3118         // determine if one, some or all matches should be returned (default is kSecMatchLimitOne) 
3119         itemParams
->maxMatches 
= 1; 
3120         itemParams
->returnAllMatches 
= FALSE
; 
3121         if (itemParams
->matchLimit
) { 
3122                 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3123                         itemParams
->returnAllMatches 
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
); 
3125                 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3126                         CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
); 
3127                         require_action(!(itemParams
->maxMatches 
< 0), error_exit
, status 
= errSecMatchLimitUnsupported
); 
3130         if (itemParams
->returnAllMatches
) { 
3131                 itemParams
->maxMatches 
= INT32_MAX
; 
3132                 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each) 
3133                 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass 
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
) 
3134                         status 
= errSecReturnDataUnsupported
; 
3135                 require_noerr(status
, error_exit
); 
3138     // if we already have an item list (to add or find items in), we don't need a search reference 
3139         if (itemParams
->useItems
) { 
3140                 if (itemParams
->itemClass 
== 0) { 
3141                         itemParams
->itemClass 
= _ItemClassFromItemList(itemParams
->useItems
); 
3144         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3145         if (itemParams
->itemClass 
!= 0) { 
3146             status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
); 
3148             status 
= errSecSuccess
; 
3150                 goto error_exit
; // all done here 
3153         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3154         require_noerr(status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
); 
3156     // if policy is a SMIME policy, copy email address in policy into emailAddrToMatch parameter 
3157     if(itemParams
->policy
) { 
3158         policyDict 
= SecPolicyCopyProperties(itemParams
->policy
); 
3159         CFStringRef oidStr 
= (CFStringRef
) CFDictionaryGetValue(policyDict
, kSecPolicyOid
); 
3160         if(oidStr 
&& CFStringCompare(kSecPolicyAppleSMIME
,oidStr
,0) == 0) { 
3161             require_noerr(status 
= _ValidateDictionaryEntry(policyDict
, kSecPolicyName
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
3163         CFReleaseNull(policyDict
); 
3166         // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) 
3167         if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) { 
3168                 // searching for certificates by email address 
3169                 char *nameBuf 
= (char*)malloc(MAXPATHLEN
); 
3171                         status 
= errSecAllocate
; 
3173                 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) { 
3174                         status 
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
); 
3177                         status 
= errSecItemInvalidValue
; 
3179                 if (nameBuf
) free(nameBuf
); 
3181         else if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) { 
3182                 // searching for certificates by issuer and serial number 
3183                 status 
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
, 
3184                                 (CFDataRef
)itemParams
->issuer
, 
3185                                 (CFDataRef
)itemParams
->serialNumber
, 
3186                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3188         else if (itemParams
->returnIdentity 
&& itemParams
->policy
) { 
3189                 // searching for identities by policy 
3190                 status 
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
, 
3191                                 (CFStringRef
)itemParams
->service
, 
3192                                 itemParams
->keyUsage
, 
3193                                 itemParams
->searchList
, 
3194                                 itemParams
->trustedOnly
, 
3195                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3197         else if (itemParams
->returnIdentity
) { 
3198                 // searching for identities 
3199                 status 
= SecIdentitySearchCreate(itemParams
->searchList
, 
3200                                 itemParams
->keyUsage
, 
3201                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3204                 // normal keychain item search 
3205                 status 
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
, 
3206                                 itemParams
->itemClass
, 
3207                                 (itemParams
->attrList
->count 
== 0) ? NULL 
: itemParams
->attrList
, 
3208                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3212     CFReleaseNull(policyDict
); 
3214                 _FreeSecItemParams(itemParams
); 
3227         SecKeychainRef keychainRef
, 
3228         SecAccessRef accessRef
, 
3229         SecKeychainAttributeList 
*attrList
, 
3230         SecKeychainItemRef 
*outItemRef
) 
3234                 // We must specify the access, since a free-floating key won't have one yet by default 
3235                 SecPointer
<Access
> access
; 
3237                         access 
= Access::required(accessRef
); 
3240                         CFStringRef descriptor 
= NULL
; 
3242                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
3243                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
3244                                         if (attr
.tag 
== kSecKeyPrintName
) { 
3245                                                 descriptor 
= CFStringCreateWithBytes(NULL
, (const UInt8 
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
); 
3250                         if (descriptor 
== NULL
) { 
3251                                 descriptor 
= (CFStringRef
) CFRetain(CFSTR("<unknown>")); 
3253                         access 
= new Access(cfString(descriptor
)); 
3254                         CFRelease(descriptor
); 
3257                 KeyItem 
*key 
= KeyItem::required(keyRef
); 
3258                 Item item 
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
); 
3260                         *outItemRef 
= item
->handle(); 
3266 _FilterWithPolicy(SecPolicyRef policy
, CFDateRef date
, SecCertificateRef cert
) 
3268         CFDictionaryRef props 
= NULL
; 
3269         CFArrayRef keychains 
= NULL
; 
3270         CFArrayRef anchors 
= NULL
; 
3271         CFArrayRef certs 
= NULL
; 
3272         CFArrayRef chain 
= NULL
; 
3273         SecTrustRef trust 
= NULL
; 
3275         SecTrustResultType      trustResult
; 
3276         Boolean needChain 
= false; 
3278         if (!policy 
|| !cert
) return errSecParam
; 
3280         certs 
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
); 
3281         status 
= SecTrustCreateWithCertificates(certs
, policy
, &trust
); 
3282         if(status
) goto cleanup
; 
3284         /* Set evaluation date, if specified (otherwise current date is implied) */ 
3285         if (date 
&& (CFGetTypeID(date
) == CFDateGetTypeID())) { 
3286                 status 
= SecTrustSetVerifyDate(trust
, date
); 
3287                 if(status
) goto cleanup
; 
3290         /* Check whether this is the X509 Basic policy, which means chain building */ 
3291         props 
= SecPolicyCopyProperties(policy
); 
3293                 CFTypeRef oid 
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
); 
3294                 if (oid 
&& (CFEqual(oid
, kSecPolicyAppleX509Basic
) || 
3295                     CFEqual(oid
, kSecPolicyAppleRevocation
))) { 
3301                 status 
= SecTrustEvaluateLeafOnly(trust
, &trustResult
); 
3303                 status 
= SecTrustEvaluate(trust
, &trustResult
); 
3306         if (!(trustResult 
== kSecTrustResultProceed 
|| 
3307                   trustResult 
== kSecTrustResultUnspecified 
|| 
3308                   trustResult 
== kSecTrustResultRecoverableTrustFailure
)) { 
3309                 /* The evaluation failed in a non-recoverable way */ 
3310                 status 
= errSecCertificateCannotOperate
; 
3314         /* If there are no per-cert policy status codes, 
3315          * and the cert has not expired, consider it valid for the policy. 
3318                 (void)SecTrustGetCssmResultCode(trust
, &status
); 
3322         if(props
) CFRelease(props
); 
3323         if(chain
) CFRelease(chain
); 
3324         if(anchors
) CFRelease(anchors
); 
3325         if(keychains
) CFRelease(keychains
); 
3326         if(certs
) CFRelease(certs
); 
3327         if(trust
) CFRelease(trust
); 
3333 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
) 
3335         if (!validOnDate 
|| !cert
) return errSecParam
; 
3337         CFAbsoluteTime at
, nb
, na
; 
3338         if (CFGetTypeID(validOnDate
) == CFDateGetTypeID()) 
3339                 at 
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
); 
3341                 at 
= CFAbsoluteTimeGetCurrent(); 
3343         OSStatus status 
= errSecSuccess
; 
3344         nb 
= SecCertificateNotValidBefore(cert
); 
3345         na 
= SecCertificateNotValidAfter(cert
); 
3347         if (nb 
== 0 || na 
== 0 || nb 
== na
) 
3348                 status 
= errSecCertificateCannotOperate
; 
3350                 status 
= errSecCertificateNotValidYet
; 
3352                 status 
= errSecCertificateExpired
; 
3358 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
) 
3360         if (!cert
) return errSecParam
; 
3361         if (!trustedOnly
) return errSecSuccess
; 
3363         CFArrayRef certArray 
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
); 
3364         SecPolicyRef policy 
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
); 
3365         OSStatus status 
= (policy 
== NULL
) ? errSecPolicyNotFound 
: errSecSuccess
; 
3368                 SecTrustRef trust 
= NULL
; 
3369                 status 
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
); 
3371                         SecTrustResultType trustResult
; 
3372                         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3374                                 if (!(trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
)) { 
3375                                         status 
= (trustResult 
== kSecTrustResultDeny
) ? errSecTrustSettingDeny 
: errSecNotTrusted
; 
3383                 CFRelease(certArray
); 
3389 static bool items_matching_issuer_parent(CFDataRef issuer
, CFArrayRef issuers
, int recurse
) { 
3390     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) { return false; } 
3392     /* We found a match, we're done. */ 
3393     if (CFArrayContainsValue(issuers
, CFRangeMake(0, CFArrayGetCount(issuers
)), issuer
)) { return true; } 
3395     /* Prevent infinite recursion */ 
3396     if (recurse 
<= 0) { return false; } 
3399     /* Query for parents */ 
3400     CFMutableDictionaryRef query 
= NULL
; 
3401     CFTypeRef parents 
= NULL
; 
3404     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 4, &kCFTypeDictionaryKeyCallBacks
, 
3405                                       &kCFTypeDictionaryValueCallBacks
), out
); 
3406     CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
3407     CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
); 
3408     CFDictionaryAddValue(query
, kSecAttrSubject
, issuer
); 
3409     CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
3410     require_noerr_quiet(SecItemCopyMatching(query
, &parents
), out
); 
3412     if (parents 
&& CFArrayGetTypeID() == CFGetTypeID(parents
)) { 
3413         CFIndex i
, count 
= CFArrayGetCount((CFArrayRef
)parents
); 
3414         for (i 
= 0; i 
< count
; i
++) { 
3415             SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)parents
, i
); 
3416             CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3417             if (CFEqual(cert_issuer
, issuer
)) { 
3418                 // Self-issued cert, don't look for parents. 
3419                 CFReleaseNull(cert_issuer
); 
3422             found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3423             CFReleaseNull(cert_issuer
); 
3424             if (found
) { break; } 
3426     } else if (parents 
&& SecCertificateGetTypeID() == CFGetTypeID(parents
)) { 
3427         SecCertificateRef cert 
= (SecCertificateRef
)parents
; 
3428         CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3429         require_action_quiet(!CFEqual(cert_issuer
, issuer
), out
, CFReleaseNull(cert_issuer
)); 
3430         found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3431         CFReleaseNull(cert_issuer
); 
3435     CFReleaseNull(query
); 
3436     CFReleaseNull(parents
); 
3441 _FilterWithIssuers(CFArrayRef issuers
, SecCertificateRef cert
) 
3443     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) return errSecParam
; 
3444     if (!cert
) return errSecParam
; 
3446     OSStatus status 
= errSecInternalError
; 
3448     /* kSecMatchIssuers matches certificates where ANY certificate in the chain has this issuer. 
3449      * So we now need to recursively query the keychain for this cert's parents to determine if 
3450      * they match. (This is why we limited the use of this key in _CreateSecItemParamsFromDictionary.) */ 
3451     CFDataRef issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3452     if (items_matching_issuer_parent(issuer
, issuers
, 10)) { 
3453         status 
= errSecSuccess
; 
3456     CFReleaseNull(issuer
); 
3460 static SecKeychainItemRef
 
3461 CopyResolvedKeychainItem(CFTypeRef item
) 
3463         SecKeychainItemRef kcItem 
= NULL
; 
3464         OSStatus status 
= errSecSuccess
; 
3466                 if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
3467                         // persistent reference, resolve first 
3468                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &kcItem
); 
3472                         kcItem 
= (SecKeychainItemRef
) CFRetain(item
); 
3475                         // ask for the item's class: 
3476                         // will return an error if the item has been deleted 
3477                         SecItemClass itemClass
; 
3478                         SecCertificateRef certRef 
= NULL
; 
3479                         CFTypeID itemTypeID 
= CFGetTypeID(kcItem
); 
3480                         if (itemTypeID 
== SecIdentityGetTypeID()) { 
3481                                 status 
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
, &certRef
); 
3483                         else if (itemTypeID 
== SecCertificateGetTypeID()) { 
3484                                 certRef 
= (SecCertificateRef
) CFRetain(kcItem
); 
3487                                 // can't call SecKeychainItemCopyAttributesAndData on a SecCertificateRef 
3488                                 itemClass 
= kSecCertificateItemClass
; 
3491                                 status 
= SecKeychainItemCopyAttributesAndData(kcItem
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3506 UpdateKeychainSearchAndCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3508         // This function refreshes the search parameters in the specific case where 
3509         // the caller is searching for kSecClassKey items but did not provide the 
3510         // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and 
3511         // we must perform separate searches to obtain all results. 
3513         OSStatus status 
= errSecItemNotFound
; 
3514         if (!params 
|| !params
->assumedKeyClass 
|| !params
->query 
|| !item
) 
3517         // Free the previous search reference and attribute list. 
3519                 CFRelease(params
->search
); 
3520         params
->search 
= NULL
; 
3521         _FreeAttrList(params
->attrList
); 
3522         params
->attrList 
= NULL
; 
3524         // Make a copy of the query dictionary so we can set the key class parameter. 
3525         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
); 
3526         CFRelease(params
->query
); 
3527         params
->query 
= dict
; 
3528         CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
); 
3530         // Determine the current item class for this search, and the next assumed key class. 
3531         if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) { 
3532                 params
->itemClass 
= kSecSymmetricKeyItemClass
; 
3533                 params
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3534         } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) { 
3535                 params
->itemClass 
= kSecPublicKeyItemClass
; 
3536                 params
->assumedKeyClass 
= kSecAttrKeyClassPrivate
; 
3538                 params
->itemClass 
= kSecPrivateKeyItemClass
; 
3539                 params
->assumedKeyClass 
= NULL
; 
3542         // Rebuild the attribute list for the new key class. 
3543         if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == errSecSuccess
) { 
3544                 // Create a new search reference for the new attribute list. 
3545                 if (SecKeychainSearchCreateFromAttributes(params
->searchList
, 
3547                         (params
->attrList
->count 
== 0) ? NULL 
: params
->attrList
, 
3548                         (SecKeychainSearchRef
*)¶ms
->search
) == errSecSuccess
) { 
3549                         // Return the first matching item from the new search. 
3550                         // We won't come back here again until there are no more matching items for this search. 
3551                         status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
); 
3559 SecItemSearchCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3561         // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef. 
3562         // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter, 
3563         // depending on the type of search reference. 
3566         CFTypeRef search 
= (params
) ? params
->search 
: NULL
; 
3567         CFTypeID typeID 
= (search
) ? CFGetTypeID(search
) : 0; 
3569         if (search 
&& typeID 
== SecIdentitySearchGetTypeID()) { 
3570                 status 
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
); 
3572         else if (search 
&& typeID 
== SecKeychainSearchGetTypeID()) { 
3573                 status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
); 
3574                 // Check if we need to refresh the search for the next key class 
3575                 while (status 
== errSecItemNotFound 
&& params
->assumedKeyClass 
!= NULL
) 
3576                         status 
= UpdateKeychainSearchAndCopyNext(params
, item
); 
3578         else if (typeID 
== 0 && params 
&& (params
->useItems 
|| params
->itemList
)) { 
3579                 // No search available, but there is an item list available. 
3580                 // Return the next candidate item from the caller's item list 
3581                 CFArrayRef itemList 
= (params
->useItems
) ? params
->useItems 
: params
->itemList
; 
3582                 CFIndex count 
= CFArrayGetCount(itemList
); 
3583                 *item 
= (CFTypeRef
) NULL
; 
3584                 if (params
->itemListIndex 
< count
) { 
3585                         *item 
= (CFTypeRef
)CFArrayGetValueAtIndex(itemList
, params
->itemListIndex
++); 
3587                                 // Potentially resolve persistent item references here, and 
3588                                 // verify the item reference we're about to hand back is still 
3589                                 // valid (it could have been deleted from the keychain while 
3590                                 // our query was holding onto the itemList). 
3591                                 *item 
= CopyResolvedKeychainItem(*item
); 
3592                                 if (*item 
&& (CFGetTypeID(*item
) == SecIdentityGetTypeID())) { 
3593                                         // Persistent reference resolved to an identity, so return that type. 
3594                                         params
->returnIdentity 
= true; 
3598                 status 
= (*item
) ? errSecSuccess 
: errSecItemNotFound
; 
3601                 status 
= errSecItemNotFound
; 
3607 FilterCandidateItem(CFTypeRef 
*item
, SecItemParams 
*itemParams
, SecIdentityRef 
*identity
) 
3609         if (!item 
|| *item 
== NULL 
|| !itemParams
) 
3610                 return errSecItemNotFound
; 
3613         CFStringRef commonName 
= NULL
; 
3614         SecIdentityRef foundIdentity 
= NULL
; 
3615         if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) { 
3616                 // we found a SecIdentityRef, rather than a SecKeychainItemRef; 
3617                 // replace the found "item" with its associated certificate (which is the 
3618                 // item we actually want for purposes of getting attributes, data, or a 
3619                 // persistent data reference), and return the identity separately. 
3620                 SecCertificateRef certificate
; 
3621                 status 
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
); 
3622                 if (itemParams
->returnIdentity
) { 
3623                         foundIdentity 
= (SecIdentityRef
) *item
; 
3625                                 *identity 
= foundIdentity
; 
3631                 *item 
= (CFTypeRef
)certificate
; 
3634         CFDictionaryRef query 
= itemParams
->query
; 
3636         if (itemParams
->itemClass 
== kSecCertificateItemClass
) { 
3637                 // perform string comparisons first 
3638                 CFStringCompareFlags flags 
= _StringCompareFlagsFromQuery(query
); 
3639                 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
; 
3640                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
)) 
3641                         nameContains 
= NULL
; 
3642                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
)) 
3644                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
)) 
3646                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
)) 
3648                 if (nameContains 
|| nameStarts 
|| nameEnds 
|| nameExact
) { 
3649                         status 
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
); 
3650                         if (status 
|| !commonName
) goto filterOut
; 
3653                         CFRange range 
= CFStringFind(commonName
, nameContains
, flags
); 
3654                         if (range
.length 
< 1) 
3656                         // certificate item contains string; proceed to next check 
3659                         CFRange range 
= CFStringFind(commonName
, nameStarts
, flags
); 
3660                         if (range
.length 
< 1 || range
.location 
> 1) 
3662                         // certificate item starts with string; proceed to next check 
3665                         CFRange range 
= CFStringFind(commonName
, nameEnds
, flags
); 
3666                         if (range
.length 
< 1 || range
.location 
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
))) 
3668                         // certificate item ends with string; proceed to next check 
3671                         CFRange range 
= CFStringFind(commonName
, nameExact
, flags
); 
3672                         if (range
.length 
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
))) 
3674                         // certificate item exactly matches string; proceed to next check 
3676                 if (itemParams
->returnIdentity
) { 
3677                         // if we already found and returned the identity, we can skip this 
3678                         if (!foundIdentity
) { 
3679                                 status 
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
); 
3680                                 if (status
) goto filterOut
; 
3682                         // certificate item is part of an identity; proceed to next check 
3684                 if (itemParams
->policy
) { 
3685                         status 
= _FilterWithPolicy(itemParams
->policy
, (CFDateRef
)itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3686                         if (status
) goto filterOut
; 
3687                         // certificate item is valid for specified policy (and optionally specified date) 
3689                 if (itemParams
->validOnDate
) { 
3690                         status 
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3691                         if (status
) goto filterOut
; 
3692                         // certificate item is valid for specified date 
3694                 if (itemParams
->trustedOnly
) { 
3695                         // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search, 
3696                         // their trust has already been validated and we can skip this part. 
3697                         if (!(foundIdentity 
&& itemParams
->returnIdentity 
&& itemParams
->policy
)) { 
3698                                 status 
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
); 
3699                                 if (status
) goto filterOut
; 
3701                         // certificate item is trusted on this system 
3703         if (itemParams
->matchIssuers
) { 
3704             status 
= _FilterWithIssuers((CFArrayRef
)itemParams
->matchIssuers
, (SecCertificateRef
) *item
); 
3705             if (status
) goto filterOut
; 
3706             // certificate item has one of the issuers 
3709         if (itemParams
->itemList
) { 
3710                 Boolean foundMatch 
= FALSE
; 
3711                 CFIndex idx
, count 
= CFArrayGetCount(itemParams
->itemList
); 
3712                 for (idx
=0; idx
<count
; idx
++) { 
3713                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
); 
3714                         SecKeychainItemRef realItem 
= NULL
; 
3715                         SecCertificateRef aCert 
= NULL
; 
3716                         if (anItem 
== NULL
) { 
3719                         if (CFDataGetTypeID() == CFGetTypeID(anItem
) && 
3720                                 errSecSuccess 
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) { 
3723                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) && 
3724                                 errSecSuccess 
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) { 
3727                         if (CFEqual(anItem
, (CFTypeRef
) *item
)) { 
3734                                 CFRelease(realItem
); 
3740                 if (!foundMatch
) goto filterOut
; 
3741                 // item was found on provided list 
3744         if (foundIdentity 
&& !identity
) { 
3745                 CFRelease(foundIdentity
); 
3748                 CFRelease(commonName
); 
3751         // if we get here, consider the item a match 
3752         return errSecSuccess
; 
3756                 CFRelease(commonName
); 
3760         if (foundIdentity
) { 
3761                 CFRelease(foundIdentity
); 
3766         return errSecItemNotFound
; 
3770 AddItemResults(SecKeychainItemRef item
, 
3771         SecIdentityRef identity
, 
3772         SecItemParams 
*itemParams
, 
3773         CFAllocatorRef allocator
, 
3774         CFMutableArrayRef 
*items
, 
3777         // Given a found item (which may also be an identity), this function adds 
3778         // the requested result types (specified in itemParams) to the appropriate 
3779         // container as follows: 
3781         // 1. If there is only one result type (numResultTypes == 1) and only one 
3782         //    match requested (maxMatches == 1), set *result directly. 
3784         // 2. If there are multiple result types (numResultTypes > 1), and only one 
3785         //    match requested (maxMatches == 1), add each result type to itemDict 
3786         //    and set itemDict as the value of *result. 
3788         // 3. If there is only one result type (numResultTypes == 1) and multiple 
3789         //    possible matches (maxMatches > 1), add the result type to *items 
3790         //    and set *items as the value of *result. 
3792         // 4. If there are multiple result types (numResultTypes > 1) and multiple 
3793         //    possible matches (maxMatches > 1), add each result type to itemDict, 
3794         //    add itemDict to *items, and set *items as the value of *result. 
3796         // Note that we allocate *items if needed. 
3798         if (!item 
|| !itemParams 
|| !result
) 
3801         if (itemParams
->maxMatches 
> 1) { 
3802                 // if we can return more than one item, we must have an array 
3805                 else if (*items 
== NULL
) 
3806                         *items 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
3809         OSStatus tmpStatus
, status 
= errSecSuccess
; 
3810         CFMutableArrayRef itemArray 
= (items
) ? *items 
: NULL
; 
3811         CFMutableDictionaryRef itemDict 
= NULL
; 
3812         if (itemParams
->numResultTypes 
> 1) { 
3813                 // if we're returning more than one result type, each item we return must be a dictionary 
3814                 itemDict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
3817         if (itemParams
->returningRef
) { 
3818                 const void* itemRef 
= (identity
) ? (const void*)identity 
: (const void*)item
; 
3820                         CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
); 
3822                 else if (itemArray
) { 
3823                         CFArrayAppendValue(itemArray
, itemRef
); 
3826                         *result 
= CFRetain((CFTypeRef
)itemRef
); 
3830         if (itemParams
->returningPersistentRef
) { 
3831                 CFDataRef persistentRef
; 
3832                 SecKeychainItemRef tmpItem 
= item
; 
3833                 if (itemParams
->identityRef
) { 
3834                         tmpItem 
= (SecKeychainItemRef
)itemParams
->identityRef
; 
3836                 tmpStatus 
= SecKeychainItemCreatePersistentReference(tmpItem
, &persistentRef
); 
3837                 if (tmpStatus 
== errSecSuccess
) { 
3839                                 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
); 
3841                         else if (itemArray
) { 
3842                                 CFArrayAppendValue(itemArray
, persistentRef
); 
3845                                 *result 
= CFRetain(persistentRef
); 
3847                         CFRelease(persistentRef
); 
3849                 else if (status 
== errSecSuccess
) { 
3854         if (itemParams
->returningData
) { 
3855                 // Use SecCertificateCopyData if we have a SecCertificateRef item. 
3856                 // Note that a SecCertificateRef may not actually be a SecKeychainItem, 
3857                 // in which case SecKeychainItemCopyContent will not obtain its data. 
3859                 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) { 
3860                         CFDataRef dataRef 
= SecCertificateCopyData((SecCertificateRef
)item
); 
3863                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3865                                 else if (itemArray
) { 
3866                                         CFArrayAppendValue(itemArray
, dataRef
); 
3869                                         *result 
= CFRetain(dataRef
); 
3872                                 status 
= errSecSuccess
; 
3875                                 status 
= errSecAllocate
; 
3881                         tmpStatus 
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
); 
3882                         if (tmpStatus 
== errSecSuccess
) { 
3883                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8 
*)data
, length
); 
3885                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3887                                 else if (itemArray
) { 
3888                                         CFArrayAppendValue(itemArray
, dataRef
); 
3891                                         *result 
= CFRetain(dataRef
); 
3894                                 (void) SecKeychainItemFreeContent(NULL
, data
); 
3896                         else if (status 
== errSecSuccess
) { 
3902         if (itemParams
->returningAttributes
) { 
3903                 CFDictionaryRef attrsDict 
= NULL
; 
3904                 SecItemClass itemClass
; 
3905                 // since we have an item, allow its actual class to override the query-specified item class 
3906                 tmpStatus 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3908                         itemClass 
= itemParams
->itemClass
; 
3910                 tmpStatus 
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
); 
3913                                 // add all keys and values from attrsDict to the item dictionary 
3914                                 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
); 
3916                         else if (itemArray
) { 
3917                                 CFArrayAppendValue(itemArray
, attrsDict
); 
3920                                 *result 
= CFRetain(attrsDict
); 
3922                         CFRelease(attrsDict
); 
3924                 if (tmpStatus 
&& (status 
== errSecSuccess
)) { 
3931                         CFArrayAppendValue(itemArray
, itemDict
); 
3932                         CFRelease(itemDict
); 
3933                         *result 
= itemArray
; 
3939         else if (itemArray
) { 
3940                 *result 
= itemArray
; 
3946 CFDataRef 
_SecItemGetPersistentReference(CFTypeRef raw_item
) 
3949                 Item item 
= ItemImpl::required((SecKeychainItemRef
)raw_item
); 
3950                 return item
->getPersistentRef(); 
3956 /******************************************************************************/ 
3957 #pragma mark SecItem API functions 
3958 /******************************************************************************/ 
3961 // Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error. 
3963 static SInt32 
readNumber(CFTypeRef obj
) { 
3964     CFTypeID tid 
= CFGetTypeID(obj
); 
3966     if (tid 
== CFNumberGetTypeID()) { 
3967         CFNumberGetValue((CFNumberRef
)obj
, kCFNumberSInt32Type
, &v
); 
3969     } else if (tid 
== CFBooleanGetTypeID()) { 
3970         v 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
3972     } else if (tid 
== CFStringGetTypeID()) { 
3973         v 
= CFStringGetIntValue((CFStringRef
)obj
); 
3974         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v
); 
3975         /* If a string converted to an int isn't equal to the int printed as 
3976          a string, return a CFStringRef instead. */ 
3977         if (!CFEqual(t
, obj
)) { 
3988 // Function to check whether the kSecAttrSynchronizable flag is set in the query. 
3990 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
) 
3992         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
3993         Boolean result 
= (value 
&& readNumber(value
)); 
3999 // Function to check whether a synchronizable persistent reference was provided. 
4001 static Boolean 
SecItemIsIOSPersistentReference(CFTypeRef value
) 
4004         return ::_SecItemParsePersistentRef((CFDataRef
)value
, NULL
, NULL
, NULL
); 
4009 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
4012 // Function to find out which keychains are targetted by the query. 
4014 static OSStatus 
SecItemCategorizeQuery(CFDictionaryRef query
, bool &can_target_ios
, bool &can_target_osx
) 
4016         // By default, target both keychain. 
4017         can_target_osx 
= can_target_ios 
= true; 
4019         // Check no-legacy flag. 
4020     // it's iOS or bust if we're on MZ! 
4021     CFTypeRef noLegacy 
= NULL
; 
4022     if (_CFMZEnabled()) { 
4023         noLegacy 
= kCFBooleanTrue
; 
4026         noLegacy 
= CFDictionaryGetValue(query
, kSecAttrNoLegacy
); 
4029         if (noLegacy 
!= NULL
) { 
4030                 can_target_ios 
= readNumber(noLegacy
) != 0; 
4031                 can_target_osx 
= !can_target_ios
; 
4032                 return errSecSuccess
; 
4035         // Check whether the query contains kSecValueRef and modify can_ flags according to the kind and type of the value. 
4036         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecValueRef
); 
4037         if (value 
!= NULL
) { 
4038                 CFTypeID typeID 
= CFGetTypeID(value
); 
4039                 if (typeID 
== SecKeyGetTypeID()) { 
4040                         can_target_osx 
= SecKeyIsCDSAKey((SecKeyRef
)value
); 
4041                         can_target_ios 
= !can_target_osx
; 
4042                 } else if (typeID 
== SecCertificateGetTypeID()) { 
4043                         // All types of certificates can target OSX keychains, but OSX certificates won't work on iOS 
4044                         can_target_ios 
&= !SecCertificateIsItemImplInstance((SecCertificateRef
)value
); 
4045                 } else if (typeID 
== SecKeychainItemGetTypeID()) { 
4046                         // SecKeychainItemRef can target iOS keychain only when it has attached iOS-style persistent reference. 
4047                         if (_SecItemGetPersistentReference(value
) == NULL
) { 
4048                                 can_target_ios 
= false; 
4053         // Check presence of kSecAttrTokenID and kSecAttrAccessControl; they are not defined for CDSA keychain. 
4054         if (CFDictionaryContainsKey(query
, kSecAttrTokenID
) || CFDictionaryContainsKey(query
, kSecAttrAccessControl
)) { 
4055                 can_target_osx 
= false; 
4058         // Check for special token access groups.  If present, redirect query to iOS keychain. 
4059         value 
= CFDictionaryGetValue(query
, kSecAttrAccessGroup
); 
4060         if (value 
!= NULL 
&& CFEqual(value
, kSecAttrAccessGroupToken
)) { 
4061                 can_target_osx 
= false; 
4064         // Synchronizable items should go to iOS keychain only. 
4065         if (SecItemSynchronizable(query
)) { 
4066                 can_target_osx 
= false; 
4069         value 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
4070         if (value 
!= NULL
) { 
4071                 if (SecItemIsIOSPersistentReference(value
)) { 
4072                         can_target_osx 
= false; 
4074                         // Non-iOS-style persistent references should not be fed to iOS keychain queries. 
4075                         can_target_ios 
= false; 
4079         // Presence of following atributes means that query is OSX-only. 
4080         static const CFStringRef 
*osx_only_items
[] = { 
4082                 &kSecMatchSearchList
, 
4083                 &kSecMatchSubjectStartsWith
, 
4084                 &kSecMatchSubjectEndsWith
, 
4085                 &kSecMatchSubjectWholeString
, 
4086                 &kSecMatchDiacriticInsensitive
, 
4087                 &kSecMatchWidthInsensitive
, 
4096         for (CFIndex i 
= 0; i 
< array_size(osx_only_items
); i
++) { 
4097                 can_target_ios 
= can_target_ios 
&& !CFDictionaryContainsKey(query
, *osx_only_items
[i
]); 
4100     // Absence of all of kSecItemClass, kSecValuePersistentRef, and kSecValueRef means that the query can't target iOS 
4101     if(CFDictionaryGetValue(query
, kSecClass
) == NULL 
&& 
4102        CFDictionaryGetValue(query
, kSecValuePersistentRef
) == NULL 
&& 
4103        CFDictionaryGetValue(query
, kSecValueRef
) == NULL
) { 
4104         can_target_ios 
= false; 
4107         return (can_target_ios 
|| can_target_osx
) ? errSecSuccess 
: errSecParam
; 
4111 // Function to check whether the kSecAttrSynchronizable attribute is being updated. 
4113 static Boolean 
SecItemHasSynchronizableUpdate(Boolean synchronizable
, CFDictionaryRef changes
) 
4115         CFTypeRef newValue 
= CFDictionaryGetValue(changes
, kSecAttrSynchronizable
); 
4119         Boolean new_sync 
= readNumber(newValue
); 
4120         Boolean old_sync 
= synchronizable
; 
4122         return (old_sync 
!= new_sync
); 
4126 // Function to apply changes to a mutable dictionary. 
4127 // (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction) 
4129 static void SecItemApplyChanges(const void *key
, const void *value
, void *context
) 
4131         CFMutableDictionaryRef dict 
= (CFMutableDictionaryRef
) context
; 
4134         CFDictionarySetValue(dict
, key
, value
); 
4138 // Function to change matching items from non-syncable to syncable 
4139 // (if toSyncable is true), otherwise from syncable to non-syncable. 
4140 // This currently moves items between keychain containers. 
4142 static OSStatus 
SecItemChangeSynchronizability(CFDictionaryRef query
, CFDictionaryRef changes
, Boolean toSyncable
) 
4144         // Note: the input query dictionary is a mutable copy of the query originally 
4145         // provided by the caller as the first parameter to SecItemUpdate. It may not 
4146         // specify returning attributes or data, but we will need both to make a copy. 
4148         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnRef
); 
4149         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnPersistentRef
); 
4150         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnData
); 
4151         CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4152         if (NULL 
== CFDictionaryGetValue(changes
, kSecValueData
)) 
4153                 CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnData
, kCFBooleanTrue
); 
4158                 status 
= SecItemCopyMatching_osx(query
, &result
); 
4160                 status 
= SecItemCopyMatching_ios(query
, &result
); 
4165                 return errSecItemNotFound
; 
4167         CFMutableArrayRef items
; 
4168         if (CFGetTypeID(result
) != CFArrayGetTypeID()) { 
4169                 items 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4170                 CFArrayAppendValue(items
, result
); 
4174                 items 
= (CFMutableArrayRef
)result
; 
4177         CFIndex idx
, count 
= (items
) ? CFArrayGetCount(items
) : 0; 
4178         int priority 
= LOG_DEBUG
; 
4180         for (idx 
= 0; idx 
< count
; idx
++) { 
4181                 CFDictionaryRef dict 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(items
, idx
); 
4182                 CFMutableDictionaryRef item 
= (CFMutableDictionaryRef
) 
4183                         SecItemCopyTranslatedAttributes(dict
, 
4184                                 CFDictionaryGetValue(query
, kSecClass
), 
4185                                 (toSyncable
) ? true : false /*iOSOut*/, 
4186                                 true /*pruneMatch*/, 
4188                                 true /*pruneReturn*/, 
4189                                 false /*pruneData*/, 
4190                                 (toSyncable
) ? true : false /*pruneAccess*/); 
4191                 // hold onto the query before applying changes, in case the item already exists. 
4192                 // note that we cannot include the creation or modification dates from our 
4193                 // found item in this query, as they may not match the item in the other keychain. 
4194                 CFMutableDictionaryRef itemQuery 
= CFDictionaryCreateMutableCopy(NULL
, 0, item
); 
4195                 CFDictionaryRemoveValue(itemQuery
, kSecAttrCreationDate
); 
4196                 CFDictionaryRemoveValue(itemQuery
, kSecAttrModificationDate
); 
4197                 // apply changes to the item dictionary that we will pass to SecItemAdd 
4198                 CFDictionaryApplyFunction(changes
, SecItemApplyChanges
, item
); 
4200                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4201                         status 
= SecItemAdd_ios(item
, NULL
); 
4202                         secitemlog(priority
, "ChangeSync: SecItemAdd_ios=%d", status
); 
4203                         if (errSecDuplicateItem 
== status
) { 
4204                                 // find and apply changes to the existing syncable item. 
4205                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4206                                 status 
= SecItemUpdate_ios(itemQuery
, changes
); 
4207                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_ios=%d", status
); 
4209                         if (errSecSuccess 
== status
) { 
4210                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4211                                 status 
= SecItemDelete_osx(itemQuery
); 
4212                                 secitemlog(priority
, "ChangeSync: SecItemDelete_osx=%d", status
); 
4216                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4217                         status 
= SecItemAdd_osx(item
, NULL
); 
4218                         secitemlog(priority
, "ChangeSync: SecItemAdd_osx=%d", status
); 
4219                         if (errSecDuplicateItem 
== status
) { 
4220                                 // find and apply changes to the existing non-syncable item. 
4221                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4222                                 status 
= SecItemUpdate_osx(itemQuery
, changes
); 
4223                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_osx=%d", status
); 
4225                         if (errSecSuccess 
== status
) { 
4226                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4227                                 status 
= SecItemDelete_ios(itemQuery
); 
4228                                 secitemlog(priority
, "ChangeSync: SecItemDelete_ios=%d", status
); 
4231                 CFReleaseSafe(item
); 
4232                 CFReleaseSafe(itemQuery
); 
4236         CFReleaseSafe(items
); 
4245 SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
) { 
4246         CFTypeRef ref 
= NULL
; 
4247         CFStringRef item_class_string 
= (CFStringRef
)CFDictionaryGetValue(refAttributes
, kSecClass
); 
4248         SecItemClass item_class 
= (SecItemClass
) 0; 
4250         if (CFEqual(item_class_string
, kSecClassGenericPassword
)) { 
4251                 item_class 
= kSecGenericPasswordItemClass
; 
4252         } else if (CFEqual(item_class_string
, kSecClassInternetPassword
)) { 
4253                 item_class 
= kSecInternetPasswordItemClass
; 
4256         if (item_class 
!= 0) { 
4257                 // we carry v_Data around here so the *_ios calls can find it and locate 
4258                 // their own data.   Putting things in the attribute list doesn't help as 
4259                 // the osx keychainitem and item calls bail when they don't see a keychain 
4260                 // object.   If we need to make them work we either have to bridge them, or 
4261                 // find a way to craft a workable keychain object.   #if'ed code left below 
4262                 // in case we need to go down that path. 
4264     SecKeychainAttributeList attrs 
= {}; 
4265     SecKeychainAttribute attr 
= {}; 
4271     Item item 
= Item(item_class
, &attrs
, 0, ""); 
4272                 v 
= CFDictionaryGetValue(refAttributes
, kSecValuePersistentRef
); 
4274                         item
->setPersistentRef((CFDataRef
)v
); 
4276                 ref 
= item
->handle(); 
4283  * SecItemValidateAppleApplicationGroupAccess determines if the caller 
4284  * is a member of the specified application group, and is signed by Apple. 
4287 SecItemValidateAppleApplicationGroupAccess(CFStringRef group
) 
4289         SecTrustedApplicationRef app 
= NULL
; 
4290         SecRequirementRef requirement 
= NULL
; 
4291         SecCodeRef code 
= NULL
; 
4292         OSStatus status 
= errSecParam
; 
4295                 CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(group
), kCFStringEncodingUTF8
) + 1; 
4296                 char* buffer 
= (char*) malloc(length
); 
4298                         if (CFStringGetCString(group
, buffer
, length
, kCFStringEncodingUTF8
)) { 
4299                                 status 
= SecTrustedApplicationCreateApplicationGroup(buffer
, NULL
, &app
); 
4303                         status 
= errSecMemoryError
; 
4307                 status 
= SecTrustedApplicationCopyRequirement(app
, &requirement
); 
4310                 status 
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
); 
4313                 status 
= SecCodeCheckValidity(code
, kSecCSDefaultFlags
, requirement
); 
4316         CFReleaseSafe(code
); 
4317         CFReleaseSafe(requirement
); 
4322 static Mutex
& gParentCertCacheLock() { 
4323     static Mutex fParentCertCacheLock
; 
4324     return fParentCertCacheLock
; 
4326 static CFMutableDictionaryRef gParentCertCache
; 
4327 static CFMutableArrayRef gParentCertCacheList
; 
4328 #define PARENT_CACHE_SIZE 100 
4330 void SecItemParentCachePurge() { 
4331     StLock
<Mutex
> _(gParentCertCacheLock()); 
4332     CFReleaseNull(gParentCertCache
); 
4333     CFReleaseNull(gParentCertCacheList
); 
4336 static CFArrayRef CF_RETURNS_RETAINED 
parentCacheRead(SecCertificateRef certificate
) { 
4337     CFArrayRef parents 
= NULL
; 
4339     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4340     if (!digest
) return NULL
; 
4342     StLock
<Mutex
> _(gParentCertCacheLock()); 
4343     if (gParentCertCache 
&& gParentCertCacheList
) { 
4344         if (0 <= (ix 
= CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4345                                                    CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4347             // Cache hit. Get value and move entry to the top of the list. 
4348             parents 
= (CFArrayRef
)CFDictionaryGetValue(gParentCertCache
, digest
); 
4349             CFArrayRemoveValueAtIndex(gParentCertCacheList
, ix
); 
4350             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4353     CFRetainSafe(parents
); 
4357 static void parentCacheWrite(SecCertificateRef certificate
, CFArrayRef parents
) { 
4358     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4359     if (!digest
) return; 
4361     StLock
<Mutex
> _(gParentCertCacheLock()); 
4362     if (!gParentCertCache 
|| !gParentCertCacheList
) { 
4363         CFReleaseNull(gParentCertCache
); 
4364         gParentCertCache 
= makeCFMutableDictionary(); 
4365         CFReleaseNull(gParentCertCacheList
); 
4366         gParentCertCacheList 
= makeCFMutableArray(0); 
4369     if (gParentCertCache 
&& gParentCertCacheList
) { 
4370         // check to make sure another thread didn't add this entry to the cache already 
4371         if (0 > CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4372                                             CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4374             CFDictionaryAddValue(gParentCertCache
, digest
, parents
); 
4375             if (PARENT_CACHE_SIZE 
<= CFArrayGetCount(gParentCertCacheList
)) { 
4376                 // Remove least recently used cache entry. 
4377                 CFDictionaryRemoveValue(gParentCertCache
, CFArrayGetValueAtIndex(gParentCertCacheList
, 0)); 
4378                 CFArrayRemoveValueAtIndex(gParentCertCacheList
, 0); 
4380             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4386  * SecItemCopyParentCertificates_osx returns an array of zero of more possible 
4387  * issuer certificates for the provided certificate. No cryptographic validation 
4388  * of the signature is performed in this function; its purpose is only to 
4389  * provide a list of candidate certificates. 
4392 SecItemCopyParentCertificates_osx(SecCertificateRef certificate
, void *context
) 
4394 #pragma unused (context) /* for now; in future this can reference a container object */ 
4395         /* Check for parents in keychain cache */ 
4396         CFArrayRef parents 
= parentCacheRead(certificate
); 
4401         /* Cache miss. Query for parents. */ 
4402 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
4403         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4405         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4406         CFRetainSafe(normalizedIssuer
); 
4409         CFMutableArrayRef combinedSearchList 
= NULL
; 
4411         /* Define the array of keychains which will be searched for parents. */ 
4412         CFArrayRef searchList 
= NULL
; 
4413         status 
= SecKeychainCopySearchList(&searchList
); 
4415                 combinedSearchList 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, searchList
); 
4416                 CFRelease(searchList
); 
4418                 combinedSearchList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4420         SecKeychainRef rootStoreKeychain 
= NULL
; 
4421         status 
= SecKeychainOpen(SYSTEM_ROOT_STORE_PATH
, &rootStoreKeychain
); 
4422         if (rootStoreKeychain
) { 
4423                 if (combinedSearchList
) { 
4424                         CFArrayAppendValue(combinedSearchList
, rootStoreKeychain
); 
4426                 CFRelease(rootStoreKeychain
); 
4429         /* Create and populate a fixed-size query dictionary. */ 
4430         CFMutableDictionaryRef query 
= CFDictionaryCreateMutable(NULL
, 5, 
4431                         &kCFTypeDictionaryKeyCallBacks
, 
4432                         &kCFTypeDictionaryValueCallBacks
); 
4433         CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
4434         CFDictionaryAddValue(query
, kSecReturnData
, kCFBooleanTrue
); 
4435         CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4436         if (combinedSearchList
) { 
4437                 CFDictionaryAddValue(query
, kSecMatchSearchList
, combinedSearchList
); 
4438                 CFRelease(combinedSearchList
); 
4441         CFTypeRef results 
= NULL
; 
4442         if (normalizedIssuer
) { 
4443                 /* Look up certs whose subject is the same as this cert's issuer. */ 
4444                 CFDictionaryAddValue(query
, kSecAttrSubject
, normalizedIssuer
); 
4445                 status 
= SecItemCopyMatching_osx(query
, &results
); 
4448                 /* Cannot match anything without an issuer! */ 
4449                 status 
= errSecItemNotFound
; 
4452         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4453                 secitemlog(LOG_WARNING
, "SecItemCopyParentCertificates_osx: %d", (int)status
); 
4457         CFMutableArrayRef result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4458         CFTypeID resultType 
= (results
) ? CFGetTypeID(results
) : 0; 
4459         if (resultType 
== CFArrayGetTypeID()) { 
4460                 CFIndex index
, count 
= CFArrayGetCount((CFArrayRef
)results
); 
4461                 for (index 
= 0; index 
< count
; index
++) { 
4462                         CFDataRef data 
= (CFDataRef
) CFArrayGetValueAtIndex((CFArrayRef
)results
, index
); 
4464                                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
4466                                         CFArrayAppendValue(result
, cert
); 
4471         } else if (results 
&& resultType 
== CFDataGetTypeID()) { 
4472                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)results
); 
4474                         CFArrayAppendValue(result
, cert
); 
4478         CFReleaseSafe(results
); 
4479         CFReleaseSafe(normalizedIssuer
); 
4482         parentCacheWrite(certificate
, result
); 
4487 SecCertificateRef 
SecItemCopyStoredCertificate(SecCertificateRef certificate
, void *context
) 
4489 #pragma unused (context) /* for now; in future this can reference a container object */ 
4491         /* Certificates are unique by issuer and serial number. */ 
4492         CFDataRef serialNumber 
= SecCertificateCopySerialNumberData(certificate
, NULL
); 
4493 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
4494         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4496         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4497         CFRetainSafe(normalizedIssuer
); 
4500         const void *keys
[] = { 
4504                 kSecAttrSerialNumber
, 
4508                 kSecClassCertificate
, 
4514         CFDictionaryRef query 
= CFDictionaryCreate(NULL
, keys
, values
, 5,       NULL
, NULL
); 
4515         CFTypeRef result 
= NULL
; 
4517         OSStatus status 
= SecItemCopyMatching_osx(query
, &result
); 
4518         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4519                 secitemlog(LOG_WARNING
, "SecItemCopyStoredCertificate: %d", (int)status
); 
4520                 CFReleaseNull(result
); 
4522         CFReleaseSafe(query
); 
4523         CFReleaseSafe(serialNumber
); 
4524         CFReleaseSafe(normalizedIssuer
); 
4526         return (SecCertificateRef
)result
; 
4530  * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary 
4531  * and attempts to return a sanitized copy for passing to the underlying 
4532  * platform-specific implementation code. 
4534  * If iOSOut is true, one or more translations may apply: 
4535  *   - SecKeychain refs are removed, since there aren't multiple keychains 
4536  *   - SecPolicy refs are removed, since they can't be externalized 
4537  *   - SecAccess refs are removed, and potentially translated to entitlements 
4539  * If pruneMatch is true, kSecMatch* attributes are removed; this avoids 
4540  * parameter errors due to strict input checks in secd, which only permits 
4541  * these constants for calls to SecItemCopyMatching. 
4543  * If pruneSync is true, the kSecAttrSynchronizable attribute is removed. 
4544  * This permits a query to be reused for non-synchronizable items, or to 
4545  * resolve a search based on a persistent item reference for iOS. 
4547  * If pruneReturn is true, kSecReturn* attributes are removed; this avoids 
4548  * parameter errors due to strict input checks in secd, which do not permit 
4549  * these constants for calls to SecItemUpdate. 
4552 SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
4553         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
) 
4555         CFMutableDictionaryRef result 
= CFDictionaryCreateMutableCopy(NULL
, 0, inOSXDict
); 
4556         if (result 
== NULL
) { 
4561                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4565                 /* Match constants are only supported on iOS for SecItemCopyMatching, 
4566                  * and will generate an error if passed to other SecItem API functions; 
4567                  * on OS X, they're just ignored if not applicable for the context. 
4569                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4570                 CFDictionaryRemoveValue(result
, kSecMatchItemList
); 
4571                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4572                 CFDictionaryRemoveValue(result
, kSecMatchIssuers
); 
4573                 CFDictionaryRemoveValue(result
, kSecMatchEmailAddressIfPresent
); 
4574                 CFDictionaryRemoveValue(result
, kSecMatchSubjectContains
); 
4575                 CFDictionaryRemoveValue(result
, kSecMatchCaseInsensitive
); 
4576                 CFDictionaryRemoveValue(result
, kSecMatchTrustedOnly
); 
4577                 CFDictionaryRemoveValue(result
, kSecMatchValidOnDate
); 
4578                 CFDictionaryRemoveValue(result
, kSecMatchLimit
); 
4579                 CFDictionaryRemoveValue(result
, kSecMatchLimitOne
); 
4580                 CFDictionaryRemoveValue(result
, kSecMatchLimitAll
); 
4584                 /* Return constants are not supported on iOS for SecItemUpdate, 
4585                  * where they will generate an error; on OS X, they're just ignored 
4586                  * if not applicable for the context. 
4588                 CFDictionaryRemoveValue(result
, kSecReturnData
); 
4589                 CFDictionaryRemoveValue(result
, kSecReturnAttributes
); 
4590                 CFDictionaryRemoveValue(result
, kSecReturnRef
); 
4591                 CFDictionaryRemoveValue(result
, kSecReturnPersistentRef
); 
4595                 /* Searching on data is not supported. */ 
4596                 CFDictionaryRemoveValue(result
, kSecValueData
); 
4600         /* Searching on access lists is not supported */ 
4601         CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4605                 /* Remove kSecMatchSearchList (value is array of SecKeychainRef); 
4606                  * cannot specify a keychain search list on iOS 
4608                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4610                 /* Remove kSecUseKeychain (value is a SecKeychainRef); 
4611                  * cannot specify a keychain on iOS 
4613                 CFDictionaryRemoveValue(result
, kSecUseKeychain
); 
4615                 /* Potentially translate kSecAttrAccess (value is a SecAccessRef), 
4616                  * unless kSecAttrAccessGroup has already been specified. 
4618                 SecAccessRef access 
= (SecAccessRef
) CFDictionaryGetValue(result
, kSecAttrAccess
); 
4619                 CFStringRef accessGroup 
= (CFStringRef
) CFDictionaryGetValue(result
, kSecAttrAccessGroup
); 
4620                 if (access 
!= NULL 
&& accessGroup 
== NULL
) { 
4621                         /* Translate "InternetAccounts" application group to an access group */ 
4622                         if (errSecSuccess 
== SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) { 
4623                                 /* The caller is a valid member of the application group. */ 
4624                                 CFStringRef groupName 
= CFSTR("appleaccount"); 
4625                                 CFTypeRef value 
= CFDictionaryGetValue(result
, kSecAttrAuthenticationType
); 
4626                                 if (value 
&& CFEqual(value
, kSecAttrAuthenticationTypeHTMLForm
)) { 
4627                                         groupName 
= CFSTR("com.apple.cfnetwork"); 
4629                                 CFDictionarySetValue(result
, kSecAttrAccessGroup
, groupName
); 
4632                 CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4634                 /* If item is specified by direct reference, and this is an iOS search, 
4635                  * replace it with a persistent reference, if it was recorded inside ItemImpl. 
4637                 CFTypeRef directRef 
= CFDictionaryGetValue(result
, kSecValueRef
); 
4638                 if (directRef 
!= NULL
) { 
4639                         CFTypeID typeID 
= CFGetTypeID(directRef
); 
4640                         if ((typeID 
!= SecKeyGetTypeID() || SecKeyIsCDSAKey((SecKeyRef
)directRef
)) && 
4641                                 (typeID 
!= SecCertificateGetTypeID() || SecCertificateIsItemImplInstance((SecCertificateRef
)directRef
)) && 
4642                                 (typeID 
!= SecIdentityGetTypeID())) { 
4643                                 CFDataRef persistentRef 
= _SecItemGetPersistentReference(directRef
); 
4644                                 if (persistentRef
) { 
4645                                         CFDictionarySetValue(result
, kSecValuePersistentRef
, persistentRef
); 
4646                                         CFDictionaryRemoveValue(result
, kSecValueRef
); 
4651                 /* If item is specified by persistent reference, and this is an iOS search, 
4652                  * remove the synchronizable attribute as it will be rejected by secd. 
4654                 CFTypeRef persistentRef 
= CFDictionaryGetValue(result
, kSecValuePersistentRef
); 
4655                 if (persistentRef
) { 
4656                         CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4659                 /* Remove kSecAttrModificationDate; this should never be used as criteria 
4660                  * for a search, or to add/modify an item. (If we are cloning an item 
4661                  * and want to keep its modification date, we don't call this function.) 
4662                  * It turns out that some clients are using the full attributes dictionary 
4663                  * returned by SecItemCopyMatching as a query to find the same item later, 
4664                  * which won't work once the item is updated. 
4666                 CFDictionaryRemoveValue(result
, kSecAttrModificationDate
); 
4668         /* Find all intermediate certificates in OSX keychain and append them in to the kSecMatchIssuers. 
4669          * This is required because secd cannot do query in to the OSX keychain 
4671         CFTypeRef matchIssuers 
= CFDictionaryGetValue(result
, kSecMatchIssuers
); 
4672         if (matchIssuers 
&& CFGetTypeID(matchIssuers
) == CFArrayGetTypeID()) { 
4673             CFArrayRef newMatchIssuers 
= _CopyMatchingIssuers((CFArrayRef
)matchIssuers
); 
4674             if (newMatchIssuers
) { 
4675                 CFDictionarySetValue(result
, kSecMatchIssuers
, newMatchIssuers
); 
4676                 CFRelease(newMatchIssuers
); 
4681                 /* iOS doesn't add the class attribute, so we must do it here. */ 
4683                         CFDictionarySetValue(result
, kSecClass
, itemClass
); 
4685                 /* Remove attributes which are not part of the OS X database schema. */ 
4686                 CFDictionaryRemoveValue(result
, kSecAttrAccessible
); 
4687                 CFDictionaryRemoveValue(result
, kSecAttrAccessControl
); 
4688                 CFDictionaryRemoveValue(result
, kSecAttrAccessGroup
); 
4689                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4690                 CFDictionaryRemoveValue(result
, kSecAttrTombstone
); 
4693     /* This attribute is consumed by the bridge itself. */ 
4694     CFDictionaryRemoveValue(result
, kSecAttrNoLegacy
); 
4702 _CopyMatchingIssuers(CFArrayRef matchIssuers
) { 
4703     CFMutableArrayRef result 
= NULL
; 
4704     CFMutableDictionaryRef query 
= NULL
; 
4705     CFMutableDictionaryRef policyProperties 
= NULL
; 
4706     SecPolicyRef policy 
= NULL
; 
4707     CFTypeRef matchedCertificates 
= NULL
; 
4709     require_quiet(policyProperties 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), out
); 
4710     CFDictionarySetValue(policyProperties
, kSecPolicyKU_KeyCertSign
, kCFBooleanTrue
); 
4711     require_quiet(policy 
= SecPolicyCreateWithProperties(kSecPolicyAppleX509Basic
, policyProperties
), out
); 
4713     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), out
); 
4714     CFDictionarySetValue(query
, kSecClass
, kSecClassCertificate
); 
4715     CFDictionarySetValue(query
, kSecMatchIssuers
, matchIssuers
); 
4716     CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4717     CFDictionarySetValue(query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4718     CFDictionarySetValue(query
, kSecUseCertificatesWithMatchIssuers
, kCFBooleanTrue
); 
4719     CFDictionarySetValue(query
, kSecMatchPolicy
, policy
); 
4721     if (SecItemCopyMatching_osx(query
, &matchedCertificates
) == errSecSuccess 
&& CFGetTypeID(matchedCertificates
) == CFArrayGetTypeID()) { 
4722         require_quiet(result 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, (CFArrayRef
)matchedCertificates
), out
); 
4723         for(CFIndex i 
= 0; i 
< CFArrayGetCount((CFArrayRef
)matchedCertificates
); ++i
) { 
4724             CFDictionaryRef attributes 
= (CFDictionaryRef
)CFArrayGetValueAtIndex((CFArrayRef
)matchedCertificates
, i
); 
4725             CFTypeRef subject 
= CFDictionaryGetValue(attributes
, kSecAttrSubject
); 
4726             if (!CFArrayContainsValue(result
, CFRangeMake(0, CFArrayGetCount(result
)), subject
)) { 
4727                 CFArrayAppendValue(result
, subject
); 
4733     CFReleaseSafe(query
); 
4734     CFReleaseSafe(policyProperties
); 
4735     CFReleaseSafe(policy
); 
4736     CFReleaseSafe(matchedCertificates
); 
4742 SecItemMergeResults(bool can_target_ios
, OSStatus status_ios
, CFTypeRef result_ios
, 
4743                                         bool can_target_osx
, OSStatus status_osx
, CFTypeRef result_osx
, 
4744                                         CFTypeRef 
*result
) { 
4745         // When querying both keychains and iOS keychain fails because of missing 
4746         // entitlements, completely ignore iOS keychain result.  This is to keep 
4747         // backward compatibility with applications which know nothing about iOS keychain 
4748         // and use SecItem API to access OSX keychain which does not need any entitlements. 
4749         if (can_target_osx 
&& can_target_ios 
&& status_ios 
== errSecMissingEntitlement
) { 
4750                 can_target_ios 
= false; 
4753         if (can_target_osx 
&& can_target_ios
) { 
4754                 // If both keychains were targetted, examine returning statuses and decide what to do. 
4755                 if (status_ios 
!= errSecSuccess
) { 
4756                         // iOS keychain failed to produce results because of some error, go with results from OSX keychain. 
4757             // Since iOS keychain queries will fail without a keychain-access-group or proper entitlements, SecItemCopyMatching 
4758             // calls against the OSX keychain API that should return errSecItemNotFound will return nonsense from the iOS keychain. 
4759                         AssignOrReleaseResult(result_osx
, result
); 
4761                 } else if (status_osx 
!= errSecSuccess
) { 
4762                         if (status_osx 
!= errSecItemNotFound
) { 
4763                                 // OSX failed to produce results with some failure mode (else than not_found), but iOS produced results. 
4764                                 // We have to either return OSX failure result and discard iOS results, or vice versa.  For now, we just 
4765                                 // ignore OSX error and return just iOS results. 
4766                                 secitemlog(LOG_NOTICE
, "SecItemMergeResults: osx_result=%d, ignoring it, iOS succeeded fine", status_osx
); 
4769                         // OSX failed to produce results, but we have success from iOS keychain; go with results from iOS keychain. 
4770                         AssignOrReleaseResult(result_ios
, result
); 
4771                         return errSecSuccess
; 
4773                         // Both searches succeeded, merge results. 
4774                         if (result 
!= NULL
) { 
4775                                 CFTypeID id_osx 
= (result_osx
) ? CFGetTypeID(result_osx
) : 0; 
4776                                 CFTypeID id_ios 
= (result_ios
) ? CFGetTypeID(result_ios
) : 0; 
4777                                 CFTypeID id_array 
= CFArrayGetTypeID(); 
4778                                 if ((id_osx 
== id_array
) && (id_ios 
== id_array
)) { 
4779                                         // Fold the arrays into one. 
4780                                         *result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4781                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_ios
, 
4782                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_ios
))); 
4783                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_osx
, 
4784                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_osx
))); 
4786                                         // Result type is not an array, so only one match can be returned. 
4787                                         *result 
= (id_ios
) ? result_ios 
: result_osx
; 
4788                                         CFRetainSafe(*result
); 
4791                         CFReleaseSafe(result_osx
); 
4792                         CFReleaseSafe(result_ios
); 
4793                         return errSecSuccess
; 
4795         } else if (can_target_ios
) { 
4796                 // Only iOS keychain was targetted. 
4797                 AssignOrReleaseResult(result_ios
, result
); 
4799         } else if (can_target_osx
) { 
4800                 // Only OSX keychain was targetted. 
4801                 AssignOrReleaseResult(result_osx
, result
); 
4804                 // Query could not run at all? 
4810 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef 
*result
) 
4812     os_activity_t activity 
= os_activity_create("SecItemCopyMatching", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4813     os_activity_scope(activity
); 
4814     os_release(activity
); 
4819         secitemshow(query
, "SecItemCopyMatching query:"); 
4821         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4822         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4823         bool can_target_ios
, can_target_osx
; 
4824         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
); 
4825         if (status 
!= errSecSuccess
) { 
4829         if (can_target_ios
) { 
4830                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4831                         CFDictionaryGetValue(query
, kSecClass
), true, false, false, false, true, true); 
4833                         status_ios 
= errSecParam
; 
4836                         status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4837                         CFRelease(attrs_ios
); 
4839                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_ios result: %d", status_ios
); 
4842         if (can_target_osx
) { 
4843                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4844                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, false, true, true); 
4846                         status_osx 
= errSecParam
; 
4849                         status_osx 
= SecItemCopyMatching_osx(attrs_osx
, &result_osx
); 
4850                         CFRelease(attrs_osx
); 
4852                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_osx result: %d", status_osx
); 
4855         status 
= SecItemMergeResults(can_target_ios
, status_ios
, result_ios
, 
4856                                                                  can_target_osx
, status_osx
, result_osx
, result
); 
4857         secitemlog(LOG_NOTICE
, "SecItemCopyMatching result: %d", status
); 
4862 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
4864     os_activity_t activity 
= os_activity_create("SecItemAdd", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4865     os_activity_scope(activity
); 
4866     os_release(activity
); 
4874         secitemshow(attributes
, "SecItemAdd attrs:"); 
4876         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4877         bool can_target_ios
, can_target_osx
; 
4878         OSStatus status 
= SecItemCategorizeQuery(attributes
, can_target_ios
, can_target_osx
); 
4879         if (status 
!= errSecSuccess
) { 
4883         // SecItemAdd cannot be really done on both keychains.  In order to keep backward compatibility 
4884         // with existing applications, we prefer to add items into legacy keychain and fallback 
4885         // into iOS (modern) keychain only when the query is not suitable for legacy keychain. 
4886         if (!can_target_osx
) { 
4887                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(attributes
, 
4888                         NULL
, true, true, false, false, false, false); 
4890                         status 
= errSecParam
; 
4892             status 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4893                         CFRelease(attrs_ios
); 
4895                 secitemlog(LOG_NOTICE
, "SecItemAdd_ios result: %d", status
); 
4896                 AssignOrReleaseResult(result_ios
, result
); 
4899                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(attributes
, 
4900                     NULL
, false, false, true, false, false, false); 
4902                         status 
= errSecParam
; 
4904                         status 
= SecItemAdd_osx(attrs_osx
, &result_osx
); 
4905                         CFRelease(attrs_osx
); 
4907                 secitemlog(LOG_NOTICE
, "SecItemAdd_osx result: %d", status
); 
4908                 AssignOrReleaseResult(result_osx
, result
); 
4914 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
4916     os_activity_t activity 
= os_activity_create("SecItemUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4917     os_activity_scope(activity
); 
4918     os_release(activity
); 
4920         if (!query 
|| !attributesToUpdate
) { 
4923         secitemshow(query
, "SecItemUpdate query:"); 
4924         secitemshow(attributesToUpdate
, "SecItemUpdate attrs:"); 
4926         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4927         bool can_target_ios
, can_target_osx
; 
4928         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
); 
4929         if (status 
!= errSecSuccess
) { 
4933         if (can_target_ios
) { 
4934                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4935                         CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4937                         status_ios 
= errSecParam
; 
4940             if (SecItemHasSynchronizableUpdate(true, attributesToUpdate
)) { 
4941                 status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
4943                 status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4945                         CFRelease(attrs_ios
); 
4947                 secitemlog(LOG_NOTICE
, "SecItemUpdate_ios result: %d", status_ios
); 
4950         if (can_target_osx
) { 
4951                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4952                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, true, true, true); 
4954                         status_osx 
= errSecParam
; 
4957                         if (SecItemHasSynchronizableUpdate(false, attributesToUpdate
)) 
4958                                 status_osx 
= SecItemChangeSynchronizability(attrs_osx
, attributesToUpdate
, true); 
4960                                 status_osx 
= SecItemUpdate_osx(attrs_osx
, attributesToUpdate
); 
4962                         CFRelease(attrs_osx
); 
4964                 secitemlog(LOG_NOTICE
, "SecItemUpdate_osx result: %d", status_osx
); 
4967         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
4968                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
4969         secitemlog(LOG_NOTICE
, "SecItemUpdate result: %d", status
); 
4974 SecItemDelete(CFDictionaryRef query
) 
4976     os_activity_t activity 
= os_activity_create("SecItemDelete", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4977     os_activity_scope(activity
); 
4978     os_release(activity
); 
4983         secitemshow(query
, "SecItemDelete query:"); 
4985         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4986         bool can_target_ios
, can_target_osx
; 
4987         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
); 
4988         if (status 
!= errSecSuccess
) { 
4992         if (can_target_ios
) { 
4993                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4994                         NULL
, true, true, false, true, true, true); 
4996                         status_ios 
= errSecParam
; 
4998             status_ios 
= SecItemDelete_ios(attrs_ios
); 
4999                         CFRelease(attrs_ios
); 
5001                 secitemlog(LOG_NOTICE
, "SecItemDelete_ios result: %d", status_ios
); 
5004         if (can_target_osx
) { 
5005                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
5006                     NULL
, false, false, true, true, true, true); 
5008                         status_osx 
= errSecParam
; 
5010                         status_osx 
= SecItemDelete_osx(attrs_osx
); 
5011                         CFRelease(attrs_osx
); 
5013                 secitemlog(LOG_NOTICE
, "SecItemDelete_osx result: %d", status_osx
); 
5016         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
5017                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
5018         secitemlog(LOG_NOTICE
, "SecItemCopyDelete result: %d", status
); 
5023 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
) 
5025         OSStatus status 
= SecItemUpdateTokenItems_ios(tokenID
, tokenItemsAttributes
); 
5026         secitemlog(LOG_NOTICE
, "SecItemUpdateTokenItems_ios result: %d", status
); 
5031 SecItemCopyMatching_osx( 
5032         CFDictionaryRef query
, 
5035         if (!query 
|| !result
) 
5040         CFAllocatorRef allocator 
= CFGetAllocator(query
); 
5041         CFIndex matchCount 
= 0; 
5042         CFMutableArrayRef itemArray 
= NULL
; 
5043         SecKeychainItemRef item 
= NULL
; 
5044         SecIdentityRef identity 
= NULL
; 
5045         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5047         // validate input query parameters and create the search reference 
5048         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(query
, &status
); 
5049         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5051         // find the next match until we hit maxMatches, or no more matches found 
5052         while ( !(!itemParams
->returnAllMatches 
&& matchCount 
>= itemParams
->maxMatches
) && 
5053                         SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == errSecSuccess
) { 
5055                 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
)) 
5056                         continue; // move on to next item 
5058                 ++matchCount
; // we have a match 
5060                 tmpStatus 
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
); 
5061                 if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5069                         CFRelease(identity
); 
5074         if (status 
== errSecSuccess
) 
5075                 status 
= (matchCount 
> 0) ? errSecSuccess 
: errSecItemNotFound
; 
5078         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5082         _FreeSecItemParams(itemParams
); 
5088 SecItemCopyDisplayNames( 
5090         CFArrayRef 
*displayNames
) 
5094         Required(displayNames
); 
5096     return errSecUnimplemented
; 
5102         CFDictionaryRef attributes
, 
5110         CFAllocatorRef allocator 
= CFGetAllocator(attributes
); 
5111         CFMutableArrayRef itemArray 
= NULL
; 
5112         SecKeychainItemRef item 
= NULL
; 
5113         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5115         // validate input attribute parameters 
5116         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(attributes
, &status
); 
5117         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5119         // currently, we don't support adding SecIdentityRef items (an aggregate item class), 
5120         // since the private key should already be in a keychain by definition. We could support 
5121         // this as a copy operation for the private key if a different keychain is specified, 
5122         // but in any case it should try to add the certificate. See <rdar://8317887>. 
5123         require_action(!itemParams
->returnIdentity
, error_exit
, status 
= errSecItemInvalidValue
); 
5125         if (itemParams
->useItems 
== NULL
) { 
5127                 require_action(itemParams
->itemData 
== NULL 
|| CFGetTypeID(itemParams
->itemData
) == CFDataGetTypeID(), 
5128                                            error_exit
, status 
= errSecItemInvalidValue
); 
5130                 // create a single keychain item specified by the input attributes 
5131                 status 
= SecKeychainItemCreateFromContent(itemParams
->itemClass
, 
5132                         itemParams
->attrList
, 
5133                         (itemParams
->itemData
) ? (UInt32
)CFDataGetLength(itemParams
->itemData
) : 0, 
5134                         (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
, 
5135                         itemParams
->keychain
, 
5138                 require_noerr(status
, error_exit
); 
5140                 // return results (if requested) 
5142                         itemParams
->maxMatches 
= 1; // in case kSecMatchLimit was set to > 1 
5143                         tmpStatus 
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5144                         if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5150                 // add multiple items which are specified in the itemParams->useItems array. 
5151                 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain. 
5152                 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain. 
5153                 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain. 
5155                 OSStatus aggregateStatus 
= errSecSuccess
; 
5156                 CFIndex ix
, count 
= CFArrayGetCount(itemParams
->useItems
); 
5157                 itemParams
->maxMatches 
= (count 
> 1) ? (int)count 
: 2; // force results to always be returned as an array 
5158                 for (ix
=0; ix 
< count
; ix
++) { 
5159                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
); 
5161                                 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) { 
5162                                         // SecCertificateRef item 
5163                                         tmpStatus 
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
); 
5164                                         if (!tmpStatus 
&& result
) { 
5165                                                 tmpStatus 
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5167                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5169                                 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) { 
5171                                         SecKeychainRef itemKeychain 
= NULL
; 
5172                                         tmpStatus 
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
); 
5173                                         if (tmpStatus 
== errSecSuccess
) { 
5174                                                 // key was in a keychain, so we can attempt to copy it 
5175                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5176                                                 tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5177                                                 if (!tmpStatus 
&& result
) { 
5178                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5181                                                         CFRelease(itemCopy
); 
5185                                                 // key was not in any keychain, so must be imported 
5186                                                 SecKeychainItemRef keyItem 
= NULL
; 
5187                                                 tmpStatus 
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
); 
5188                                                 if (!tmpStatus 
&& result
) { 
5189                                                         tmpStatus 
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5196                                                 CFRelease(itemKeychain
); 
5198                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5200                                 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) { 
5201                                         // SecKeychainItemRef item 
5202                                         SecKeychainItemRef itemCopy 
= NULL
; 
5203                                         tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5204                                         if (!tmpStatus 
&& result
) { 
5205                                                 tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5208                                                 CFRelease(itemCopy
); 
5210                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5212                                 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) { 
5213                                         // CFDataRef item (persistent reference) 
5214                                         SecKeychainItemRef realItem 
= NULL
; 
5215                                         tmpStatus 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
); 
5216                                         if (tmpStatus 
== errSecSuccess
) { 
5217                                                 // persistent reference resolved to a keychain item, so we can attempt to copy it 
5218                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5219                                                 tmpStatus 
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5220                                                 if (!tmpStatus 
&& result
) { 
5221                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5224                                                         CFRelease(itemCopy
); 
5228                                                 CFRelease(realItem
); 
5230                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5233                 } // end of itemList array loop 
5234                 status 
= aggregateStatus
; 
5235         } // end processing multiple items 
5238         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5242         _FreeSecItemParams(itemParams
); 
5249         CFDictionaryRef query
, 
5250         CFDictionaryRef attributesToUpdate
) 
5252         if (!query 
|| !attributesToUpdate
) 
5255         // run the provided query to get a list of items to update 
5256         CFTypeRef results 
= NULL
; 
5257         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5258         if (status 
!= errSecSuccess
) 
5259                 return status
; // nothing was matched, or the query was bad 
5261         CFArrayRef items 
= NULL
; 
5262         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5263                 items 
= (CFArrayRef
) results
; 
5266                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5270         OSStatus result 
= errSecSuccess
; 
5271         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5272         for (ix
=0; ix 
< count
; ix
++) { 
5273                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5275                         status 
= _UpdateKeychainItem(anItem
, attributesToUpdate
); 
5276                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
); 
5288         CFDictionaryRef query
) 
5293         // run the provided query to get a list of items to delete 
5294         CFTypeRef results 
= NULL
; 
5295         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5296         if (status 
!= errSecSuccess
) 
5297                 return status
; // nothing was matched, or the query was bad 
5299         CFArrayRef items 
= NULL
; 
5300         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5301                 items 
= (CFArrayRef
) results
; 
5304                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5308         OSStatus result 
= errSecSuccess
; 
5309         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5310         for (ix
=0; ix 
< count
; ix
++) { 
5311                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5313                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) { 
5314                                 status 
= _DeleteIdentity((SecIdentityRef
)anItem
); 
5317                                 status 
= _DeleteKeychainItem(anItem
); 
5319                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
);