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 "SecCertificatePrivP.h" 
  40 #include "TrustAdditions.h" 
  41 #include "TrustSettingsSchema.h" 
  42 #include <Security/SecTrustPriv.h> 
  43 #include "utilities/array_size.h" 
  45 #include <AssertMacros.h> 
  49 #include <Security/SecTrustedApplication.h> 
  50 #include <Security/SecTrustedApplicationPriv.h> 
  51 #include <Security/SecCode.h> 
  52 #include <Security/SecCodePriv.h> 
  53 #include <Security/SecRequirement.h> 
  55 #include <login/SessionAgentCom.h> 
  56 #include <login/SessionAgentStatusCom.h> 
  57 #include <os/activity.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
); 
  85 static void secitemlog(int priority
, const char *format
, ...) 
  90         if (priority 
< LOG_NOTICE
) // log warnings and errors 
  94                 va_start(list
, format
); 
  95                 vsyslog(priority
, format
, list
); 
 100 static void secitemshow(CFTypeRef obj
, const char *context
) 
 103         CFStringRef desc 
= CFCopyDescription(obj
); 
 106         CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1; 
 107         char* buffer 
= (char*) malloc(length
); 
 109                 Boolean converted 
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
); 
 111                         const char *prefix 
= (context
) ? context 
: ""; 
 112                         const char *separator 
= (context
) ? " " : ""; 
 113                         secitemlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
); 
 122 #define CFDataGetBytePtrVoid CFDataGetBytePtr 
 124 #pragma mark SecItem private utility functions 
 126 /******************************************************************************/ 
 128 struct ProtocolAttributeInfo 
{ 
 129         const CFStringRef 
*protocolValue
; 
 130         SecProtocolType protocolType
; 
 133 static ProtocolAttributeInfo gProtocolTypes
[] = { 
 134         { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP 
}, 
 135         { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount 
}, 
 136         { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP 
}, 
 137         { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC 
}, 
 138         { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP 
}, 
 139         { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3 
}, 
 140         { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP 
}, 
 141         { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS 
}, 
 142         { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP 
}, 
 143         { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP 
}, 
 144         { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk 
}, 
 145         { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP 
}, 
 146         { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet 
}, 
 147         { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH 
}, 
 148         { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS 
}, 
 149         { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS 
}, 
 150         { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy 
}, 
 151         { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy 
}, 
 152         { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy 
}, 
 153         { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB 
}, 
 154         { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP 
}, 
 155         { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy 
}, 
 156         { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP 
}, 
 157         { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC 
}, 
 158         { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP 
}, 
 159         { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS 
}, 
 160         { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS 
}, 
 161         { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS 
}, 
 162         { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS 
}, 
 163         { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS 
}, 
 164         { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S 
} 
 167 static const int kNumberOfProtocolTypes 
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
); 
 170  * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType. 
 172 static SecProtocolType
 
 173 _SecProtocolTypeForSecAttrProtocol( 
 176         SecProtocolType result 
= kSecProtocolTypeAny
; 
 178         if (protocol 
!= NULL
) { 
 180                 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 181                         if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) { 
 182                                 result 
= gProtocolTypes
[count
].protocolType
; 
 192  * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol. 
 195 _SecAttrProtocolForSecProtocolType( 
 196         SecProtocolType protocolType
) 
 198         CFTypeRef result 
= NULL
; 
 200         for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 201                 if (gProtocolTypes
[count
].protocolType 
== protocolType
) { 
 202                         result 
= *(gProtocolTypes
[count
].protocolValue
); 
 211 /******************************************************************************/ 
 213 struct AuthenticationAttributeInfo 
{ 
 214         const CFStringRef 
*authValue
; 
 215         SecAuthenticationType authType
; 
 218 static AuthenticationAttributeInfo gAuthTypes
[] = { 
 219         { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM 
}, 
 220         { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN 
}, 
 221         { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA 
}, 
 222         { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA 
}, 
 223         { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic 
}, 
 224         { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest 
}, 
 225         { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm 
}, 
 226         { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault 
} 
 229 static const int kNumberOfAuthenticationTypes 
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
); 
 232  * _SecAuthenticationTypeForSecAttrAuthenticationType converts a 
 233  * SecAttrAuthenticationType to a SecAuthenticationType. 
 235 static SecAuthenticationType
 
 236 _SecAuthenticationTypeForSecAttrAuthenticationType( 
 237         CFTypeRef authenticationType
) 
 239         SecAuthenticationType result 
= kSecAuthenticationTypeAny
; 
 241         if (authenticationType 
!= NULL
) { 
 243                 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 244                         if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) { 
 245                                 result 
= gAuthTypes
[count
].authType
; 
 255  * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType 
 256  * to a SecAttrAuthenticationType. 
 259 _SecAttrAuthenticationTypeForSecAuthenticationType( 
 260         SecAuthenticationType authenticationType
) 
 262         CFTypeRef result 
= NULL
; 
 264         for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 265                 if (gAuthTypes
[count
].authType 
== authenticationType
) { 
 266                         result 
= *(gAuthTypes
[count
].authValue
); 
 275 /******************************************************************************/ 
 277 struct KeyAlgorithmInfo 
{ 
 278         const CFStringRef 
*keyType
; 
 282 static KeyAlgorithmInfo gKeyTypes
[] = { 
 283         { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA 
}, 
 284         { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA 
}, 
 285         { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES 
}, 
 286         { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES 
}, 
 287         { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES 
}, 
 288         { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4 
}, 
 289         { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2 
}, 
 290         { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST 
}, 
 291         { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA 
}, 
 292         { &kSecAttrKeyTypeEC
, CSSM_ALGID_ECDSA 
} 
 295 static const int kNumberOfKeyTypes 
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
); 
 298 static UInt32 
_SecAlgorithmTypeFromSecAttrKeyType( 
 299         CFTypeRef keyTypeRef
) 
 301         UInt32 keyAlgValue 
= 0; 
 302         if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
)) 
 306         for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) { 
 307                 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) { 
 308                         keyAlgValue 
= gKeyTypes
[ix
].keyValue
; 
 313         //%%%TODO try to convert the input string to a number here 
 319 enum ItemRepresentation
 
 321         kStringRepresentation
, 
 323         kNumberRepresentation
, 
 324         kBooleanRepresentation
, 
 329 struct InternalAttributeListInfo
 
 332         const CFStringRef 
*newItemType
; 
 333         ItemRepresentation itemRepresentation
; 
 337 static InternalAttributeListInfo gGenericPasswordAttributes
[] = 
 339         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 340         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 341         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 342         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 343         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 344         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 345         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 346         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 347         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 348         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 349         { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation 
}, 
 350         { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation 
} 
 353 static const int kNumberOfGenericPasswordAttributes 
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 356 static InternalAttributeListInfo gInternetPasswordAttributes
[] = 
 358         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 359         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 360         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 361         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 362         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 363         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 364         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 365         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 366         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 367         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 368         { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation 
}, 
 369         { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation 
}, 
 370         { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation 
}, // maps from UInt32 value to string constant 
 371         { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation 
}, 
 372         { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation 
} 
 375 static const int kNumberOfInternetPasswordAttributes 
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 378 static InternalAttributeListInfo gCertificateAttributes
[] = 
 380         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 381         { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation 
}, 
 382         { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation 
}, 
 383         { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation 
}, 
 384         { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation 
}, 
 385         { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation 
}, 
 386         { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation 
}, 
 387         { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation 
} 
 390 static const int kNumberOfCertificateAttributes 
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
); 
 393 static InternalAttributeListInfo gKeyAttributes
[] = 
 395     { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation 
}, // key class maps from UInt32 value to string constant 
 396     { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation 
}, // note that "print name" maps to the user-visible label 
 397 //  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation }, 
 398     { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation 
}, 
 399 //  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 400 //  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 401     { 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 
 402     { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation 
}, 
 403 //  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key 
 404     { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation 
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES) 
 405     { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation 
}, 
 406     { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation 
}, 
 407 //  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 408 //  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 409 //  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 410 //  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 411 //  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 412 //  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 413     { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation 
}, 
 414     { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation 
}, 
 415     { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation 
}, 
 416     { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation 
}, 
 417     { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation 
}, 
 418 //  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 419 //  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 420     { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation 
}, 
 421     { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation 
} 
 424 static const int kNumberOfKeyAttributes 
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
); 
 427 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
) 
 431                 case kStringRepresentation
: 
 433                         if (CFStringGetTypeID() != CFGetTypeID(value
)) { 
 437                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 438                         char* buffer 
= (char*) malloc(maxLength
); 
 439                         Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 441                                 length 
= (UInt32
)strlen(buffer
); 
 451                 case kDataRepresentation
: 
 453                         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 454                 // We may have a string here, since the key label may be a GUID for the symmetric keys 
 455                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 456                 char* buffer 
= (char*) malloc(maxLength
); 
 457                 Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 459                     length 
= (UInt32
)strlen(buffer
); 
 469                         if (CFDataGetTypeID() != CFGetTypeID(value
)) { 
 473                         length 
= (UInt32
)CFDataGetLength((CFDataRef
) value
); 
 474                         uint8_t* buffer 
= (uint8_t*) malloc(length
); 
 475                         CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
); 
 479                 case kNumberRepresentation
: 
 481                         if (CFNumberGetTypeID() != CFGetTypeID(value
)) { 
 485                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 486                         Boolean converted 
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
); 
 488                                 length 
= sizeof(uint32_t); 
 498                 case kBooleanRepresentation
: 
 500                         if (CFBooleanGetTypeID() != CFGetTypeID(value
)) { 
 504                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 505                         *buffer 
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
 506                         length 
= sizeof(uint32_t); 
 510                 case kDateRepresentation
: 
 512                         if (CFDateGetTypeID() != CFGetTypeID(value
)) { 
 516                         char* buffer 
= (char*) calloc(1, 32); // max length of a CSSM date string 
 517                         CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
); 
 518                         length 
= (UInt32
)strlen(buffer
); 
 532 _ConvertNewFormatToOldFormat( 
 533         CFAllocatorRef allocator
, 
 534         const InternalAttributeListInfo
* info
, 
 536         CFDictionaryRef dictionaryRef
, 
 537         SecKeychainAttributeList
* &attrList
 
 540         // get the keychain attributes array from the data item 
 541         // here's the problem.  On the one hand, we have a dictionary that is purported to contain 
 542         // attributes for our type.  On the other hand, the dictionary may contain items we don't support, 
 543         // and we therefore don't know how many attributes we will have unless we count them first 
 546         attrList 
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
)); 
 548         // make storage to extract the dictionary items 
 549         CFIndex itemsInDictionary 
= CFDictionaryGetCount(dictionaryRef
); 
 550         CFTypeRef keys
[itemsInDictionary
]; 
 551         CFTypeRef values
[itemsInDictionary
]; 
 553         CFTypeRef 
*keysPtr 
= keys
; 
 554         CFTypeRef 
*valuesPtr 
= values
; 
 556         CFDictionaryGetKeysAndValues(dictionaryRef
, keys
, values
); 
 558         // count the number of items we are interested in 
 562         // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that 
 563         // we don't pay the price for this twice 
 564         SecKeychainAttrType tags
[itemsInDictionary
]; 
 565         ItemRepresentation types
[itemsInDictionary
]; 
 567         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 569                 CFTypeRef key 
= keysPtr
[i
]; 
 572                 for (j 
= 0; j 
< infoNumItems
; ++j
) 
 574                         if (CFEqual(*(info
[j
].newItemType
), key
)) 
 576                                 tags
[i
] = info
[j
].oldItemType
; 
 577                                 types
[i
] = info
[j
].itemRepresentation
; 
 583                 if (j 
>= infoNumItems
) 
 585                         // if we got here, we aren't interested in this item. 
 590         // now we can make the result array 
 591         attrList
->count 
= (UInt32
)count
; 
 592     attrList
->attr 
= (count 
> 0) ? (SecKeychainAttribute
*) malloc(sizeof(SecKeychainAttribute
) * count
) : NULL
; 
 594         // fill out the array 
 595         int resultPointer 
= 0; 
 596         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 598                 if (values
[i
] != NULL
) 
 600                         attrList
->attr
[resultPointer
].tag 
= tags
[i
]; 
 602                         // we have to clone the data pointer.  The caller will need to make sure to throw these away 
 603                         // with _FreeAttrList when it is done... 
 604                         attrList
->attr
[resultPointer
].data 
= CloneDataByType(types
[i
], valuesPtr
[i
], attrList
->attr
[resultPointer
].length
); 
 609         return errSecSuccess
; 
 615 _ConvertOldFormatToNewFormat( 
 616         CFAllocatorRef allocator
, 
 617         const InternalAttributeListInfo
* info
, 
 619         SecKeychainItemRef itemRef
, 
 620         CFMutableDictionaryRef
& dictionaryRef
) 
 622         SecKeychainAttributeList list
; 
 623         list
.count 
= infoNumItems
; 
 624         list
.attr 
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
)); 
 626         // fill out the array.  We only need to fill in the tags, since calloc zeros what it returns 
 628         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 630                 list
.attr
[i
].tag 
= info
[i
].oldItemType
; 
 633         OSStatus result 
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
); 
 634         if (result 
!= errSecSuccess
) 
 636                 dictionaryRef 
= NULL
; 
 641         // create the dictionary 
 642         dictionaryRef 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 645         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 647                 if (list
.attr
[i
].data 
== NULL
) 
 650                 switch (info
[i
].itemRepresentation
) 
 652                         case kStringRepresentation
: 
 654                                 CFStringRef stringRef
; 
 655                                 if (info
[i
].oldItemType 
== kSecKeyKeyClass
) { 
 656                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 657                                         uint32_t keyRecordValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 658                                         bool retainString 
= true; 
 659                                         switch (keyRecordValue
) { 
 660                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 661                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 663                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 664                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 666                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 667                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 670                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
); 
 671                             retainString 
= false; 
 675                                                 if (retainString
) CFRetain(stringRef
); 
 676                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 677                                                 CFRelease(stringRef
); 
 680                                 else if (info
[i
].oldItemType 
== kSecKeyKeyType
) { 
 681                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 682                                         uint32_t keyAlgValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 683                                         bool retainString 
= true; 
 684                                         switch (keyAlgValue
) { 
 685                                                 case CSSM_ALGID_RSA 
: 
 686                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 688                                                 case CSSM_ALGID_DSA 
: 
 689                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 691                                                 case CSSM_ALGID_AES 
: 
 692                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 694                                                 case CSSM_ALGID_DES 
: 
 695                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 697                                                 case CSSM_ALGID_3DES 
: 
 698                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 700                                                 case CSSM_ALGID_RC4 
: 
 701                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 703                                                 case CSSM_ALGID_RC2 
: 
 704                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 706                                                 case CSSM_ALGID_CAST 
: 
 707                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 709                                                 case CSSM_ALGID_ECDSA 
: 
 710                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 713                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
); 
 714                                                         retainString 
= false; 
 718                                                 if (retainString
) CFRetain(stringRef
); 
 719                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 720                                                 CFRelease(stringRef
); 
 724                                         // normal case: attribute contains a string 
 725                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 726                                         if (stringRef 
== NULL
) 
 727                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 728                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 729                                         CFRelease(stringRef
); 
 734                         case kDataRepresentation
: 
 736                 if ((info
[i
].oldItemType 
== kSecKeyLabel
) && (list
.attr
[i
].length 
== kUUIDStringLength
)) { 
 737                                         // It's possible that there could be a string here because the key label may have a UUID 
 738                                         CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 739                                         if (stringRef 
== NULL
) 
 740                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 741                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 742                                         CFRelease(stringRef
); 
 745                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
); 
 747                     dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
 748                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
); 
 753                         case kNumberRepresentation
: 
 755                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
); 
 756                                 if (numberRef 
== NULL
) 
 757                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
 758                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
); 
 759                                 CFRelease(numberRef
); 
 763                         case kBooleanRepresentation
: 
 765                                 uint32_t value 
= *((uint32_t*)list
.attr
[i
].data
); 
 766                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
 767                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
); 
 771                         case kDateRepresentation
: 
 773                                 CFDateRef dateRef 
= NULL
; 
 774                                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
); 
 776                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
 777                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
); 
 785         SecKeychainItemFreeContent(&list
, NULL
); 
 795  * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the 
 796  * attributes of item. 
 799 _CreateAttributesDictionaryFromGenericPasswordItem( 
 800         CFAllocatorRef allocator
, 
 801         SecKeychainItemRef item
, 
 802         CFDictionaryRef 
*dictionary
) 
 804         // do the basic allocations 
 805         CFMutableDictionaryRef dict 
= NULL
; 
 806         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
); 
 807         if (result 
== errSecSuccess
) // did we complete OK 
 809                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
); 
 820  * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the 
 821  * attributes of item. 
 824 _CreateAttributesDictionaryFromCertificateItem( 
 825         CFAllocatorRef allocator
, 
 826         SecKeychainItemRef item
, 
 827         CFDictionaryRef 
*dictionary
) 
 829         // do the basic allocations 
 830         CFMutableDictionaryRef dict 
= NULL
; 
 831         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
); 
 832         if (result 
== errSecSuccess
) // did we complete OK 
 834                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
); 
 839         return errSecSuccess
; 
 843  * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the 
 844  * attributes of item. 
 847 _CreateAttributesDictionaryFromKeyItem( 
 848         CFAllocatorRef allocator
, 
 849         SecKeychainItemRef item
, 
 850         CFDictionaryRef 
*dictionary
) 
 853 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails. 
 854 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and 
 855 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent. 
 858                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 861         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 863         // do the basic allocations 
 864         CFMutableDictionaryRef dict 
= NULL
; 
 865         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
); 
 866         if (result 
== errSecSuccess
) // did we complete OK 
 868                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
 873         return errSecSuccess
; 
 876         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 878         SecItemClass itemClass 
= (SecItemClass
) 0; 
 880         SecKeychainAttributeList 
*attrList 
= NULL
; 
 881         SecKeychainAttributeInfo 
*info 
= NULL
; 
 882         SecKeychainRef keychain 
= NULL
; 
 884         OSStatus status 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
 886                 goto error_exit
; // item must have an itemClass 
 891     case kSecInternetPasswordItemClass
: 
 892                 itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
 894     case kSecGenericPasswordItemClass
: 
 895                 itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
 897     case 'ashp': /* kSecAppleSharePasswordItemClass */ 
 898                 itemID 
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
; 
 905         status 
= SecKeychainItemCopyKeychain(item
, &keychain
); 
 907                 goto error_exit
; // item must have a keychain, so we can get the attribute info for it 
 910         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
 912                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 915         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 917                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 920         for (ix 
= 0; ix 
< info
->count
; ++ix
) 
 922                 SecKeychainAttribute 
*attribute 
= &attrList
->attr
[ix
]; 
 923                 if (!attribute
->length 
&& !attribute
->data
) 
 926                 UInt32 j
, count 
= kNumberOfKeyAttributes
; 
 927                 InternalAttributeListInfo 
*intInfo 
= NULL
; 
 928                 for (j
=0; j
<count
; j
++) { 
 929                         if (gKeyAttributes
[j
].oldItemType 
== info
->tag
[ix
]) { 
 930                                 intInfo 
= &gKeyAttributes
[j
]; 
 937                 switch (intInfo
->itemRepresentation
) 
 939                         case kStringRepresentation
: 
 941                                 CFStringRef stringRef
; 
 942                                 if (intInfo
->oldItemType 
== kSecKeyKeyClass
) { 
 943                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 944                                         UInt32 keyRecordValue 
= *((UInt32
*)attribute
->data
); 
 945                                         bool retainString 
= true; 
 946                                         switch (keyRecordValue
) { 
 947                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 948                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 950                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 951                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 953                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 954                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 957                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyRecordValue
); 
 958                             retainString 
= false; 
 962                                                 if (retainString
) CFRetain(stringRef
); 
 963                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 964                                                 CFRelease(stringRef
); 
 967                                 else if (intInfo
->oldItemType 
== kSecKeyKeyType
) { 
 968                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 969                                         UInt32 keyAlgValue 
= *((UInt32
*)attribute
->data
); 
 970                                         bool retainString 
= true; 
 971                                         switch (keyAlgValue
) { 
 972                                                 case CSSM_ALGID_RSA 
: 
 973                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 975                                                 case CSSM_ALGID_DSA 
: 
 976                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 978                                                 case CSSM_ALGID_AES 
: 
 979                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 981                                                 case CSSM_ALGID_DES 
: 
 982                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 984                                                 case CSSM_ALGID_3DES 
: 
 985                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 987                                                 case CSSM_ALGID_RC4 
: 
 988                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 990                                                 case CSSM_ALGID_RC2 
: 
 991                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 993                                                 case CSSM_ALGID_CAST 
: 
 994                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 996                                                 case CSSM_ALGID_ECDSA 
: 
 997                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
1000                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyAlgValue
); 
1001                                                         retainString 
= false; 
1005                                                 if (retainString
) CFRetain(stringRef
); 
1006                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1007                                                 CFRelease(stringRef
); 
1011                                         // normal case: attribute contains a string 
1012                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1013                                         if (stringRef 
== NULL
) 
1014                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1015                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1016                                         CFRelease(stringRef
); 
1021                         case kDataRepresentation
: 
1023                 if ((intInfo
->oldItemType 
== kSecKeyLabel
) && (attribute
->length 
== kUUIDStringLength
)) { 
1024                                         // It's possible that there could be a string here because the key label may have a UUID 
1025                     CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1026                                         if (stringRef 
== NULL
) 
1027                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1028                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1029                                         CFRelease(stringRef
); 
1033                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
); 
1034                                 if (dataRef 
== NULL
) 
1035                                         dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
1036                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
); 
1041                         case kNumberRepresentation
: 
1043                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
); 
1044                                 if (numberRef 
== NULL
) 
1045                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
1046                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
); 
1047                                 CFRelease(numberRef
); 
1051                         case kBooleanRepresentation
: 
1053                                 UInt32 value 
= *((UInt32
*)attribute
->data
); 
1054                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1055                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
); 
1059                         case kDateRepresentation
: 
1061                                 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here 
1062                                 CFDateRef dateRef 
= NULL
; 
1063                                 if (dateRef 
== NULL
) 
1064                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
1065                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
); 
1072         CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
1077                 SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
1080                 SecKeychainFreeAttributeInfo(info
); 
1083                 CFRelease(keychain
); 
1092  * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the 
1093  * attributes of item. 
1096 _CreateAttributesDictionaryFromInternetPasswordItem( 
1097         CFAllocatorRef allocator
, 
1098         SecKeychainItemRef item
, 
1099         CFDictionaryRef 
*dictionary
) 
1102         SecKeychainAttribute attr
[] = { 
1103                 { kSecServerItemAttr
, 0, NULL 
},                /* [0] server */ 
1104                 { kSecSecurityDomainItemAttr
, 0, NULL 
},        /* [1] securityDomain */ 
1105                 { kSecAccountItemAttr
, 0, NULL 
},               /* [2] account */ 
1106                 { kSecPathItemAttr
, 0, NULL 
},                  /* [3] path */ 
1107                 { kSecPortItemAttr
, 0, NULL 
},                  /* [4] port */ 
1108                 { kSecProtocolItemAttr
, 0, NULL 
},              /* [5] protocol */ 
1109                 { kSecAuthenticationTypeItemAttr
, 0, NULL 
},    /* [6] authenticationType */ 
1110                 { kSecCommentItemAttr
, 0, NULL 
},               /* [7] comment */ 
1111                 { kSecDescriptionItemAttr
, 0, NULL 
},           /* [8] description */ 
1112                 { kSecLabelItemAttr
, 0, NULL 
},                 /* [9] label */ 
1113                 { kSecCreationDateItemAttr
, 0, NULL 
},  /* [10] creation date */ 
1114                 { kSecModDateItemAttr
, 0, NULL 
},               /* [11] modification date */ 
1115                 { kSecCreatorItemAttr
, 0, NULL 
},               /* [12] creator */ 
1116                 { kSecTypeItemAttr
, 0, NULL 
},                  /* [13] type */ 
1117                 { kSecInvisibleItemAttr
, 0, NULL 
},             /* [14] invisible */ 
1118                 { kSecNegativeItemAttr
, 0, NULL 
},              /* [15] negative */ 
1120         SecKeychainAttributeList attrList 
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr 
}; 
1123         CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1124         CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1128         // copy the item's attributes 
1129         status 
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
); 
1130         require_noerr(status
, SecKeychainItemCopyContent_failed
); 
1135         keys
[numValues
] = kSecClass
; 
1136         values
[numValues
] = kSecClassInternetPassword
; 
1139         // add kSecAttrServer 
1140         if ( attrList
.attr
[0].length 
> 0 ) { 
1141                 keys
[numValues
] = kSecAttrServer
; 
1142                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
); 
1143                 if ( values
[numValues
] != NULL 
) { 
1148         // add kSecAttrSecurityDomain 
1149         if ( attrList
.attr
[1].length 
> 0 ) { 
1150                 keys
[numValues
] = kSecAttrSecurityDomain
; 
1151                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
); 
1152                 if ( values
[numValues
] != NULL 
) { 
1157         // add kSecAttrAccount 
1158         if ( attrList
.attr
[2].length 
> 0 ) { 
1159                 keys
[numValues
] = kSecAttrAccount
; 
1160                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
); 
1161                 if ( values
[numValues
] != NULL 
) { 
1167         if ( attrList
.attr
[3].length 
> 0 ) { 
1168                 keys
[numValues
] = kSecAttrPath
; 
1169                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
); 
1170                 if ( values
[numValues
] != NULL 
) { 
1176         if ( attrList
.attr
[4].length 
> 0 ) { 
1177                 keys
[numValues
] = kSecAttrPort
; 
1178                 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
); 
1179                 if ( values
[numValues
] != NULL 
) { 
1184         // add kSecAttrProtocol 
1185         if ( attrList
.attr
[5].length 
> 0 ) { 
1186                 keys
[numValues
] = kSecAttrProtocol
; 
1187                 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
); 
1188                 if ( values
[numValues
] != NULL 
) { 
1189                         CFRetain(values
[numValues
]); 
1194         // add kSecAttrAuthenticationType 
1195         if ( attrList
.attr
[6].length 
> 0 ) { 
1196                 keys
[numValues
] = kSecAttrAuthenticationType
; 
1197                 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType( (SecAuthenticationType
) (*(SecProtocolType
*)attrList
.attr
[6].data
)); 
1198                 if ( values
[numValues
] != NULL 
) { 
1199                         CFRetain(values
[numValues
]); 
1204         // add kSecAttrComment 
1205         if ( attrList
.attr
[7].length 
> 0 ) { 
1206                 keys
[numValues
] = kSecAttrComment
; 
1207                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
); 
1208                 if ( values
[numValues
] != NULL 
) { 
1213         // add kSecAttrDescription 
1214         if ( attrList
.attr
[8].length 
> 0 ) { 
1215                 keys
[numValues
] = kSecAttrDescription
; 
1216                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
); 
1217                 if ( values
[numValues
] != NULL 
) { 
1222         // add kSecAttrLabel 
1223         if ( attrList
.attr
[9].length 
> 0 ) { 
1224                 keys
[numValues
] = kSecAttrLabel
; 
1225                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
); 
1226                 if ( values
[numValues
] != NULL 
) { 
1231         // add kSecAttrCreationDate 
1232         if ( attrList
.attr
[10].length 
> 0 ) { 
1233                 CFDateRef creationDate 
= NULL
; 
1234                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
); 
1235                 keys
[numValues
] = kSecAttrCreationDate
; 
1236                 values
[numValues
] = creationDate
; 
1237                 if ( values
[numValues
] != NULL 
) { 
1242         // add kSecAttrModificationDate 
1243         if ( attrList
.attr
[11].length 
> 0 ) { 
1244                 CFDateRef modDate 
= NULL
; 
1245                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
); 
1246                 keys
[numValues
] = kSecAttrModificationDate
; 
1247                 values
[numValues
] = modDate
; 
1248                 if ( values
[numValues
] != NULL 
) { 
1253         // add kSecCreatorItemAttr 
1254         if ( attrList
.attr
[12].length 
> 0 ) { 
1255                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
); 
1256                 keys
[numValues
] = kSecAttrCreator
; 
1257                 values
[numValues
] = numberRef
; 
1258                 if ( values
[numValues
] != NULL 
) { 
1259                         CFRetain(values
[numValues
]); 
1264         // add kSecTypeItemAttr 
1265         if ( attrList
.attr
[13].length 
> 0 ) { 
1266                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
); 
1267                 keys
[numValues
] = kSecAttrType
; 
1268                 values
[numValues
] = numberRef
; 
1269                 if ( values
[numValues
] != NULL 
) { 
1270                         CFRetain(values
[numValues
]); 
1275         // add kSecInvisibleItemAttr 
1276         if ( attrList
.attr
[14].length 
> 0 ) { 
1277                 uint32_t value 
= *((uint32_t*)attrList
.attr
[14].data
); 
1278                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1279                 keys
[numValues
] = kSecAttrIsInvisible
; 
1280                 values
[numValues
] = boolRef
; 
1281                 if ( values
[numValues
] != NULL 
) { 
1282                         CFRetain(values
[numValues
]); 
1287         // add kSecNegativeItemAttr 
1288         if ( attrList
.attr
[15].length 
> 0 ) { 
1289                 uint32_t value 
= *((uint32_t*)attrList
.attr
[15].data
); 
1290                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1291                 keys
[numValues
] = kSecAttrIsNegative
; 
1292                 values
[numValues
] = boolRef
; 
1293                 if ( values
[numValues
] != NULL 
) { 
1294                         CFRetain(values
[numValues
]); 
1299         // create the dictionary 
1300         *dictionary 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1302         // release the values added to the dictionary 
1303         for ( index 
= 0; index 
< numValues
; ++index 
) 
1305                 CFRelease(values
[index
]); 
1308         // and free the attributes 
1309         (void) SecKeychainItemFreeContent(&attrList
, NULL
); 
1311 SecKeychainItemCopyContent_failed
: 
1318  * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the 
1319  * attributes of the specified item class and item. 
1322 _CreateAttributesDictionaryFromItem( 
1323         CFAllocatorRef allocator
, 
1324         SecItemClass itemClass
, 
1325         SecKeychainItemRef item
, 
1326         CFDictionaryRef 
*dictionary
) 
1330                 case kSecInternetPasswordItemClass
: 
1331                         return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
); 
1333                 case kSecGenericPasswordItemClass
: 
1334                         return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
); 
1336                 case kSecCertificateItemClass
: 
1337                         return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
); 
1339                 case kSecPublicKeyItemClass
: 
1340                 case kSecPrivateKeyItemClass
: 
1341                 case kSecSymmetricKeyItemClass
: 
1342                         return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
); 
1353  * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList 
1354  * by the _CreateSecKeychainAttributeListFromDictionary function. 
1358         SecKeychainAttributeList 
*attrListPtr
) 
1362         if ( attrListPtr 
!= NULL 
) { 
1363                 if ( attrListPtr
->attr 
!= NULL 
) { 
1364                         // free any attribute data 
1365                         for ( index 
= 0; index 
< attrListPtr
->count
; ++index 
) { 
1366                                 free(attrListPtr
->attr
[index
].data
); 
1368                         // free the attribute array 
1369                         free(attrListPtr
->attr
); 
1371                 // free the attribute list 
1377  * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by 
1378  * attr using the data and tag parameters. 
1380  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1381  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1384 _CFDataCreateAttribute( 
1386         SecKeychainAttrType tag
, 
1387         SecKeychainAttributePtr attr
) 
1389         OSStatus status 
= errSecSuccess
; 
1392         // set the attribute tag 
1395         // determine the attribute length 
1396         attr
->length 
= (UInt32
) CFDataGetLength(data
); 
1397         range 
= CFRangeMake(0, (CFIndex
)attr
->length
); 
1399         // allocate memory for the attribute bytes 
1400         attr
->data 
= malloc(attr
->length
); 
1401         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1403         // get the attribute bytes 
1404         CFDataGetBytes(data
, range
, (UInt8 
*)attr
->data
); 
1412  * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by 
1413  * attr using the string and tag parameters. 
1415  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1416  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1419 _CFStringCreateAttribute( 
1421         SecKeychainAttrType tag
, 
1422         SecKeychainAttributePtr attr
) 
1424         OSStatus status 
= errSecSuccess
; 
1427         // set the attribute tag 
1430         // determine the attribute length 
1431         range 
= CFRangeMake(0, CFStringGetLength(string
)); 
1432         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex 
*)&attr
->length
); 
1434         // allocate memory for the attribute bytes 
1435         attr
->data 
= malloc(attr
->length
); 
1436         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1438         // get the attribute bytes 
1439         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8 
*)attr
->data
, attr
->length
, NULL
); 
1448  * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1449  * from the attribute key/values in attrDictionary. 
1451  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1452  * must be freed by the caller with _FreeAttrList() 
1455 _CreateSecKeychainGenericPasswordAttributeListFromDictionary( 
1456         CFDictionaryRef attrDictionary
, 
1457         SecKeychainAttributeList 
**attrList
) 
1459         return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
); 
1464  * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList 
1465  * from the attribute key/values in attrDictionary. 
1467  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1468  * must be freed by the caller with _FreeAttrList() 
1471 _CreateSecKeychainCertificateAttributeListFromDictionary( 
1472         CFDictionaryRef attrDictionary
, 
1473         SecKeychainAttributeList 
**attrList
) 
1475         return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
); 
1480  * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList 
1481  * from the attribute key/values in attrDictionary. 
1483  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1484  * must be freed by the caller with _FreeAttrList() 
1487 _CreateSecKeychainKeyAttributeListFromDictionary( 
1488         CFDictionaryRef attrDictionary
, 
1489         SecKeychainAttributeList 
**attrList
) 
1492         //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug 
1493         return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
); 
1495         // explicitly build attribute list for supported key attributes 
1496         // NOTE: this code supports only MaxSecKeyAttributes (15) attributes 
1497         const int MaxSecKeyAttributes 
= 15; 
1501         SecKeychainAttributeList 
*attrListPtr
; 
1503         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1504         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1506         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
)); 
1507         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1509         // [0] get the kSecKeyKeyClass value 
1510         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) { 
1511                 UInt32 keyRecordValue 
= 0; 
1512                 if (CFEqual(kSecAttrKeyClassPublic
, value
)) 
1513                         keyRecordValue 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
1514                 else if (CFEqual(kSecAttrKeyClassPrivate
, value
)) 
1515                         keyRecordValue 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
1516                 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
)) 
1517                         keyRecordValue 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
1519                 // only use this attribute if we recognize the value! 
1520                 if (keyRecordValue 
!= 0) { 
1521                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1522                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1524                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyClass
; 
1525                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1526                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
; 
1528                         ++attrListPtr
->count
; 
1532         // [1] get the kSecKeyPrintName string 
1533         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) { 
1534                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1535                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1537                 ++attrListPtr
->count
; 
1540         // [2] get the kSecKeyPermanent boolean 
1541         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) { 
1542                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1543                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1545                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyPermanent
; 
1546                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1547                 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1549                 ++attrListPtr
->count
; 
1552         // [3] get the kSecKeyLabel string 
1553         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) { 
1554         if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1555             status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1556         else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1557             status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1559             status 
= errSecParam
; 
1561                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1563                 ++attrListPtr
->count
; 
1566         // [4] get the kSecKeyApplicationTag data 
1567         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) { 
1568                 if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1569                         status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1570                 else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1571                         status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1573                         status 
= errSecParam
; 
1575                 require_noerr_quiet(status
, CFDataCreateAttribute_failed
); 
1576                 ++attrListPtr
->count
; 
1579         // [5] get the kSecKeyKeyType number 
1580         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) { 
1581                 UInt32 keyAlgValue 
= _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType
); 
1582                 if (keyAlgValue 
!= 0) { 
1583                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1584                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1586                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyType
; 
1587                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1588                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
; 
1590                         ++attrListPtr
->count
; 
1594         // [6] get the kSecKeyKeySizeInBits number 
1595         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) { 
1596                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1597                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1598                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1600                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeySizeInBits
; 
1601                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1602                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1604                         ++attrListPtr
->count
; 
1608         // [7] get the kSecKeyEffectiveKeySize number 
1609         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) { 
1610                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1611                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1612                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1614                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEffectiveKeySize
; 
1615                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1616                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1618                         ++attrListPtr
->count
; 
1622         // [8] get the kSecKeyEncrypt boolean 
1623         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) { 
1624                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1625                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1626                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1628                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEncrypt
; 
1629                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1630                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1632                         ++attrListPtr
->count
; 
1636         // [9] get the kSecKeyDecrypt boolean 
1637         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) { 
1638                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1639                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1640                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1642                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDecrypt
; 
1643                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1644                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1646                         ++attrListPtr
->count
; 
1650         // [10] get the kSecKeyDerive boolean 
1651         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) { 
1652                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1653                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1654                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1656                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDerive
; 
1657                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1658                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1660                         ++attrListPtr
->count
; 
1664         // [11] get the kSecKeySign boolean 
1665         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) { 
1666                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1667                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1668                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1670                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeySign
; 
1671                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1672                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1674                         ++attrListPtr
->count
; 
1678         // [12] get the kSecKeyVerify boolean 
1679         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) { 
1680                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1681                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1682                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1684                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyVerify
; 
1685                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1686                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1688                         ++attrListPtr
->count
; 
1692         // [13] get the kSecKeyWrap boolean 
1693         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) { 
1694                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1695                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1696                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1698                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyWrap
; 
1699                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1700                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1702                         ++attrListPtr
->count
; 
1706         // [14] get the kSecKeyUnwrap boolean 
1707         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) { 
1708                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1709                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1710                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1712                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyUnwrap
; 
1713                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1714                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1716                         ++attrListPtr
->count
; 
1720         // return the pointer to the attrList 
1721         *attrList 
= attrListPtr
; 
1723         return ( errSecSuccess 
); 
1727 malloc_number_failed
: 
1728 CFDataCreateAttribute_failed
: 
1729 CFStringCreateAttribute_failed
: 
1730 malloc_attrPtr_failed
: 
1732         // free any attributes 
1733         _FreeAttrList(attrListPtr
); 
1735 calloc_attrListPtr_failed
: 
1737         return ( errSecBufferTooSmall 
); 
1742 static CFTypeRef 
copyNumber(CFTypeRef obj
) 
1747     CFTypeID tid 
= CFGetTypeID(obj
); 
1748     if (tid 
== CFNumberGetTypeID()) 
1754     if (tid 
== CFBooleanGetTypeID()) 
1756         SInt32 value 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
1757         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1760     if (tid 
== CFStringGetTypeID()) 
1762         SInt32 value 
= CFStringGetIntValue((CFStringRef
)obj
); 
1763         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value
); 
1764         /* If a string converted to an int isn't equal to the int printed as 
1765          a string, return a NULL instead. */ 
1766         if (!CFEqual(t
, obj
)) 
1772         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1778  * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1779  * from the attribute key/values in attrDictionary. 
1781  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1782  * must be freed by the caller with _FreeAttrList() 
1785 _CreateSecKeychainInternetPasswordAttributeListFromDictionary( 
1786         CFDictionaryRef attrDictionary
, 
1787         SecKeychainAttributeList 
**attrList
) 
1789         // explicitly build attribute list for supported key attributes 
1790         // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes 
1791         const int MaxSecKeychainAttributes 
= 14; 
1795         SecKeychainAttributeList 
*attrListPtr
; 
1797         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1798         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1800         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
)); 
1801         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1804         // [0] get the serverName string 
1805         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) { 
1806                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1807                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1809                 ++attrListPtr
->count
; 
1812         // [1] get the securityDomain string 
1813         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) { 
1814                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1815                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1817                 ++attrListPtr
->count
; 
1820         // [2] get the accountName string 
1821         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) { 
1822                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1823                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1825                 ++attrListPtr
->count
; 
1828         // [3] get the path string 
1829         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) { 
1830                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1831                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1833                 ++attrListPtr
->count
; 
1836         // [4] get the port number 
1837         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) { 
1838                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt16
)); 
1839                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1841         CFTypeRef num 
= copyNumber(value
); 
1842                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1843                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecPortItemAttr
; 
1844                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt16
); 
1845                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1848                 ++attrListPtr
->count
; 
1851         // [5] get the protocol 
1852         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) { 
1853                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecProtocolType
)); 
1854                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_protocol_failed
, status 
= errSecBufferTooSmall
); 
1856                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecProtocolItemAttr
; 
1857                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecProtocolType
); 
1858                 *(SecProtocolType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
); 
1860                 ++attrListPtr
->count
; 
1863         // [6] get the authenticationType 
1864         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) { 
1865                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecAuthenticationType
)); 
1866                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_authenticationType_failed
, status 
= errSecBufferTooSmall
); 
1868                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecAuthenticationTypeItemAttr
; 
1869                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecAuthenticationType
); 
1870                 *(SecAuthenticationType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
); 
1872                 ++attrListPtr
->count
; 
1875         // [7] get the comment string 
1876         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) { 
1877                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1878                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1880                 ++attrListPtr
->count
; 
1883         // [8] get the description string 
1884         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) { 
1885                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1886                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1888                 ++attrListPtr
->count
; 
1891         // [9] get the label string 
1892         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) { 
1893                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1894                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1896                 ++attrListPtr
->count
; 
1899         // [10] get the creator code 
1900         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) { 
1901                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1902                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1904         CFTypeRef num 
= copyNumber(value
); 
1905                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1906                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecCreatorItemAttr
; 
1907                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1908                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1911                 ++attrListPtr
->count
; 
1914         // [11] get the type code 
1915         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) { 
1916                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1917                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1919         CFTypeRef num 
= copyNumber(value
); 
1920                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1921                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecTypeItemAttr
; 
1922                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1923                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1926                 ++attrListPtr
->count
; 
1929         // [12] get the invisible flag 
1930         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) { 
1931                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1932                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1934                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecInvisibleItemAttr
; 
1935                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1936                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1938                 ++attrListPtr
->count
; 
1941         // [13] get the negative flag 
1942         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) { 
1943                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1944                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1946                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecNegativeItemAttr
; 
1947                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1948                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1950                 ++attrListPtr
->count
; 
1953         // return the pointer to the attrList 
1954         *attrList 
= attrListPtr
; 
1956         return ( errSecSuccess 
); 
1960 malloc_authenticationType_failed
: 
1961 malloc_protocol_failed
: 
1963 CFStringCreateAttribute_failed
: 
1964 malloc_attrPtr_failed
: 
1966         // free any attributes 
1967         _FreeAttrList(attrListPtr
); 
1969 calloc_attrListPtr_failed
: 
1971         return ( errSecBufferTooSmall 
); 
1976  * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList 
1977  * from the attribute key/values in attrDictionary for the specified item class. 
1979  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1980  * must be freed by the caller with _FreeAttrList() 
1983 _CreateSecKeychainAttributeListFromDictionary( 
1984         CFDictionaryRef attrDictionary
, 
1985         SecItemClass itemClass
, 
1986         SecKeychainAttributeList 
**attrList
) 
1990                 case kSecInternetPasswordItemClass
: 
1991                         return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1993                 case kSecGenericPasswordItemClass
: 
1994                         return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1996                 case kSecCertificateItemClass
: 
1997                         return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
); 
1999                 case kSecPublicKeyItemClass
: 
2000                 case kSecPrivateKeyItemClass
: 
2001                 case kSecSymmetricKeyItemClass
: 
2002                         return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
); 
2012  * _AppNameFromSecTrustedApplication attempts to pull the name of the 
2013  * application/tool from the SecTrustedApplicationRef. 
2015 static CFStringRef CF_RETURNS_RETAINED
 
2016 _AppNameFromSecTrustedApplication( 
2017         CFAllocatorRef alloc
, 
2018         SecTrustedApplicationRef appRef
) 
2022         CFDataRef appDataRef
; 
2026         // get the data for item's application/tool 
2027         status 
= SecTrustedApplicationCopyData(appRef
, &appDataRef
); 
2028         if ( status 
== errSecSuccess 
) { 
2031                 // convert it to a CFString potentially containing the path 
2032                 path 
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
); 
2033                 if ( path 
!= NULL 
) { 
2034                         // the path has to start with a "/" and cannot contain "://" 
2035                         if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location 
== kCFNotFound
) ) { 
2036                                 CFRange nameRange
, compRg
; 
2038                                 nameRange 
= CFRangeMake(0, CFStringGetLength(path
)); 
2040                                 // remove the trailing slashes (if any) 
2041                                 while ( (nameRange
.length 
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length 
- 1) == '/') ) { 
2042                                         nameRange
.length 
--; 
2045                                 if ( nameRange
.length 
> 0 ) { 
2046                                         // find last slash and adjust nameRange to be everything after it 
2047                                         if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) { 
2048                                                 nameRange
.length 
= nameRange
.location 
+ nameRange
.length 
- (compRg
.location 
+ 1); 
2049                                                 nameRange
.location 
= compRg
.location 
+ 1; 
2052                                         result 
= CFStringCreateWithSubstring(alloc
, path
, nameRange
); 
2057                 CFRelease(appDataRef
); 
2063 /* (This function really belongs in SecIdentity.cpp!) 
2065  * Returns the public key item corresponding to the identity, if it exists in 
2066  * the same keychain as the private key. Note that the public key might not 
2067  * exist in the same keychain (e.g. if the identity was imported via PKCS12), 
2068  * in which case it will not be found. 
2071 _SecIdentityCopyPublicKey( 
2072         SecIdentityRef identityRef
, 
2073         SecKeyRef 
*publicKeyRef
) 
2077         SecKeychainAttribute attr 
= { kSecKeyLabel
, 0, NULL 
}; 
2078         SecKeychainAttributeList attrList 
= { 1, &attr 
}; 
2079         SecKeychainAttributeList 
*keyAttrList 
= NULL
; 
2080         SecKeychainAttributeInfo 
*info 
= NULL
; 
2081         SecKeychainSearchRef search 
= NULL
; 
2082         SecKeychainRef keychain 
= NULL
; 
2083         SecKeychainItemRef privateKey 
= NULL
; 
2084         SecKeychainItemRef publicKey 
= NULL
; 
2086         status 
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef 
*)&privateKey
); 
2088                 goto error_exit
; // identity must have a private key 
2090         status 
= SecKeychainItemCopyKeychain(privateKey
, &keychain
); 
2092                 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it 
2094         status 
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
); 
2096                 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys 
2098         status 
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
); 
2100                 goto error_exit
; // unable to get the key label attribute for the private key 
2103         // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching 
2104         for (count 
= 0; count 
< keyAttrList
->count
; count
++) { 
2105                 if (keyAttrList
->attr
[count
].tag 
== kSecKeyLabel
) { 
2106                         attr
.length 
= keyAttrList
->attr
[count
].length
; 
2107                         attr
.data 
= keyAttrList
->attr
[count
].data
; 
2111         if (!attr
.length 
|| !attr
.data
) { 
2112                 status 
= errSecNoSuchAttr
; 
2113                 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel 
2115         status 
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
); 
2117                 goto error_exit
; // unable to create the search reference 
2119         status 
= SecKeychainSearchCopyNext(search
, &publicKey
); 
2121                 goto error_exit
; // unable to find the public key 
2125                 *publicKeyRef 
= (SecKeyRef
)publicKey
; 
2127                 CFRelease(publicKey
); 
2130         if (status 
!= errSecSuccess
) { 
2132                         *publicKeyRef 
= NULL
; 
2134                         CFRelease(publicKey
); 
2140                 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
); 
2143                 SecKeychainFreeAttributeInfo(info
); 
2146                 CFRelease(keychain
); 
2149                 CFRelease(privateKey
); 
2156  * Deletes a keychain item if the current application/tool is the only application/tool 
2157  * with decrypt access to that keychain item. If more than one application/tool 
2158  * has decrypt access to the keychain item, the item is left on the keychain. 
2160  * TBD: If more than one app/tool has access to the keychain item, we should remove 
2161  * the current app/tool's decrypt access. There's no easy way to do that with 
2162  * current keychain APIs without bringing up the security UI. 
2165 _SafeSecKeychainItemDelete( 
2166         SecKeychainItemRef itemRef
) 
2169         SecAccessRef access 
= NULL
; 
2170         CFArrayRef aclList 
= NULL
; 
2171         SecACLRef acl 
= NULL
; 
2172         CFArrayRef appList 
= NULL
; 
2173         CFStringRef description 
= NULL
; 
2174         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
2175         CFIndex idx
, count 
= 0; 
2176         SecTrustedApplicationRef currentAppRef 
= NULL
; 
2177         CFStringRef itemAppName 
= NULL
, currentAppName 
= NULL
; 
2179         SecItemClass itemClass 
= (SecItemClass
)0; 
2180         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2181         if (!(itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2182                 // only perform the access control safety check on deletion of password credentials; 
2183                 // if the item is of some other type, delete it normally. 
2184                 return SecKeychainItemDelete(itemRef
); 
2187         // skip access control checking for web form passwords: <rdar://10957301> 
2188         // This permits Safari to manage the removal of all web form passwords, 
2189         // regardless of whether they are shared by multiple applications. 
2190         if (itemClass 
== kSecInternetPasswordItemClass
) { 
2191                 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr 
}; 
2192                 SecKeychainAttributeInfo attrInfo 
= { 1, tags
, NULL 
}; 
2193                 SecKeychainAttributeList 
*attrs 
= NULL
; 
2194                 status 
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
); 
2195                 if (!status 
&& attrs
) { 
2196                         bool webFormPassword 
= (attrs
->attr
[0].length 
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4))); 
2197                         SecKeychainItemFreeAttributesAndData(attrs
, NULL
); 
2198                         if (webFormPassword
) { 
2199                                 return SecKeychainItemDelete(itemRef
); 
2204         // copy the access of the keychain item 
2205         status 
= SecKeychainItemCopyAccess(itemRef
, &access
); 
2206         require_noerr(status
, finish
); 
2207         require_quiet(access 
!= NULL
, finish
); 
2209         // copy the decrypt access control lists -- this is what has access to the keychain item 
2210         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
2211         require_noerr(status
, finish
); 
2212         require_quiet(aclList 
!= NULL
, finish
); 
2214         // get the access control list 
2215         acl 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
2216         require_quiet(acl 
!= NULL
, finish
); 
2218         // copy the application list, description, and CSSM prompt selector for a given access control list entry 
2219         status 
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
); 
2220         require_noerr(status
, finish
); 
2221         require_quiet(appList 
!= NULL
, finish
); 
2223         // does the calling application/tool have decrypt access to this item? 
2224         count 
= CFArrayGetCount(appList
); 
2225         for ( idx 
= 0; idx 
< count
; idx
++ ) { 
2226                 // get SecTrustedApplicationRef for this entry 
2227                 SecTrustedApplicationRef itemAppRef 
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, idx
); 
2228                 require_quiet(itemAppRef 
!= NULL
, finish
); 
2230                 // copy the name out 
2231                 CFReleaseSafe(itemAppName
); 
2232                 itemAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
); 
2233                 if (itemAppName 
== NULL
) { 
2235                          * If there is no app name, it's probably because it's not an appname 
2236                          * in the ACE but an entitlement/info.plist based rule instead; 
2237                          * just let the caller have it. */ 
2242                 // create SecTrustedApplicationRef for current application/tool 
2243                 CFReleaseNull(currentAppRef
); 
2244                 status 
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
); 
2245                 require_noerr(status
, finish
); 
2246                 require_quiet(currentAppRef 
!= NULL
, finish
); 
2248                 // copy the name out 
2249                 CFReleaseSafe(currentAppName
); 
2250                 currentAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
); 
2251                 require_quiet(currentAppName 
!= NULL
, finish
); 
2253                 // compare the names to see if we own the decrypt access 
2254                 // TBD: validation of membership in an application group 
2255                 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo 
) { 
2263         CFReleaseSafe(currentAppName
); 
2264         CFReleaseSafe(itemAppName
); 
2265         CFReleaseSafe(currentAppRef
); 
2266         CFReleaseSafe(description
); 
2267         CFReleaseSafe(appList
); 
2268         CFReleaseSafe(aclList
); 
2269         CFReleaseSafe(access
); 
2271         if ((count 
== 0) || (status 
== errSecVerifyFailed
)) { 
2272                 // no "owners" remain in the ACL list (or unable to get ACL) 
2273                 status 
= SecKeychainItemDelete(itemRef
); 
2275                 // caller is not the "owner" of the item 
2276                 status 
= errSecInvalidOwnerEdit
; 
2283 _ReplaceKeychainItem( 
2284         SecKeychainItemRef itemToUpdate
, 
2285         SecKeychainAttributeList 
*changeAttrList
, 
2290         SecItemClass itemClass
; 
2291         SecKeychainAttributeInfo 
*info 
= NULL
; 
2292         SecKeychainAttributeList 
*attrList 
= NULL
; 
2293         SecKeychainAttributeList newAttrList 
= { 0, NULL
}; 
2294         SecKeychainRef keychain 
= NULL
; 
2295         SecKeychainItemRef newItem 
= NULL
; 
2297         int priority 
= LOG_DEBUG
; 
2298         const char *format 
= "ReplaceKeychainItem (%d) error %d"; 
2300         // get existing item's keychain 
2301         status 
= SecKeychainItemCopyKeychain(itemToUpdate
, &keychain
); 
2302         if (status
) { secitemlog(priority
, format
, 1, (int)status
); } 
2303         require_noerr(status
, replace_failed
); 
2305         // get attribute info (i.e. database schema) for the item class 
2306         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2307         if (status
) { secitemlog(priority
, format
, 2, (int)status
); } 
2308         require_noerr(status
, replace_failed
); 
2312                 case kSecInternetPasswordItemClass
: 
2313                         itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
2315                 case kSecGenericPasswordItemClass
: 
2316                         itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
2322         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
2323         if (status
) { secitemlog(priority
, format
, 3, (int)status
); } 
2325         // get item's existing attributes (but not data!) 
2326         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
2327         if (status
) { secitemlog(priority
, format
, 4, (int)status
); } 
2328         require(attrList 
!= NULL
, replace_failed
); 
2330         // move aside the item by changing a primary attribute 
2331     // (currently only for passwords) 
2332         if (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
) { 
2333                 CFUUIDRef uuid 
= CFUUIDCreate(kCFAllocatorDefault
); 
2334                 CFStringRef uuidStr 
= (uuid
) ? CFUUIDCreateString(kCFAllocatorDefault
, uuid
) : CFSTR("MOVED"); 
2335                 CFReleaseSafe(uuid
); 
2337                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr
), kCFStringEncodingUTF8
) + 1; 
2338                         char* buffer 
= (char*) malloc(maxLength
); 
2340                                 if (CFStringGetCString(uuidStr
, buffer
, maxLength
, kCFStringEncodingUTF8
)) { 
2341                                         UInt32 length 
= (UInt32
)strlen(buffer
); 
2342                                         SecKeychainAttribute attrs
[] = { { kSecAccountItemAttr
, length
, (char*)buffer 
}, }; 
2343                                         SecKeychainAttributeList updateAttrList 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
2344                                         status 
= SecKeychainItemModifyAttributesAndData(itemToUpdate
, &updateAttrList
, 0, NULL
); 
2345                                         if (status
) { secitemlog(priority
, format
, 5, (int)status
); } 
2346                                         if (status 
== errSecVerifyFailed
) { 
2347                                                 // still unable to change attrs? delete unconditionally here 
2348                                                 status 
= SecKeychainItemDelete(itemToUpdate
); 
2349                                                 if (status
) { secitemlog(priority
, format
, 6, (int)status
); } 
2354                         CFReleaseSafe(uuidStr
); 
2357         require_noerr(status
, replace_failed
); 
2359         // make attribute list for new item (the data is still owned by attrList) 
2360         newAttrList
.count 
= attrList
->count
; 
2361         newAttrList
.attr 
= (SecKeychainAttribute 
*) malloc(sizeof(SecKeychainAttribute
) * attrList
->count
); 
2363         for (i
=0, newCount
=0; i 
< attrList
->count
; i
++) { 
2364                 if (attrList
->attr
[i
].length 
> 0) { 
2365                         newAttrList
.attr
[newCount
++] = attrList
->attr
[i
]; 
2367                         // debugging code to log item attributes 
2368                         SecKeychainAttrType tag 
= attrList
->attr
[i
].tag
; 
2369                         SecKeychainAttrType htag
=(SecKeychainAttrType
)OSSwapConstInt32(tag
); 
2370                         char tmp
[sizeof(SecKeychainAttrType
) + 1]; 
2371                         char tmpdata
[attrList
->attr
[i
].length 
+ 1]; 
2372                         memcpy(tmp
, &htag
, sizeof(SecKeychainAttrType
)); 
2373                         tmp
[sizeof(SecKeychainAttrType
)]=0; 
2374                         memcpy(tmpdata
, attrList
->attr
[i
].data
, attrList
->attr
[i
].length
); 
2375                         tmpdata
[attrList
->attr
[i
].length
]=0; 
2376                         secitemlog(priority
, "item attr '%s' = %d bytes: \"%s\"", 
2377                                 tmp
, (int)attrList
->attr
[i
].length
, tmpdata
); 
2381         newAttrList
.count 
= newCount
; 
2383         // create new item in the same keychain 
2384         status 
= SecKeychainItemCreateFromContent(itemClass
, &newAttrList
, 
2385                 (UInt32
)((itemData
) ? CFDataGetLength(itemData
) : 0), 
2386                 (const void *)((itemData
) ? CFDataGetBytePtr(itemData
) : NULL
), 
2387                 keychain
, NULL
, &newItem
); 
2388         if (status
) { secitemlog(priority
, format
, 7, (int)status
); } 
2389         require_noerr(status
, replace_failed
); 
2391         // delete the old item unconditionally once new item exists 
2392         status 
= SecKeychainItemDelete(itemToUpdate
); 
2394         // update the new item with changed attributes, if any 
2395         status 
= (changeAttrList
) ? SecKeychainItemModifyContent(newItem
, changeAttrList
, 0, NULL
) : errSecSuccess
; 
2396         if (status
) { secitemlog(priority
, format
, 8, (int)status
); } 
2397         if (status 
== errSecSuccess
) { 
2398                 // say the item already exists, because it does now. <rdar://19063674> 
2399                 status 
= errSecDuplicateItem
; 
2403         if (newAttrList
.attr
) { 
2404                 free(newAttrList
.attr
); 
2407         SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
2410         SecKeychainFreeAttributeInfo(info
); 
2412         CFReleaseSafe(newItem
); 
2413         CFReleaseSafe(keychain
); 
2419 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
) 
2421         // This function updates a single keychain item, which may be specified as 
2422         // a reference, persistent reference or attribute dictionary, with the 
2423         // attributes provided. 
2425         OSStatus status 
= errSecSuccess
; 
2430         SecItemClass itemClass 
= (SecItemClass
) 0; 
2431         SecAccessRef access 
= NULL
; 
2432         SecKeychainAttributeList 
*changeAttrList 
= NULL
; 
2433         SecKeychainItemRef itemToUpdate 
= NULL
; 
2434         CFDataRef theData 
= NULL
; 
2435         CFTypeID itemType 
= CFGetTypeID(item
); 
2437         // validate input item (must be convertible to a SecKeychainItemRef) 
2438         if (SecKeychainItemGetTypeID() == itemType 
|| 
2439                 SecCertificateGetTypeID() == itemType 
|| 
2440                 SecKeyGetTypeID() == itemType
) { 
2441                 // item is already a reference, retain it 
2442                 itemToUpdate 
= (SecKeychainItemRef
) CFRetain(item
); 
2444         else if (CFDataGetTypeID() == itemType
) { 
2445                 // item is a persistent reference, must convert it 
2446                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
); 
2448         else if (CFDictionaryGetTypeID() == itemType
) { 
2449                 // item is a dictionary 
2450                 CFTypeRef value 
= NULL
; 
2451                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2452                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2453                         itemToUpdate 
= (SecKeychainItemRef
) CFRetain(value
); 
2455                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2456                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2457                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
); 
2460         else if (SecIdentityGetTypeID() == itemType
) { 
2461                 // item is a certificate + private key; since we can't really change the 
2462                 // certificate's attributes, assume we want to update the private key 
2463                 status 
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
); 
2465         require_action(itemToUpdate 
!= NULL
, update_failed
, status 
= errSecInvalidItemRef
); 
2466         require_noerr(status
, update_failed
); 
2468         status 
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
); 
2469         require_noerr(status
, update_failed
); 
2471         // build changeAttrList from changedAttributes dictionary 
2474                 case kSecInternetPasswordItemClass
: 
2476                         status 
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2477                         require_noerr(status
, update_failed
); 
2481                 case kSecGenericPasswordItemClass
: 
2483                         status 
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2484                         require_noerr(status
, update_failed
); 
2488                 case kSecCertificateItemClass
: 
2490                         status 
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2491                         require_noerr(status
, update_failed
); 
2495                 case kSecPublicKeyItemClass
: 
2496                 case kSecPrivateKeyItemClass
: 
2497                 case kSecSymmetricKeyItemClass
: 
2499                         status 
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2500                         require_noerr(status
, update_failed
); 
2503                 case kSecAppleSharePasswordItemClass
: 
2505                         // do nothing (legacy behavior). 
2512         // (if the caller is not updating the password, this value will be NULL) 
2513         theData 
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
); 
2514         if (theData 
!= NULL
) { 
2515                 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status 
= errSecParam
); 
2518         status 
= SecKeychainItemModifyContent(itemToUpdate
, 
2519                                 (!changeAttrList 
|| changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2520                                 (theData 
!= NULL
) ? (UInt32
)CFDataGetLength(theData
) : 0, 
2521                                 (theData 
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
); 
2522         require_noerr(status
, update_failed
); 
2524         // one more thing... update access? 
2525         if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) { 
2526                 status 
= SecKeychainItemSetAccess(itemToUpdate
, access
); 
2530         if (status 
== errSecVerifyFailed 
&& 
2531                 (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2532                 // if we got a cryptographic failure updating a password item, it needs to be replaced 
2533                 status 
= _ReplaceKeychainItem(itemToUpdate
, 
2534                                         (!changeAttrList 
||  changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2538                 CFRelease(itemToUpdate
); 
2539         _FreeAttrList(changeAttrList
); 
2544 _DeleteKeychainItem(CFTypeRef item
) 
2546         // This function deletes a single keychain item, which may be specified as 
2547         // a reference, persistent reference or attribute dictionary. It will not 
2548         // delete non-keychain items or aggregate items (such as a SecIdentityRef); 
2549         // it is assumed that the caller will pass identity components separately. 
2551         OSStatus status 
= errSecSuccess
; 
2556         SecKeychainItemRef itemToDelete 
= NULL
; 
2557         CFTypeID itemType 
= CFGetTypeID(item
); 
2558         if (SecKeychainItemGetTypeID() == itemType 
|| 
2559                 SecCertificateGetTypeID() == itemType 
|| 
2560                 SecKeyGetTypeID() == itemType
) { 
2561                 // item is already a reference, retain it 
2562                 itemToDelete 
= (SecKeychainItemRef
) CFRetain(item
); 
2564         else if (CFDataGetTypeID() == itemType
) { 
2565                 // item is a persistent reference, must convert it 
2566                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
); 
2568         else if (CFDictionaryGetTypeID() == itemType
) { 
2569                 // item is a dictionary 
2570                 CFTypeRef value 
= NULL
; 
2571                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2572                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2573                         itemToDelete 
= (SecKeychainItemRef
) CFRetain(value
); 
2575                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2576                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2577                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
); 
2583                         status 
= _SafeSecKeychainItemDelete(itemToDelete
); 
2585                 CFRelease(itemToDelete
); 
2592 _DeleteIdentity(SecIdentityRef identity
) 
2594         OSStatus status
, result 
= errSecSuccess
; 
2595         SecKeyRef privateKey 
= NULL
; 
2596         SecCertificateRef certificate 
= NULL
; 
2598         status 
= SecIdentityCopyPrivateKey(identity
, &privateKey
); 
2600                 SecKeyRef publicKey 
= NULL
; 
2601                 status 
= _SecIdentityCopyPublicKey(identity
, &publicKey
); 
2603                         status 
= _DeleteKeychainItem(publicKey
); 
2604                         CFRelease(publicKey
); 
2606                 status 
= _DeleteKeychainItem(privateKey
); 
2609         if (privateKey
) CFRelease(privateKey
); 
2610         if (status
) result 
= status
; 
2612         status 
= SecIdentityCopyCertificate(identity
, &certificate
); 
2614                 status 
= _DeleteKeychainItem(certificate
); 
2617         if (certificate
) CFRelease(certificate
); 
2618         if (status
) result 
= status
; 
2624 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
) 
2626         // This function is used when atomically processing multiple items, 
2627         // where an overall error result must be returned for the entire operation. 
2628         // When newStatus is something other than errSecSuccess, we want to keep the "most 
2629         // interesting" status (which usually will be newStatus, unless curStatus is 
2630         // already set; in that case, newStatus can trump curStatus only by being 
2631         // something different than baseStatus.) 
2633         OSStatus result 
= curStatus
; 
2635         if (newStatus 
!= errSecSuccess
) { 
2637                 if (curStatus 
!= errSecSuccess
) { 
2638                         result 
= (newStatus 
!= baseStatus
) ? newStatus 
: curStatus
; 
2645 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
) 
2647         // CFDictionaryApplierFunction 
2648         // This function just takes the given key/value pair, 
2649         // and adds it to another dictionary supplied in the context argument. 
2651         CFMutableDictionaryRef dict 
= *((CFMutableDictionaryRef
*) context
); 
2653                 CFDictionaryAddValue(dict
, key
, value
); 
2657 static CFStringCompareFlags
 
2658 _StringCompareFlagsFromQuery(CFDictionaryRef query
) 
2661         CFStringCompareFlags flags 
= 0; 
2662         if (!query
) return flags
; 
2664         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) || 
2665                 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2666                 flags 
|= kCFCompareAnchored
; 
2668         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2669                 flags 
|= kCFCompareBackwards
; 
2671         if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2672                 flags 
|= kCFCompareCaseInsensitive
; 
2674         if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2675                 flags 
|= kCFCompareDiacriticInsensitive
; 
2677         if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2678                 flags 
|= kCFCompareWidthInsensitive
; 
2684 _CssmKeyUsageFromQuery(CFDictionaryRef query
) 
2687         uint32 keyUsage 
= 0; 
2688         if (!query
) return keyUsage
; 
2690         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2691                 keyUsage 
|= CSSM_KEYUSE_ENCRYPT
; 
2693         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2694                 keyUsage 
|= CSSM_KEYUSE_DECRYPT
; 
2696         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2697                 keyUsage 
|= CSSM_KEYUSE_SIGN
; 
2699         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2700                 keyUsage 
|= CSSM_KEYUSE_VERIFY
; 
2702         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2703                 keyUsage 
|= CSSM_KEYUSE_WRAP
; 
2705         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2706                 keyUsage 
|= CSSM_KEYUSE_UNWRAP
; 
2708         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2709                 keyUsage 
|= CSSM_KEYUSE_DERIVE
; 
2715 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean 
*isIdentity
) 
2717         SecItemClass itemClass 
= (SecItemClass
) 0; 
2718         if (isIdentity
) *isIdentity 
= false; 
2720         if (CFEqual(item
, kSecClassGenericPassword
)) { 
2721                 itemClass 
= kSecGenericPasswordItemClass
; 
2723         else if (CFEqual(item
, kSecClassInternetPassword
)) { 
2724                 itemClass 
= kSecInternetPasswordItemClass
; 
2726         else if (CFEqual(item
, kSecClassCertificate
)) { 
2727                 itemClass 
= kSecCertificateItemClass
; 
2729         else if (CFEqual(item
, kSecClassIdentity
)) { 
2730                 // will perform a certificate lookup 
2731                 itemClass 
= kSecCertificateItemClass
; 
2732                 if (isIdentity
) *isIdentity 
= true; 
2734         else if (CFEqual(item
, kSecClassKey
)) { 
2735                 // examine second parameter to determine type of key 
2736                 if (!keyClass 
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) { 
2737                         itemClass 
= kSecSymmetricKeyItemClass
; 
2739                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) { 
2740                         itemClass 
= kSecPublicKeyItemClass
; 
2742                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) { 
2743                         itemClass 
= kSecPrivateKeyItemClass
; 
2751 _ItemClassFromItemList(CFArrayRef itemList
) 
2753         // Given a list of items (standard or persistent references), 
2754         // determine whether they all have the same item class. Returns 
2755         // the item class, or 0 if multiple classes in list. 
2756         SecItemClass result 
= (SecItemClass
) 0; 
2757         CFIndex index
, count 
= (itemList
) ? CFArrayGetCount(itemList
) : 0; 
2758         for (index
=0; index 
< count
; index
++) { 
2759                 CFTypeRef item 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemList
, index
); 
2761                         SecKeychainItemRef itemRef 
= NULL
; 
2763                         if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
2764                                 // persistent reference, resolve first 
2765                                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemRef
); 
2768                                 itemRef 
= (SecKeychainItemRef
) CFRetain(item
); 
2771                                 SecItemClass itemClass 
= (SecItemClass
) 0; 
2772                                 CFTypeID itemTypeID 
= CFGetTypeID(itemRef
); 
2773                                 if (itemTypeID 
== SecIdentityGetTypeID() || itemTypeID 
== SecCertificateGetTypeID()) { 
2774                                         // Identities and certificates have the same underlying item class 
2775                                         itemClass 
= kSecCertificateItemClass
; 
2777                                 else if (itemTypeID 
== SecKeychainItemGetTypeID()) { 
2778                                         // Reference to item in a keychain 
2779                                         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2781                                 else if (itemTypeID 
== SecKeyGetTypeID()) { 
2782                                         // SecKey that isn't stored in a keychain 
2783                                         // %%% will need to change this code when SecKey is no longer CSSM-based %%% 
2784                                         const CSSM_KEY 
*cssmKey
; 
2785                                         status 
= SecKeyGetCSSMKey((SecKeyRef
)itemRef
, &cssmKey
); 
2786                                         if (status 
== errSecSuccess
) { 
2787                                                 if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) 
2788                                                         itemClass 
= kSecPublicKeyItemClass
; 
2789                                                 else if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY
) 
2790                                                         itemClass 
= kSecPrivateKeyItemClass
; 
2792                                                         itemClass 
= kSecSymmetricKeyItemClass
; 
2796                                 if (itemClass 
!= 0) { 
2797                                         if (result 
!= 0 && result 
!= itemClass
) { 
2798                                                 return (SecItemClass
) 0; // different item classes in list; bail out 
2808 // SecItemParams contains a validated set of input parameters, as well as a 
2809 // search reference and attribute list built from those parameters. It is 
2810 // designed to be allocated with _CreateSecItemParamsFromDictionary, and 
2811 // freed with _FreeSecItemParams. 
2813 struct SecItemParams 
{ 
2814         CFDictionaryRef query
;                          // caller-supplied query 
2815         int numResultTypes
;                                     // number of result types requested 
2816         int maxMatches
;                                         // max number of matches to return 
2817         uint32 keyUsage
;                                        // key usage(s) requested 
2818         Boolean returningAttributes
;            // true if returning attributes dictionary 
2819         Boolean returningData
;                          // true if returning item's data 
2820         Boolean returningRef
;                           // true if returning item reference 
2821         Boolean returningPersistentRef
;         // true if returing a persistent reference 
2822         Boolean returnAllMatches
;                       // true if we should return all matches 
2823         Boolean returnIdentity
;                         // true if we are returning a SecIdentityRef 
2824         Boolean trustedOnly
;                            // true if we only return trusted certs 
2825         Boolean issuerAndSNToMatch
;                     // true if both issuer and SN were provided 
2826         SecItemClass itemClass
;                         // item class for this query 
2827         SecPolicyRef policy
;                            // value for kSecMatchPolicy (may be NULL) 
2828         SecKeychainRef keychain
;                        // value for kSecUseKeychain (may be NULL) 
2829         CFArrayRef useItems
;                            // value for kSecUseItemList (may be NULL) 
2830         CFArrayRef itemList
;                            // value for kSecMatchItemList (may be NULL) 
2831         CFTypeRef searchList
;                           // value for kSecMatchSearchList (may be NULL) 
2832         CFTypeRef matchLimit
;                           // value for kSecMatchLimit (may be NULL) 
2833         CFTypeRef emailAddrToMatch
;                     // value for kSecMatchEmailAddressIfPresent (may be NULL) 
2834         CFTypeRef validOnDate
;                          // value for kSecMatchValidOnDate (may be NULL) 
2835         CFTypeRef keyClass
;                                     // value for kSecAttrKeyClass (may be NULL) 
2836         CFTypeRef service
;                                      // value for kSecAttrService (may be NULL) 
2837         CFTypeRef issuer
;                                       // value for kSecAttrIssuer (may be NULL) 
2838         CFTypeRef matchIssuers
;                                 // value for kSecMatchIssuers (may be NULL) 
2839         CFTypeRef serialNumber
;                         // value for kSecAttrSerialNumber (may be NULL) 
2840         CFTypeRef search
;                                       // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) 
2841         CFTypeRef assumedKeyClass
;                      // if no kSecAttrKeyClass provided, holds the current class we're searching for 
2842         CFIndex itemListIndex
;                          // if no search reference but we have itemList, holds index of next item to return 
2843         SecKeychainAttributeList 
*attrList
;     // attribute list for this query 
2844         SecAccessRef access
;                            // access reference (for SecItemAdd only, not used to find items) 
2845         CFDataRef itemData
;                                     // item data (for SecItemAdd only, not used to find items) 
2846         CFTypeRef itemRef
;                                      // item reference (to find, add, update or delete, depending on context) 
2847         SecIdentityRef identityRef
;                     // identity reference (input as kSecValueRef) 
2848         CFDataRef itemPersistentRef
;            // item persistent reference (to find, add, update or delete, depending on context) 
2849         Boolean isPCSItem
;                                      // true if this query is for a Protected Cloud Storage item 
2853 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
) 
2855         if (!dict 
|| !key 
|| !value 
|| !expectedTypeID
) 
2858         if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) { 
2859                 // value was not provided for this key (not an error!) 
2862         else if (!(*value
)) { 
2863                 // provided value is NULL (also not an error!) 
2864                 return errSecSuccess
; 
2867                 CFTypeID actualTypeID 
= CFGetTypeID(*value
); 
2868                 if (!((expectedTypeID 
== actualTypeID
) || (altTypeID 
&& altTypeID 
== actualTypeID
))) { 
2869                         // provided value does not have the expected (or alternate) CF type ID 
2870                         if ((expectedTypeID 
== SecKeychainItemGetTypeID()) && 
2871                                 (actualTypeID 
== SecKeyGetTypeID() || actualTypeID 
== SecCertificateGetTypeID())) { 
2872                                 // provided value is a "floating" reference which is not yet in a keychain 
2874                                 return errSecSuccess
; 
2876                         return errSecItemInvalidValue
; 
2879                         // provided value is OK; retain it 
2883         return errSecSuccess
; 
2887 _EnsureUserDefaultKeychainIsSearched(SecItemParams 
*itemParams
) 
2890         CFArrayRef tmpList 
= (CFArrayRef
) itemParams
->searchList
; 
2892                 // search list exists; make it mutable 
2893                 itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2896                 // no search list; start with default list 
2897                 status 
= SecKeychainCopySearchList(&tmpList
); 
2898                 if (!status 
&& tmpList
) { 
2899                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2903                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2907         SecKeychainRef userKeychain 
= NULL
; 
2908         status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2909         if (!status 
&& userKeychain
) { 
2910                 if (!CFArrayContainsValue((CFArrayRef
)itemParams
->searchList
, 
2911                         CFRangeMake(0, CFArrayGetCount((CFArrayRef
)itemParams
->searchList
)), userKeychain
)) { 
2912                         // user's default keychain isn't currently in the search list, so append it 
2913                         CFArrayAppendValue((CFMutableArrayRef
)itemParams
->searchList
, userKeychain
); 
2915                 CFRelease(userKeychain
); 
2920 _EnsureUserDefaultKeychainIsTargeted(SecItemParams 
*itemParams
) 
2922         if (itemParams
->keychain
) { 
2923                 return; // keychain is already explicitly specified, assume it's correct 
2925         SecKeychainRef userKeychain 
= NULL
; 
2926         OSStatus status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2927         if (!status 
&& userKeychain
) { 
2928                 itemParams
->keychain 
= userKeychain
; 
2933 _FreeSecItemParams(SecItemParams 
*itemParams
) 
2938         if (itemParams
->query
) CFRelease(itemParams
->query
); 
2939         if (itemParams
->policy
) CFRelease(itemParams
->policy
); 
2940         if (itemParams
->keychain
) CFRelease(itemParams
->keychain
); 
2941         if (itemParams
->useItems
) CFRelease(itemParams
->useItems
); 
2942         if (itemParams
->itemList
) CFRelease(itemParams
->itemList
); 
2943         if (itemParams
->searchList
) CFRelease(itemParams
->searchList
); 
2944         if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
); 
2945         if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
); 
2946         if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
); 
2947         if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
); 
2948         if (itemParams
->service
) CFRelease(itemParams
->service
); 
2949         if (itemParams
->issuer
) CFRelease(itemParams
->issuer
); 
2950         if (itemParams
->matchIssuers
) CFRelease(itemParams
->matchIssuers
); 
2951         if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
); 
2952         if (itemParams
->search
) CFRelease(itemParams
->search
); 
2953         if (itemParams
->access
) CFRelease(itemParams
->access
); 
2954         if (itemParams
->itemData
) CFRelease(itemParams
->itemData
); 
2955         if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
); 
2956         if (itemParams
->identityRef
) CFRelease(itemParams
->identityRef
); 
2957         if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
); 
2959         _FreeAttrList(itemParams
->attrList
); 
2964 static SecItemParams
* 
2965 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus 
*error
) 
2968         CFTypeRef value 
= NULL
; 
2969     CFDictionaryRef policyDict 
= NULL
; 
2970         SecItemParams 
*itemParams 
= (SecItemParams 
*)calloc(1, sizeof(struct SecItemParams
)); 
2972         require_action(itemParams 
!= NULL
, error_exit
, status 
= errSecAllocate
); 
2973         require_action(dict 
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status 
= errSecParam
); 
2975         itemParams
->query 
= (CFDictionaryRef
) CFRetain(dict
); 
2977         // validate input search parameters 
2978         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
); 
2979         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2980         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2981         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
2982         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
); 
2983         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
); 
2985         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
); 
2986         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
); 
2988         // validate a subset of input attributes (used to create an appropriate search reference) 
2989         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
); 
2990         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
); 
2991         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
); 
2992         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
); 
2994         if (itemParams
->service 
&& CFStringHasPrefix((CFStringRef
)itemParams
->service
, CFSTR("ProtectedCloudStorage"))) { 
2995                 itemParams
->isPCSItem 
= true; 
2996                 if (!SecItemSynchronizable(dict
)) { 
2997                         _EnsureUserDefaultKeychainIsSearched(itemParams
); // for SecItemCopyMatching, SecItemUpdate, SecItemDelete 
2998                         _EnsureUserDefaultKeychainIsTargeted(itemParams
); // for SecItemAdd 
3002         // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items 
3003         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
); 
3004         if (itemParams
->itemData 
&& CFGetTypeID(itemParams
->itemData
) == CFStringGetTypeID()) { 
3005                 /* If we got a string, convert it into a data object */ 
3006                 CFStringRef string 
= (CFStringRef
)itemParams
->itemData
; 
3007                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(string
), kCFStringEncodingUTF8
) + 1; 
3008                 CFMutableDataRef data 
= CFDataCreateMutable(NULL
, maxLength
); 
3009                 require_action(data
, error_exit
, status 
= errSecAllocate
); 
3011                 CFDataSetLength(data
, maxLength
); 
3013                 if (!CFStringGetCString(string
, (char *)CFDataGetMutableBytePtr(data
), maxLength
, kCFStringEncodingUTF8
)) { 
3015                         status 
= errSecAllocate
; 
3019                 CFDataSetLength(data
, strlen((const char *)CFDataGetBytePtr(data
))); /* dont include NUL in string */ 
3020                 itemParams
->itemData 
= data
; 
3024         // validate item references 
3025         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit
); 
3026         if (itemParams
->itemRef 
&& (CFGetTypeID(itemParams
->itemRef
) == SecIdentityGetTypeID())) { 
3027                 itemParams
->identityRef 
= (SecIdentityRef
)itemParams
->itemRef
; 
3028                 itemParams
->itemRef 
= NULL
; 
3029                 SecIdentityCopyCertificate(itemParams
->identityRef
, (SecCertificateRef 
*)&itemParams
->itemRef
); 
3031         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
); 
3032         if (itemParams
->itemRef 
|| itemParams
->itemPersistentRef
) { 
3033                 // Caller is trying to add or find an item by reference. 
3034                 // The supported method for doing that is to provide a kSecUseItemList array 
3035                 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al, 
3036                 // so add the item reference to those arrays here. 
3037                 if (itemParams
->useItems
) { 
3038                         CFArrayRef tmpItems 
= itemParams
->useItems
; 
3039                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3040                         CFRelease(tmpItems
); 
3042                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3044                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
); 
3045                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
); 
3047                 if (itemParams
->itemList
) { 
3048                         CFArrayRef tmpItems 
= itemParams
->itemList
; 
3049                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3050                         CFRelease(tmpItems
); 
3052                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3054                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
); 
3055                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
); 
3058         // must have an explicit item class, unless one of the following is true: 
3059         //   - we have an item list to add or search (kSecUseItemList) 
3060         //   - we have an item reference or persistent reference for the thing we want to look up 
3061         // Note that both of these cases will set itemParams->useItems. 
3062         // If we have an item list to match (kSecMatchItemList), that still requires an item class, 
3063         // so we can perform a search and see if the results match items in the list. 
3065         if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
) { 
3066                 require_action(false, error_exit
, status 
= errSecItemClassMissing
); 
3069                 itemParams
->itemClass 
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
); 
3070                 if (itemParams
->itemClass 
== kSecSymmetricKeyItemClass 
&& !itemParams
->keyClass
) { 
3071             // no key class specified, so start with symmetric key class; will search the others later in UpdateKeychainSearchAndCopyNext 
3072             itemParams
->itemClass 
= kSecSymmetricKeyItemClass
; 
3073             itemParams
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3075                 require_action(!(itemParams
->itemClass 
== 0 && !itemParams
->useItems
), error_exit
, status 
= errSecItemClassMissing
); 
3078     // kSecMatchIssuers is only permitted with identities. 
3079     // Convert the input issuers to normalized form. 
3080     require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchIssuers
, (const void **)&itemParams
->matchIssuers
, CFArrayGetTypeID(), NULL
), error_exit
); 
3081     if (itemParams
->matchIssuers
) { 
3082         require_action(itemParams
->returnIdentity
, error_exit
, status 
= errSecParam
); 
3083         CFMutableArrayRef canonical_issuers 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3084         CFArrayRef issuers 
= (CFArrayRef
)itemParams
->matchIssuers
; 
3085         if (canonical_issuers
) { 
3086             CFIndex i
, count 
= CFArrayGetCount(issuers
); 
3087             for (i 
= 0; i 
< count
; i
++) { 
3088                 CFTypeRef issuer_data 
= CFArrayGetValueAtIndex(issuers
, i
); 
3089                 CFDataRef issuer_canonical 
= NULL
; 
3090                 if (CFDataGetTypeID() == CFGetTypeID(issuer_data
)) 
3091                     issuer_canonical 
= SecDistinguishedNameCopyNormalizedSequence((CFDataRef
)issuer_data
); 
3092                 if (issuer_canonical
) { 
3093                     CFArrayAppendValue(canonical_issuers
, issuer_canonical
); 
3094                     CFRelease(issuer_canonical
); 
3097             if (CFArrayGetCount(canonical_issuers
) > 0) { 
3098                 CFAssignRetained(itemParams
->matchIssuers
, canonical_issuers
); 
3100                 CFRelease(canonical_issuers
); 
3104         itemParams
->keyUsage 
= _CssmKeyUsageFromQuery(dict
); 
3105         itemParams
->trustedOnly 
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3106         itemParams
->issuerAndSNToMatch 
= (itemParams
->issuer 
!= NULL 
&& itemParams
->serialNumber 
!= NULL
); 
3108         // other input attributes, used for SecItemAdd but not for finding items 
3109         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3110         if (itemParams
->access 
== NULL
) { 
3111                 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>) 
3112                 require_noerr(status 
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3115         // determine how to return the result 
3116         itemParams
->numResultTypes 
= 0; 
3117         itemParams
->returningRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3118         if (itemParams
->returningRef
) ++itemParams
->numResultTypes
; 
3119         itemParams
->returningPersistentRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3120         if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
; 
3121         itemParams
->returningAttributes 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3122         if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
; 
3123         itemParams
->returningData 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3124         if (itemParams
->returningData
) ++itemParams
->numResultTypes
; 
3126         // default is kSecReturnRef if no result types were specified 
3127         if (!itemParams
->numResultTypes
) { 
3128                 itemParams
->returningRef 
= TRUE
; 
3129                 itemParams
->numResultTypes 
= 1; 
3132         // determine if one, some or all matches should be returned (default is kSecMatchLimitOne) 
3133         itemParams
->maxMatches 
= 1; 
3134         itemParams
->returnAllMatches 
= FALSE
; 
3135         if (itemParams
->matchLimit
) { 
3136                 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3137                         itemParams
->returnAllMatches 
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
); 
3139                 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3140                         CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
); 
3141                         require_action(!(itemParams
->maxMatches 
< 0), error_exit
, status 
= errSecMatchLimitUnsupported
); 
3144         if (itemParams
->returnAllMatches
) { 
3145                 itemParams
->maxMatches 
= INT32_MAX
; 
3146                 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each) 
3147                 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass 
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
) 
3148                         status 
= errSecReturnDataUnsupported
; 
3149                 require_noerr(status
, error_exit
); 
3152     // if we already have an item list (to add or find items in), we don't need a search reference 
3153         if (itemParams
->useItems
) { 
3154                 if (itemParams
->itemClass 
== 0) { 
3155                         itemParams
->itemClass 
= _ItemClassFromItemList(itemParams
->useItems
); 
3158         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3159         if (itemParams
->itemClass 
!= 0) { 
3160             status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
); 
3162             status 
= errSecSuccess
; 
3164                 goto error_exit
; // all done here 
3167         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3168         require_noerr(status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
); 
3170     // if policy is a SMIME policy, copy email address in policy into emailAddrToMatch parameter 
3171     if(itemParams
->policy
) { 
3172         policyDict 
= SecPolicyCopyProperties(itemParams
->policy
); 
3173         CFStringRef oidStr 
= (CFStringRef
) CFDictionaryGetValue(policyDict
, kSecPolicyOid
); 
3174         if(oidStr 
&& CFStringCompare(kSecPolicyAppleSMIME
,oidStr
,0) == 0) { 
3175             require_noerr(status 
= _ValidateDictionaryEntry(policyDict
, kSecPolicyName
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
3177         CFReleaseNull(policyDict
); 
3180         // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) 
3181         if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) { 
3182                 // searching for certificates by email address 
3183                 char *nameBuf 
= (char*)malloc(MAXPATHLEN
); 
3185                         status 
= errSecAllocate
; 
3187                 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) { 
3188                         status 
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
); 
3191                         status 
= errSecItemInvalidValue
; 
3193                 if (nameBuf
) free(nameBuf
); 
3195         else if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) { 
3196                 // searching for certificates by issuer and serial number 
3197                 status 
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
, 
3198                                 (CFDataRef
)itemParams
->issuer
, 
3199                                 (CFDataRef
)itemParams
->serialNumber
, 
3200                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3202         else if (itemParams
->returnIdentity 
&& itemParams
->policy
) { 
3203                 // searching for identities by policy 
3204                 status 
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
, 
3205                                 (CFStringRef
)itemParams
->service
, 
3206                                 itemParams
->keyUsage
, 
3207                                 itemParams
->searchList
, 
3208                                 itemParams
->trustedOnly
, 
3209                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3211         else if (itemParams
->returnIdentity
) { 
3212                 // searching for identities 
3213                 status 
= SecIdentitySearchCreate(itemParams
->searchList
, 
3214                                 itemParams
->keyUsage
, 
3215                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3218                 // normal keychain item search 
3219                 status 
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
, 
3220                                 itemParams
->itemClass
, 
3221                                 (itemParams
->attrList
->count 
== 0) ? NULL 
: itemParams
->attrList
, 
3222                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3226     CFReleaseNull(policyDict
); 
3228                 _FreeSecItemParams(itemParams
); 
3241         SecKeychainRef keychainRef
, 
3242         SecAccessRef accessRef
, 
3243         SecKeychainAttributeList 
*attrList
, 
3244         SecKeychainItemRef 
*outItemRef
) 
3248                 // We must specify the access, since a free-floating key won't have one yet by default 
3249                 SecPointer
<Access
> access
; 
3251                         access 
= Access::required(accessRef
); 
3254                         CFStringRef descriptor 
= NULL
; 
3256                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
3257                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
3258                                         if (attr
.tag 
== kSecKeyPrintName
) { 
3259                                                 descriptor 
= CFStringCreateWithBytes(NULL
, (const UInt8 
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
); 
3264                         if (descriptor 
== NULL
) { 
3265                                 descriptor 
= (CFStringRef
) CFRetain(CFSTR("<unknown>")); 
3267                         access 
= new Access(cfString(descriptor
)); 
3268                         CFRelease(descriptor
); 
3271                 KeyItem 
*key 
= KeyItem::required(keyRef
); 
3272                 Item item 
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
); 
3274                         *outItemRef 
= item
->handle(); 
3280 _FilterWithPolicy(SecPolicyRef policy
, CFDateRef date
, SecCertificateRef cert
) 
3282         CFDictionaryRef props 
= NULL
; 
3283         CFArrayRef keychains 
= NULL
; 
3284         CFArrayRef anchors 
= NULL
; 
3285         CFArrayRef certs 
= NULL
; 
3286         CFArrayRef chain 
= NULL
; 
3287         SecTrustRef trust 
= NULL
; 
3289         SecTrustResultType      trustResult
; 
3290         Boolean needChain 
= false; 
3292         if (!policy 
|| !cert
) return errSecParam
; 
3294         certs 
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
); 
3295         status 
= SecTrustCreateWithCertificates(certs
, policy
, &trust
); 
3296         if(status
) goto cleanup
; 
3298         /* Set evaluation date, if specified (otherwise current date is implied) */ 
3299         if (date 
&& (CFGetTypeID(date
) == CFDateGetTypeID())) { 
3300                 status 
= SecTrustSetVerifyDate(trust
, date
); 
3301                 if(status
) goto cleanup
; 
3304         /* Check whether this is the X509 Basic policy, which means chain building */ 
3305         props 
= SecPolicyCopyProperties(policy
); 
3307                 CFTypeRef oid 
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
); 
3308                 if (oid 
&& (CFEqual(oid
, kSecPolicyAppleX509Basic
) || 
3309                     CFEqual(oid
, kSecPolicyAppleRevocation
))) { 
3315                 status 
= SecTrustEvaluateLeafOnly(trust
, &trustResult
); 
3317                 status 
= SecTrustEvaluate(trust
, &trustResult
); 
3320         if (!(trustResult 
== kSecTrustResultProceed 
|| 
3321                   trustResult 
== kSecTrustResultUnspecified 
|| 
3322                   trustResult 
== kSecTrustResultRecoverableTrustFailure
)) { 
3323                 /* The evaluation failed in a non-recoverable way */ 
3324                 status 
= errSecCertificateCannotOperate
; 
3328         /* If there are no per-cert policy status codes, 
3329          * and the cert has not expired, consider it valid for the policy. 
3332                 (void)SecTrustGetCssmResultCode(trust
, &status
); 
3336         if(props
) CFRelease(props
); 
3337         if(chain
) CFRelease(chain
); 
3338         if(anchors
) CFRelease(anchors
); 
3339         if(keychains
) CFRelease(keychains
); 
3340         if(certs
) CFRelease(certs
); 
3341         if(trust
) CFRelease(trust
); 
3347 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
) 
3349         if (!validOnDate 
|| !cert
) return errSecParam
; 
3351         CFAbsoluteTime at
, nb
, na
; 
3352         if (CFGetTypeID(validOnDate
) == CFDateGetTypeID()) 
3353                 at 
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
); 
3355                 at 
= CFAbsoluteTimeGetCurrent(); 
3357         OSStatus status 
= errSecSuccess
; 
3358         nb 
= SecCertificateNotValidBefore(cert
); 
3359         na 
= SecCertificateNotValidAfter(cert
); 
3361         if (nb 
== 0 || na 
== 0 || nb 
== na
) 
3362                 status 
= errSecCertificateCannotOperate
; 
3364                 status 
= errSecCertificateNotValidYet
; 
3366                 status 
= errSecCertificateExpired
; 
3372 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
) 
3374         if (!cert
) return errSecParam
; 
3375         if (!trustedOnly
) return errSecSuccess
; 
3377         CFArrayRef certArray 
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
); 
3378         SecPolicyRef policy 
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
); 
3379         OSStatus status 
= (policy 
== NULL
) ? errSecPolicyNotFound 
: errSecSuccess
; 
3382                 SecTrustRef trust 
= NULL
; 
3383                 status 
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
); 
3385                         SecTrustResultType trustResult
; 
3386                         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3388                                 if (!(trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
)) { 
3389                                         status 
= (trustResult 
== kSecTrustResultDeny
) ? errSecTrustSettingDeny 
: errSecNotTrusted
; 
3397                 CFRelease(certArray
); 
3403 static bool items_matching_issuer_parent(CFDataRef issuer
, CFArrayRef issuers
, int recurse
) { 
3404     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) { return false; } 
3406     /* We found a match, we're done. */ 
3407     if (CFArrayContainsValue(issuers
, CFRangeMake(0, CFArrayGetCount(issuers
)), issuer
)) { return true; } 
3409     /* Prevent infinite recursion */ 
3410     if (recurse 
<= 0) { return false; } 
3413     /* Query for parents */ 
3414     CFMutableDictionaryRef query 
= NULL
; 
3415     CFTypeRef parents 
= NULL
; 
3418     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 4, &kCFTypeDictionaryKeyCallBacks
, 
3419                                       &kCFTypeDictionaryValueCallBacks
), out
); 
3420     CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
3421     CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
); 
3422     CFDictionaryAddValue(query
, kSecAttrSubject
, issuer
); 
3423     CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
3424     require_noerr_quiet(SecItemCopyMatching(query
, &parents
), out
); 
3426     if (parents 
&& CFArrayGetTypeID() == CFGetTypeID(parents
)) { 
3427         CFIndex i
, count 
= CFArrayGetCount((CFArrayRef
)parents
); 
3428         for (i 
= 0; i 
< count
; i
++) { 
3429             SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)parents
, i
); 
3430             CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3431             if (CFEqual(cert_issuer
, issuer
)) { 
3432                 // Self-issued cert, don't look for parents. 
3433                 CFReleaseNull(cert_issuer
); 
3436             found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3437             CFReleaseNull(cert_issuer
); 
3438             if (found
) { break; } 
3440     } else if (parents 
&& SecCertificateGetTypeID() == CFGetTypeID(parents
)) { 
3441         SecCertificateRef cert 
= (SecCertificateRef
)parents
; 
3442         CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3443         require_action_quiet(!CFEqual(cert_issuer
, issuer
), out
, CFReleaseNull(cert_issuer
)); 
3444         found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3445         CFReleaseNull(cert_issuer
); 
3449     CFReleaseNull(query
); 
3450     CFReleaseNull(parents
); 
3455 _FilterWithIssuers(CFArrayRef issuers
, SecCertificateRef cert
) 
3457     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) return errSecParam
; 
3458     if (!cert
) return errSecParam
; 
3460     OSStatus status 
= errSecInternalError
; 
3462     /* kSecMatchIssuers matches certificates where ANY certificate in the chain has this issuer. 
3463      * So we now need to recursively query the keychain for this cert's parents to determine if 
3464      * they match. (This is why we limited the use of this key in _CreateSecItemParamsFromDictionary.) */ 
3465     CFDataRef issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3466     if (items_matching_issuer_parent(issuer
, issuers
, 10)) { 
3467         status 
= errSecSuccess
; 
3470     CFReleaseNull(issuer
); 
3474 static SecKeychainItemRef
 
3475 CopyResolvedKeychainItem(CFTypeRef item
) 
3477         SecKeychainItemRef kcItem 
= NULL
; 
3478         OSStatus status 
= errSecSuccess
; 
3480                 if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
3481                         // persistent reference, resolve first 
3482                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &kcItem
); 
3486                         kcItem 
= (SecKeychainItemRef
) CFRetain(item
); 
3489                         // ask for the item's class: 
3490                         // will return an error if the item has been deleted 
3491                         SecItemClass itemClass
; 
3492                         SecCertificateRef certRef 
= NULL
; 
3493                         CFTypeID itemTypeID 
= CFGetTypeID(kcItem
); 
3494                         if (itemTypeID 
== SecIdentityGetTypeID()) { 
3495                                 status 
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
, &certRef
); 
3497                         else if (itemTypeID 
== SecCertificateGetTypeID()) { 
3498                                 certRef 
= (SecCertificateRef
) CFRetain(kcItem
); 
3501                                 // can't call SecKeychainItemCopyAttributesAndData on a SecCertificateRef 
3502                                 itemClass 
= kSecCertificateItemClass
; 
3505                                 status 
= SecKeychainItemCopyAttributesAndData(kcItem
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3520 UpdateKeychainSearchAndCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3522         // This function refreshes the search parameters in the specific case where 
3523         // the caller is searching for kSecClassKey items but did not provide the 
3524         // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and 
3525         // we must perform separate searches to obtain all results. 
3527         OSStatus status 
= errSecItemNotFound
; 
3528         if (!params 
|| !params
->assumedKeyClass 
|| !params
->query 
|| !item
) 
3531         // Free the previous search reference and attribute list. 
3533                 CFRelease(params
->search
); 
3534         params
->search 
= NULL
; 
3535         _FreeAttrList(params
->attrList
); 
3536         params
->attrList 
= NULL
; 
3538         // Make a copy of the query dictionary so we can set the key class parameter. 
3539         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
); 
3540         CFRelease(params
->query
); 
3541         params
->query 
= dict
; 
3542         CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
); 
3544         // Determine the current item class for this search, and the next assumed key class. 
3545         if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) { 
3546                 params
->itemClass 
= kSecSymmetricKeyItemClass
; 
3547                 params
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3548         } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) { 
3549                 params
->itemClass 
= kSecPublicKeyItemClass
; 
3550                 params
->assumedKeyClass 
= kSecAttrKeyClassPrivate
; 
3552                 params
->itemClass 
= kSecPrivateKeyItemClass
; 
3553                 params
->assumedKeyClass 
= NULL
; 
3556         // Rebuild the attribute list for the new key class. 
3557         if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == errSecSuccess
) { 
3558                 // Create a new search reference for the new attribute list. 
3559                 if (SecKeychainSearchCreateFromAttributes(params
->searchList
, 
3561                         (params
->attrList
->count 
== 0) ? NULL 
: params
->attrList
, 
3562                         (SecKeychainSearchRef
*)¶ms
->search
) == errSecSuccess
) { 
3563                         // Return the first matching item from the new search. 
3564                         // We won't come back here again until there are no more matching items for this search. 
3565                         status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
); 
3573 SecItemSearchCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3575         // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef. 
3576         // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter, 
3577         // depending on the type of search reference. 
3580         CFTypeRef search 
= (params
) ? params
->search 
: NULL
; 
3581         CFTypeID typeID 
= (search
) ? CFGetTypeID(search
) : 0; 
3583         if (search 
&& typeID 
== SecIdentitySearchGetTypeID()) { 
3584                 status 
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
); 
3586         else if (search 
&& typeID 
== SecKeychainSearchGetTypeID()) { 
3587                 status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
); 
3588                 // Check if we need to refresh the search for the next key class 
3589                 while (status 
== errSecItemNotFound 
&& params
->assumedKeyClass 
!= NULL
) 
3590                         status 
= UpdateKeychainSearchAndCopyNext(params
, item
); 
3592         else if (typeID 
== 0 && params 
&& (params
->useItems 
|| params
->itemList
)) { 
3593                 // No search available, but there is an item list available. 
3594                 // Return the next candidate item from the caller's item list 
3595                 CFArrayRef itemList 
= (params
->useItems
) ? params
->useItems 
: params
->itemList
; 
3596                 CFIndex count 
= CFArrayGetCount(itemList
); 
3597                 *item 
= (CFTypeRef
) NULL
; 
3598                 if (params
->itemListIndex 
< count
) { 
3599                         *item 
= (CFTypeRef
)CFArrayGetValueAtIndex(itemList
, params
->itemListIndex
++); 
3601                                 // Potentially resolve persistent item references here, and 
3602                                 // verify the item reference we're about to hand back is still 
3603                                 // valid (it could have been deleted from the keychain while 
3604                                 // our query was holding onto the itemList). 
3605                                 *item 
= CopyResolvedKeychainItem(*item
); 
3606                                 if (*item 
&& (CFGetTypeID(*item
) == SecIdentityGetTypeID())) { 
3607                                         // Persistent reference resolved to an identity, so return that type. 
3608                                         params
->returnIdentity 
= true; 
3612                 status 
= (*item
) ? errSecSuccess 
: errSecItemNotFound
; 
3615                 status 
= errSecItemNotFound
; 
3621 FilterCandidateItem(CFTypeRef 
*item
, SecItemParams 
*itemParams
, SecIdentityRef 
*identity
) 
3623         if (!item 
|| *item 
== NULL 
|| !itemParams
) 
3624                 return errSecItemNotFound
; 
3627         CFStringRef commonName 
= NULL
; 
3628         SecIdentityRef foundIdentity 
= NULL
; 
3629         if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) { 
3630                 // we found a SecIdentityRef, rather than a SecKeychainItemRef; 
3631                 // replace the found "item" with its associated certificate (which is the 
3632                 // item we actually want for purposes of getting attributes, data, or a 
3633                 // persistent data reference), and return the identity separately. 
3634                 SecCertificateRef certificate
; 
3635                 status 
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
); 
3636                 if (itemParams
->returnIdentity
) { 
3637                         foundIdentity 
= (SecIdentityRef
) *item
; 
3639                                 *identity 
= foundIdentity
; 
3645                 *item 
= (CFTypeRef
)certificate
; 
3648         CFDictionaryRef query 
= itemParams
->query
; 
3650         if (itemParams
->itemClass 
== kSecCertificateItemClass
) { 
3651                 // perform string comparisons first 
3652                 CFStringCompareFlags flags 
= _StringCompareFlagsFromQuery(query
); 
3653                 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
; 
3654                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
)) 
3655                         nameContains 
= NULL
; 
3656                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
)) 
3658                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
)) 
3660                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
)) 
3662                 if (nameContains 
|| nameStarts 
|| nameEnds 
|| nameExact
) { 
3663                         status 
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
); 
3664                         if (status 
|| !commonName
) goto filterOut
; 
3667                         CFRange range 
= CFStringFind(commonName
, nameContains
, flags
); 
3668                         if (range
.length 
< 1) 
3670                         // certificate item contains string; proceed to next check 
3673                         CFRange range 
= CFStringFind(commonName
, nameStarts
, flags
); 
3674                         if (range
.length 
< 1 || range
.location 
> 1) 
3676                         // certificate item starts with string; proceed to next check 
3679                         CFRange range 
= CFStringFind(commonName
, nameEnds
, flags
); 
3680                         if (range
.length 
< 1 || range
.location 
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
))) 
3682                         // certificate item ends with string; proceed to next check 
3685                         CFRange range 
= CFStringFind(commonName
, nameExact
, flags
); 
3686                         if (range
.length 
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
))) 
3688                         // certificate item exactly matches string; proceed to next check 
3690                 if (itemParams
->returnIdentity
) { 
3691                         // if we already found and returned the identity, we can skip this 
3692                         if (!foundIdentity
) { 
3693                                 status 
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
); 
3694                                 if (status
) goto filterOut
; 
3696                         // certificate item is part of an identity; proceed to next check 
3698                 if (itemParams
->policy
) { 
3699                         status 
= _FilterWithPolicy(itemParams
->policy
, (CFDateRef
)itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3700                         if (status
) goto filterOut
; 
3701                         // certificate item is valid for specified policy (and optionally specified date) 
3703                 if (itemParams
->validOnDate
) { 
3704                         status 
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3705                         if (status
) goto filterOut
; 
3706                         // certificate item is valid for specified date 
3708                 if (itemParams
->trustedOnly
) { 
3709                         // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search, 
3710                         // their trust has already been validated and we can skip this part. 
3711                         if (!(foundIdentity 
&& itemParams
->returnIdentity 
&& itemParams
->policy
)) { 
3712                                 status 
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
); 
3713                                 if (status
) goto filterOut
; 
3715                         // certificate item is trusted on this system 
3717         if (itemParams
->matchIssuers
) { 
3718             status 
= _FilterWithIssuers((CFArrayRef
)itemParams
->matchIssuers
, (SecCertificateRef
) *item
); 
3719             if (status
) goto filterOut
; 
3720             // certificate item has one of the issuers 
3723         if (itemParams
->itemList
) { 
3724                 Boolean foundMatch 
= FALSE
; 
3725                 CFIndex idx
, count 
= CFArrayGetCount(itemParams
->itemList
); 
3726                 for (idx
=0; idx
<count
; idx
++) { 
3727                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
); 
3728                         SecKeychainItemRef realItem 
= NULL
; 
3729                         SecCertificateRef aCert 
= NULL
; 
3730                         if (anItem 
== NULL
) { 
3733                         if (CFDataGetTypeID() == CFGetTypeID(anItem
) && 
3734                                 errSecSuccess 
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) { 
3737                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) && 
3738                                 errSecSuccess 
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) { 
3741                         if (CFEqual(anItem
, (CFTypeRef
) *item
)) { 
3748                                 CFRelease(realItem
); 
3754                 if (!foundMatch
) goto filterOut
; 
3755                 // item was found on provided list 
3758         if (foundIdentity 
&& !identity
) { 
3759                 CFRelease(foundIdentity
); 
3762                 CFRelease(commonName
); 
3765         // if we get here, consider the item a match 
3766         return errSecSuccess
; 
3770                 CFRelease(commonName
); 
3774         if (foundIdentity
) { 
3775                 CFRelease(foundIdentity
); 
3780         return errSecItemNotFound
; 
3784 AddItemResults(SecKeychainItemRef item
, 
3785         SecIdentityRef identity
, 
3786         SecItemParams 
*itemParams
, 
3787         CFAllocatorRef allocator
, 
3788         CFMutableArrayRef 
*items
, 
3791         // Given a found item (which may also be an identity), this function adds 
3792         // the requested result types (specified in itemParams) to the appropriate 
3793         // container as follows: 
3795         // 1. If there is only one result type (numResultTypes == 1) and only one 
3796         //    match requested (maxMatches == 1), set *result directly. 
3798         // 2. If there are multiple result types (numResultTypes > 1), and only one 
3799         //    match requested (maxMatches == 1), add each result type to itemDict 
3800         //    and set itemDict as the value of *result. 
3802         // 3. If there is only one result type (numResultTypes == 1) and multiple 
3803         //    possible matches (maxMatches > 1), add the result type to *items 
3804         //    and set *items as the value of *result. 
3806         // 4. If there are multiple result types (numResultTypes > 1) and multiple 
3807         //    possible matches (maxMatches > 1), add each result type to itemDict, 
3808         //    add itemDict to *items, and set *items as the value of *result. 
3810         // Note that we allocate *items if needed. 
3812         if (!item 
|| !itemParams 
|| !result
) 
3815         if (itemParams
->maxMatches 
> 1) { 
3816                 // if we can return more than one item, we must have an array 
3819                 else if (*items 
== NULL
) 
3820                         *items 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
3823         OSStatus tmpStatus
, status 
= errSecSuccess
; 
3824         CFMutableArrayRef itemArray 
= (items
) ? *items 
: NULL
; 
3825         CFMutableDictionaryRef itemDict 
= NULL
; 
3826         if (itemParams
->numResultTypes 
> 1) { 
3827                 // if we're returning more than one result type, each item we return must be a dictionary 
3828                 itemDict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
3831         if (itemParams
->returningRef
) { 
3832                 const void* itemRef 
= (identity
) ? (const void*)identity 
: (const void*)item
; 
3834                         CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
); 
3836                 else if (itemArray
) { 
3837                         CFArrayAppendValue(itemArray
, itemRef
); 
3840                         *result 
= CFRetain((CFTypeRef
)itemRef
); 
3844         if (itemParams
->returningPersistentRef
) { 
3845                 CFDataRef persistentRef
; 
3846                 SecKeychainItemRef tmpItem 
= item
; 
3847                 if (itemParams
->identityRef
) { 
3848                         tmpItem 
= (SecKeychainItemRef
)itemParams
->identityRef
; 
3850                 tmpStatus 
= SecKeychainItemCreatePersistentReference(tmpItem
, &persistentRef
); 
3851                 if (tmpStatus 
== errSecSuccess
) { 
3853                                 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
); 
3855                         else if (itemArray
) { 
3856                                 CFArrayAppendValue(itemArray
, persistentRef
); 
3859                                 *result 
= CFRetain(persistentRef
); 
3861                         CFRelease(persistentRef
); 
3863                 else if (status 
== errSecSuccess
) { 
3868         if (itemParams
->returningData
) { 
3869                 // Use SecCertificateCopyData if we have a SecCertificateRef item. 
3870                 // Note that a SecCertificateRef may not actually be a SecKeychainItem, 
3871                 // in which case SecKeychainItemCopyContent will not obtain its data. 
3873                 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) { 
3874                         CFDataRef dataRef 
= SecCertificateCopyData((SecCertificateRef
)item
); 
3877                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3879                                 else if (itemArray
) { 
3880                                         CFArrayAppendValue(itemArray
, dataRef
); 
3883                                         *result 
= CFRetain(dataRef
); 
3886                                 status 
= errSecSuccess
; 
3889                                 status 
= errSecAllocate
; 
3895                         tmpStatus 
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
); 
3896                         if (tmpStatus 
== errSecSuccess
) { 
3897                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8 
*)data
, length
); 
3899                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3901                                 else if (itemArray
) { 
3902                                         CFArrayAppendValue(itemArray
, dataRef
); 
3905                                         *result 
= CFRetain(dataRef
); 
3908                                 (void) SecKeychainItemFreeContent(NULL
, data
); 
3910                         else if (status 
== errSecSuccess
) { 
3916         if (itemParams
->returningAttributes
) { 
3917                 CFDictionaryRef attrsDict 
= NULL
; 
3918                 SecItemClass itemClass
; 
3919                 // since we have an item, allow its actual class to override the query-specified item class 
3920                 tmpStatus 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3922                         itemClass 
= itemParams
->itemClass
; 
3924                 tmpStatus 
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
); 
3927                                 // add all keys and values from attrsDict to the item dictionary 
3928                                 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
); 
3930                         else if (itemArray
) { 
3931                                 CFArrayAppendValue(itemArray
, attrsDict
); 
3934                                 *result 
= CFRetain(attrsDict
); 
3936                         CFRelease(attrsDict
); 
3938                 if (tmpStatus 
&& (status 
== errSecSuccess
)) { 
3945                         CFArrayAppendValue(itemArray
, itemDict
); 
3946                         CFRelease(itemDict
); 
3947                         *result 
= itemArray
; 
3953         else if (itemArray
) { 
3954                 *result 
= itemArray
; 
3960 CFDataRef 
_SecItemGetPersistentReference(CFTypeRef raw_item
) 
3963                 Item item 
= ItemImpl::required((SecKeychainItemRef
)raw_item
); 
3964                 return item
->getPersistentRef(); 
3970 /******************************************************************************/ 
3971 #pragma mark SecItem API functions 
3972 /******************************************************************************/ 
3975 // Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error. 
3977 static SInt32 
readNumber(CFTypeRef obj
) { 
3978     CFTypeID tid 
= CFGetTypeID(obj
); 
3980     if (tid 
== CFNumberGetTypeID()) { 
3981         CFNumberGetValue((CFNumberRef
)obj
, kCFNumberSInt32Type
, &v
); 
3983     } else if (tid 
== CFBooleanGetTypeID()) { 
3984         v 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
3986     } else if (tid 
== CFStringGetTypeID()) { 
3987         v 
= CFStringGetIntValue((CFStringRef
)obj
); 
3988         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v
); 
3989         /* If a string converted to an int isn't equal to the int printed as 
3990          a string, return a CFStringRef instead. */ 
3991         if (!CFEqual(t
, obj
)) { 
4002 // Function to check whether the kSecAttrSynchronizable flag is set in the query. 
4004 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
) 
4006         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
4007         Boolean result 
= (value 
&& readNumber(value
)); 
4013 // Function to check whether a synchronizable persistent reference was provided. 
4015 static Boolean 
SecItemIsIOSPersistentReference(CFTypeRef value
) 
4018         return ::_SecItemParsePersistentRef((CFDataRef
)value
, NULL
, NULL
, NULL
); 
4023 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
4026 // Function to find out which keychains are targetted by the query. 
4028 static OSStatus 
SecItemCategorizeQuery(CFDictionaryRef query
, bool &can_target_ios
, bool &can_target_osx
) 
4030         // By default, target both keychain. 
4031         can_target_osx 
= can_target_ios 
= true; 
4033         // Check no-legacy flag. 
4034     CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrNoLegacy
); 
4035         if (value 
!= NULL
) { 
4036                 can_target_ios 
= readNumber(value
) != 0; 
4037                 can_target_osx 
= !can_target_ios
; 
4038                 return errSecSuccess
; 
4041         // Check whether the query contains kSecValueRef and modify can_ flags according to the kind and type of the value. 
4042         value 
= CFDictionaryGetValue(query
, kSecValueRef
); 
4043         if (value 
!= NULL
) { 
4044                 CFTypeID typeID 
= CFGetTypeID(value
); 
4045                 if (typeID 
== SecKeyGetTypeID()) { 
4046                         can_target_osx 
= SecKeyIsCDSAKey((SecKeyRef
)value
); 
4047                         can_target_ios 
= !can_target_osx
; 
4048                 } else if (typeID 
== SecCertificateGetTypeID()) { 
4049                         // All types of certificates can target OSX keychains, but OSX certificates won't work on iOS 
4050                         can_target_ios 
&= !SecCertificateIsItemImplInstance((SecCertificateRef
)value
); 
4051                 } else if (typeID 
== SecKeychainItemGetTypeID()) { 
4052                         // SecKeychainItemRef can target iOS keychain only when it has attached iOS-style persistent reference. 
4053                         if (_SecItemGetPersistentReference(value
) == NULL
) { 
4054                                 can_target_ios 
= false; 
4059         // Check presence of kSecAttrTokenID and kSecAttrAccessControl; they are not defined for CDSA keychain. 
4060         if (CFDictionaryContainsKey(query
, kSecAttrTokenID
) || CFDictionaryContainsKey(query
, kSecAttrAccessControl
)) { 
4061                 can_target_osx 
= false; 
4064         // Check for special token access groups.  If present, redirect query to iOS keychain. 
4065         value 
= CFDictionaryGetValue(query
, kSecAttrAccessGroup
); 
4066         if (value 
!= NULL 
&& CFEqual(value
, kSecAttrAccessGroupToken
)) { 
4067                 can_target_osx 
= false; 
4070         // Synchronizable items should go to iOS keychain only. 
4071         if (SecItemSynchronizable(query
)) { 
4072                 can_target_osx 
= false; 
4075         value 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
4076         if (value 
!= NULL
) { 
4077                 if (SecItemIsIOSPersistentReference(value
)) { 
4078                         can_target_osx 
= false; 
4080                         // Non-iOS-style persistent references should not be fed to iOS keychain queries. 
4081                         can_target_ios 
= false; 
4085         // Presence of following atributes means that query is OSX-only. 
4086         static const CFStringRef 
*osx_only_items
[] = { 
4088                 &kSecMatchSearchList
, 
4089                 &kSecMatchSubjectStartsWith
, 
4090                 &kSecMatchSubjectEndsWith
, 
4091                 &kSecMatchSubjectWholeString
, 
4092                 &kSecMatchDiacriticInsensitive
, 
4093                 &kSecMatchWidthInsensitive
, 
4102         for (CFIndex i 
= 0; i 
< array_size(osx_only_items
); i
++) { 
4103                 can_target_ios 
= can_target_ios 
&& !CFDictionaryContainsKey(query
, *osx_only_items
[i
]); 
4106         return (can_target_ios 
|| can_target_osx
) ? errSecSuccess 
: errSecParam
; 
4110 // Function to check whether the kSecAttrSynchronizable attribute is being updated. 
4112 static Boolean 
SecItemHasSynchronizableUpdate(Boolean synchronizable
, CFDictionaryRef changes
) 
4114         CFTypeRef newValue 
= CFDictionaryGetValue(changes
, kSecAttrSynchronizable
); 
4118         Boolean new_sync 
= readNumber(newValue
); 
4119         Boolean old_sync 
= synchronizable
; 
4121         return (old_sync 
!= new_sync
); 
4125 // Function to apply changes to a mutable dictionary. 
4126 // (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction) 
4128 static void SecItemApplyChanges(const void *key
, const void *value
, void *context
) 
4130         CFMutableDictionaryRef dict 
= (CFMutableDictionaryRef
) context
; 
4133         CFDictionarySetValue(dict
, key
, value
); 
4137 // Function to change matching items from non-syncable to syncable 
4138 // (if toSyncable is true), otherwise from syncable to non-syncable. 
4139 // This currently moves items between keychain containers. 
4141 static OSStatus 
SecItemChangeSynchronizability(CFDictionaryRef query
, CFDictionaryRef changes
, Boolean toSyncable
) 
4143         // Note: the input query dictionary is a mutable copy of the query originally 
4144         // provided by the caller as the first parameter to SecItemUpdate. It may not 
4145         // specify returning attributes or data, but we will need both to make a copy. 
4147         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnRef
); 
4148         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnPersistentRef
); 
4149         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnData
); 
4150         CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4151         if (NULL 
== CFDictionaryGetValue(changes
, kSecValueData
)) 
4152                 CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnData
, kCFBooleanTrue
); 
4157                 status 
= SecItemCopyMatching_osx(query
, &result
); 
4159                 status 
= SecItemCopyMatching_ios(query
, &result
); 
4164                 return errSecItemNotFound
; 
4166         CFMutableArrayRef items
; 
4167         if (CFGetTypeID(result
) != CFArrayGetTypeID()) { 
4168                 items 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4169                 CFArrayAppendValue(items
, result
); 
4173                 items 
= (CFMutableArrayRef
)result
; 
4176         CFIndex idx
, count 
= (items
) ? CFArrayGetCount(items
) : 0; 
4177         int priority 
= LOG_DEBUG
; 
4179         for (idx 
= 0; idx 
< count
; idx
++) { 
4180                 CFDictionaryRef dict 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(items
, idx
); 
4181                 CFMutableDictionaryRef item 
= (CFMutableDictionaryRef
) 
4182                         SecItemCopyTranslatedAttributes(dict
, 
4183                                 CFDictionaryGetValue(query
, kSecClass
), 
4184                                 (toSyncable
) ? true : false /*iOSOut*/, 
4185                                 true /*pruneMatch*/, 
4187                                 true /*pruneReturn*/, 
4188                                 false /*pruneData*/, 
4189                                 (toSyncable
) ? true : false /*pruneAccess*/); 
4190                 // hold onto the query before applying changes, in case the item already exists. 
4191                 // note that we cannot include the creation or modification dates from our 
4192                 // found item in this query, as they may not match the item in the other keychain. 
4193                 CFMutableDictionaryRef itemQuery 
= CFDictionaryCreateMutableCopy(NULL
, 0, item
); 
4194                 CFDictionaryRemoveValue(itemQuery
, kSecAttrCreationDate
); 
4195                 CFDictionaryRemoveValue(itemQuery
, kSecAttrModificationDate
); 
4196                 // apply changes to the item dictionary that we will pass to SecItemAdd 
4197                 CFDictionaryApplyFunction(changes
, SecItemApplyChanges
, item
); 
4199                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4200                         status 
= SecItemAdd_ios(item
, NULL
); 
4201                         secitemlog(priority
, "ChangeSync: SecItemAdd_ios=%d", status
); 
4202                         if (errSecDuplicateItem 
== status
) { 
4203                                 // find and apply changes to the existing syncable item. 
4204                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4205                                 status 
= SecItemUpdate_ios(itemQuery
, changes
); 
4206                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_ios=%d", status
); 
4208                         if (errSecSuccess 
== status
) { 
4209                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4210                                 status 
= SecItemDelete_osx(itemQuery
); 
4211                                 secitemlog(priority
, "ChangeSync: SecItemDelete_osx=%d", status
); 
4215                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4216                         status 
= SecItemAdd_osx(item
, NULL
); 
4217                         secitemlog(priority
, "ChangeSync: SecItemAdd_osx=%d", status
); 
4218                         if (errSecDuplicateItem 
== status
) { 
4219                                 // find and apply changes to the existing non-syncable item. 
4220                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4221                                 status 
= SecItemUpdate_osx(itemQuery
, changes
); 
4222                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_osx=%d", status
); 
4224                         if (errSecSuccess 
== status
) { 
4225                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4226                                 status 
= SecItemDelete_ios(itemQuery
); 
4227                                 secitemlog(priority
, "ChangeSync: SecItemDelete_ios=%d", status
); 
4230                 CFReleaseSafe(item
); 
4231                 CFReleaseSafe(itemQuery
); 
4235         CFReleaseSafe(items
); 
4244 SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
) { 
4245         CFTypeRef ref 
= NULL
; 
4246         CFStringRef item_class_string 
= (CFStringRef
)CFDictionaryGetValue(refAttributes
, kSecClass
); 
4247         SecItemClass item_class 
= (SecItemClass
) 0; 
4249         if (CFEqual(item_class_string
, kSecClassGenericPassword
)) { 
4250                 item_class 
= kSecGenericPasswordItemClass
; 
4251         } else if (CFEqual(item_class_string
, kSecClassInternetPassword
)) { 
4252                 item_class 
= kSecInternetPasswordItemClass
; 
4255         if (item_class 
!= 0) { 
4256                 // we carry v_Data around here so the *_ios calls can find it and locate 
4257                 // their own data.   Putting things in the attribute list doesn't help as 
4258                 // the osx keychainitem and item calls bail when they don't see a keychain 
4259                 // object.   If we need to make them work we either have to bridge them, or 
4260                 // find a way to craft a workable keychain object.   #if'ed code left below 
4261                 // in case we need to go down that path. 
4263     SecKeychainAttributeList attrs 
= {}; 
4264     SecKeychainAttribute attr 
= {}; 
4270     Item item 
= Item(item_class
, &attrs
, 0, ""); 
4271                 v 
= CFDictionaryGetValue(refAttributes
, kSecValuePersistentRef
); 
4273                         item
->setPersistentRef((CFDataRef
)v
); 
4275                 ref 
= item
->handle(); 
4282  * SecItemValidateAppleApplicationGroupAccess determines if the caller 
4283  * is a member of the specified application group, and is signed by Apple. 
4286 SecItemValidateAppleApplicationGroupAccess(CFStringRef group
) 
4288         SecTrustedApplicationRef app 
= NULL
; 
4289         SecRequirementRef requirement 
= NULL
; 
4290         SecCodeRef code 
= NULL
; 
4291         OSStatus status 
= errSecParam
; 
4294                 CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(group
), kCFStringEncodingUTF8
) + 1; 
4295                 char* buffer 
= (char*) malloc(length
); 
4297                         if (CFStringGetCString(group
, buffer
, length
, kCFStringEncodingUTF8
)) { 
4298                                 status 
= SecTrustedApplicationCreateApplicationGroup(buffer
, NULL
, &app
); 
4302                         status 
= errSecMemoryError
; 
4306                 status 
= SecTrustedApplicationCopyRequirement(app
, &requirement
); 
4309                 status 
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
); 
4312                 status 
= SecCodeCheckValidity(code
, kSecCSDefaultFlags
, requirement
); 
4315         CFReleaseSafe(code
); 
4316         CFReleaseSafe(requirement
); 
4321 static Mutex gParentCertCacheLock
; 
4322 static CFMutableDictionaryRef gParentCertCache
; 
4323 static CFMutableArrayRef gParentCertCacheList
; 
4324 #define PARENT_CACHE_SIZE 100 
4326 void SecItemParentCachePurge() { 
4327     StLock
<Mutex
> _(gParentCertCacheLock
); 
4328     CFReleaseNull(gParentCertCache
); 
4329     CFReleaseNull(gParentCertCacheList
); 
4332 static CFArrayRef CF_RETURNS_RETAINED 
parentCacheRead(SecCertificateRef certificate
) { 
4333     CFArrayRef parents 
= NULL
; 
4335     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4336     if (!digest
) return NULL
; 
4338     StLock
<Mutex
> _(gParentCertCacheLock
); 
4339     if (gParentCertCache 
&& gParentCertCacheList
) { 
4340         if (0 <= (ix 
= CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4341                                                    CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4343             // Cache hit. Get value and move entry to the top of the list. 
4344             parents 
= (CFArrayRef
)CFDictionaryGetValue(gParentCertCache
, digest
); 
4345             CFArrayRemoveValueAtIndex(gParentCertCacheList
, ix
); 
4346             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4349     CFRetainSafe(parents
); 
4353 static void parentCacheWrite(SecCertificateRef certificate
, CFArrayRef parents
) { 
4354     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4355     if (!digest
) return; 
4357     StLock
<Mutex
> _(gParentCertCacheLock
); 
4358     if (!gParentCertCache 
|| !gParentCertCacheList
) { 
4359         CFReleaseNull(gParentCertCache
); 
4360         gParentCertCache 
= makeCFMutableDictionary(); 
4361         CFReleaseNull(gParentCertCacheList
); 
4362         gParentCertCacheList 
= makeCFMutableArray(0); 
4365     if (gParentCertCache 
&& gParentCertCacheList
) { 
4366         // check to make sure another thread didn't add this entry to the cache already 
4367         if (0 > CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4368                                             CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4370             CFDictionaryAddValue(gParentCertCache
, digest
, parents
); 
4371             if (PARENT_CACHE_SIZE 
<= CFArrayGetCount(gParentCertCacheList
)) { 
4372                 // Remove least recently used cache entry. 
4373                 CFArrayRemoveValueAtIndex(gParentCertCacheList
, 0); 
4375             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4381  * SecItemCopyParentCertificates_osx returns an array of zero of more possible 
4382  * issuer certificates for the provided certificate. No cryptographic validation 
4383  * of the signature is performed in this function; its purpose is only to 
4384  * provide a list of candidate certificates. 
4387 SecItemCopyParentCertificates_osx(SecCertificateRef certificate
, void *context
) 
4389 #pragma unused (context) /* for now; in future this can reference a container object */ 
4390         /* Check for parents in keychain cache */ 
4391         CFArrayRef parents 
= parentCacheRead(certificate
); 
4396         /* Cache miss. Query for parents. */ 
4397 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
4398         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4400         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4401         CFRetainSafe(normalizedIssuer
); 
4404         CFMutableArrayRef combinedSearchList 
= NULL
; 
4406         /* Define the array of keychains which will be searched for parents. */ 
4407         CFArrayRef searchList 
= NULL
; 
4408         status 
= SecKeychainCopySearchList(&searchList
); 
4410                 combinedSearchList 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, searchList
); 
4411                 CFRelease(searchList
); 
4413                 combinedSearchList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4415         SecKeychainRef rootStoreKeychain 
= NULL
; 
4416         status 
= SecKeychainOpen(SYSTEM_ROOT_STORE_PATH
, &rootStoreKeychain
); 
4417         if (rootStoreKeychain
) { 
4418                 if (combinedSearchList
) { 
4419                         CFArrayAppendValue(combinedSearchList
, rootStoreKeychain
); 
4421                 CFRelease(rootStoreKeychain
); 
4424         /* Create and populate a fixed-size query dictionary. */ 
4425         CFMutableDictionaryRef query 
= CFDictionaryCreateMutable(NULL
, 5, 
4426                         &kCFTypeDictionaryKeyCallBacks
, 
4427                         &kCFTypeDictionaryValueCallBacks
); 
4428         CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
4429         CFDictionaryAddValue(query
, kSecReturnData
, kCFBooleanTrue
); 
4430         CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4431         if (combinedSearchList
) { 
4432                 CFDictionaryAddValue(query
, kSecMatchSearchList
, combinedSearchList
); 
4433                 CFRelease(combinedSearchList
); 
4436         CFTypeRef results 
= NULL
; 
4437         if (normalizedIssuer
) { 
4438                 /* Look up certs whose subject is the same as this cert's issuer. */ 
4439                 CFDictionaryAddValue(query
, kSecAttrSubject
, normalizedIssuer
); 
4440                 status 
= SecItemCopyMatching_osx(query
, &results
); 
4443                 /* Cannot match anything without an issuer! */ 
4444                 status 
= errSecItemNotFound
; 
4447         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4448                 secitemlog(LOG_WARNING
, "SecItemCopyParentCertificates_osx: %d", (int)status
); 
4452         CFMutableArrayRef result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4453         CFTypeID resultType 
= (results
) ? CFGetTypeID(results
) : 0; 
4454         if (resultType 
== CFArrayGetTypeID()) { 
4455                 CFIndex index
, count 
= CFArrayGetCount((CFArrayRef
)results
); 
4456                 for (index 
= 0; index 
< count
; index
++) { 
4457                         CFDataRef data 
= (CFDataRef
) CFArrayGetValueAtIndex((CFArrayRef
)results
, index
); 
4459                                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
4461                                         CFArrayAppendValue(result
, cert
); 
4466         } else if (results 
&& resultType 
== CFDataGetTypeID()) { 
4467                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)results
); 
4469                         CFArrayAppendValue(result
, cert
); 
4473         CFReleaseSafe(results
); 
4474         CFReleaseSafe(normalizedIssuer
); 
4477         parentCacheWrite(certificate
, result
); 
4482 SecCertificateRef 
SecItemCopyStoredCertificate(SecCertificateRef certificate
, void *context
) 
4484 #pragma unused (context) /* for now; in future this can reference a container object */ 
4486         /* Certificates are unique by issuer and serial number. */ 
4487 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
4488         CFDataRef serialNumber 
= SecCertificateCopySerialNumber(certificate
, NULL
); 
4489         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4491         CFDataRef serialNumber 
= SecCertificateCopySerialNumber(certificate
); 
4492         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4493         CFRetainSafe(normalizedIssuer
); 
4496         const void *keys
[] = { 
4500                 kSecAttrSerialNumber
, 
4504                 kSecClassCertificate
, 
4510         CFDictionaryRef query 
= CFDictionaryCreate(NULL
, keys
, values
, 5,       NULL
, NULL
); 
4511         CFTypeRef result 
= NULL
; 
4513         OSStatus status 
= SecItemCopyMatching_osx(query
, &result
); 
4514         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4515                 secitemlog(LOG_WARNING
, "SecItemCopyStoredCertificate: %d", (int)status
); 
4516                 CFReleaseNull(result
); 
4518         CFReleaseSafe(query
); 
4519         CFReleaseSafe(serialNumber
); 
4520         CFReleaseSafe(normalizedIssuer
); 
4522         return (SecCertificateRef
)result
; 
4526  * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary 
4527  * and attempts to return a sanitized copy for passing to the underlying 
4528  * platform-specific implementation code. 
4530  * If iOSOut is true, one or more translations may apply: 
4531  *   - SecKeychain refs are removed, since there aren't multiple keychains 
4532  *   - SecPolicy refs are removed, since they can't be externalized 
4533  *   - SecAccess refs are removed, and potentially translated to entitlements 
4535  * If pruneMatch is true, kSecMatch* attributes are removed; this avoids 
4536  * parameter errors due to strict input checks in secd, which only permits 
4537  * these constants for calls to SecItemCopyMatching. 
4539  * If pruneSync is true, the kSecAttrSynchronizable attribute is removed. 
4540  * This permits a query to be reused for non-synchronizable items, or to 
4541  * resolve a search based on a persistent item reference for iOS. 
4543  * If pruneReturn is true, kSecReturn* attributes are removed; this avoids 
4544  * parameter errors due to strict input checks in secd, which do not permit 
4545  * these constants for calls to SecItemUpdate. 
4548 SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
4549         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
) 
4551         CFMutableDictionaryRef result 
= CFDictionaryCreateMutableCopy(NULL
, 0, inOSXDict
); 
4552         if (result 
== NULL
) { 
4557                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4561                 /* Match constants are only supported on iOS for SecItemCopyMatching, 
4562                  * and will generate an error if passed to other SecItem API functions; 
4563                  * on OS X, they're just ignored if not applicable for the context. 
4565                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4566                 CFDictionaryRemoveValue(result
, kSecMatchItemList
); 
4567                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4568                 CFDictionaryRemoveValue(result
, kSecMatchIssuers
); 
4569                 CFDictionaryRemoveValue(result
, kSecMatchEmailAddressIfPresent
); 
4570                 CFDictionaryRemoveValue(result
, kSecMatchSubjectContains
); 
4571                 CFDictionaryRemoveValue(result
, kSecMatchCaseInsensitive
); 
4572                 CFDictionaryRemoveValue(result
, kSecMatchTrustedOnly
); 
4573                 CFDictionaryRemoveValue(result
, kSecMatchValidOnDate
); 
4574                 CFDictionaryRemoveValue(result
, kSecMatchLimit
); 
4575                 CFDictionaryRemoveValue(result
, kSecMatchLimitOne
); 
4576                 CFDictionaryRemoveValue(result
, kSecMatchLimitAll
); 
4580                 /* Return constants are not supported on iOS for SecItemUpdate, 
4581                  * where they will generate an error; on OS X, they're just ignored 
4582                  * if not applicable for the context. 
4584                 CFDictionaryRemoveValue(result
, kSecReturnData
); 
4585                 CFDictionaryRemoveValue(result
, kSecReturnAttributes
); 
4586                 CFDictionaryRemoveValue(result
, kSecReturnRef
); 
4587                 CFDictionaryRemoveValue(result
, kSecReturnPersistentRef
); 
4591                 /* Searching on data is not supported. */ 
4592                 CFDictionaryRemoveValue(result
, kSecValueData
); 
4596         /* Searching on access lists is not supported */ 
4597         CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4601                 /* Remove kSecMatchSearchList (value is array of SecKeychainRef); 
4602                  * cannot specify a keychain search list on iOS 
4604                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4606                 /* Remove kSecUseKeychain (value is a SecKeychainRef); 
4607                  * cannot specify a keychain on iOS 
4609                 CFDictionaryRemoveValue(result
, kSecUseKeychain
); 
4611                 /* Potentially translate kSecAttrAccess (value is a SecAccessRef), 
4612                  * unless kSecAttrAccessGroup has already been specified. 
4614                 SecAccessRef access 
= (SecAccessRef
) CFDictionaryGetValue(result
, kSecAttrAccess
); 
4615                 CFStringRef accessGroup 
= (CFStringRef
) CFDictionaryGetValue(result
, kSecAttrAccessGroup
); 
4616                 if (access 
!= NULL 
&& accessGroup 
== NULL
) { 
4617                         /* Translate "InternetAccounts" application group to an access group */ 
4618                         if (errSecSuccess 
== SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) { 
4619                                 /* The caller is a valid member of the application group. */ 
4620                                 CFStringRef groupName 
= CFSTR("appleaccount"); 
4621                                 CFTypeRef value 
= CFDictionaryGetValue(result
, kSecAttrAuthenticationType
); 
4622                                 if (value 
&& CFEqual(value
, kSecAttrAuthenticationTypeHTMLForm
)) { 
4623                                         groupName 
= CFSTR("com.apple.cfnetwork"); 
4625                                 CFDictionarySetValue(result
, kSecAttrAccessGroup
, groupName
); 
4628                 CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4630                 /* If item is specified by direct reference, and this is an iOS search, 
4631                  * replace it with a persistent reference, if it was recorded inside ItemImpl. 
4633                 CFTypeRef directRef 
= CFDictionaryGetValue(result
, kSecValueRef
); 
4634                 if (directRef 
!= NULL
) { 
4635                         CFTypeID typeID 
= CFGetTypeID(directRef
); 
4636                         if ((typeID 
!= SecKeyGetTypeID() || SecKeyIsCDSAKey((SecKeyRef
)directRef
)) && 
4637                                 (typeID 
!= SecCertificateGetTypeID() || SecCertificateIsItemImplInstance((SecCertificateRef
)directRef
)) && 
4638                                 (typeID 
!= SecIdentityGetTypeID())) { 
4639                                 CFDataRef persistentRef 
= _SecItemGetPersistentReference(directRef
); 
4640                                 if (persistentRef
) { 
4641                                         CFDictionarySetValue(result
, kSecValuePersistentRef
, persistentRef
); 
4642                                         CFDictionaryRemoveValue(result
, kSecValueRef
); 
4647                 /* If item is specified by persistent reference, and this is an iOS search, 
4648                  * remove the synchronizable attribute as it will be rejected by secd. 
4650                 CFTypeRef persistentRef 
= CFDictionaryGetValue(result
, kSecValuePersistentRef
); 
4651                 if (persistentRef
) { 
4652                         CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4655                 /* Remove kSecAttrModificationDate; this should never be used as criteria 
4656                  * for a search, or to add/modify an item. (If we are cloning an item 
4657                  * and want to keep its modification date, we don't call this function.) 
4658                  * It turns out that some clients are using the full attributes dictionary 
4659                  * returned by SecItemCopyMatching as a query to find the same item later, 
4660                  * which won't work once the item is updated. 
4662                 CFDictionaryRemoveValue(result
, kSecAttrModificationDate
); 
4665                 /* iOS doesn't add the class attribute, so we must do it here. */ 
4667                         CFDictionarySetValue(result
, kSecClass
, itemClass
); 
4669                 /* Remove attributes which are not part of the OS X database schema. */ 
4670                 CFDictionaryRemoveValue(result
, kSecAttrAccessible
); 
4671                 CFDictionaryRemoveValue(result
, kSecAttrAccessControl
); 
4672                 CFDictionaryRemoveValue(result
, kSecAttrAccessGroup
); 
4673                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4674                 CFDictionaryRemoveValue(result
, kSecAttrTombstone
); 
4677     /* This attribute is consumed by the bridge itself. */ 
4678     CFDictionaryRemoveValue(result
, kSecAttrNoLegacy
); 
4686 SecItemMergeResults(bool can_target_ios
, OSStatus status_ios
, CFTypeRef result_ios
, 
4687                                         bool can_target_osx
, OSStatus status_osx
, CFTypeRef result_osx
, 
4688                                         CFTypeRef 
*result
) { 
4689         // When querying both keychains and iOS keychain fails because of missing 
4690         // entitlements, completely ignore iOS keychain result.  This is to keep 
4691         // backward compatibility with applications which know nothing about iOS keychain 
4692         // and use SecItem API to access OSX keychain which does not need any entitlements. 
4693         if (can_target_osx 
&& can_target_ios 
&& status_ios 
== errSecMissingEntitlement
) { 
4694                 can_target_ios 
= false; 
4697         if (can_target_osx 
&& can_target_ios
) { 
4698                 // If both keychains were targetted, examine returning statuses and decide what to do. 
4699                 if (status_ios 
!= errSecSuccess
) { 
4700                         // iOS keychain failed to produce results because of some error, go with results from OSX keychain. 
4701             // Since iOS keychain queries will fail without a keychain-access-group or proper entitlements, SecItemCopyMatching 
4702             // calls against the OSX keychain API that should return errSecItemNotFound will return nonsense from the iOS keychain. 
4703                         AssignOrReleaseResult(result_osx
, result
); 
4705                 } else if (status_osx 
!= errSecSuccess
) { 
4706                         if (status_osx 
!= errSecItemNotFound
) { 
4707                                 // OSX failed to produce results with some failure mode (else than not_found), but iOS produced results. 
4708                                 // We have to either return OSX failure result and discard iOS results, or vice versa.  For now, we just 
4709                                 // ignore OSX error and return just iOS results. 
4710                                 secitemlog(LOG_NOTICE
, "SecItemMergeResults: osx_result=%d, ignoring it, iOS succeeded fine", status_osx
); 
4713                         // OSX failed to produce results, but we have success from iOS keychain; go with results from iOS keychain. 
4714                         AssignOrReleaseResult(result_ios
, result
); 
4715                         return errSecSuccess
; 
4717                         // Both searches succeeded, merge results. 
4718                         if (result 
!= NULL
) { 
4719                                 CFTypeID id_osx 
= (result_osx
) ? CFGetTypeID(result_osx
) : 0; 
4720                                 CFTypeID id_ios 
= (result_ios
) ? CFGetTypeID(result_ios
) : 0; 
4721                                 CFTypeID id_array 
= CFArrayGetTypeID(); 
4722                                 if ((id_osx 
== id_array
) && (id_ios 
== id_array
)) { 
4723                                         // Fold the arrays into one. 
4724                                         *result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4725                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_ios
, 
4726                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_ios
))); 
4727                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_osx
, 
4728                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_osx
))); 
4730                                         // Result type is not an array, so only one match can be returned. 
4731                                         *result 
= (id_ios
) ? result_ios 
: result_osx
; 
4732                                         CFRetainSafe(*result
); 
4735                         CFReleaseSafe(result_osx
); 
4736                         CFReleaseSafe(result_ios
); 
4737                         return errSecSuccess
; 
4739         } else if (can_target_ios
) { 
4740                 // Only iOS keychain was targetted. 
4741                 AssignOrReleaseResult(result_ios
, result
); 
4743         } else if (can_target_osx
) { 
4744                 // Only OSX keychain was targetted. 
4745                 AssignOrReleaseResult(result_osx
, result
); 
4748                 // Query could not run at all? 
4754 ShouldTryUnlockKeybag(CFDictionaryRef query
, OSErr status
) 
4756     static __typeof(SASSessionStateForUser
) *soft_SASSessionStateForUser 
= NULL
; 
4757         static dispatch_once_t onceToken
; 
4758         static void *framework
; 
4760         if (status 
!= errSecInteractionNotAllowed
) 
4763     // If the query disabled authUI, respect it. 
4764     CFTypeRef authUI 
= NULL
; 
4766         authUI 
= CFDictionaryGetValue(query
, kSecUseAuthenticationUI
); 
4767         if (authUI 
== NULL
) { 
4768             authUI 
= CFDictionaryGetValue(query
, kSecUseNoAuthenticationUI
); 
4769             authUI 
= (authUI 
!= NULL 
&& CFEqual(authUI
, kCFBooleanTrue
)) ? kSecUseAuthenticationUIFail 
: NULL
; 
4772     if (authUI 
&& !CFEqual(authUI
, kSecUseAuthenticationUIAllow
)) 
4775     dispatch_once(&onceToken
, ^{ 
4776                 framework 
= dlopen("/System/Library/PrivateFrameworks/login.framework/login", RTLD_LAZY
); 
4777                 if (framework 
== NULL
) 
4779                 soft_SASSessionStateForUser 
= (__typeof(soft_SASSessionStateForUser
)) dlsym(framework
, "SASSessionStateForUser"); 
4782     if (soft_SASSessionStateForUser 
== NULL
) 
4785     SessionAgentState sessionState 
= soft_SASSessionStateForUser(getuid()); 
4786     if(sessionState 
!= kSA_state_desktopshowing
) 
4793 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef 
*result
) 
4795     os_activity_t activity 
= os_activity_create("SecItemCopyMatching", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4796     os_activity_scope(activity
); 
4797     os_release(activity
); 
4802         secitemshow(query
, "SecItemCopyMatching query:"); 
4804         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4805         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4806         bool can_target_ios
, can_target_osx
; 
4807         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
); 
4808         if (status 
!= errSecSuccess
) { 
4812         if (can_target_ios
) { 
4813                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4814                         CFDictionaryGetValue(query
, kSecClass
), true, false, false, false, true, true); 
4816                         status_ios 
= errSecParam
; 
4819                         status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4820             if(ShouldTryUnlockKeybag(query
, status_ios
)) { 
4821                 // The keybag is locked. Attempt to unlock it... 
4822                                 secitemlog(LOG_WARNING
, "SecItemCopyMatching triggering SecurityAgent"); 
4823                 if(errSecSuccess 
== SecKeychainVerifyKeyStorePassphrase(1)) { 
4824                     CFReleaseNull(result_ios
); 
4825                     status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4828                         CFRelease(attrs_ios
); 
4830                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_ios result: %d", status_ios
); 
4833         if (can_target_osx
) { 
4834                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4835                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, false, true, true); 
4837                         status_osx 
= errSecParam
; 
4840                         status_osx 
= SecItemCopyMatching_osx(attrs_osx
, &result_osx
); 
4841                         CFRelease(attrs_osx
); 
4843                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_osx result: %d", status_osx
); 
4846         status 
= SecItemMergeResults(can_target_ios
, status_ios
, result_ios
, 
4847                                                                  can_target_osx
, status_osx
, result_osx
, result
); 
4848         secitemlog(LOG_NOTICE
, "SecItemCopyMatching result: %d", status
); 
4853 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
4855     os_activity_t activity 
= os_activity_create("SecItemAdd", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4856     os_activity_scope(activity
); 
4857     os_release(activity
); 
4865         secitemshow(attributes
, "SecItemAdd attrs:"); 
4867         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4868         bool can_target_ios
, can_target_osx
; 
4869         OSStatus status 
= SecItemCategorizeQuery(attributes
, can_target_ios
, can_target_osx
); 
4870         if (status 
!= errSecSuccess
) { 
4874         // SecItemAdd cannot be really done on both keychains.  In order to keep backward compatibility 
4875         // with existing applications, we prefer to add items into legacy keychain and fallback 
4876         // into iOS (modern) keychain only when the query is not suitable for legacy keychain. 
4877         if (!can_target_osx
) { 
4878                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(attributes
, 
4879                         NULL
, true, true, false, false, false, false); 
4881                         status 
= errSecParam
; 
4883             status 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4884             if(ShouldTryUnlockKeybag(attributes
, status
)) { 
4885                 // The keybag is locked. Attempt to unlock it... 
4886                                 secitemlog(LOG_WARNING
, "SecItemAdd triggering SecurityAgent"); 
4887                 if(errSecSuccess 
== SecKeychainVerifyKeyStorePassphrase(3)) { 
4888                     CFReleaseNull(result_ios
); 
4889                     status 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4892                         CFRelease(attrs_ios
); 
4894                 secitemlog(LOG_NOTICE
, "SecItemAdd_ios result: %d", status
); 
4895                 AssignOrReleaseResult(result_ios
, result
); 
4898                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(attributes
, 
4899                     NULL
, false, false, true, false, false, false); 
4901                         status 
= errSecParam
; 
4903                         status 
= SecItemAdd_osx(attrs_osx
, &result_osx
); 
4904                         CFRelease(attrs_osx
); 
4906                 secitemlog(LOG_NOTICE
, "SecItemAdd_osx result: %d", status
); 
4907                 AssignOrReleaseResult(result_osx
, result
); 
4913 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
4915     os_activity_t activity 
= os_activity_create("SecItemUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4916     os_activity_scope(activity
); 
4917     os_release(activity
); 
4919         if (!query 
|| !attributesToUpdate
) { 
4922         secitemshow(query
, "SecItemUpdate query:"); 
4923         secitemshow(attributesToUpdate
, "SecItemUpdate attrs:"); 
4925         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4926         bool can_target_ios
, can_target_osx
; 
4927         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
); 
4928         if (status 
!= errSecSuccess
) { 
4932         if (can_target_ios
) { 
4933                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4934                         CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4936                         status_ios 
= errSecParam
; 
4939             if (SecItemHasSynchronizableUpdate(true, attributesToUpdate
)) { 
4940                 status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
4941                 if(ShouldTryUnlockKeybag(query
, status_ios
)) { 
4942                     // The keybag is locked. Attempt to unlock it... 
4943                                         secitemlog(LOG_WARNING
, "SecItemUpdate triggering SecurityAgent"); 
4944                     if(errSecSuccess 
== SecKeychainVerifyKeyStorePassphrase(1)) { 
4945                         status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
4949                 status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4950                 if(ShouldTryUnlockKeybag(query
, status_ios
)) { 
4951                     // The keybag is locked. Attempt to unlock it... 
4952                                         secitemlog(LOG_WARNING
, "SecItemUpdate triggering SecurityAgent"); 
4953                     if(errSecSuccess 
== SecKeychainVerifyKeyStorePassphrase(1)) { 
4954                         status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4958                         CFRelease(attrs_ios
); 
4960                 secitemlog(LOG_NOTICE
, "SecItemUpdate_ios result: %d", status_ios
); 
4963         if (can_target_osx
) { 
4964                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4965                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, true, true, true); 
4967                         status_osx 
= errSecParam
; 
4970                         if (SecItemHasSynchronizableUpdate(false, attributesToUpdate
)) 
4971                                 status_osx 
= SecItemChangeSynchronizability(attrs_osx
, attributesToUpdate
, true); 
4973                                 status_osx 
= SecItemUpdate_osx(attrs_osx
, attributesToUpdate
); 
4975                         CFRelease(attrs_osx
); 
4977                 secitemlog(LOG_NOTICE
, "SecItemUpdate_osx result: %d", status_osx
); 
4980         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
4981                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
4982         secitemlog(LOG_NOTICE
, "SecItemUpdate result: %d", status
); 
4987 SecItemDelete(CFDictionaryRef query
) 
4989     os_activity_t activity 
= os_activity_create("SecItemDelete", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4990     os_activity_scope(activity
); 
4991     os_release(activity
); 
4996         secitemshow(query
, "SecItemDelete query:"); 
4998         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4999         bool can_target_ios
, can_target_osx
; 
5000         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
); 
5001         if (status 
!= errSecSuccess
) { 
5005         if (can_target_ios
) { 
5006                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
5007                         NULL
, true, true, false, true, true, true); 
5009                         status_ios 
= errSecParam
; 
5011             status_ios 
= SecItemDelete_ios(attrs_ios
); 
5012                         CFRelease(attrs_ios
); 
5014                 secitemlog(LOG_NOTICE
, "SecItemDelete_ios result: %d", status_ios
); 
5017         if (can_target_osx
) { 
5018                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
5019                     NULL
, false, false, true, true, true, true); 
5021                         status_osx 
= errSecParam
; 
5023                         status_osx 
= SecItemDelete_osx(attrs_osx
); 
5024                         CFRelease(attrs_osx
); 
5026                 secitemlog(LOG_NOTICE
, "SecItemDelete_osx result: %d", status_osx
); 
5029         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
5030                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
5031         secitemlog(LOG_NOTICE
, "SecItemCopyDelete result: %d", status
); 
5036 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
) 
5038         OSStatus status 
= SecItemUpdateTokenItems_ios(tokenID
, tokenItemsAttributes
); 
5039     if(ShouldTryUnlockKeybag(NULL
, status
)) { 
5040         // The keybag is locked. Attempt to unlock it... 
5041         if(errSecSuccess 
== SecKeychainVerifyKeyStorePassphrase(1)) { 
5042                         secitemlog(LOG_WARNING
, "SecItemUpdateTokenItems triggering SecurityAgent"); 
5043             status 
= SecItemUpdateTokenItems_ios(tokenID
, tokenItemsAttributes
); 
5046         secitemlog(LOG_NOTICE
, "SecItemUpdateTokenItems_ios result: %d", status
); 
5051 SecItemCopyMatching_osx( 
5052         CFDictionaryRef query
, 
5055         if (!query 
|| !result
) 
5060         CFAllocatorRef allocator 
= CFGetAllocator(query
); 
5061         CFIndex matchCount 
= 0; 
5062         CFMutableArrayRef itemArray 
= NULL
; 
5063         SecKeychainItemRef item 
= NULL
; 
5064         SecIdentityRef identity 
= NULL
; 
5065         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5067         // validate input query parameters and create the search reference 
5068         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(query
, &status
); 
5069         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5071         // find the next match until we hit maxMatches, or no more matches found 
5072         while ( !(!itemParams
->returnAllMatches 
&& matchCount 
>= itemParams
->maxMatches
) && 
5073                         SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == errSecSuccess
) { 
5075                 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
)) 
5076                         continue; // move on to next item 
5078                 ++matchCount
; // we have a match 
5080                 tmpStatus 
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
); 
5081                 if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5089                         CFRelease(identity
); 
5094         if (status 
== errSecSuccess
) 
5095                 status 
= (matchCount 
> 0) ? errSecSuccess 
: errSecItemNotFound
; 
5098         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5102         _FreeSecItemParams(itemParams
); 
5108 SecItemCopyDisplayNames( 
5110         CFArrayRef 
*displayNames
) 
5114         Required(displayNames
); 
5116     return errSecUnimplemented
; 
5122         CFDictionaryRef attributes
, 
5130         CFAllocatorRef allocator 
= CFGetAllocator(attributes
); 
5131         CFMutableArrayRef itemArray 
= NULL
; 
5132         SecKeychainItemRef item 
= NULL
; 
5133         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5135         // validate input attribute parameters 
5136         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(attributes
, &status
); 
5137         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5139         // currently, we don't support adding SecIdentityRef items (an aggregate item class), 
5140         // since the private key should already be in a keychain by definition. We could support 
5141         // this as a copy operation for the private key if a different keychain is specified, 
5142         // but in any case it should try to add the certificate. See <rdar://8317887>. 
5143         require_action(!itemParams
->returnIdentity
, error_exit
, status 
= errSecItemInvalidValue
); 
5145         if (itemParams
->useItems 
== NULL
) { 
5147                 require_action(itemParams
->itemData 
== NULL 
|| CFGetTypeID(itemParams
->itemData
) == CFDataGetTypeID(), 
5148                                            error_exit
, status 
= errSecItemInvalidValue
); 
5150                 // create a single keychain item specified by the input attributes 
5151                 status 
= SecKeychainItemCreateFromContent(itemParams
->itemClass
, 
5152                         itemParams
->attrList
, 
5153                         (itemParams
->itemData
) ? (UInt32
)CFDataGetLength(itemParams
->itemData
) : 0, 
5154                         (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
, 
5155                         itemParams
->keychain
, 
5158                 require_noerr(status
, error_exit
); 
5160                 // return results (if requested) 
5162                         itemParams
->maxMatches 
= 1; // in case kSecMatchLimit was set to > 1 
5163                         tmpStatus 
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5164                         if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5170                 // add multiple items which are specified in the itemParams->useItems array. 
5171                 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain. 
5172                 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain. 
5173                 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain. 
5175                 OSStatus aggregateStatus 
= errSecSuccess
; 
5176                 CFIndex ix
, count 
= CFArrayGetCount(itemParams
->useItems
); 
5177                 itemParams
->maxMatches 
= (count 
> 1) ? (int)count 
: 2; // force results to always be returned as an array 
5178                 for (ix
=0; ix 
< count
; ix
++) { 
5179                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
); 
5181                                 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) { 
5182                                         // SecCertificateRef item 
5183                                         tmpStatus 
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
); 
5184                                         if (!tmpStatus 
&& result
) { 
5185                                                 tmpStatus 
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5187                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5189                                 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) { 
5191                                         SecKeychainRef itemKeychain 
= NULL
; 
5192                                         tmpStatus 
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
); 
5193                                         if (tmpStatus 
== errSecSuccess
) { 
5194                                                 // key was in a keychain, so we can attempt to copy it 
5195                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5196                                                 tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5197                                                 if (!tmpStatus 
&& result
) { 
5198                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5201                                                         CFRelease(itemCopy
); 
5205                                                 // key was not in any keychain, so must be imported 
5206                                                 SecKeychainItemRef keyItem 
= NULL
; 
5207                                                 tmpStatus 
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
); 
5208                                                 if (!tmpStatus 
&& result
) { 
5209                                                         tmpStatus 
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5216                                                 CFRelease(itemKeychain
); 
5218                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5220                                 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) { 
5221                                         // SecKeychainItemRef item 
5222                                         SecKeychainItemRef itemCopy 
= NULL
; 
5223                                         tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5224                                         if (!tmpStatus 
&& result
) { 
5225                                                 tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5228                                                 CFRelease(itemCopy
); 
5230                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5232                                 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) { 
5233                                         // CFDataRef item (persistent reference) 
5234                                         SecKeychainItemRef realItem 
= NULL
; 
5235                                         tmpStatus 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
); 
5236                                         if (tmpStatus 
== errSecSuccess
) { 
5237                                                 // persistent reference resolved to a keychain item, so we can attempt to copy it 
5238                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5239                                                 tmpStatus 
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5240                                                 if (!tmpStatus 
&& result
) { 
5241                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5244                                                         CFRelease(itemCopy
); 
5248                                                 CFRelease(realItem
); 
5250                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5253                 } // end of itemList array loop 
5254                 status 
= aggregateStatus
; 
5255         } // end processing multiple items 
5258         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5262         _FreeSecItemParams(itemParams
); 
5269         CFDictionaryRef query
, 
5270         CFDictionaryRef attributesToUpdate
) 
5272         if (!query 
|| !attributesToUpdate
) 
5275         // run the provided query to get a list of items to update 
5276         CFTypeRef results 
= NULL
; 
5277         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5278         if (status 
!= errSecSuccess
) 
5279                 return status
; // nothing was matched, or the query was bad 
5281         CFArrayRef items 
= NULL
; 
5282         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5283                 items 
= (CFArrayRef
) results
; 
5286                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5290         OSStatus result 
= errSecSuccess
; 
5291         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5292         for (ix
=0; ix 
< count
; ix
++) { 
5293                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5295                         status 
= _UpdateKeychainItem(anItem
, attributesToUpdate
); 
5296                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
); 
5308         CFDictionaryRef query
) 
5313         // run the provided query to get a list of items to delete 
5314         CFTypeRef results 
= NULL
; 
5315         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5316         if (status 
!= errSecSuccess
) 
5317                 return status
; // nothing was matched, or the query was bad 
5319         CFArrayRef items 
= NULL
; 
5320         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5321                 items 
= (CFArrayRef
) results
; 
5324                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5328         OSStatus result 
= errSecSuccess
; 
5329         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5330         for (ix
=0; ix 
< count
; ix
++) { 
5331                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5333                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) { 
5334                                 status 
= _DeleteIdentity((SecIdentityRef
)anItem
); 
5337                                 status 
= _DeleteKeychainItem(anItem
); 
5339                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
);