2  * Copyright (c) 2006-2019 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 #include "SecBridge.h" 
  25 #include <Security/SecInternal.h> 
  26 #include <CoreFoundation/CoreFoundation.h> 
  27 #include <security_utilities/cfutilities.h> 
  28 #include <Security/SecBase.h> 
  29 #include <Security/SecKeychainItem.h> 
  30 #include <Security/SecCertificate.h> 
  31 #include <Security/SecCertificatePriv.h> 
  32 #include <sys/param.h> 
  33 #include "cssmdatetime.h" 
  34 #include <Security/SecItem.h> 
  35 #include <Security/SecItemPriv.h> 
  36 #include <Security/SecIdentitySearchPriv.h> 
  37 #include <Security/SecKeychainPriv.h> 
  38 #include <Security/SecCertificatePriv.h> 
  39 #include <Security/SecPolicyPriv.h> 
  40 #include "TrustAdditions.h" 
  41 #include "TrustSettingsSchema.h" 
  42 #include <Security/SecTrustPriv.h> 
  43 #include "utilities/array_size.h" 
  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> 
  58 #include <CoreFoundation/CFPriv.h> 
  61 const uint8_t kUUIDStringLength 
= 36; 
  63 OSStatus 
SecItemAdd_osx(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  64 OSStatus 
SecItemCopyMatching_osx(CFDictionaryRef query
, CFTypeRef 
*result
); 
  65 OSStatus 
SecItemUpdate_osx(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  66 OSStatus 
SecItemDelete_osx(CFDictionaryRef query
); 
  69 OSStatus 
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  70 OSStatus 
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef 
*result
); 
  71 OSStatus 
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  72 OSStatus 
SecItemDelete_ios(CFDictionaryRef query
); 
  73 OSStatus 
SecItemUpdateTokenItems_ios(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
); 
  76 OSStatus 
SecItemValidateAppleApplicationGroupAccess(CFStringRef group
); 
  77 CFDictionaryRef 
SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
  78         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
); 
  80 bool _SecItemParsePersistentRef(CFDataRef persistent_ref
, CFStringRef 
*return_class
, 
  81                                 long long int *return_rowid
, CFDictionaryRef 
*return_token_attrs
); 
  84 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
); 
  85 static CFArrayRef 
_CopyMatchingIssuers(CFArrayRef issuers
); 
  87 static void secitemlog(int priority
, const char *format
, ...) 
  92         if (priority 
< LOG_NOTICE
) // log warnings and errors 
  96                 va_start(list
, format
); 
  97                 vsyslog(priority
, format
, list
); 
 102 static void secitemshow(CFTypeRef obj
, const char *context
) 
 105         CFStringRef desc 
= CFCopyDescription(obj
); 
 108         CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1; 
 109         char* buffer 
= (char*) malloc(length
); 
 111                 Boolean converted 
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
); 
 113                         const char *prefix 
= (context
) ? context 
: ""; 
 114                         const char *separator 
= (context
) ? " " : ""; 
 115                         secitemlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
); 
 124 #define CFDataGetBytePtrVoid CFDataGetBytePtr 
 126 #pragma mark SecItem private utility functions 
 128 /******************************************************************************/ 
 130 struct ProtocolAttributeInfo 
{ 
 131         const CFStringRef 
*protocolValue
; 
 132         SecProtocolType protocolType
; 
 135 static ProtocolAttributeInfo gProtocolTypes
[] = { 
 136         { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP 
}, 
 137         { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount 
}, 
 138         { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP 
}, 
 139         { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC 
}, 
 140         { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP 
}, 
 141         { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3 
}, 
 142         { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP 
}, 
 143         { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS 
}, 
 144         { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP 
}, 
 145         { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP 
}, 
 146         { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk 
}, 
 147         { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP 
}, 
 148         { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet 
}, 
 149         { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH 
}, 
 150         { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS 
}, 
 151         { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS 
}, 
 152         { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy 
}, 
 153         { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy 
}, 
 154         { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy 
}, 
 155         { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB 
}, 
 156         { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP 
}, 
 157         { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy 
}, 
 158         { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP 
}, 
 159         { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC 
}, 
 160         { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP 
}, 
 161         { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS 
}, 
 162         { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS 
}, 
 163         { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS 
}, 
 164         { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS 
}, 
 165         { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS 
}, 
 166         { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S 
} 
 169 static const int kNumberOfProtocolTypes 
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
); 
 172  * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType. 
 174 static SecProtocolType
 
 175 _SecProtocolTypeForSecAttrProtocol( 
 178         SecProtocolType result 
= kSecProtocolTypeAny
; 
 180         if (protocol 
!= NULL
) { 
 182                 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 183                         if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) { 
 184                                 result 
= gProtocolTypes
[count
].protocolType
; 
 194  * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol. 
 197 _SecAttrProtocolForSecProtocolType( 
 198         SecProtocolType protocolType
) 
 200         CFTypeRef result 
= NULL
; 
 202         for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 203                 if (gProtocolTypes
[count
].protocolType 
== protocolType
) { 
 204                         result 
= *(gProtocolTypes
[count
].protocolValue
); 
 213 /******************************************************************************/ 
 215 struct AuthenticationAttributeInfo 
{ 
 216         const CFStringRef 
*authValue
; 
 217         SecAuthenticationType authType
; 
 220 static AuthenticationAttributeInfo gAuthTypes
[] = { 
 221         { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM 
}, 
 222         { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN 
}, 
 223         { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA 
}, 
 224         { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA 
}, 
 225         { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic 
}, 
 226         { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest 
}, 
 227         { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm 
}, 
 228         { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault 
} 
 231 static const int kNumberOfAuthenticationTypes 
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
); 
 234  * _SecAuthenticationTypeForSecAttrAuthenticationType converts a 
 235  * SecAttrAuthenticationType to a SecAuthenticationType. 
 237 static SecAuthenticationType
 
 238 _SecAuthenticationTypeForSecAttrAuthenticationType( 
 239         CFTypeRef authenticationType
) 
 241         SecAuthenticationType result 
= kSecAuthenticationTypeAny
; 
 243         if (authenticationType 
!= NULL
) { 
 245                 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 246                         if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) { 
 247                                 result 
= gAuthTypes
[count
].authType
; 
 257  * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType 
 258  * to a SecAttrAuthenticationType. 
 261 _SecAttrAuthenticationTypeForSecAuthenticationType( 
 262         SecAuthenticationType authenticationType
) 
 264         CFTypeRef result 
= NULL
; 
 266         for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 267                 if (gAuthTypes
[count
].authType 
== authenticationType
) { 
 268                         result 
= *(gAuthTypes
[count
].authValue
); 
 277 /******************************************************************************/ 
 279 struct KeyAlgorithmInfo 
{ 
 280         const CFStringRef 
*keyType
; 
 284 static KeyAlgorithmInfo gKeyTypes
[] = { 
 285         { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA 
}, 
 286         { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA 
}, 
 287         { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES 
}, 
 288         { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES 
}, 
 289         { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES 
}, 
 290         { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4 
}, 
 291         { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2 
}, 
 292         { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST 
}, 
 293         { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA 
}, 
 294         { &kSecAttrKeyTypeEC
, CSSM_ALGID_ECDSA 
} 
 297 static const int kNumberOfKeyTypes 
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
); 
 300 static UInt32 
_SecAlgorithmTypeFromSecAttrKeyType( 
 301         CFTypeRef keyTypeRef
) 
 303         UInt32 keyAlgValue 
= 0; 
 304         if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
)) 
 308         for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) { 
 309                 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) { 
 310                         keyAlgValue 
= gKeyTypes
[ix
].keyValue
; 
 315         //%%%TODO try to convert the input string to a number here 
 321 enum ItemRepresentation
 
 323         kStringRepresentation
, 
 325         kNumberRepresentation
, 
 326         kBooleanRepresentation
, 
 331 struct InternalAttributeListInfo
 
 334         const CFStringRef 
*newItemType
; 
 335         ItemRepresentation itemRepresentation
; 
 339 static InternalAttributeListInfo gGenericPasswordAttributes
[] = 
 341         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 342         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 343         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 344         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 345         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 346         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 347         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 348         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 349         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 350         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 351         { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation 
}, 
 352         { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation 
} 
 355 static const int kNumberOfGenericPasswordAttributes 
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 358 static InternalAttributeListInfo gInternetPasswordAttributes
[] = 
 360         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 361         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 362         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 363         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 364         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 365         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 366         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 367         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 368         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 369         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 370         { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation 
}, 
 371         { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation 
}, 
 372         { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation 
}, // maps from UInt32 value to string constant 
 373         { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation 
}, 
 374         { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation 
} 
 377 static const int kNumberOfInternetPasswordAttributes 
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 380 static InternalAttributeListInfo gCertificateAttributes
[] = 
 382         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 383         { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation 
}, 
 384         { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation 
}, 
 385         { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation 
}, 
 386         { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation 
}, 
 387         { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation 
}, 
 388         { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation 
}, 
 389         { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation 
} 
 392 static const int kNumberOfCertificateAttributes 
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
); 
 395 static InternalAttributeListInfo gKeyAttributes
[] = 
 397     { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation 
}, // key class maps from UInt32 value to string constant 
 398     { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation 
}, // note that "print name" maps to the user-visible label 
 399 //  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation }, 
 400     { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation 
}, 
 401 //  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 402 //  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 403     { 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 
 404     { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation 
}, 
 405 //  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key 
 406     { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation 
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES) 
 407     { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation 
}, 
 408     { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation 
}, 
 409 //  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 410 //  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 411 //  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 412 //  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 413 //  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 414 //  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 415     { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation 
}, 
 416     { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation 
}, 
 417     { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation 
}, 
 418     { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation 
}, 
 419     { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation 
}, 
 420 //  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 421 //  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 422     { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation 
}, 
 423     { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation 
} 
 426 static const int kNumberOfKeyAttributes 
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
); 
 429 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
) 
 433                 case kStringRepresentation
: 
 435                         if (CFStringGetTypeID() != CFGetTypeID(value
)) { 
 439                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 440                         char* buffer 
= (char*) malloc(maxLength
); 
 441                         Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 443                                 length 
= (UInt32
)strlen(buffer
); 
 453                 case kDataRepresentation
: 
 455                         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 456                 // We may have a string here, since the key label may be a GUID for the symmetric keys 
 457                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 458                 char* buffer 
= (char*) malloc(maxLength
); 
 459                 Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 461                     length 
= (UInt32
)strlen(buffer
); 
 471                         if (CFDataGetTypeID() != CFGetTypeID(value
)) { 
 475                         length 
= (UInt32
)CFDataGetLength((CFDataRef
) value
); 
 476                         uint8_t* buffer 
= (uint8_t*) malloc(length
); 
 477                         CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
); 
 481                 case kNumberRepresentation
: 
 483                         if (CFNumberGetTypeID() != CFGetTypeID(value
)) { 
 487                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 488                         Boolean converted 
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
); 
 490                                 length 
= sizeof(uint32_t); 
 500                 case kBooleanRepresentation
: 
 502                         if (CFBooleanGetTypeID() != CFGetTypeID(value
)) { 
 506                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 507                         *buffer 
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
 508                         length 
= sizeof(uint32_t); 
 512                 case kDateRepresentation
: 
 514                         if (CFDateGetTypeID() != CFGetTypeID(value
)) { 
 518                         char* buffer 
= (char*) calloc(1, 32); // max length of a CSSM date string 
 519                         CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
); 
 520                         length 
= (UInt32
)strlen(buffer
); 
 534 _ConvertNewFormatToOldFormat( 
 535         CFAllocatorRef allocator
, 
 536         const InternalAttributeListInfo
* info
, 
 538         CFDictionaryRef dictionaryRef
, 
 539         SecKeychainAttributeList
* &attrList
 
 542         // get the keychain attributes array from the data item 
 543         // here's the problem.  On the one hand, we have a dictionary that is purported to contain 
 544         // attributes for our type.  On the other hand, the dictionary may contain items we don't support, 
 545         // and we therefore don't know how many attributes we will have unless we count them first 
 548         attrList 
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
)); 
 550         // make storage to extract the dictionary items 
 551         CFIndex itemsInDictionary 
= CFDictionaryGetCount(dictionaryRef
); 
 552         std::vector
<CFTypeRef
> keys(itemsInDictionary
); 
 553         std::vector
<CFTypeRef
> values(itemsInDictionary
); 
 555         CFDictionaryGetKeysAndValues(dictionaryRef
, keys
.data(), values
.data()); 
 557         // count the number of items we are interested in 
 561         // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that 
 562         // we don't pay the price for this twice 
 563         std::vector
<SecKeychainAttrType
> tags(itemsInDictionary
); 
 564         std::vector
<ItemRepresentation
> types(itemsInDictionary
); 
 566         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 568                 CFTypeRef key 
= keys
[i
]; 
 571                 for (j 
= 0; j 
< infoNumItems
; ++j
) 
 573                         if (CFEqual(*(info
[j
].newItemType
), key
)) 
 575                                 tags
[i
] = info
[j
].oldItemType
; 
 576                                 types
[i
] = info
[j
].itemRepresentation
; 
 582                 if (j 
>= infoNumItems
) 
 584                         // if we got here, we aren't interested in this item. 
 589         // now we can make the result array 
 590         attrList
->count 
= (UInt32
)count
; 
 593         attrList
->attr 
= NULL
; 
 595         attrList
->attr 
= (SecKeychainAttribute
*) malloc(sizeof(SecKeychainAttribute
) * count
); 
 597         // fill out the array 
 598         int resultPointer 
= 0; 
 599         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 601             if (values
[i
] != NULL
) 
 603                 attrList
->attr
[resultPointer
].tag 
= tags
[i
]; 
 605                 // we have to clone the data pointer.  The caller will need to make sure to throw these away 
 606                 // with _FreeAttrList when it is done... 
 607                 attrList
->attr
[resultPointer
].data 
= CloneDataByType(types
[i
], values
[i
], attrList
->attr
[resultPointer
].length
); 
 613         return errSecSuccess
; 
 619 _ConvertOldFormatToNewFormat( 
 620         CFAllocatorRef allocator
, 
 621         const InternalAttributeListInfo
* info
, 
 623         SecKeychainItemRef itemRef
, 
 624         CFMutableDictionaryRef
& dictionaryRef
) 
 626         SecKeychainAttributeList list
; 
 627         list
.count 
= infoNumItems
; 
 628         list
.attr 
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
)); 
 630         // fill out the array.  We only need to fill in the tags, since calloc zeros what it returns 
 632         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 634                 list
.attr
[i
].tag 
= info
[i
].oldItemType
; 
 637         OSStatus result 
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
); 
 638         if (result 
!= errSecSuccess
) 
 640                 dictionaryRef 
= NULL
; 
 645         // create the dictionary 
 646         dictionaryRef 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 649         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 651                 if (list
.attr
[i
].data 
== NULL
) 
 654                 switch (info
[i
].itemRepresentation
) 
 656                         case kStringRepresentation
: 
 658                                 CFStringRef stringRef
; 
 659                                 if (info
[i
].oldItemType 
== kSecKeyKeyClass
) { 
 660                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 661                                         uint32_t keyRecordValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 662                                         bool retainString 
= true; 
 663                                         switch (keyRecordValue
) { 
 664                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 665                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 667                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 668                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 670                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 671                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 674                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
); 
 675                             retainString 
= false; 
 679                                                 if (retainString
) CFRetain(stringRef
); 
 680                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 681                                                 CFRelease(stringRef
); 
 684                                 else if (info
[i
].oldItemType 
== kSecKeyKeyType
) { 
 685                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 686                                         uint32_t keyAlgValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 687                                         bool retainString 
= true; 
 688                                         switch (keyAlgValue
) { 
 689                                                 case CSSM_ALGID_RSA 
: 
 690                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 692                                                 case CSSM_ALGID_DSA 
: 
 693                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 695                                                 case CSSM_ALGID_AES 
: 
 696                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 698                                                 case CSSM_ALGID_DES 
: 
 699                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 701                                                 case CSSM_ALGID_3DES 
: 
 702                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 704                                                 case CSSM_ALGID_RC4 
: 
 705                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 707                                                 case CSSM_ALGID_RC2 
: 
 708                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 710                                                 case CSSM_ALGID_CAST 
: 
 711                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 713                                                 case CSSM_ALGID_ECDSA 
: 
 714                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 717                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
); 
 718                                                         retainString 
= false; 
 722                                                 if (retainString
) CFRetain(stringRef
); 
 723                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 724                                                 CFRelease(stringRef
); 
 728                                         // normal case: attribute contains a string 
 729                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 730                                         if (stringRef 
== NULL
) 
 731                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 732                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 733                                         CFRelease(stringRef
); 
 738                         case kDataRepresentation
: 
 740                 if ((info
[i
].oldItemType 
== kSecKeyLabel
) && (list
.attr
[i
].length 
== kUUIDStringLength
)) { 
 741                                         // It's possible that there could be a string here because the key label may have a UUID 
 742                                         CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 743                                         if (stringRef 
== NULL
) 
 744                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 745                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 746                                         CFRelease(stringRef
); 
 749                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
); 
 751                     dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
 752                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
); 
 757                         case kNumberRepresentation
: 
 759                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
); 
 760                                 if (numberRef 
== NULL
) 
 761                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
 762                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
); 
 763                                 CFRelease(numberRef
); 
 767                         case kBooleanRepresentation
: 
 769                                 uint32_t value 
= *((uint32_t*)list
.attr
[i
].data
); 
 770                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
 771                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
); 
 775                         case kDateRepresentation
: 
 777                                 CFDateRef dateRef 
= NULL
; 
 778                                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
); 
 780                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
 781                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
); 
 789         SecKeychainItemFreeContent(&list
, NULL
); 
 799  * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the 
 800  * attributes of item. 
 803 _CreateAttributesDictionaryFromGenericPasswordItem( 
 804         CFAllocatorRef allocator
, 
 805         SecKeychainItemRef item
, 
 806         CFDictionaryRef 
*dictionary
) 
 808         // do the basic allocations 
 809         CFMutableDictionaryRef dict 
= NULL
; 
 810         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
); 
 811         if (result 
== errSecSuccess
) // did we complete OK 
 813                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
); 
 824  * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the 
 825  * attributes of item. 
 828 _CreateAttributesDictionaryFromCertificateItem( 
 829         CFAllocatorRef allocator
, 
 830         SecKeychainItemRef item
, 
 831         CFDictionaryRef 
*dictionary
) 
 833         // do the basic allocations 
 834         CFMutableDictionaryRef dict 
= NULL
; 
 835         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
); 
 836         if (result 
== errSecSuccess
) // did we complete OK 
 838                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
); 
 843         return errSecSuccess
; 
 847  * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the 
 848  * attributes of item. 
 851 _CreateAttributesDictionaryFromKeyItem( 
 852         CFAllocatorRef allocator
, 
 853         SecKeychainItemRef item
, 
 854         CFDictionaryRef 
*dictionary
) 
 857 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails. 
 858 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and 
 859 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent. 
 862                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 865         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 867         // do the basic allocations 
 868         CFMutableDictionaryRef dict 
= NULL
; 
 869         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
); 
 870         if (result 
== errSecSuccess
) // did we complete OK 
 872                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
 877         return errSecSuccess
; 
 880         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 882         SecItemClass itemClass 
= (SecItemClass
) 0; 
 884         SecKeychainAttributeList 
*attrList 
= NULL
; 
 885         SecKeychainAttributeInfo 
*info 
= NULL
; 
 886         SecKeychainRef keychain 
= NULL
; 
 888         OSStatus status 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
 890                 goto error_exit
; // item must have an itemClass 
 895     case kSecInternetPasswordItemClass
: 
 896                 itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
 898     case kSecGenericPasswordItemClass
: 
 899                 itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
 901     case 'ashp': /* kSecAppleSharePasswordItemClass */ 
 902                 itemID 
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
; 
 909         status 
= SecKeychainItemCopyKeychain(item
, &keychain
); 
 911                 goto error_exit
; // item must have a keychain, so we can get the attribute info for it 
 914         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
 916                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 919         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 921                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 924         for (ix 
= 0; ix 
< info
->count
; ++ix
) 
 926                 SecKeychainAttribute 
*attribute 
= &attrList
->attr
[ix
]; 
 927                 if (!attribute
->length 
&& !attribute
->data
) 
 930                 UInt32 j
, count 
= kNumberOfKeyAttributes
; 
 931                 InternalAttributeListInfo 
*intInfo 
= NULL
; 
 932                 for (j
=0; j
<count
; j
++) { 
 933                         if (gKeyAttributes
[j
].oldItemType 
== info
->tag
[ix
]) { 
 934                                 intInfo 
= &gKeyAttributes
[j
]; 
 941                 switch (intInfo
->itemRepresentation
) 
 943                         case kStringRepresentation
: 
 945                                 CFStringRef stringRef
; 
 946                                 if (intInfo
->oldItemType 
== kSecKeyKeyClass
) { 
 947                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 948                                         UInt32 keyRecordValue 
= *((UInt32
*)attribute
->data
); 
 949                                         bool retainString 
= true; 
 950                                         switch (keyRecordValue
) { 
 951                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 952                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 954                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 955                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 957                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 958                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 961                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyRecordValue
); 
 962                             retainString 
= false; 
 966                                                 if (retainString
) CFRetain(stringRef
); 
 967                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 968                                                 CFRelease(stringRef
); 
 971                                 else if (intInfo
->oldItemType 
== kSecKeyKeyType
) { 
 972                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 973                                         UInt32 keyAlgValue 
= *((UInt32
*)attribute
->data
); 
 974                                         bool retainString 
= true; 
 975                                         switch (keyAlgValue
) { 
 976                                                 case CSSM_ALGID_RSA 
: 
 977                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 979                                                 case CSSM_ALGID_DSA 
: 
 980                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 982                                                 case CSSM_ALGID_AES 
: 
 983                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 985                                                 case CSSM_ALGID_DES 
: 
 986                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 988                                                 case CSSM_ALGID_3DES 
: 
 989                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 991                                                 case CSSM_ALGID_RC4 
: 
 992                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 994                                                 case CSSM_ALGID_RC2 
: 
 995                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 997                                                 case CSSM_ALGID_CAST 
: 
 998                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
1000                                                 case CSSM_ALGID_ECDSA 
: 
1001                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
1004                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyAlgValue
); 
1005                                                         retainString 
= false; 
1009                                                 if (retainString
) CFRetain(stringRef
); 
1010                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1011                                                 CFRelease(stringRef
); 
1015                                         // normal case: attribute contains a string 
1016                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1017                                         if (stringRef 
== NULL
) 
1018                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1019                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1020                                         CFRelease(stringRef
); 
1025                         case kDataRepresentation
: 
1027                 if ((intInfo
->oldItemType 
== kSecKeyLabel
) && (attribute
->length 
== kUUIDStringLength
)) { 
1028                                         // It's possible that there could be a string here because the key label may have a UUID 
1029                     CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1030                                         if (stringRef 
== NULL
) 
1031                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1032                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1033                                         CFRelease(stringRef
); 
1037                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
); 
1038                                 if (dataRef 
== NULL
) 
1039                                         dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
1040                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
); 
1045                         case kNumberRepresentation
: 
1047                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
); 
1048                                 if (numberRef 
== NULL
) 
1049                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
1050                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
); 
1051                                 CFRelease(numberRef
); 
1055                         case kBooleanRepresentation
: 
1057                                 UInt32 value 
= *((UInt32
*)attribute
->data
); 
1058                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1059                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
); 
1063                         case kDateRepresentation
: 
1065                                 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here 
1066                                 CFDateRef dateRef 
= NULL
; 
1067                                 if (dateRef 
== NULL
) 
1068                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
1069                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
); 
1076         CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
1081                 SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
1084                 SecKeychainFreeAttributeInfo(info
); 
1087                 CFRelease(keychain
); 
1096  * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the 
1097  * attributes of item. 
1100 _CreateAttributesDictionaryFromInternetPasswordItem( 
1101         CFAllocatorRef allocator
, 
1102         SecKeychainItemRef item
, 
1103         CFDictionaryRef 
*dictionary
) 
1106         SecKeychainAttribute attr
[] = { 
1107                 { kSecServerItemAttr
, 0, NULL 
},                /* [0] server */ 
1108                 { kSecSecurityDomainItemAttr
, 0, NULL 
},        /* [1] securityDomain */ 
1109                 { kSecAccountItemAttr
, 0, NULL 
},               /* [2] account */ 
1110                 { kSecPathItemAttr
, 0, NULL 
},                  /* [3] path */ 
1111                 { kSecPortItemAttr
, 0, NULL 
},                  /* [4] port */ 
1112                 { kSecProtocolItemAttr
, 0, NULL 
},              /* [5] protocol */ 
1113                 { kSecAuthenticationTypeItemAttr
, 0, NULL 
},    /* [6] authenticationType */ 
1114                 { kSecCommentItemAttr
, 0, NULL 
},               /* [7] comment */ 
1115                 { kSecDescriptionItemAttr
, 0, NULL 
},           /* [8] description */ 
1116                 { kSecLabelItemAttr
, 0, NULL 
},                 /* [9] label */ 
1117                 { kSecCreationDateItemAttr
, 0, NULL 
},  /* [10] creation date */ 
1118                 { kSecModDateItemAttr
, 0, NULL 
},               /* [11] modification date */ 
1119                 { kSecCreatorItemAttr
, 0, NULL 
},               /* [12] creator */ 
1120                 { kSecTypeItemAttr
, 0, NULL 
},                  /* [13] type */ 
1121                 { kSecInvisibleItemAttr
, 0, NULL 
},             /* [14] invisible */ 
1122                 { kSecNegativeItemAttr
, 0, NULL 
},              /* [15] negative */ 
1124         SecKeychainAttributeList attrList 
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr 
}; 
1127         CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1128         CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1132         // copy the item's attributes 
1133         status 
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
); 
1134         require_noerr(status
, SecKeychainItemCopyContent_failed
); 
1139         keys
[numValues
] = kSecClass
; 
1140         values
[numValues
] = kSecClassInternetPassword
; 
1143         // add kSecAttrServer 
1144         if ( attrList
.attr
[0].length 
> 0 ) { 
1145                 keys
[numValues
] = kSecAttrServer
; 
1146                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
); 
1147                 if ( values
[numValues
] != NULL 
) { 
1152         // add kSecAttrSecurityDomain 
1153         if ( attrList
.attr
[1].length 
> 0 ) { 
1154                 keys
[numValues
] = kSecAttrSecurityDomain
; 
1155                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
); 
1156                 if ( values
[numValues
] != NULL 
) { 
1161         // add kSecAttrAccount 
1162         if ( attrList
.attr
[2].length 
> 0 ) { 
1163                 keys
[numValues
] = kSecAttrAccount
; 
1164                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
); 
1165                 if ( values
[numValues
] != NULL 
) { 
1171         if ( attrList
.attr
[3].length 
> 0 ) { 
1172                 keys
[numValues
] = kSecAttrPath
; 
1173                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
); 
1174                 if ( values
[numValues
] != NULL 
) { 
1180         if ( attrList
.attr
[4].length 
> 0 ) { 
1181                 keys
[numValues
] = kSecAttrPort
; 
1182                 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
); 
1183                 if ( values
[numValues
] != NULL 
) { 
1188         // add kSecAttrProtocol 
1189         if ( attrList
.attr
[5].length 
> 0 ) { 
1190                 keys
[numValues
] = kSecAttrProtocol
; 
1191                 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
); 
1192                 if ( values
[numValues
] != NULL 
) { 
1193                         CFRetain(values
[numValues
]); 
1198         // add kSecAttrAuthenticationType 
1199         if ( attrList
.attr
[6].length 
> 0 ) { 
1200                 keys
[numValues
] = kSecAttrAuthenticationType
; 
1201                 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType( (SecAuthenticationType
) (*(SecProtocolType
*)attrList
.attr
[6].data
)); 
1202                 if ( values
[numValues
] != NULL 
) { 
1203                         CFRetain(values
[numValues
]); 
1208         // add kSecAttrComment 
1209         if ( attrList
.attr
[7].length 
> 0 ) { 
1210                 keys
[numValues
] = kSecAttrComment
; 
1211                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
); 
1212                 if ( values
[numValues
] != NULL 
) { 
1217         // add kSecAttrDescription 
1218         if ( attrList
.attr
[8].length 
> 0 ) { 
1219                 keys
[numValues
] = kSecAttrDescription
; 
1220                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
); 
1221                 if ( values
[numValues
] != NULL 
) { 
1226         // add kSecAttrLabel 
1227         if ( attrList
.attr
[9].length 
> 0 ) { 
1228                 keys
[numValues
] = kSecAttrLabel
; 
1229                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
); 
1230                 if ( values
[numValues
] != NULL 
) { 
1235         // add kSecAttrCreationDate 
1236         if ( attrList
.attr
[10].length 
> 0 ) { 
1237                 CFDateRef creationDate 
= NULL
; 
1238                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
); 
1239                 keys
[numValues
] = kSecAttrCreationDate
; 
1240                 values
[numValues
] = creationDate
; 
1241                 if ( values
[numValues
] != NULL 
) { 
1246         // add kSecAttrModificationDate 
1247         if ( attrList
.attr
[11].length 
> 0 ) { 
1248                 CFDateRef modDate 
= NULL
; 
1249                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
); 
1250                 keys
[numValues
] = kSecAttrModificationDate
; 
1251                 values
[numValues
] = modDate
; 
1252                 if ( values
[numValues
] != NULL 
) { 
1257         // add kSecCreatorItemAttr 
1258         if ( attrList
.attr
[12].length 
> 0 ) { 
1259                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
); 
1260                 keys
[numValues
] = kSecAttrCreator
; 
1261                 values
[numValues
] = numberRef
; 
1262                 if ( values
[numValues
] != NULL 
) { 
1263                         CFRetain(values
[numValues
]); 
1268         // add kSecTypeItemAttr 
1269         if ( attrList
.attr
[13].length 
> 0 ) { 
1270                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
); 
1271                 keys
[numValues
] = kSecAttrType
; 
1272                 values
[numValues
] = numberRef
; 
1273                 if ( values
[numValues
] != NULL 
) { 
1274                         CFRetain(values
[numValues
]); 
1279         // add kSecInvisibleItemAttr 
1280         if ( attrList
.attr
[14].length 
> 0 ) { 
1281                 uint32_t value 
= *((uint32_t*)attrList
.attr
[14].data
); 
1282                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1283                 keys
[numValues
] = kSecAttrIsInvisible
; 
1284                 values
[numValues
] = boolRef
; 
1285                 if ( values
[numValues
] != NULL 
) { 
1286                         CFRetain(values
[numValues
]); 
1291         // add kSecNegativeItemAttr 
1292         if ( attrList
.attr
[15].length 
> 0 ) { 
1293                 uint32_t value 
= *((uint32_t*)attrList
.attr
[15].data
); 
1294                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1295                 keys
[numValues
] = kSecAttrIsNegative
; 
1296                 values
[numValues
] = boolRef
; 
1297                 if ( values
[numValues
] != NULL 
) { 
1298                         CFRetain(values
[numValues
]); 
1303         // create the dictionary 
1304         *dictionary 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1306         // release the values added to the dictionary 
1307         for ( index 
= 0; index 
< numValues
; ++index 
) 
1309                 CFRelease(values
[index
]); 
1312         // and free the attributes 
1313         (void) SecKeychainItemFreeContent(&attrList
, NULL
); 
1315 SecKeychainItemCopyContent_failed
: 
1322  * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the 
1323  * attributes of the specified item class and item. 
1326 _CreateAttributesDictionaryFromItem( 
1327         CFAllocatorRef allocator
, 
1328         SecItemClass itemClass
, 
1329         SecKeychainItemRef item
, 
1330         CFDictionaryRef 
*dictionary
) 
1334                 case kSecInternetPasswordItemClass
: 
1335                         return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
); 
1337                 case kSecGenericPasswordItemClass
: 
1338                         return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
); 
1340                 case kSecCertificateItemClass
: 
1341                         return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
); 
1343                 case kSecPublicKeyItemClass
: 
1344                 case kSecPrivateKeyItemClass
: 
1345                 case kSecSymmetricKeyItemClass
: 
1346                         return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
); 
1357  * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList 
1358  * by the _CreateSecKeychainAttributeListFromDictionary function. 
1362         SecKeychainAttributeList 
*attrListPtr
) 
1366         if ( attrListPtr 
!= NULL 
) { 
1367                 if ( attrListPtr
->attr 
!= NULL 
) { 
1368                         // free any attribute data 
1369                         for ( index 
= 0; index 
< attrListPtr
->count
; ++index 
) { 
1370                                 free(attrListPtr
->attr
[index
].data
); 
1372                         // free the attribute array 
1373                         free(attrListPtr
->attr
); 
1375                 // free the attribute list 
1381  * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by 
1382  * attr using the data and tag parameters. 
1384  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1385  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1388 _CFDataCreateAttribute( 
1390         SecKeychainAttrType tag
, 
1391         SecKeychainAttributePtr attr
) 
1393         OSStatus status 
= errSecSuccess
; 
1396         // set the attribute tag 
1399         // determine the attribute length 
1400         attr
->length 
= (UInt32
) CFDataGetLength(data
); 
1401         range 
= CFRangeMake(0, (CFIndex
)attr
->length
); 
1403         // allocate memory for the attribute bytes 
1404         attr
->data 
= malloc(attr
->length
); 
1405         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1407         // get the attribute bytes 
1408         CFDataGetBytes(data
, range
, (UInt8 
*)attr
->data
); 
1416  * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by 
1417  * attr using the string and tag parameters. 
1419  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1420  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1423 _CFStringCreateAttribute( 
1425         SecKeychainAttrType tag
, 
1426         SecKeychainAttributePtr attr
) 
1428         OSStatus status 
= errSecSuccess
; 
1431         // set the attribute tag 
1434         // determine the attribute length 
1435         range 
= CFRangeMake(0, CFStringGetLength(string
)); 
1436         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex 
*)&attr
->length
); 
1438         // allocate memory for the attribute bytes 
1439         attr
->data 
= malloc(attr
->length
); 
1440         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1442         // get the attribute bytes 
1443         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8 
*)attr
->data
, attr
->length
, NULL
); 
1452  * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1453  * from the attribute key/values in attrDictionary. 
1455  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1456  * must be freed by the caller with _FreeAttrList() 
1459 _CreateSecKeychainGenericPasswordAttributeListFromDictionary( 
1460         CFDictionaryRef attrDictionary
, 
1461         SecKeychainAttributeList 
**attrList
) 
1463         return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
); 
1468  * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList 
1469  * from the attribute key/values in attrDictionary. 
1471  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1472  * must be freed by the caller with _FreeAttrList() 
1475 _CreateSecKeychainCertificateAttributeListFromDictionary( 
1476         CFDictionaryRef attrDictionary
, 
1477         SecKeychainAttributeList 
**attrList
) 
1479         return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
); 
1484  * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList 
1485  * from the attribute key/values in attrDictionary. 
1487  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1488  * must be freed by the caller with _FreeAttrList() 
1491 _CreateSecKeychainKeyAttributeListFromDictionary( 
1492         CFDictionaryRef attrDictionary
, 
1493         SecKeychainAttributeList 
**attrList
) 
1496         //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug 
1497         return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
); 
1499         // explicitly build attribute list for supported key attributes 
1500         // NOTE: this code supports only MaxSecKeyAttributes (15) attributes 
1501         const int MaxSecKeyAttributes 
= 15; 
1505         SecKeychainAttributeList 
*attrListPtr
; 
1507         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1508         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1510         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
)); 
1511         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1513         // [0] get the kSecKeyKeyClass value 
1514         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) { 
1515                 UInt32 keyRecordValue 
= 0; 
1516                 if (CFEqual(kSecAttrKeyClassPublic
, value
)) 
1517                         keyRecordValue 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
1518                 else if (CFEqual(kSecAttrKeyClassPrivate
, value
)) 
1519                         keyRecordValue 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
1520                 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
)) 
1521                         keyRecordValue 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
1523                 // only use this attribute if we recognize the value! 
1524                 if (keyRecordValue 
!= 0) { 
1525                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1526                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1528                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyClass
; 
1529                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1530                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
; 
1532                         ++attrListPtr
->count
; 
1536         // [1] get the kSecKeyPrintName string 
1537         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) { 
1538                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1539                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1541                 ++attrListPtr
->count
; 
1544         // [2] get the kSecKeyPermanent boolean 
1545         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) { 
1546                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1547                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1549                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyPermanent
; 
1550                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1551                 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1553                 ++attrListPtr
->count
; 
1556         // [3] get the kSecKeyLabel string 
1557         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) { 
1558         if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1559             status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1560         else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1561             status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1563             status 
= errSecParam
; 
1565                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1567                 ++attrListPtr
->count
; 
1570         // [4] get the kSecKeyApplicationTag data 
1571         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) { 
1572                 if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1573                         status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1574                 else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1575                         status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1577                         status 
= errSecParam
; 
1579                 require_noerr_quiet(status
, CFDataCreateAttribute_failed
); 
1580                 ++attrListPtr
->count
; 
1583         // [5] get the kSecKeyKeyType number 
1584         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) { 
1585                 UInt32 keyAlgValue 
= _SecAlgorithmTypeFromSecAttrKeyType(value
); 
1586                 if (keyAlgValue 
!= 0) { 
1587                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1588                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1590                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyType
; 
1591                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1592                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
; 
1594                         ++attrListPtr
->count
; 
1598         // [6] get the kSecKeyKeySizeInBits number 
1599         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) { 
1600                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1601                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1602                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1604                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeySizeInBits
; 
1605                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1606                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1608                         ++attrListPtr
->count
; 
1612         // [7] get the kSecKeyEffectiveKeySize number 
1613         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) { 
1614                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1615                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1616                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1618                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEffectiveKeySize
; 
1619                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1620                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1622                         ++attrListPtr
->count
; 
1626         // [8] get the kSecKeyEncrypt boolean 
1627         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) { 
1628                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1629                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1630                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1632                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEncrypt
; 
1633                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1634                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1636                         ++attrListPtr
->count
; 
1640         // [9] get the kSecKeyDecrypt boolean 
1641         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) { 
1642                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1643                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1644                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1646                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDecrypt
; 
1647                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1648                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1650                         ++attrListPtr
->count
; 
1654         // [10] get the kSecKeyDerive boolean 
1655         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) { 
1656                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1657                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1658                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1660                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDerive
; 
1661                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1662                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1664                         ++attrListPtr
->count
; 
1668         // [11] get the kSecKeySign boolean 
1669         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) { 
1670                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1671                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1672                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1674                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeySign
; 
1675                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1676                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1678                         ++attrListPtr
->count
; 
1682         // [12] get the kSecKeyVerify boolean 
1683         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) { 
1684                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1685                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1686                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1688                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyVerify
; 
1689                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1690                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1692                         ++attrListPtr
->count
; 
1696         // [13] get the kSecKeyWrap boolean 
1697         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) { 
1698                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1699                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1700                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1702                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyWrap
; 
1703                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1704                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1706                         ++attrListPtr
->count
; 
1710         // [14] get the kSecKeyUnwrap boolean 
1711         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) { 
1712                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1713                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1714                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1716                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyUnwrap
; 
1717                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1718                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1720                         ++attrListPtr
->count
; 
1724         // return the pointer to the attrList 
1725         *attrList 
= attrListPtr
; 
1727         return ( errSecSuccess 
); 
1731 malloc_number_failed
: 
1732 CFDataCreateAttribute_failed
: 
1733 CFStringCreateAttribute_failed
: 
1734 malloc_attrPtr_failed
: 
1736         // free any attributes 
1737         _FreeAttrList(attrListPtr
); 
1739 calloc_attrListPtr_failed
: 
1741         return ( errSecBufferTooSmall 
); 
1746 static CFTypeRef 
copyNumber(CFTypeRef obj
) 
1751     CFTypeID tid 
= CFGetTypeID(obj
); 
1752     if (tid 
== CFNumberGetTypeID()) 
1758     if (tid 
== CFBooleanGetTypeID()) 
1760         SInt32 value 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
1761         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1764     if (tid 
== CFStringGetTypeID()) 
1766         SInt32 value 
= CFStringGetIntValue((CFStringRef
)obj
); 
1767         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value
); 
1768         /* If a string converted to an int isn't equal to the int printed as 
1769          a string, return a NULL instead. */ 
1770         if (!CFEqual(t
, obj
)) 
1776         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1782  * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1783  * from the attribute key/values in attrDictionary. 
1785  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1786  * must be freed by the caller with _FreeAttrList() 
1789 _CreateSecKeychainInternetPasswordAttributeListFromDictionary( 
1790         CFDictionaryRef attrDictionary
, 
1791         SecKeychainAttributeList 
**attrList
) 
1793         // explicitly build attribute list for supported key attributes 
1794         // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes 
1795         const int MaxSecKeychainAttributes 
= 14; 
1799         SecKeychainAttributeList 
*attrListPtr
; 
1801         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1802         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1804         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
)); 
1805         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1808         // [0] get the serverName string 
1809         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) { 
1810                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1811                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1813                 ++attrListPtr
->count
; 
1816         // [1] get the securityDomain string 
1817         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) { 
1818                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1819                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1821                 ++attrListPtr
->count
; 
1824         // [2] get the accountName string 
1825         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) { 
1826                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1827                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1829                 ++attrListPtr
->count
; 
1832         // [3] get the path string 
1833         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) { 
1834                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1835                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1837                 ++attrListPtr
->count
; 
1840         // [4] get the port number 
1841         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) { 
1842                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt16
)); 
1843                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1845         CFTypeRef num 
= copyNumber(value
); 
1846                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1847                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecPortItemAttr
; 
1848                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt16
); 
1849                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1852                 ++attrListPtr
->count
; 
1855         // [5] get the protocol 
1856         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) { 
1857                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecProtocolType
)); 
1858                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_protocol_failed
, status 
= errSecBufferTooSmall
); 
1860                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecProtocolItemAttr
; 
1861                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecProtocolType
); 
1862                 *(SecProtocolType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
); 
1864                 ++attrListPtr
->count
; 
1867         // [6] get the authenticationType 
1868         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) { 
1869                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecAuthenticationType
)); 
1870                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_authenticationType_failed
, status 
= errSecBufferTooSmall
); 
1872                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecAuthenticationTypeItemAttr
; 
1873                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecAuthenticationType
); 
1874                 *(SecAuthenticationType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
); 
1876                 ++attrListPtr
->count
; 
1879         // [7] get the comment string 
1880         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) { 
1881                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1882                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1884                 ++attrListPtr
->count
; 
1887         // [8] get the description string 
1888         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) { 
1889                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1890                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1892                 ++attrListPtr
->count
; 
1895         // [9] get the label string 
1896         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) { 
1897                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1898                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1900                 ++attrListPtr
->count
; 
1903         // [10] get the creator code 
1904         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) { 
1905                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1906                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1908         CFTypeRef num 
= copyNumber(value
); 
1909                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1910                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecCreatorItemAttr
; 
1911                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1912                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1915                 ++attrListPtr
->count
; 
1918         // [11] get the type code 
1919         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) { 
1920                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1921                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1923         CFTypeRef num 
= copyNumber(value
); 
1924                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1925                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecTypeItemAttr
; 
1926                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1927                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1930                 ++attrListPtr
->count
; 
1933         // [12] get the invisible flag 
1934         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) { 
1935                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1936                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1938                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecInvisibleItemAttr
; 
1939                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1940                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1942                 ++attrListPtr
->count
; 
1945         // [13] get the negative flag 
1946         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) { 
1947                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1948                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1950                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecNegativeItemAttr
; 
1951                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1952                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1954                 ++attrListPtr
->count
; 
1957         // return the pointer to the attrList 
1958         *attrList 
= attrListPtr
; 
1960         return ( errSecSuccess 
); 
1964 malloc_authenticationType_failed
: 
1965 malloc_protocol_failed
: 
1967 CFStringCreateAttribute_failed
: 
1968 malloc_attrPtr_failed
: 
1970         // free any attributes 
1971         _FreeAttrList(attrListPtr
); 
1973 calloc_attrListPtr_failed
: 
1975         return ( errSecBufferTooSmall 
); 
1980  * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList 
1981  * from the attribute key/values in attrDictionary for the specified item class. 
1983  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1984  * must be freed by the caller with _FreeAttrList() 
1987 _CreateSecKeychainAttributeListFromDictionary( 
1988         CFDictionaryRef attrDictionary
, 
1989         SecItemClass itemClass
, 
1990         SecKeychainAttributeList 
**attrList
) 
1994                 case kSecInternetPasswordItemClass
: 
1995                         return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1997                 case kSecGenericPasswordItemClass
: 
1998                         return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
2000                 case kSecCertificateItemClass
: 
2001                         return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
); 
2003                 case kSecPublicKeyItemClass
: 
2004                 case kSecPrivateKeyItemClass
: 
2005                 case kSecSymmetricKeyItemClass
: 
2006                         return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
); 
2016  * _AppNameFromSecTrustedApplication attempts to pull the name of the 
2017  * application/tool from the SecTrustedApplicationRef. 
2019 static CFStringRef CF_RETURNS_RETAINED
 
2020 _AppNameFromSecTrustedApplication( 
2021         CFAllocatorRef alloc
, 
2022         SecTrustedApplicationRef appRef
) 
2026         CFDataRef appDataRef
; 
2030         // get the data for item's application/tool 
2031         status 
= SecTrustedApplicationCopyData(appRef
, &appDataRef
); 
2032         if ( status 
== errSecSuccess 
) { 
2035                 // convert it to a CFString potentially containing the path 
2036                 path 
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
); 
2037                 if ( path 
!= NULL 
) { 
2038                         // the path has to start with a "/" and cannot contain "://" 
2039                         if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location 
== kCFNotFound
) ) { 
2040                                 CFRange nameRange
, compRg
; 
2042                                 nameRange 
= CFRangeMake(0, CFStringGetLength(path
)); 
2044                                 // remove the trailing slashes (if any) 
2045                                 while ( (nameRange
.length 
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length 
- 1) == '/') ) { 
2046                                         nameRange
.length 
--; 
2049                                 if ( nameRange
.length 
> 0 ) { 
2050                                         // find last slash and adjust nameRange to be everything after it 
2051                                         if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) { 
2052                                                 nameRange
.length 
= nameRange
.location 
+ nameRange
.length 
- (compRg
.location 
+ 1); 
2053                                                 nameRange
.location 
= compRg
.location 
+ 1; 
2056                                         result 
= CFStringCreateWithSubstring(alloc
, path
, nameRange
); 
2061                 CFRelease(appDataRef
); 
2067 /* (This function really belongs in SecIdentity.cpp!) 
2069  * Returns the public key item corresponding to the identity, if it exists in 
2070  * the same keychain as the private key. Note that the public key might not 
2071  * exist in the same keychain (e.g. if the identity was imported via PKCS12), 
2072  * in which case it will not be found. 
2075 _SecIdentityCopyPublicKey( 
2076         SecIdentityRef identityRef
, 
2077         SecKeyRef 
*publicKeyRef
) 
2081         SecKeychainAttribute attr 
= { kSecKeyLabel
, 0, NULL 
}; 
2082         SecKeychainAttributeList attrList 
= { 1, &attr 
}; 
2083         SecKeychainAttributeList 
*keyAttrList 
= NULL
; 
2084         SecKeychainAttributeInfo 
*info 
= NULL
; 
2085         SecKeychainSearchRef search 
= NULL
; 
2086         SecKeychainRef keychain 
= NULL
; 
2087         SecKeychainItemRef privateKey 
= NULL
; 
2088         SecKeychainItemRef publicKey 
= NULL
; 
2090         status 
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef 
*)&privateKey
); 
2092                 goto error_exit
; // identity must have a private key 
2094         status 
= SecKeychainItemCopyKeychain(privateKey
, &keychain
); 
2096                 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it 
2098         status 
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
); 
2100                 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys 
2102         status 
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
); 
2104                 goto error_exit
; // unable to get the key label attribute for the private key 
2107         // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching 
2108         for (count 
= 0; count 
< keyAttrList
->count
; count
++) { 
2109                 if (keyAttrList
->attr
[count
].tag 
== kSecKeyLabel
) { 
2110                         attr
.length 
= keyAttrList
->attr
[count
].length
; 
2111                         attr
.data 
= keyAttrList
->attr
[count
].data
; 
2115         if (!attr
.length 
|| !attr
.data
) { 
2116                 status 
= errSecNoSuchAttr
; 
2117                 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel 
2119         status 
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
); 
2121                 goto error_exit
; // unable to create the search reference 
2123         status 
= SecKeychainSearchCopyNext(search
, &publicKey
); 
2125                 goto error_exit
; // unable to find the public key 
2129                 *publicKeyRef 
= (SecKeyRef
)publicKey
; 
2131                 CFRelease(publicKey
); 
2134         if (status 
!= errSecSuccess
) { 
2136                         *publicKeyRef 
= NULL
; 
2138                         CFRelease(publicKey
); 
2144                 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
); 
2147                 SecKeychainFreeAttributeInfo(info
); 
2150                 CFRelease(keychain
); 
2153                 CFRelease(privateKey
); 
2160  * Deletes a keychain item if the current application/tool is the only application/tool 
2161  * with decrypt access to that keychain item. If more than one application/tool 
2162  * has decrypt access to the keychain item, the item is left on the keychain. 
2164  * TBD: If more than one app/tool has access to the keychain item, we should remove 
2165  * the current app/tool's decrypt access. There's no easy way to do that with 
2166  * current keychain APIs without bringing up the security UI. 
2169 _SafeSecKeychainItemDelete( 
2170         SecKeychainItemRef itemRef
) 
2173         SecAccessRef access 
= NULL
; 
2174         CFArrayRef aclList 
= NULL
; 
2175         SecACLRef acl 
= NULL
; 
2176         CFArrayRef appList 
= NULL
; 
2177         CFStringRef description 
= NULL
; 
2178         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
2179         CFIndex idx
, count 
= 0; 
2180         SecTrustedApplicationRef currentAppRef 
= NULL
; 
2181         CFStringRef itemAppName 
= NULL
, currentAppName 
= NULL
; 
2183         SecItemClass itemClass 
= (SecItemClass
)0; 
2184         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2185         if (!(itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2186                 // only perform the access control safety check on deletion of password credentials; 
2187                 // if the item is of some other type, delete it normally. 
2188                 return SecKeychainItemDelete(itemRef
); 
2191         // skip access control checking for web form passwords: <rdar://10957301> 
2192         // This permits Safari to manage the removal of all web form passwords, 
2193         // regardless of whether they are shared by multiple applications. 
2194         if (itemClass 
== kSecInternetPasswordItemClass
) { 
2195                 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr 
}; 
2196                 SecKeychainAttributeInfo attrInfo 
= { 1, tags
, NULL 
}; 
2197                 SecKeychainAttributeList 
*attrs 
= NULL
; 
2198                 status 
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
); 
2199                 if (!status 
&& attrs
) { 
2200                         bool webFormPassword 
= (attrs
->attr
[0].length 
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4))); 
2201                         SecKeychainItemFreeAttributesAndData(attrs
, NULL
); 
2202                         if (webFormPassword
) { 
2203                                 return SecKeychainItemDelete(itemRef
); 
2208         // copy the access of the keychain item 
2209         status 
= SecKeychainItemCopyAccess(itemRef
, &access
); 
2210         require_noerr(status
, finish
); 
2211         require_quiet(access 
!= NULL
, finish
); 
2213         // copy the decrypt access control lists -- this is what has access to the keychain item 
2214         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
2215         require_noerr(status
, finish
); 
2216         require_quiet(aclList 
!= NULL
, finish
); 
2218         // get the access control list 
2219         acl 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
2220         require_quiet(acl 
!= NULL
, finish
); 
2222         // copy the application list, description, and CSSM prompt selector for a given access control list entry 
2223         status 
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
); 
2224         require_noerr(status
, finish
); 
2225         require_quiet(appList 
!= NULL
, finish
); 
2227         // does the calling application/tool have decrypt access to this item? 
2228         count 
= CFArrayGetCount(appList
); 
2229         for ( idx 
= 0; idx 
< count
; idx
++ ) { 
2230                 // get SecTrustedApplicationRef for this entry 
2231                 SecTrustedApplicationRef itemAppRef 
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, idx
); 
2232                 require_quiet(itemAppRef 
!= NULL
, finish
); 
2234                 // copy the name out 
2235                 CFReleaseSafe(itemAppName
); 
2236                 itemAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
); 
2237                 if (itemAppName 
== NULL
) { 
2239                          * If there is no app name, it's probably because it's not an appname 
2240                          * in the ACE but an entitlement/info.plist based rule instead; 
2241                          * just let the caller have it. */ 
2246                 // create SecTrustedApplicationRef for current application/tool 
2247                 CFReleaseNull(currentAppRef
); 
2248                 status 
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
); 
2249                 require_noerr(status
, finish
); 
2250                 require_quiet(currentAppRef 
!= NULL
, finish
); 
2252                 // copy the name out 
2253                 CFReleaseSafe(currentAppName
); 
2254                 currentAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
); 
2255                 require_quiet(currentAppName 
!= NULL
, finish
); 
2257                 // compare the names to see if we own the decrypt access 
2258                 // TBD: validation of membership in an application group 
2259                 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo 
) { 
2267         CFReleaseSafe(currentAppName
); 
2268         CFReleaseSafe(itemAppName
); 
2269         CFReleaseSafe(currentAppRef
); 
2270         CFReleaseSafe(description
); 
2271         CFReleaseSafe(appList
); 
2272         CFReleaseSafe(aclList
); 
2273         CFReleaseSafe(access
); 
2275         if ((count 
== 0) || (status 
== errSecVerifyFailed
)) { 
2276                 // no "owners" remain in the ACL list (or unable to get ACL) 
2277                 status 
= SecKeychainItemDelete(itemRef
); 
2279                 // caller is not the "owner" of the item 
2280                 status 
= errSecInvalidOwnerEdit
; 
2287 _ReplaceKeychainItem( 
2288         SecKeychainItemRef itemToUpdate
, 
2289         SecKeychainAttributeList 
*changeAttrList
, 
2294         SecItemClass itemClass
; 
2295         SecKeychainAttributeInfo 
*info 
= NULL
; 
2296         SecKeychainAttributeList 
*attrList 
= NULL
; 
2297         SecKeychainAttributeList newAttrList 
= { 0, NULL
}; 
2298         SecKeychainRef keychain 
= NULL
; 
2299         SecKeychainItemRef newItem 
= NULL
; 
2301         int priority 
= LOG_DEBUG
; 
2302         const char *format 
= "ReplaceKeychainItem (%d) error %d"; 
2304         // get existing item's keychain 
2305         status 
= SecKeychainItemCopyKeychain(itemToUpdate
, &keychain
); 
2306         if (status
) { secitemlog(priority
, format
, 1, (int)status
); } 
2307         require_noerr(status
, replace_failed
); 
2309         // get attribute info (i.e. database schema) for the item class 
2310         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2311         if (status
) { secitemlog(priority
, format
, 2, (int)status
); } 
2312         require_noerr(status
, replace_failed
); 
2316                 case kSecInternetPasswordItemClass
: 
2317                         itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
2319                 case kSecGenericPasswordItemClass
: 
2320                         itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
2326         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
2327         if (status
) { secitemlog(priority
, format
, 3, (int)status
); } 
2329         // get item's existing attributes (but not data!) 
2330         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
2331         if (status
) { secitemlog(priority
, format
, 4, (int)status
); } 
2332         require(attrList 
!= NULL
, replace_failed
); 
2334         // move aside the item by changing a primary attribute 
2335     // (currently only for passwords) 
2336         if (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
) { 
2337                 CFUUIDRef uuid 
= CFUUIDCreate(kCFAllocatorDefault
); 
2338                 CFStringRef uuidStr 
= (uuid
) ? CFUUIDCreateString(kCFAllocatorDefault
, uuid
) : CFSTR("MOVED"); 
2339                 CFReleaseSafe(uuid
); 
2341                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr
), kCFStringEncodingUTF8
) + 1; 
2342                         char* buffer 
= (char*) malloc(maxLength
); 
2344                                 if (CFStringGetCString(uuidStr
, buffer
, maxLength
, kCFStringEncodingUTF8
)) { 
2345                                         UInt32 length 
= (UInt32
)strlen(buffer
); 
2346                                         SecKeychainAttribute attrs
[] = { { kSecAccountItemAttr
, length
, (char*)buffer 
}, }; 
2347                                         SecKeychainAttributeList updateAttrList 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
2348                                         status 
= SecKeychainItemModifyAttributesAndData(itemToUpdate
, &updateAttrList
, 0, NULL
); 
2349                                         if (status
) { secitemlog(priority
, format
, 5, (int)status
); } 
2350                                         if (status 
== errSecVerifyFailed
) { 
2351                                                 // still unable to change attrs? delete unconditionally here 
2352                                                 status 
= SecKeychainItemDelete(itemToUpdate
); 
2353                                                 if (status
) { secitemlog(priority
, format
, 6, (int)status
); } 
2358                         CFReleaseSafe(uuidStr
); 
2361         require_noerr(status
, replace_failed
); 
2363         // make attribute list for new item (the data is still owned by attrList) 
2364         newAttrList
.count 
= attrList
->count
; 
2365         newAttrList
.attr 
= (SecKeychainAttribute 
*) malloc(sizeof(SecKeychainAttribute
) * attrList
->count
); 
2367         for (i
=0, newCount
=0; i 
< attrList
->count
; i
++) { 
2368                 if (attrList
->attr
[i
].length 
> 0) { 
2369                         newAttrList
.attr
[newCount
++] = attrList
->attr
[i
]; 
2372         newAttrList
.count 
= newCount
; 
2374         // create new item in the same keychain 
2375         status 
= SecKeychainItemCreateFromContent(itemClass
, &newAttrList
, 
2376                 (UInt32
)((itemData
) ? CFDataGetLength(itemData
) : 0), 
2377                 (const void *)((itemData
) ? CFDataGetBytePtr(itemData
) : NULL
), 
2378                 keychain
, NULL
, &newItem
); 
2379         if (status
) { secitemlog(priority
, format
, 7, (int)status
); } 
2380         require_noerr(status
, replace_failed
); 
2382         // delete the old item unconditionally once new item exists 
2383         status 
= SecKeychainItemDelete(itemToUpdate
); 
2385         // update the new item with changed attributes, if any 
2386         status 
= (changeAttrList
) ? SecKeychainItemModifyContent(newItem
, changeAttrList
, 0, NULL
) : errSecSuccess
; 
2387         if (status
) { secitemlog(priority
, format
, 8, (int)status
); } 
2388         if (status 
== errSecSuccess
) { 
2389                 // say the item already exists, because it does now. <rdar://19063674> 
2390                 status 
= errSecDuplicateItem
; 
2394         if (newAttrList
.attr
) { 
2395                 free(newAttrList
.attr
); 
2398         SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
2401         SecKeychainFreeAttributeInfo(info
); 
2403         CFReleaseSafe(newItem
); 
2404         CFReleaseSafe(keychain
); 
2410 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
) 
2412         // This function updates a single keychain item, which may be specified as 
2413         // a reference, persistent reference or attribute dictionary, with the 
2414         // attributes provided. 
2416         OSStatus status 
= errSecSuccess
; 
2421         SecItemClass itemClass 
= (SecItemClass
) 0; 
2422         SecAccessRef access 
= NULL
; 
2423         SecKeychainAttributeList 
*changeAttrList 
= NULL
; 
2424         SecKeychainItemRef itemToUpdate 
= NULL
; 
2425         CFDataRef theData 
= NULL
; 
2426         CFTypeID itemType 
= CFGetTypeID(item
); 
2428         // validate input item (must be convertible to a SecKeychainItemRef) 
2429         if (SecKeychainItemGetTypeID() == itemType 
|| 
2430                 SecCertificateGetTypeID() == itemType 
|| 
2431                 SecKeyGetTypeID() == itemType
) { 
2432                 // item is already a reference, retain it 
2433                 itemToUpdate 
= (SecKeychainItemRef
) CFRetain(item
); 
2435         else if (CFDataGetTypeID() == itemType
) { 
2436                 // item is a persistent reference, must convert it 
2437                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
); 
2439         else if (CFDictionaryGetTypeID() == itemType
) { 
2440                 // item is a dictionary 
2441                 CFTypeRef value 
= NULL
; 
2442                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2443                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2444                         itemToUpdate 
= (SecKeychainItemRef
) CFRetain(value
); 
2446                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2447                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2448                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
); 
2451         else if (SecIdentityGetTypeID() == itemType
) { 
2452                 // item is a certificate + private key; since we can't really change the 
2453                 // certificate's attributes, assume we want to update the private key 
2454                 status 
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
); 
2456         require_action(itemToUpdate 
!= NULL
, update_failed
, status 
= errSecInvalidItemRef
); 
2457         require_noerr(status
, update_failed
); 
2459         status 
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
); 
2460         require_noerr(status
, update_failed
); 
2462         // build changeAttrList from changedAttributes dictionary 
2465                 case kSecInternetPasswordItemClass
: 
2467                         status 
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2468                         require_noerr(status
, update_failed
); 
2472                 case kSecGenericPasswordItemClass
: 
2474                         status 
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2475                         require_noerr(status
, update_failed
); 
2479                 case kSecCertificateItemClass
: 
2481                         status 
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2482                         require_noerr(status
, update_failed
); 
2486                 case kSecPublicKeyItemClass
: 
2487                 case kSecPrivateKeyItemClass
: 
2488                 case kSecSymmetricKeyItemClass
: 
2490                         status 
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2491                         require_noerr(status
, update_failed
); 
2494                 case kSecAppleSharePasswordItemClass
: 
2496                         // do nothing (legacy behavior). 
2503         // (if the caller is not updating the password, this value will be NULL) 
2504         theData 
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
); 
2505         if (theData 
!= NULL
) { 
2506                 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status 
= errSecParam
); 
2509         status 
= SecKeychainItemModifyContent(itemToUpdate
, 
2510                                 (!changeAttrList 
|| changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2511                                 (theData 
!= NULL
) ? (UInt32
)CFDataGetLength(theData
) : 0, 
2512                                 (theData 
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
); 
2513         require_noerr(status
, update_failed
); 
2515         // one more thing... update access? 
2516         if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) { 
2517                 status 
= SecKeychainItemSetAccess(itemToUpdate
, access
); 
2521         if (status 
== errSecVerifyFailed 
&& 
2522                 (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2523                 // if we got a cryptographic failure updating a password item, it needs to be replaced 
2524                 status 
= _ReplaceKeychainItem(itemToUpdate
, 
2525                                         (!changeAttrList 
||  changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2529                 CFRelease(itemToUpdate
); 
2530         _FreeAttrList(changeAttrList
); 
2535 _DeleteKeychainItem(CFTypeRef item
) 
2537         // This function deletes a single keychain item, which may be specified as 
2538         // a reference, persistent reference or attribute dictionary. It will not 
2539         // delete non-keychain items or aggregate items (such as a SecIdentityRef); 
2540         // it is assumed that the caller will pass identity components separately. 
2542         OSStatus status 
= errSecSuccess
; 
2547         SecKeychainItemRef itemToDelete 
= NULL
; 
2548         CFTypeID itemType 
= CFGetTypeID(item
); 
2549         if (SecKeychainItemGetTypeID() == itemType 
|| 
2550                 SecCertificateGetTypeID() == itemType 
|| 
2551                 SecKeyGetTypeID() == itemType
) { 
2552                 // item is already a reference, retain it 
2553                 itemToDelete 
= (SecKeychainItemRef
) CFRetain(item
); 
2555         else if (CFDataGetTypeID() == itemType
) { 
2556                 // item is a persistent reference, must convert it 
2557                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
); 
2559         else if (CFDictionaryGetTypeID() == itemType
) { 
2560                 // item is a dictionary 
2561                 CFTypeRef value 
= NULL
; 
2562                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2563                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2564                         itemToDelete 
= (SecKeychainItemRef
) CFRetain(value
); 
2566                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2567                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2568                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
); 
2574                         status 
= _SafeSecKeychainItemDelete(itemToDelete
); 
2576                 CFRelease(itemToDelete
); 
2583 _DeleteIdentity(SecIdentityRef identity
) 
2585         OSStatus status
, result 
= errSecSuccess
; 
2586         SecKeyRef privateKey 
= NULL
; 
2587         SecCertificateRef certificate 
= NULL
; 
2589         status 
= SecIdentityCopyPrivateKey(identity
, &privateKey
); 
2591                 SecKeyRef publicKey 
= NULL
; 
2592                 status 
= _SecIdentityCopyPublicKey(identity
, &publicKey
); 
2594                         status 
= _DeleteKeychainItem(publicKey
); 
2595                         CFRelease(publicKey
); 
2597                 status 
= _DeleteKeychainItem(privateKey
); 
2600         if (privateKey
) CFRelease(privateKey
); 
2601         if (status
) result 
= status
; 
2603         status 
= SecIdentityCopyCertificate(identity
, &certificate
); 
2605                 status 
= _DeleteKeychainItem(certificate
); 
2608         if (certificate
) CFRelease(certificate
); 
2609         if (status
) result 
= status
; 
2615 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
) 
2617         // This function is used when atomically processing multiple items, 
2618         // where an overall error result must be returned for the entire operation. 
2619         // When newStatus is something other than errSecSuccess, we want to keep the "most 
2620         // interesting" status (which usually will be newStatus, unless curStatus is 
2621         // already set; in that case, newStatus can trump curStatus only by being 
2622         // something different than baseStatus.) 
2624         OSStatus result 
= curStatus
; 
2626         if (newStatus 
!= errSecSuccess
) { 
2628                 if (curStatus 
!= errSecSuccess
) { 
2629                         result 
= (newStatus 
!= baseStatus
) ? newStatus 
: curStatus
; 
2636 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
) 
2638         // CFDictionaryApplierFunction 
2639         // This function just takes the given key/value pair, 
2640         // and adds it to another dictionary supplied in the context argument. 
2642         CFMutableDictionaryRef dict 
= *((CFMutableDictionaryRef
*) context
); 
2644                 CFDictionaryAddValue(dict
, key
, value
); 
2648 static CFStringCompareFlags
 
2649 _StringCompareFlagsFromQuery(CFDictionaryRef query
) 
2652         CFStringCompareFlags flags 
= 0; 
2653         if (!query
) return flags
; 
2655         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) || 
2656                 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2657                 flags 
|= kCFCompareAnchored
; 
2659         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2660                 flags 
|= kCFCompareBackwards
; 
2662         if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2663                 flags 
|= kCFCompareCaseInsensitive
; 
2665         if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2666                 flags 
|= kCFCompareDiacriticInsensitive
; 
2668         if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2669                 flags 
|= kCFCompareWidthInsensitive
; 
2675 _CssmKeyUsageFromQuery(CFDictionaryRef query
) 
2678         uint32 keyUsage 
= 0; 
2679         if (!query
) return keyUsage
; 
2681         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2682                 keyUsage 
|= CSSM_KEYUSE_ENCRYPT
; 
2684         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2685                 keyUsage 
|= CSSM_KEYUSE_DECRYPT
; 
2687         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2688                 keyUsage 
|= CSSM_KEYUSE_SIGN
; 
2690         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2691                 keyUsage 
|= CSSM_KEYUSE_VERIFY
; 
2693         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2694                 keyUsage 
|= CSSM_KEYUSE_WRAP
; 
2696         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2697                 keyUsage 
|= CSSM_KEYUSE_UNWRAP
; 
2699         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2700                 keyUsage 
|= CSSM_KEYUSE_DERIVE
; 
2706 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean 
*isIdentity
) 
2708         SecItemClass itemClass 
= (SecItemClass
) 0; 
2709         if (isIdentity
) *isIdentity 
= false; 
2711         if (CFEqual(item
, kSecClassGenericPassword
)) { 
2712                 itemClass 
= kSecGenericPasswordItemClass
; 
2714         else if (CFEqual(item
, kSecClassInternetPassword
)) { 
2715                 itemClass 
= kSecInternetPasswordItemClass
; 
2717         else if (CFEqual(item
, kSecClassCertificate
)) { 
2718                 itemClass 
= kSecCertificateItemClass
; 
2720         else if (CFEqual(item
, kSecClassIdentity
)) { 
2721                 // will perform a certificate lookup 
2722                 itemClass 
= kSecCertificateItemClass
; 
2723                 if (isIdentity
) *isIdentity 
= true; 
2725         else if (CFEqual(item
, kSecClassKey
)) { 
2726                 // examine second parameter to determine type of key 
2727                 if (!keyClass 
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) { 
2728                         itemClass 
= kSecSymmetricKeyItemClass
; 
2730                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) { 
2731                         itemClass 
= kSecPublicKeyItemClass
; 
2733                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) { 
2734                         itemClass 
= kSecPrivateKeyItemClass
; 
2742 _ItemClassFromItemList(CFArrayRef itemList
) 
2744         // Given a list of items (standard or persistent references), 
2745         // determine whether they all have the same item class. Returns 
2746         // the item class, or 0 if multiple classes in list. 
2747         SecItemClass result 
= (SecItemClass
) 0; 
2748         CFIndex index
, count 
= (itemList
) ? CFArrayGetCount(itemList
) : 0; 
2749         for (index
=0; index 
< count
; index
++) { 
2750                 CFTypeRef item 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemList
, index
); 
2752                         SecKeychainItemRef itemRef 
= NULL
; 
2754                         if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
2755                                 // persistent reference, resolve first 
2756                                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemRef
); 
2759                                 itemRef 
= (SecKeychainItemRef
) CFRetain(item
); 
2762                                 SecItemClass itemClass 
= (SecItemClass
) 0; 
2763                                 CFTypeID itemTypeID 
= CFGetTypeID(itemRef
); 
2764                                 if (itemTypeID 
== SecIdentityGetTypeID() || itemTypeID 
== SecCertificateGetTypeID()) { 
2765                                         // Identities and certificates have the same underlying item class 
2766                                         itemClass 
= kSecCertificateItemClass
; 
2768                                 else if (itemTypeID 
== SecKeychainItemGetTypeID()) { 
2769                                         // Reference to item in a keychain 
2770                                         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2772                                 else if (itemTypeID 
== SecKeyGetTypeID()) { 
2773                                         // SecKey that isn't stored in a keychain 
2774                                         // %%% will need to change this code when SecKey is no longer CSSM-based %%% 
2775                                         const CSSM_KEY 
*cssmKey
; 
2776                                         status 
= SecKeyGetCSSMKey((SecKeyRef
)itemRef
, &cssmKey
); 
2777                                         if (status 
== errSecSuccess
) { 
2778                                                 if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) 
2779                                                         itemClass 
= kSecPublicKeyItemClass
; 
2780                                                 else if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY
) 
2781                                                         itemClass 
= kSecPrivateKeyItemClass
; 
2783                                                         itemClass 
= kSecSymmetricKeyItemClass
; 
2787                                 if (itemClass 
!= 0) { 
2788                                         if (result 
!= 0 && result 
!= itemClass
) { 
2789                                                 return (SecItemClass
) 0; // different item classes in list; bail out 
2799 // SecItemParams contains a validated set of input parameters, as well as a 
2800 // search reference and attribute list built from those parameters. It is 
2801 // designed to be allocated with _CreateSecItemParamsFromDictionary, and 
2802 // freed with _FreeSecItemParams. 
2804 struct SecItemParams 
{ 
2805         CFDictionaryRef query
;                          // caller-supplied query 
2806         int numResultTypes
;                                     // number of result types requested 
2807         int maxMatches
;                                         // max number of matches to return 
2808         uint32 keyUsage
;                                        // key usage(s) requested 
2809         Boolean returningAttributes
;            // true if returning attributes dictionary 
2810         Boolean returningData
;                          // true if returning item's data 
2811         Boolean returningRef
;                           // true if returning item reference 
2812         Boolean returningPersistentRef
;         // true if returing a persistent reference 
2813         Boolean returnAllMatches
;                       // true if we should return all matches 
2814         Boolean returnIdentity
;                         // true if we are returning a SecIdentityRef 
2815         Boolean trustedOnly
;                            // true if we only return trusted certs 
2816         Boolean issuerAndSNToMatch
;                     // true if both issuer and SN were provided 
2817         SecItemClass itemClass
;                         // item class for this query 
2818         SecPolicyRef policy
;                            // value for kSecMatchPolicy (may be NULL) 
2819         SecKeychainRef keychain
;                        // value for kSecUseKeychain (may be NULL) 
2820         CFArrayRef useItems
;                            // value for kSecUseItemList (may be NULL) 
2821         CFArrayRef itemList
;                            // value for kSecMatchItemList (may be NULL) 
2822         CFTypeRef searchList
;                           // value for kSecMatchSearchList (may be NULL) 
2823         CFTypeRef matchLimit
;                           // value for kSecMatchLimit (may be NULL) 
2824         CFTypeRef emailAddrToMatch
;                     // value for kSecMatchEmailAddressIfPresent (may be NULL) 
2825         CFTypeRef validOnDate
;                          // value for kSecMatchValidOnDate (may be NULL) 
2826         CFTypeRef keyClass
;                                     // value for kSecAttrKeyClass (may be NULL) 
2827         CFTypeRef service
;                                      // value for kSecAttrService (may be NULL) 
2828         CFTypeRef issuer
;                                       // value for kSecAttrIssuer (may be NULL) 
2829         CFTypeRef matchIssuers
;                                 // value for kSecMatchIssuers (may be NULL) 
2830         CFTypeRef serialNumber
;                         // value for kSecAttrSerialNumber (may be NULL) 
2831         CFTypeRef search
;                                       // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) 
2832         CFTypeRef assumedKeyClass
;                      // if no kSecAttrKeyClass provided, holds the current class we're searching for 
2833         CFIndex itemListIndex
;                          // if no search reference but we have itemList, holds index of next item to return 
2834         SecKeychainAttributeList 
*attrList
;     // attribute list for this query 
2835         SecAccessRef access
;                            // access reference (for SecItemAdd only, not used to find items) 
2836         CFDataRef itemData
;                                     // item data (for SecItemAdd only, not used to find items) 
2837         CFTypeRef itemRef
;                                      // item reference (to find, add, update or delete, depending on context) 
2838         SecIdentityRef identityRef
;                     // identity reference (input as kSecValueRef) 
2839         CFDataRef itemPersistentRef
;            // item persistent reference (to find, add, update or delete, depending on context) 
2840         Boolean isPCSItem
;                                      // true if this query is for a Protected Cloud Storage item 
2844 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
) 
2846         if (!dict 
|| !key 
|| !value 
|| !expectedTypeID
) 
2849         if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) { 
2850                 // value was not provided for this key (not an error!) 
2853         else if (!(*value
)) { 
2854                 // provided value is NULL (also not an error!) 
2855                 return errSecSuccess
; 
2858                 CFTypeID actualTypeID 
= CFGetTypeID(*value
); 
2859                 if (!((expectedTypeID 
== actualTypeID
) || (altTypeID 
&& altTypeID 
== actualTypeID
))) { 
2860                         // provided value does not have the expected (or alternate) CF type ID 
2861                         if ((expectedTypeID 
== SecKeychainItemGetTypeID()) && 
2862                                 (actualTypeID 
== SecKeyGetTypeID() || actualTypeID 
== SecCertificateGetTypeID())) { 
2863                                 // provided value is a "floating" reference which is not yet in a keychain 
2865                                 return errSecSuccess
; 
2867                         return errSecItemInvalidValue
; 
2870                         // provided value is OK; retain it 
2874         return errSecSuccess
; 
2878 _EnsureUserDefaultKeychainIsSearched(SecItemParams 
*itemParams
) 
2881         CFArrayRef tmpList 
= (CFArrayRef
) itemParams
->searchList
; 
2883                 // search list exists; make it mutable 
2884                 itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2887                 // no search list; start with default list 
2888                 status 
= SecKeychainCopySearchList(&tmpList
); 
2889                 if (!status 
&& tmpList
) { 
2890                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2894                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2898         SecKeychainRef userKeychain 
= NULL
; 
2899         status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2900         if (!status 
&& userKeychain
) { 
2901                 if (!CFArrayContainsValue((CFArrayRef
)itemParams
->searchList
, 
2902                         CFRangeMake(0, CFArrayGetCount((CFArrayRef
)itemParams
->searchList
)), userKeychain
)) { 
2903                         // user's default keychain isn't currently in the search list, so append it 
2904                         CFArrayAppendValue((CFMutableArrayRef
)itemParams
->searchList
, userKeychain
); 
2906                 CFRelease(userKeychain
); 
2911 _EnsureUserDefaultKeychainIsTargeted(SecItemParams 
*itemParams
) 
2913         if (itemParams
->keychain
) { 
2914                 return; // keychain is already explicitly specified, assume it's correct 
2916         SecKeychainRef userKeychain 
= NULL
; 
2917         OSStatus status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2918         if (!status 
&& userKeychain
) { 
2919                 itemParams
->keychain 
= userKeychain
; 
2924 _FreeSecItemParams(SecItemParams 
*itemParams
) 
2929         if (itemParams
->query
) CFRelease(itemParams
->query
); 
2930         if (itemParams
->policy
) CFRelease(itemParams
->policy
); 
2931         if (itemParams
->keychain
) CFRelease(itemParams
->keychain
); 
2932         if (itemParams
->useItems
) CFRelease(itemParams
->useItems
); 
2933         if (itemParams
->itemList
) CFRelease(itemParams
->itemList
); 
2934         if (itemParams
->searchList
) CFRelease(itemParams
->searchList
); 
2935         if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
); 
2936         if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
); 
2937         if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
); 
2938         if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
); 
2939         if (itemParams
->service
) CFRelease(itemParams
->service
); 
2940         if (itemParams
->issuer
) CFRelease(itemParams
->issuer
); 
2941         if (itemParams
->matchIssuers
) CFRelease(itemParams
->matchIssuers
); 
2942         if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
); 
2943         if (itemParams
->search
) CFRelease(itemParams
->search
); 
2944         if (itemParams
->access
) CFRelease(itemParams
->access
); 
2945         if (itemParams
->itemData
) CFRelease(itemParams
->itemData
); 
2946         if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
); 
2947         if (itemParams
->identityRef
) CFRelease(itemParams
->identityRef
); 
2948         if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
); 
2950         _FreeAttrList(itemParams
->attrList
); 
2955 static SecItemParams
* 
2956 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus 
*error
) 
2959         CFTypeRef value 
= NULL
; 
2960     CFDictionaryRef policyDict 
= NULL
; 
2961         SecItemParams 
*itemParams 
= (SecItemParams 
*)calloc(1, sizeof(struct SecItemParams
)); 
2963         require_action(itemParams 
!= NULL
, error_exit
, status 
= errSecAllocate
); 
2964         require_action(dict 
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status 
= errSecParam
); 
2966         itemParams
->query 
= (CFDictionaryRef
) CFRetain(dict
); 
2968         // validate input search parameters 
2969         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
); 
2970         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2971         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2972         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
2973         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
); 
2974         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
); 
2976         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
); 
2977         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
); 
2979         // validate a subset of input attributes (used to create an appropriate search reference) 
2980         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
); 
2981         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
); 
2982         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
); 
2983         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
); 
2985         if (itemParams
->service 
&& CFStringHasPrefix((CFStringRef
)itemParams
->service
, CFSTR("ProtectedCloudStorage"))) { 
2986                 itemParams
->isPCSItem 
= true; 
2987                 if (!SecItemSynchronizable(dict
)) { 
2988                         _EnsureUserDefaultKeychainIsSearched(itemParams
); // for SecItemCopyMatching, SecItemUpdate, SecItemDelete 
2989                         _EnsureUserDefaultKeychainIsTargeted(itemParams
); // for SecItemAdd 
2993         // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items 
2994         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
); 
2995         if (itemParams
->itemData 
&& CFGetTypeID(itemParams
->itemData
) == CFStringGetTypeID()) { 
2996                 /* If we got a string, convert it into a data object */ 
2997                 CFStringRef string 
= (CFStringRef
)itemParams
->itemData
; 
2998                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(string
), kCFStringEncodingUTF8
) + 1; 
2999                 CFMutableDataRef data 
= CFDataCreateMutable(NULL
, maxLength
); 
3000                 require_action(data
, error_exit
, status 
= errSecAllocate
); 
3002                 CFDataSetLength(data
, maxLength
); 
3004                 if (!CFStringGetCString(string
, (char *)CFDataGetMutableBytePtr(data
), maxLength
, kCFStringEncodingUTF8
)) { 
3006                         status 
= errSecAllocate
; 
3010                 CFDataSetLength(data
, strlen((const char *)CFDataGetBytePtr(data
))); /* dont include NUL in string */ 
3011                 itemParams
->itemData 
= data
; 
3015         // validate item references 
3016         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit
); 
3017         if (itemParams
->itemRef 
&& (CFGetTypeID(itemParams
->itemRef
) == SecIdentityGetTypeID())) { 
3018                 itemParams
->identityRef 
= (SecIdentityRef
)itemParams
->itemRef
; 
3019                 itemParams
->itemRef 
= NULL
; 
3020                 SecIdentityCopyCertificate(itemParams
->identityRef
, (SecCertificateRef 
*)&itemParams
->itemRef
); 
3022         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
); 
3023         if (itemParams
->itemRef 
|| itemParams
->itemPersistentRef
) { 
3024                 // Caller is trying to add or find an item by reference. 
3025                 // The supported method for doing that is to provide a kSecUseItemList array 
3026                 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al, 
3027                 // so add the item reference to those arrays here. 
3028                 if (itemParams
->useItems
) { 
3029                         CFArrayRef tmpItems 
= itemParams
->useItems
; 
3030                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3031                         CFRelease(tmpItems
); 
3033                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3035                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
); 
3036                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
); 
3038                 if (itemParams
->itemList
) { 
3039                         CFArrayRef tmpItems 
= itemParams
->itemList
; 
3040                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3041                         CFRelease(tmpItems
); 
3043                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3045                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
); 
3046                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
); 
3049         // must have an explicit item class, unless one of the following is true: 
3050         //   - we have an item list to add or search (kSecUseItemList) 
3051         //   - we have an item reference or persistent reference for the thing we want to look up 
3052         // Note that both of these cases will set itemParams->useItems. 
3053         // If we have an item list to match (kSecMatchItemList), that still requires an item class, 
3054         // so we can perform a search and see if the results match items in the list. 
3056         if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
) { 
3057                 require_action(false, error_exit
, status 
= errSecItemClassMissing
); 
3060                 itemParams
->itemClass 
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
); 
3061                 if (itemParams
->itemClass 
== kSecSymmetricKeyItemClass 
&& !itemParams
->keyClass
) { 
3062             // no key class specified, so start with symmetric key class; will search the others later in UpdateKeychainSearchAndCopyNext 
3063             itemParams
->itemClass 
= kSecSymmetricKeyItemClass
; 
3064             itemParams
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3066                 require_action(!(itemParams
->itemClass 
== 0 && !itemParams
->useItems
), error_exit
, status 
= errSecItemClassMissing
); 
3069     // kSecMatchIssuers is only permitted with identities or certificates. 
3070     // Convert the input issuers to normalized form. 
3071     require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchIssuers
, (const void **)&itemParams
->matchIssuers
, CFArrayGetTypeID(), NULL
), error_exit
); 
3072     if (itemParams
->matchIssuers
) { 
3073         CFTypeRef allowCerts 
= CFDictionaryGetValue(itemParams
->query
, kSecUseCertificatesWithMatchIssuers
); 
3074         require_action(itemParams
->returnIdentity 
|| (allowCerts 
&& CFEqual(allowCerts
, kCFBooleanTrue
)), error_exit
, status 
= errSecParam
); 
3075         CFMutableArrayRef canonical_issuers 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3076         CFArrayRef issuers 
= (CFArrayRef
)itemParams
->matchIssuers
; 
3077         if (canonical_issuers
) { 
3078             CFIndex i
, count 
= CFArrayGetCount(issuers
); 
3079             for (i 
= 0; i 
< count
; i
++) { 
3080                 CFTypeRef issuer_data 
= CFArrayGetValueAtIndex(issuers
, i
); 
3081                 CFDataRef issuer_canonical 
= NULL
; 
3082                 if (CFDataGetTypeID() == CFGetTypeID(issuer_data
)) 
3083                     issuer_canonical 
= SecDistinguishedNameCopyNormalizedSequence((CFDataRef
)issuer_data
); 
3084                 if (issuer_canonical
) { 
3085                     CFArrayAppendValue(canonical_issuers
, issuer_canonical
); 
3086                     CFRelease(issuer_canonical
); 
3089             if (CFArrayGetCount(canonical_issuers
) > 0) { 
3090                 CFAssignRetained(itemParams
->matchIssuers
, canonical_issuers
); 
3092                 CFRelease(canonical_issuers
); 
3096         itemParams
->keyUsage 
= _CssmKeyUsageFromQuery(dict
); 
3097         itemParams
->trustedOnly 
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3098         itemParams
->issuerAndSNToMatch 
= (itemParams
->issuer 
!= NULL 
&& itemParams
->serialNumber 
!= NULL
); 
3100         // other input attributes, used for SecItemAdd but not for finding items 
3101         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3102         if (itemParams
->access 
== NULL
) { 
3103                 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>) 
3104                 require_noerr(status 
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3107         // determine how to return the result 
3108         itemParams
->numResultTypes 
= 0; 
3109         itemParams
->returningRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3110         if (itemParams
->returningRef
) ++itemParams
->numResultTypes
; 
3111         itemParams
->returningPersistentRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3112         if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
; 
3113         itemParams
->returningAttributes 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3114         if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
; 
3115         itemParams
->returningData 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3116         if (itemParams
->returningData
) ++itemParams
->numResultTypes
; 
3118         // default is kSecReturnRef if no result types were specified 
3119         if (!itemParams
->numResultTypes
) { 
3120                 itemParams
->returningRef 
= TRUE
; 
3121                 itemParams
->numResultTypes 
= 1; 
3124         // determine if one, some or all matches should be returned (default is kSecMatchLimitOne) 
3125         itemParams
->maxMatches 
= 1; 
3126         itemParams
->returnAllMatches 
= FALSE
; 
3127         if (itemParams
->matchLimit
) { 
3128                 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3129                         itemParams
->returnAllMatches 
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
); 
3131                 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3132                         CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
); 
3133                         require_action(!(itemParams
->maxMatches 
< 0), error_exit
, status 
= errSecMatchLimitUnsupported
); 
3136         if (itemParams
->returnAllMatches
) { 
3137                 itemParams
->maxMatches 
= INT32_MAX
; 
3138                 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each) 
3139                 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass 
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
) 
3140                         status 
= errSecReturnDataUnsupported
; 
3141                 require_noerr(status
, error_exit
); 
3144     // if we already have an item list (to add or find items in), we don't need a search reference 
3145         if (itemParams
->useItems
) { 
3146                 if (itemParams
->itemClass 
== 0) { 
3147                         itemParams
->itemClass 
= _ItemClassFromItemList(itemParams
->useItems
); 
3150         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3151         if (itemParams
->itemClass 
!= 0) { 
3152             status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
); 
3154             status 
= errSecSuccess
; 
3156                 goto error_exit
; // all done here 
3159         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3160         require_noerr(status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
); 
3162     // if policy is a SMIME policy, copy email address in policy into emailAddrToMatch parameter 
3163     if(itemParams
->policy
) { 
3164         policyDict 
= SecPolicyCopyProperties(itemParams
->policy
); 
3165         CFStringRef oidStr 
= (CFStringRef
) CFDictionaryGetValue(policyDict
, kSecPolicyOid
); 
3166         if(oidStr 
&& CFStringCompare(kSecPolicyAppleSMIME
,oidStr
,0) == 0) { 
3167             require_noerr(status 
= _ValidateDictionaryEntry(policyDict
, kSecPolicyName
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
3169         CFReleaseNull(policyDict
); 
3172         // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) 
3173         if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) { 
3174                 // searching for certificates by email address 
3175                 char *nameBuf 
= (char*)malloc(MAXPATHLEN
); 
3177                         status 
= errSecAllocate
; 
3179                 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) { 
3180                         status 
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
); 
3183                         status 
= errSecItemInvalidValue
; 
3185                 if (nameBuf
) free(nameBuf
); 
3187         else if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) { 
3188                 // searching for certificates by issuer and serial number 
3189                 status 
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
, 
3190                                 (CFDataRef
)itemParams
->issuer
, 
3191                                 (CFDataRef
)itemParams
->serialNumber
, 
3192                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3194         else if (itemParams
->returnIdentity 
&& itemParams
->policy
) { 
3195                 // searching for identities by policy 
3196                 status 
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
, 
3197                                 (CFStringRef
)itemParams
->service
, 
3198                                 itemParams
->keyUsage
, 
3199                                 itemParams
->searchList
, 
3200                                 itemParams
->trustedOnly
, 
3201                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3203         else if (itemParams
->returnIdentity
) { 
3204                 // searching for identities 
3205                 status 
= SecIdentitySearchCreate(itemParams
->searchList
, 
3206                                 itemParams
->keyUsage
, 
3207                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3210                 // normal keychain item search 
3211                 status 
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
, 
3212                                 itemParams
->itemClass
, 
3213                                 (itemParams
->attrList
->count 
== 0) ? NULL 
: itemParams
->attrList
, 
3214                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3218     CFReleaseNull(policyDict
); 
3220                 _FreeSecItemParams(itemParams
); 
3233         SecKeychainRef keychainRef
, 
3234         SecAccessRef accessRef
, 
3235         SecKeychainAttributeList 
*attrList
, 
3236         SecKeychainItemRef 
*outItemRef
) 
3240                 // We must specify the access, since a free-floating key won't have one yet by default 
3241                 SecPointer
<Access
> access
; 
3243                         access 
= Access::required(accessRef
); 
3246                         CFStringRef descriptor 
= NULL
; 
3248                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
3249                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
3250                                         if (attr
.tag 
== kSecKeyPrintName
) { 
3251                                                 descriptor 
= CFStringCreateWithBytes(NULL
, (const UInt8 
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
); 
3256                         if (descriptor 
== NULL
) { 
3257                                 descriptor 
= (CFStringRef
) CFRetain(CFSTR("<unknown>")); 
3259                         access 
= new Access(cfString(descriptor
)); 
3260                         CFRelease(descriptor
); 
3263                 KeyItem 
*key 
= KeyItem::required(keyRef
); 
3264                 Item item 
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
); 
3266                         *outItemRef 
= item
->handle(); 
3272 _FilterWithPolicy(SecPolicyRef policy
, CFDateRef date
, SecCertificateRef cert
) 
3274         CFDictionaryRef props 
= NULL
; 
3275         CFArrayRef keychains 
= NULL
; 
3276         CFArrayRef anchors 
= NULL
; 
3277         CFArrayRef certs 
= NULL
; 
3278         CFArrayRef chain 
= NULL
; 
3279         SecTrustRef trust 
= NULL
; 
3281         SecTrustResultType      trustResult
; 
3282         Boolean needChain 
= false; 
3283         Boolean needCSEKU 
= false; 
3285         if (!policy 
|| !cert
) return errSecParam
; 
3287         certs 
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
); 
3288         status 
= SecTrustCreateWithCertificates(certs
, policy
, &trust
); 
3289         if(status
) goto cleanup
; 
3291         /* Set evaluation date, if specified (otherwise current date is implied) */ 
3292         if (date 
&& (CFGetTypeID(date
) == CFDateGetTypeID())) { 
3293                 status 
= SecTrustSetVerifyDate(trust
, date
); 
3294                 if(status
) goto cleanup
; 
3297         /* Check whether we can avoid full chain evaluation, based on policy */ 
3298         props 
= SecPolicyCopyProperties(policy
); 
3300                 CFTypeRef oid 
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
); 
3301                 if (oid 
&& (CFEqual(oid
, kSecPolicyAppleX509Basic
) || 
3302                             CFEqual(oid
, kSecPolicyAppleRevocation
))) { 
3304                 } else if (oid 
&& (CFEqual(oid
, kSecPolicyAppleCodeSigning
))) { 
3309         /* If a code signing EKU purpose is needed, filter out certs without it here 
3310            to reduce log noise associated with evaluation failures. */ 
3312                 CFDataRef eku 
= CFDataCreate(kCFAllocatorDefault
, 
3313                                              oidExtendedKeyUsageCodeSigning
.data
, 
3314                                              oidExtendedKeyUsageCodeSigning
.length
); 
3316                         if (!SecPolicyCheckCertExtendedKeyUsage(cert
, eku
)) { 
3322                         status 
= errSecCertificateCannotOperate
; 
3328                 status 
= SecTrustEvaluateLeafOnly(trust
, &trustResult
); 
3330                 status 
= SecTrustEvaluate(trust
, &trustResult
); 
3333         if (!(trustResult 
== kSecTrustResultProceed 
|| 
3334                   trustResult 
== kSecTrustResultUnspecified 
|| 
3335                   trustResult 
== kSecTrustResultRecoverableTrustFailure
)) { 
3336                 /* The evaluation failed in a non-recoverable way */ 
3337                 status 
= errSecCertificateCannotOperate
; 
3341         /* If there are no per-cert policy status codes, 
3342          * and the cert has not expired, consider it valid for the policy. 
3345                 (void)SecTrustGetCssmResultCode(trust
, &status
); 
3349         if(props
) CFRelease(props
); 
3350         if(chain
) CFRelease(chain
); 
3351         if(anchors
) CFRelease(anchors
); 
3352         if(keychains
) CFRelease(keychains
); 
3353         if(certs
) CFRelease(certs
); 
3354         if(trust
) CFRelease(trust
); 
3360 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
) 
3362         if (!validOnDate 
|| !cert
) return errSecParam
; 
3364         CFAbsoluteTime at
, nb
, na
; 
3365         if (CFGetTypeID(validOnDate
) == CFDateGetTypeID()) 
3366                 at 
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
); 
3368                 at 
= CFAbsoluteTimeGetCurrent(); 
3370         OSStatus status 
= errSecSuccess
; 
3371         nb 
= SecCertificateNotValidBefore(cert
); 
3372         na 
= SecCertificateNotValidAfter(cert
); 
3374         if (nb 
== 0 || na 
== 0 || nb 
== na
) 
3375                 status 
= errSecCertificateCannotOperate
; 
3377                 status 
= errSecCertificateNotValidYet
; 
3379                 status 
= errSecCertificateExpired
; 
3385 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
) 
3387         if (!cert
) return errSecParam
; 
3388         if (!trustedOnly
) return errSecSuccess
; 
3390         CFArrayRef certArray 
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
); 
3391         SecPolicyRef policy 
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
); 
3392         OSStatus status 
= (policy 
== NULL
) ? errSecPolicyNotFound 
: errSecSuccess
; 
3395                 SecTrustRef trust 
= NULL
; 
3396                 status 
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
); 
3398                         SecTrustResultType trustResult
; 
3399                         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3401                                 if (!(trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
)) { 
3402                                         status 
= (trustResult 
== kSecTrustResultDeny
) ? errSecTrustSettingDeny 
: errSecNotTrusted
; 
3410                 CFRelease(certArray
); 
3416 static bool items_matching_issuer_parent(CFDataRef issuer
, CFArrayRef issuers
, int recurse
) { 
3417     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) { return false; } 
3419     /* We found a match, we're done. */ 
3420     if (CFArrayContainsValue(issuers
, CFRangeMake(0, CFArrayGetCount(issuers
)), issuer
)) { return true; } 
3422     /* Prevent infinite recursion */ 
3423     if (recurse 
<= 0) { return false; } 
3426     /* Query for parents */ 
3427     CFMutableDictionaryRef query 
= NULL
; 
3428     CFTypeRef parents 
= NULL
; 
3431     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 4, &kCFTypeDictionaryKeyCallBacks
, 
3432                                       &kCFTypeDictionaryValueCallBacks
), out
); 
3433     CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
3434     CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
); 
3435     CFDictionaryAddValue(query
, kSecAttrSubject
, issuer
); 
3436     CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
3437     require_noerr_quiet(SecItemCopyMatching(query
, &parents
), out
); 
3439     if (parents 
&& CFArrayGetTypeID() == CFGetTypeID(parents
)) { 
3440         CFIndex i
, count 
= CFArrayGetCount((CFArrayRef
)parents
); 
3441         for (i 
= 0; i 
< count
; i
++) { 
3442             SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)parents
, i
); 
3443             CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3444             if (CFEqual(cert_issuer
, issuer
)) { 
3445                 // Self-issued cert, don't look for parents. 
3446                 CFReleaseNull(cert_issuer
); 
3449             found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3450             CFReleaseNull(cert_issuer
); 
3451             if (found
) { break; } 
3453     } else if (parents 
&& SecCertificateGetTypeID() == CFGetTypeID(parents
)) { 
3454         SecCertificateRef cert 
= (SecCertificateRef
)parents
; 
3455         CFDataRef cert_issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3456         require_action_quiet(!CFEqual(cert_issuer
, issuer
), out
, CFReleaseNull(cert_issuer
)); 
3457         found 
= items_matching_issuer_parent(cert_issuer
, issuers
, recurse
); 
3458         CFReleaseNull(cert_issuer
); 
3462     CFReleaseNull(query
); 
3463     CFReleaseNull(parents
); 
3468 _FilterWithIssuers(CFArrayRef issuers
, SecCertificateRef cert
) 
3470     if (!issuers 
|| CFArrayGetCount(issuers
) == 0) return errSecParam
; 
3471     if (!cert
) return errSecParam
; 
3473     OSStatus status 
= errSecInternalError
; 
3475     /* kSecMatchIssuers matches certificates where ANY certificate in the chain has this issuer. 
3476      * So we now need to recursively query the keychain for this cert's parents to determine if 
3477      * they match. (This is why we limited the use of this key in _CreateSecItemParamsFromDictionary.) */ 
3478     CFDataRef issuer 
= SecCertificateCopyNormalizedIssuerSequence(cert
); 
3479     if (items_matching_issuer_parent(issuer
, issuers
, 10)) { 
3480         status 
= errSecSuccess
; 
3483     CFReleaseNull(issuer
); 
3487 static SecKeychainItemRef
 
3488 CopyResolvedKeychainItem(CFTypeRef item
) 
3490         SecKeychainItemRef kcItem 
= NULL
; 
3491         OSStatus status 
= errSecSuccess
; 
3493                 if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
3494                         // persistent reference, resolve first 
3495                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &kcItem
); 
3499                         kcItem 
= (SecKeychainItemRef
) CFRetain(item
); 
3502                         // ask for the item's class: 
3503                         // will return an error if the item has been deleted 
3504                         SecItemClass itemClass
; 
3505                         SecCertificateRef certRef 
= NULL
; 
3506                         CFTypeID itemTypeID 
= CFGetTypeID(kcItem
); 
3507                         if (itemTypeID 
== SecIdentityGetTypeID()) { 
3508                                 status 
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
, &certRef
); 
3510                         else if (itemTypeID 
== SecCertificateGetTypeID()) { 
3511                                 certRef 
= (SecCertificateRef
) CFRetain(kcItem
); 
3514                                 // can't call SecKeychainItemCopyAttributesAndData on a SecCertificateRef 
3515                                 itemClass 
= kSecCertificateItemClass
; 
3518                                 status 
= SecKeychainItemCopyAttributesAndData(kcItem
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3533 UpdateKeychainSearchAndCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3535         // This function refreshes the search parameters in the specific case where 
3536         // the caller is searching for kSecClassKey items but did not provide the 
3537         // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and 
3538         // we must perform separate searches to obtain all results. 
3540         OSStatus status 
= errSecItemNotFound
; 
3541         if (!params 
|| !params
->assumedKeyClass 
|| !params
->query 
|| !item
) 
3544         // Free the previous search reference and attribute list. 
3546                 CFRelease(params
->search
); 
3547         params
->search 
= NULL
; 
3548         _FreeAttrList(params
->attrList
); 
3549         params
->attrList 
= NULL
; 
3551         // Make a copy of the query dictionary so we can set the key class parameter. 
3552         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
); 
3553         CFRelease(params
->query
); 
3554         params
->query 
= dict
; 
3555         CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
); 
3557         // Determine the current item class for this search, and the next assumed key class. 
3558         if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) { 
3559                 params
->itemClass 
= kSecSymmetricKeyItemClass
; 
3560                 params
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3561         } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) { 
3562                 params
->itemClass 
= kSecPublicKeyItemClass
; 
3563                 params
->assumedKeyClass 
= kSecAttrKeyClassPrivate
; 
3565                 params
->itemClass 
= kSecPrivateKeyItemClass
; 
3566                 params
->assumedKeyClass 
= NULL
; 
3569         // Rebuild the attribute list for the new key class. 
3570         if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == errSecSuccess
) { 
3571                 // Create a new search reference for the new attribute list. 
3572                 if (SecKeychainSearchCreateFromAttributes(params
->searchList
, 
3574                         (params
->attrList
->count 
== 0) ? NULL 
: params
->attrList
, 
3575                         (SecKeychainSearchRef
*)¶ms
->search
) == errSecSuccess
) { 
3576                         // Return the first matching item from the new search. 
3577                         // We won't come back here again until there are no more matching items for this search. 
3578                         status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
); 
3586 SecItemSearchCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3588         // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef. 
3589         // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter, 
3590         // depending on the type of search reference. 
3593         CFTypeRef search 
= (params
) ? params
->search 
: NULL
; 
3594         CFTypeID typeID 
= (search
) ? CFGetTypeID(search
) : 0; 
3596         if (search 
&& typeID 
== SecIdentitySearchGetTypeID()) { 
3597                 status 
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
); 
3599         else if (search 
&& typeID 
== SecKeychainSearchGetTypeID()) { 
3600                 status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
); 
3601                 // Check if we need to refresh the search for the next key class 
3602                 while (status 
== errSecItemNotFound 
&& params
->assumedKeyClass 
!= NULL
) 
3603                         status 
= UpdateKeychainSearchAndCopyNext(params
, item
); 
3605         else if (typeID 
== 0 && params 
&& (params
->useItems 
|| params
->itemList
)) { 
3606                 // No search available, but there is an item list available. 
3607                 // Return the next candidate item from the caller's item list 
3608                 CFArrayRef itemList 
= (params
->useItems
) ? params
->useItems 
: params
->itemList
; 
3609                 CFIndex count 
= CFArrayGetCount(itemList
); 
3610                 *item 
= (CFTypeRef
) NULL
; 
3611                 if (params
->itemListIndex 
< count
) { 
3612                         *item 
= (CFTypeRef
)CFArrayGetValueAtIndex(itemList
, params
->itemListIndex
++); 
3614                                 // Potentially resolve persistent item references here, and 
3615                                 // verify the item reference we're about to hand back is still 
3616                                 // valid (it could have been deleted from the keychain while 
3617                                 // our query was holding onto the itemList). 
3618                                 *item 
= CopyResolvedKeychainItem(*item
); 
3619                                 if (*item 
&& (CFGetTypeID(*item
) == SecIdentityGetTypeID())) { 
3620                                         // Persistent reference resolved to an identity, so return that type. 
3621                                         params
->returnIdentity 
= true; 
3625                 status 
= (*item
) ? errSecSuccess 
: errSecItemNotFound
; 
3628                 status 
= errSecItemNotFound
; 
3634 FilterCandidateItem(CFTypeRef 
*item
, SecItemParams 
*itemParams
, SecIdentityRef 
*identity
) 
3636         if (!item 
|| *item 
== NULL 
|| !itemParams
) 
3637                 return errSecItemNotFound
; 
3640         CFStringRef commonName 
= NULL
; 
3641         SecIdentityRef foundIdentity 
= NULL
; 
3642         if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) { 
3643                 // we found a SecIdentityRef, rather than a SecKeychainItemRef; 
3644                 // replace the found "item" with its associated certificate (which is the 
3645                 // item we actually want for purposes of getting attributes, data, or a 
3646                 // persistent data reference), and return the identity separately. 
3647                 SecCertificateRef certificate
; 
3648                 status 
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
); 
3649                 if (itemParams
->returnIdentity
) { 
3650                         foundIdentity 
= (SecIdentityRef
) *item
; 
3652                                 *identity 
= foundIdentity
; 
3658                 *item 
= (CFTypeRef
)certificate
; 
3661         CFDictionaryRef query 
= itemParams
->query
; 
3663         if (itemParams
->itemClass 
== kSecCertificateItemClass
) { 
3664                 // perform string comparisons first 
3665                 CFStringCompareFlags flags 
= _StringCompareFlagsFromQuery(query
); 
3666                 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
; 
3667                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
)) 
3668                         nameContains 
= NULL
; 
3669                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
)) 
3671                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
)) 
3673                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
)) 
3675                 if (nameContains 
|| nameStarts 
|| nameEnds 
|| nameExact
) { 
3676                         status 
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
); 
3677                         if (status 
|| !commonName
) goto filterOut
; 
3680                         CFRange range 
= CFStringFind(commonName
, nameContains
, flags
); 
3681                         if (range
.length 
< 1) 
3683                         // certificate item contains string; proceed to next check 
3686                         CFRange range 
= CFStringFind(commonName
, nameStarts
, flags
); 
3687                         if (range
.length 
< 1 || range
.location 
> 1) 
3689                         // certificate item starts with string; proceed to next check 
3692                         CFRange range 
= CFStringFind(commonName
, nameEnds
, flags
); 
3693                         if (range
.length 
< 1 || range
.location 
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
))) 
3695                         // certificate item ends with string; proceed to next check 
3698                         CFRange range 
= CFStringFind(commonName
, nameExact
, flags
); 
3699                         if (range
.length 
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
))) 
3701                         // certificate item exactly matches string; proceed to next check 
3703                 if (itemParams
->returnIdentity
) { 
3704                         // if we already found and returned the identity, we can skip this 
3705                         if (!foundIdentity
) { 
3706                                 status 
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
); 
3707                                 if (status
) goto filterOut
; 
3709                         // certificate item is part of an identity; proceed to next check 
3711                 if (itemParams
->policy
) { 
3712                         status 
= _FilterWithPolicy(itemParams
->policy
, (CFDateRef
)itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3713                         if (status
) goto filterOut
; 
3714                         // certificate item is valid for specified policy (and optionally specified date) 
3716                 if (itemParams
->validOnDate
) { 
3717                         status 
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3718                         if (status
) goto filterOut
; 
3719                         // certificate item is valid for specified date 
3721                 if (itemParams
->trustedOnly
) { 
3722                         // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search, 
3723                         // their trust has already been validated and we can skip this part. 
3724                         if (!(foundIdentity 
&& itemParams
->returnIdentity 
&& itemParams
->policy
)) { 
3725                                 status 
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
); 
3726                                 if (status
) goto filterOut
; 
3728                         // certificate item is trusted on this system 
3730         if (itemParams
->matchIssuers
) { 
3731             status 
= _FilterWithIssuers((CFArrayRef
)itemParams
->matchIssuers
, (SecCertificateRef
) *item
); 
3732             if (status
) goto filterOut
; 
3733             // certificate item has one of the issuers 
3736         if (itemParams
->itemList
) { 
3737                 Boolean foundMatch 
= FALSE
; 
3738                 CFIndex idx
, count 
= CFArrayGetCount(itemParams
->itemList
); 
3739                 for (idx
=0; idx
<count
; idx
++) { 
3740                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
); 
3741                         SecKeychainItemRef realItem 
= NULL
; 
3742                         SecCertificateRef aCert 
= NULL
; 
3743                         if (anItem 
== NULL
) { 
3746                         if (CFDataGetTypeID() == CFGetTypeID(anItem
) && 
3747                                 errSecSuccess 
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) { 
3750                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) && 
3751                                 errSecSuccess 
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) { 
3754                         if (CFEqual(anItem
, (CFTypeRef
) *item
)) { 
3761                                 CFRelease(realItem
); 
3767                 if (!foundMatch
) goto filterOut
; 
3768                 // item was found on provided list 
3771         if (foundIdentity 
&& !identity
) { 
3772                 CFRelease(foundIdentity
); 
3775                 CFRelease(commonName
); 
3778         // if we get here, consider the item a match 
3779         return errSecSuccess
; 
3783                 CFRelease(commonName
); 
3787         if (foundIdentity
) { 
3788                 CFRelease(foundIdentity
); 
3793         return errSecItemNotFound
; 
3797 AddItemResults(SecKeychainItemRef item
, 
3798         SecIdentityRef identity
, 
3799         SecItemParams 
*itemParams
, 
3800         CFAllocatorRef allocator
, 
3801         CFMutableArrayRef 
*items
, 
3804         // Given a found item (which may also be an identity), this function adds 
3805         // the requested result types (specified in itemParams) to the appropriate 
3806         // container as follows: 
3808         // 1. If there is only one result type (numResultTypes == 1) and only one 
3809         //    match requested (maxMatches == 1), set *result directly. 
3811         // 2. If there are multiple result types (numResultTypes > 1), and only one 
3812         //    match requested (maxMatches == 1), add each result type to itemDict 
3813         //    and set itemDict as the value of *result. 
3815         // 3. If there is only one result type (numResultTypes == 1) and multiple 
3816         //    possible matches (maxMatches > 1), add the result type to *items 
3817         //    and set *items as the value of *result. 
3819         // 4. If there are multiple result types (numResultTypes > 1) and multiple 
3820         //    possible matches (maxMatches > 1), add each result type to itemDict, 
3821         //    add itemDict to *items, and set *items as the value of *result. 
3823         // Note that we allocate *items if needed. 
3825         if (!item 
|| !itemParams 
|| !result
) 
3828         if (itemParams
->maxMatches 
> 1) { 
3829                 // if we can return more than one item, we must have an array 
3832                 else if (*items 
== NULL
) 
3833                         *items 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
3836         OSStatus tmpStatus
, status 
= errSecSuccess
; 
3837         CFMutableArrayRef itemArray 
= (items
) ? *items 
: NULL
; 
3838         CFMutableDictionaryRef itemDict 
= NULL
; 
3839         if (itemParams
->numResultTypes 
> 1) { 
3840                 // if we're returning more than one result type, each item we return must be a dictionary 
3841                 itemDict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
3844         if (itemParams
->returningRef
) { 
3845                 const void* itemRef 
= (identity
) ? (const void*)identity 
: (const void*)item
; 
3847                         CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
); 
3849                 else if (itemArray
) { 
3850                         CFArrayAppendValue(itemArray
, itemRef
); 
3853                         *result 
= CFRetain((CFTypeRef
)itemRef
); 
3857         if (itemParams
->returningPersistentRef
) { 
3858                 CFDataRef persistentRef
; 
3859                 SecKeychainItemRef tmpItem 
= item
; 
3860                 if (itemParams
->identityRef
) { 
3861                         tmpItem 
= (SecKeychainItemRef
)itemParams
->identityRef
; 
3863                 tmpStatus 
= SecKeychainItemCreatePersistentReference(tmpItem
, &persistentRef
); 
3864                 if (tmpStatus 
== errSecSuccess
) { 
3866                                 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
); 
3868                         else if (itemArray
) { 
3869                                 CFArrayAppendValue(itemArray
, persistentRef
); 
3872                                 *result 
= CFRetain(persistentRef
); 
3874                         CFRelease(persistentRef
); 
3876                 else if (status 
== errSecSuccess
) { 
3881         if (itemParams
->returningData
) { 
3882                 // Use SecCertificateCopyData if we have a SecCertificateRef item. 
3883                 // Note that a SecCertificateRef may not actually be a SecKeychainItem, 
3884                 // in which case SecKeychainItemCopyContent will not obtain its data. 
3886                 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) { 
3887                         CFDataRef dataRef 
= SecCertificateCopyData((SecCertificateRef
)item
); 
3890                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3892                                 else if (itemArray
) { 
3893                                         CFArrayAppendValue(itemArray
, dataRef
); 
3896                                         *result 
= CFRetain(dataRef
); 
3899                                 status 
= errSecSuccess
; 
3902                                 status 
= errSecAllocate
; 
3908                         tmpStatus 
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
); 
3909                         if (tmpStatus 
== errSecSuccess
) { 
3910                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8 
*)data
, length
); 
3912                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3914                                 else if (itemArray
) { 
3915                                         CFArrayAppendValue(itemArray
, dataRef
); 
3918                                         *result 
= CFRetain(dataRef
); 
3921                                 (void) SecKeychainItemFreeContent(NULL
, data
); 
3923                         else if (status 
== errSecSuccess
) { 
3929         if (itemParams
->returningAttributes
) { 
3930                 CFDictionaryRef attrsDict 
= NULL
; 
3931                 SecItemClass itemClass
; 
3932                 // since we have an item, allow its actual class to override the query-specified item class 
3933                 tmpStatus 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3935                         itemClass 
= itemParams
->itemClass
; 
3937                 tmpStatus 
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
); 
3940                                 // add all keys and values from attrsDict to the item dictionary 
3941                                 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
); 
3943                         else if (itemArray
) { 
3944                                 CFArrayAppendValue(itemArray
, attrsDict
); 
3947                                 *result 
= CFRetain(attrsDict
); 
3949                         CFRelease(attrsDict
); 
3951                 if (tmpStatus 
&& (status 
== errSecSuccess
)) { 
3958                         CFArrayAppendValue(itemArray
, itemDict
); 
3959                         CFRelease(itemDict
); 
3960                         *result 
= itemArray
; 
3966         else if (itemArray
) { 
3967                 *result 
= itemArray
; 
3973 CFDataRef 
_SecItemGetPersistentReference(CFTypeRef raw_item
) 
3976                 Item item 
= ItemImpl::required((SecKeychainItemRef
)raw_item
); 
3977                 return item
->getPersistentRef(); 
3983 /******************************************************************************/ 
3984 #pragma mark SecItem API functions 
3985 /******************************************************************************/ 
3988 // Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error. 
3990 static SInt32 
readNumber(CFTypeRef obj
) { 
3991     CFTypeID tid 
= CFGetTypeID(obj
); 
3993     if (tid 
== CFNumberGetTypeID()) { 
3994         CFNumberGetValue((CFNumberRef
)obj
, kCFNumberSInt32Type
, &v
); 
3996     } else if (tid 
== CFBooleanGetTypeID()) { 
3997         v 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
3999     } else if (tid 
== CFStringGetTypeID()) { 
4000         v 
= CFStringGetIntValue((CFStringRef
)obj
); 
4001         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v
); 
4002         /* If a string converted to an int isn't equal to the int printed as 
4003          a string, return a CFStringRef instead. */ 
4004         if (!CFEqual(t
, obj
)) { 
4015 // Function to check whether the kSecAttrSynchronizable flag is set in the query. 
4017 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
) 
4019         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
4020         Boolean result 
= (value 
&& readNumber(value
)); 
4026 // Function to check whether a synchronizable persistent reference was provided. 
4028 static Boolean 
SecItemIsIOSPersistentReference(CFTypeRef value
) 
4031         return ::_SecItemParsePersistentRef((CFDataRef
)value
, NULL
, NULL
, NULL
); 
4036 extern "C" Boolean 
SecKeyIsCDSAKey(SecKeyRef ref
); 
4039 // Function to find out which keychains are targetted by the query. 
4041 static OSStatus 
SecItemCategorizeQuery(CFDictionaryRef query
, bool &can_target_ios
, bool &can_target_osx
, bool &useDataProtectionKeychainFlag
) 
4043         // By default, target both keychain. 
4044         can_target_osx 
= can_target_ios 
= true; 
4045     useDataProtectionKeychainFlag 
= false; 
4047         // Check no-legacy flag. 
4048     // it's iOS or bust if we're on MZ! 
4049     CFTypeRef useDataProtection 
= NULL
; 
4050     if (_CFMZEnabled()) { 
4051         useDataProtection 
= kCFBooleanTrue
; 
4054         // In case your CFDict is dumb and compares by pointer equality we check both versions of the symbol 
4055         if (!CFDictionaryGetValueIfPresent(query
, kSecUseDataProtectionKeychain
, &useDataProtection
)) { 
4056             // Ah the irony of ignoring deprecation while checking for a legacy-avoiding attribute 
4057 #pragma clang diagnostic push 
4058 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
4059             useDataProtection 
= CFDictionaryGetValue(query
, kSecAttrNoLegacy
); 
4060 #pragma clang diagnostic pop 
4064         if (useDataProtection 
!= NULL
) { 
4065         useDataProtectionKeychainFlag 
= readNumber(useDataProtection
); 
4066                 can_target_ios 
= useDataProtectionKeychainFlag
; 
4067                 can_target_osx 
= !can_target_ios
; 
4068                 return errSecSuccess
; 
4071         // Check whether the query contains kSecValueRef and modify can_ flags according to the kind and type of the value. 
4072         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecValueRef
); 
4073         if (value 
!= NULL
) { 
4074                 CFTypeID typeID 
= CFGetTypeID(value
); 
4075                 if (typeID 
== SecKeyGetTypeID()) { 
4076                         can_target_osx 
= SecKeyIsCDSAKey((SecKeyRef
)value
); 
4077                         can_target_ios 
= !can_target_osx
; 
4078                 } else if (typeID 
== SecCertificateGetTypeID()) { 
4079                         // All types of certificates can target OSX keychains, but OSX certificates won't work on iOS 
4080                         can_target_ios 
&= !SecCertificateIsItemImplInstance((SecCertificateRef
)value
); 
4081                 } else if (typeID 
== SecKeychainItemGetTypeID()) { 
4082                         // SecKeychainItemRef can target iOS keychain only when it has attached iOS-style persistent reference. 
4083                         if (_SecItemGetPersistentReference(value
) == NULL
) { 
4084                                 can_target_ios 
= false; 
4089         // Check presence of kSecAttrTokenID and kSecAttrAccessControl; they are not defined for CDSA keychain. 
4090         if (CFDictionaryContainsKey(query
, kSecAttrTokenID
) || CFDictionaryContainsKey(query
, kSecAttrAccessControl
)) { 
4091                 can_target_osx 
= false; 
4094         // Check for special token access groups.  If present, redirect query to iOS keychain. 
4095         value 
= CFDictionaryGetValue(query
, kSecAttrAccessGroup
); 
4096         if (value 
!= NULL 
&& CFEqual(value
, kSecAttrAccessGroupToken
)) { 
4097                 can_target_osx 
= false; 
4100         // Synchronizable items should go to iOS keychain only. 
4101         if (SecItemSynchronizable(query
)) { 
4102                 can_target_osx 
= false; 
4105         value 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
4106         if (value 
!= NULL
) { 
4107                 if (SecItemIsIOSPersistentReference(value
)) { 
4108                         can_target_osx 
= false; 
4110                         // Non-iOS-style persistent references should not be fed to iOS keychain queries. 
4111                         can_target_ios 
= false; 
4115         // Presence of following atributes means that query is OSX-only. 
4116         static const CFStringRef 
*osx_only_items
[] = { 
4118                 &kSecMatchSearchList
, 
4119                 &kSecMatchSubjectStartsWith
, 
4120                 &kSecMatchSubjectEndsWith
, 
4121                 &kSecMatchSubjectWholeString
, 
4122                 &kSecMatchDiacriticInsensitive
, 
4123                 &kSecMatchWidthInsensitive
, 
4132         for (CFIndex i 
= 0; i 
< array_size(osx_only_items
); i
++) { 
4133                 can_target_ios 
= can_target_ios 
&& !CFDictionaryContainsKey(query
, *osx_only_items
[i
]); 
4136     // Absence of all of kSecItemClass, kSecValuePersistentRef, and kSecValueRef means that the query can't target iOS 
4137     if(CFDictionaryGetValue(query
, kSecClass
) == NULL 
&& 
4138        CFDictionaryGetValue(query
, kSecValuePersistentRef
) == NULL 
&& 
4139        CFDictionaryGetValue(query
, kSecValueRef
) == NULL
) { 
4140         can_target_ios 
= false; 
4143         return (can_target_ios 
|| can_target_osx
) ? errSecSuccess 
: errSecParam
; 
4147 // Function to check whether the kSecAttrSynchronizable attribute is being updated. 
4149 static Boolean 
SecItemHasSynchronizableUpdate(Boolean synchronizable
, CFDictionaryRef changes
) 
4151         CFTypeRef newValue 
= CFDictionaryGetValue(changes
, kSecAttrSynchronizable
); 
4155         Boolean new_sync 
= readNumber(newValue
); 
4156         Boolean old_sync 
= synchronizable
; 
4158         return (old_sync 
!= new_sync
); 
4162 // Function to apply changes to a mutable dictionary. 
4163 // (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction) 
4165 static void SecItemApplyChanges(const void *key
, const void *value
, void *context
) 
4167         CFMutableDictionaryRef dict 
= (CFMutableDictionaryRef
) context
; 
4170         CFDictionarySetValue(dict
, key
, value
); 
4174 // Function to change matching items from non-syncable to syncable 
4175 // (if toSyncable is true), otherwise from syncable to non-syncable. 
4176 // This currently moves items between keychain containers. 
4178 static OSStatus 
SecItemChangeSynchronizability(CFDictionaryRef query
, CFDictionaryRef changes
, Boolean toSyncable
) 
4180         // Note: the input query dictionary is a mutable copy of the query originally 
4181         // provided by the caller as the first parameter to SecItemUpdate. It may not 
4182         // specify returning attributes or data, but we will need both to make a copy. 
4184         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnRef
); 
4185         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnPersistentRef
); 
4186         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnData
); 
4187         CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4188         if (NULL 
== CFDictionaryGetValue(changes
, kSecValueData
)) 
4189                 CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnData
, kCFBooleanTrue
); 
4194                 status 
= SecItemCopyMatching_osx(query
, &result
); 
4196                 status 
= SecItemCopyMatching_ios(query
, &result
); 
4201                 return errSecItemNotFound
; 
4203         CFMutableArrayRef items
; 
4204         if (CFGetTypeID(result
) != CFArrayGetTypeID()) { 
4205                 items 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4206                 CFArrayAppendValue(items
, result
); 
4210                 items 
= (CFMutableArrayRef
)result
; 
4213         CFIndex idx
, count 
= (items
) ? CFArrayGetCount(items
) : 0; 
4214         int priority 
= LOG_DEBUG
; 
4216         for (idx 
= 0; idx 
< count
; idx
++) { 
4217                 CFDictionaryRef dict 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(items
, idx
); 
4218                 CFMutableDictionaryRef item 
= (CFMutableDictionaryRef
) 
4219                         SecItemCopyTranslatedAttributes(dict
, 
4220                                 CFDictionaryGetValue(query
, kSecClass
), 
4221                                 (toSyncable
) ? true : false /*iOSOut*/, 
4222                                 true /*pruneMatch*/, 
4224                                 true /*pruneReturn*/, 
4225                                 false /*pruneData*/, 
4226                                 (toSyncable
) ? true : false /*pruneAccess*/); 
4227                 // hold onto the query before applying changes, in case the item already exists. 
4228                 // note that we cannot include the creation or modification dates from our 
4229                 // found item in this query, as they may not match the item in the other keychain. 
4230                 CFMutableDictionaryRef itemQuery 
= CFDictionaryCreateMutableCopy(NULL
, 0, item
); 
4231                 CFDictionaryRemoveValue(itemQuery
, kSecAttrCreationDate
); 
4232                 CFDictionaryRemoveValue(itemQuery
, kSecAttrModificationDate
); 
4233                 // apply changes to the item dictionary that we will pass to SecItemAdd 
4234                 CFDictionaryApplyFunction(changes
, SecItemApplyChanges
, item
); 
4236                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4237                         status 
= SecItemAdd_ios(item
, NULL
); 
4238                         secitemlog(priority
, "ChangeSync: SecItemAdd_ios=%d", status
); 
4239                         if (errSecDuplicateItem 
== status
) { 
4240                                 // find and apply changes to the existing syncable item. 
4241                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4242                                 status 
= SecItemUpdate_ios(itemQuery
, changes
); 
4243                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_ios=%d", status
); 
4245                         if (errSecSuccess 
== status
) { 
4246                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4247                                 status 
= SecItemDelete_osx(itemQuery
); 
4248                                 secitemlog(priority
, "ChangeSync: SecItemDelete_osx=%d", status
); 
4252                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4253                         status 
= SecItemAdd_osx(item
, NULL
); 
4254                         secitemlog(priority
, "ChangeSync: SecItemAdd_osx=%d", status
); 
4255                         if (errSecDuplicateItem 
== status
) { 
4256                                 // find and apply changes to the existing non-syncable item. 
4257                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4258                                 status 
= SecItemUpdate_osx(itemQuery
, changes
); 
4259                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_osx=%d", status
); 
4261                         if (errSecSuccess 
== status
) { 
4262                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4263                                 status 
= SecItemDelete_ios(itemQuery
); 
4264                                 secitemlog(priority
, "ChangeSync: SecItemDelete_ios=%d", status
); 
4267                 CFReleaseSafe(item
); 
4268                 CFReleaseSafe(itemQuery
); 
4272         CFReleaseSafe(items
); 
4281 SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes
) { 
4282         CFTypeRef ref 
= NULL
; 
4283         CFStringRef item_class_string 
= (CFStringRef
)CFDictionaryGetValue(refAttributes
, kSecClass
); 
4284         SecItemClass item_class 
= (SecItemClass
) 0; 
4286         if (CFEqual(item_class_string
, kSecClassGenericPassword
)) { 
4287                 item_class 
= kSecGenericPasswordItemClass
; 
4288         } else if (CFEqual(item_class_string
, kSecClassInternetPassword
)) { 
4289                 item_class 
= kSecInternetPasswordItemClass
; 
4292         if (item_class 
!= 0) { 
4293                 // we carry v_Data around here so the *_ios calls can find it and locate 
4294                 // their own data.   Putting things in the attribute list doesn't help as 
4295                 // the osx keychainitem and item calls bail when they don't see a keychain 
4296                 // object.   If we need to make them work we either have to bridge them, or 
4297                 // find a way to craft a workable keychain object.   #if'ed code left below 
4298                 // in case we need to go down that path. 
4300     SecKeychainAttributeList attrs 
= {}; 
4301     SecKeychainAttribute attr 
= {}; 
4307     Item item 
= Item(item_class
, &attrs
, 0, ""); 
4308                 v 
= CFDictionaryGetValue(refAttributes
, kSecValuePersistentRef
); 
4310                         item
->setPersistentRef((CFDataRef
)v
); 
4312                 ref 
= item
->handle(); 
4319  * SecItemValidateAppleApplicationGroupAccess determines if the caller 
4320  * is a member of the specified application group, and is signed by Apple. 
4323 SecItemValidateAppleApplicationGroupAccess(CFStringRef group
) 
4325         SecTrustedApplicationRef app 
= NULL
; 
4326         SecRequirementRef requirement 
= NULL
; 
4327         SecCodeRef code 
= NULL
; 
4328         OSStatus status 
= errSecParam
; 
4331                 CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(group
), kCFStringEncodingUTF8
) + 1; 
4332                 char* buffer 
= (char*) malloc(length
); 
4334                         if (CFStringGetCString(group
, buffer
, length
, kCFStringEncodingUTF8
)) { 
4335                                 status 
= SecTrustedApplicationCreateApplicationGroup(buffer
, NULL
, &app
); 
4339                         status 
= errSecMemoryError
; 
4343                 status 
= SecTrustedApplicationCopyRequirement(app
, &requirement
); 
4346                 status 
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
); 
4349                 status 
= SecCodeCheckValidity(code
, kSecCSDefaultFlags
, requirement
); 
4352         CFReleaseSafe(code
); 
4353         CFReleaseSafe(requirement
); 
4358 static Mutex
& gParentCertCacheLock() { 
4359     static Mutex fParentCertCacheLock
; 
4360     return fParentCertCacheLock
; 
4362 static CFMutableDictionaryRef gParentCertCache
; 
4363 static CFMutableArrayRef gParentCertCacheList
; 
4364 #define PARENT_CACHE_SIZE 100 
4366 void SecItemParentCachePurge() { 
4367     StLock
<Mutex
> _(gParentCertCacheLock()); 
4368     CFReleaseNull(gParentCertCache
); 
4369     CFReleaseNull(gParentCertCacheList
); 
4372 static CFArrayRef CF_RETURNS_RETAINED 
parentCacheRead(SecCertificateRef certificate
) { 
4373     CFArrayRef parents 
= NULL
; 
4375     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4376     if (!digest
) return NULL
; 
4378     StLock
<Mutex
> _(gParentCertCacheLock()); 
4379     if (gParentCertCache 
&& gParentCertCacheList
) { 
4380         if (0 <= (ix 
= CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4381                                                    CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4383             // Cache hit. Get value and move entry to the top of the list. 
4384             parents 
= (CFArrayRef
)CFDictionaryGetValue(gParentCertCache
, digest
); 
4385             CFArrayRemoveValueAtIndex(gParentCertCacheList
, ix
); 
4386             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4389     CFRetainSafe(parents
); 
4393 static void parentCacheWrite(SecCertificateRef certificate
, CFArrayRef parents
) { 
4394     CFDataRef digest 
= SecCertificateGetSHA1Digest(certificate
); 
4395     if (!digest
) return; 
4397     StLock
<Mutex
> _(gParentCertCacheLock()); 
4398     if (!gParentCertCache 
|| !gParentCertCacheList
) { 
4399         CFReleaseNull(gParentCertCache
); 
4400         gParentCertCache 
= makeCFMutableDictionary(); 
4401         CFReleaseNull(gParentCertCacheList
); 
4402         gParentCertCacheList 
= makeCFMutableArray(0); 
4405     if (gParentCertCache 
&& gParentCertCacheList
) { 
4406         // check to make sure another thread didn't add this entry to the cache already 
4407         if (0 > CFArrayGetFirstIndexOfValue(gParentCertCacheList
, 
4408                                             CFRangeMake(0, CFArrayGetCount(gParentCertCacheList
)), 
4410             CFDictionaryAddValue(gParentCertCache
, digest
, parents
); 
4411             if (PARENT_CACHE_SIZE 
<= CFArrayGetCount(gParentCertCacheList
)) { 
4412                 // Remove least recently used cache entry. 
4413                 CFDictionaryRemoveValue(gParentCertCache
, CFArrayGetValueAtIndex(gParentCertCacheList
, 0)); 
4414                 CFArrayRemoveValueAtIndex(gParentCertCacheList
, 0); 
4416             CFArrayAppendValue(gParentCertCacheList
, digest
); 
4422  * SecItemCopyParentCertificates_osx returns an array of zero of more possible 
4423  * issuer certificates for the provided certificate. No cryptographic validation 
4424  * of the signature is performed in this function; its purpose is only to 
4425  * provide a list of candidate certificates. 
4428 SecItemCopyParentCertificates_osx(SecCertificateRef certificate
, void *context
) 
4430 #pragma unused (context) /* for now; in future this can reference a container object */ 
4431         /* Check for parents in keychain cache */ 
4432         CFArrayRef parents 
= parentCacheRead(certificate
); 
4437         /* Cache miss. Query for parents. */ 
4439         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4441         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4442         CFRetainSafe(normalizedIssuer
); 
4445         CFMutableArrayRef combinedSearchList 
= NULL
; 
4447         /* Define the array of keychains which will be searched for parents. */ 
4448         CFArrayRef searchList 
= NULL
; 
4449         status 
= SecKeychainCopySearchList(&searchList
); 
4451                 combinedSearchList 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, searchList
); 
4452                 CFRelease(searchList
); 
4454                 combinedSearchList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4456         SecKeychainRef rootStoreKeychain 
= NULL
; 
4457         status 
= SecKeychainOpen(SYSTEM_ROOT_STORE_PATH
, &rootStoreKeychain
); 
4458         if (rootStoreKeychain
) { 
4459                 if (combinedSearchList
) { 
4460                         CFArrayAppendValue(combinedSearchList
, rootStoreKeychain
); 
4462                 CFRelease(rootStoreKeychain
); 
4465         /* Create and populate a fixed-size query dictionary. */ 
4466         CFMutableDictionaryRef query 
= CFDictionaryCreateMutable(NULL
, 5, 
4467                         &kCFTypeDictionaryKeyCallBacks
, 
4468                         &kCFTypeDictionaryValueCallBacks
); 
4469         CFDictionaryAddValue(query
, kSecClass
, kSecClassCertificate
); 
4470         CFDictionaryAddValue(query
, kSecReturnData
, kCFBooleanTrue
); 
4471         CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4472         if (combinedSearchList
) { 
4473                 CFDictionaryAddValue(query
, kSecMatchSearchList
, combinedSearchList
); 
4474                 CFRelease(combinedSearchList
); 
4477         CFTypeRef results 
= NULL
; 
4478         if (normalizedIssuer
) { 
4479                 /* Look up certs whose subject is the same as this cert's issuer. */ 
4480                 CFDictionaryAddValue(query
, kSecAttrSubject
, normalizedIssuer
); 
4481                 status 
= SecItemCopyMatching_osx(query
, &results
); 
4484                 /* Cannot match anything without an issuer! */ 
4485                 status 
= errSecItemNotFound
; 
4488         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4489                 secitemlog(LOG_WARNING
, "SecItemCopyParentCertificates_osx: %d", (int)status
); 
4493         CFMutableArrayRef result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4494         CFTypeID resultType 
= (results
) ? CFGetTypeID(results
) : 0; 
4495         if (resultType 
== CFArrayGetTypeID()) { 
4496                 CFIndex index
, count 
= CFArrayGetCount((CFArrayRef
)results
); 
4497                 for (index 
= 0; index 
< count
; index
++) { 
4498                         CFDataRef data 
= (CFDataRef
) CFArrayGetValueAtIndex((CFArrayRef
)results
, index
); 
4500                                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
4502                                         CFArrayAppendValue(result
, cert
); 
4507         } else if (results 
&& resultType 
== CFDataGetTypeID()) { 
4508                 SecCertificateRef cert 
= SecCertificateCreateWithData(kCFAllocatorDefault
, (CFDataRef
)results
); 
4510                         CFArrayAppendValue(result
, cert
); 
4514         CFReleaseSafe(results
); 
4515         CFReleaseSafe(normalizedIssuer
); 
4518         parentCacheWrite(certificate
, result
); 
4523 SecCertificateRef 
SecItemCopyStoredCertificate(SecCertificateRef certificate
, void *context
) 
4525 #pragma unused (context) /* for now; in future this can reference a container object */ 
4527         /* Certificates are unique by issuer and serial number. */ 
4528         CFDataRef serialNumber 
= SecCertificateCopySerialNumberData(certificate
, NULL
); 
4530         CFDataRef normalizedIssuer 
= SecCertificateCopyNormalizedIssuerContent(certificate
, NULL
); 
4532         CFDataRef normalizedIssuer 
= SecCertificateGetNormalizedIssuerContent(certificate
); 
4533         CFRetainSafe(normalizedIssuer
); 
4536         const void *keys
[] = { 
4540                 kSecAttrSerialNumber
, 
4544                 kSecClassCertificate
, 
4550         CFDictionaryRef query 
= CFDictionaryCreate(NULL
, keys
, values
, 5,       NULL
, NULL
); 
4551         CFTypeRef result 
= NULL
; 
4553         OSStatus status 
= SecItemCopyMatching_osx(query
, &result
); 
4554         if ((status 
!= errSecSuccess
) && (status 
!= errSecItemNotFound
)) { 
4555                 secitemlog(LOG_WARNING
, "SecItemCopyStoredCertificate: %d", (int)status
); 
4556                 CFReleaseNull(result
); 
4558         CFReleaseSafe(query
); 
4559         CFReleaseSafe(serialNumber
); 
4560         CFReleaseSafe(normalizedIssuer
); 
4562         return (SecCertificateRef
)result
; 
4566  * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary 
4567  * and attempts to return a sanitized copy for passing to the underlying 
4568  * platform-specific implementation code. 
4570  * If iOSOut is true, one or more translations may apply: 
4571  *   - SecKeychain refs are removed, since there aren't multiple keychains 
4572  *   - SecPolicy refs are removed, since they can't be externalized 
4573  *   - SecAccess refs are removed, and potentially translated to entitlements 
4575  * If pruneMatch is true, kSecMatch* attributes are removed; this avoids 
4576  * parameter errors due to strict input checks in secd, which only permits 
4577  * these constants for calls to SecItemCopyMatching. 
4579  * If pruneSync is true, the kSecAttrSynchronizable attribute is removed. 
4580  * This permits a query to be reused for non-synchronizable items, or to 
4581  * resolve a search based on a persistent item reference for iOS. 
4583  * If pruneReturn is true, kSecReturn* attributes are removed; this avoids 
4584  * parameter errors due to strict input checks in secd, which do not permit 
4585  * these constants for calls to SecItemUpdate. 
4588 SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
4589         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
) 
4591         CFMutableDictionaryRef result 
= CFDictionaryCreateMutableCopy(NULL
, 0, inOSXDict
); 
4592         if (result 
== NULL
) { 
4597                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4601                 /* Match constants are only supported on iOS for SecItemCopyMatching, 
4602                  * and will generate an error if passed to other SecItem API functions; 
4603                  * on OS X, they're just ignored if not applicable for the context. 
4605                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4606                 CFDictionaryRemoveValue(result
, kSecMatchItemList
); 
4607                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4608                 CFDictionaryRemoveValue(result
, kSecMatchIssuers
); 
4609                 CFDictionaryRemoveValue(result
, kSecMatchEmailAddressIfPresent
); 
4610                 CFDictionaryRemoveValue(result
, kSecMatchSubjectContains
); 
4611                 CFDictionaryRemoveValue(result
, kSecMatchCaseInsensitive
); 
4612                 CFDictionaryRemoveValue(result
, kSecMatchTrustedOnly
); 
4613                 CFDictionaryRemoveValue(result
, kSecMatchValidOnDate
); 
4614                 CFDictionaryRemoveValue(result
, kSecMatchLimit
); 
4615                 CFDictionaryRemoveValue(result
, kSecMatchLimitOne
); 
4616                 CFDictionaryRemoveValue(result
, kSecMatchLimitAll
); 
4620                 /* Return constants are not supported on iOS for SecItemUpdate, 
4621                  * where they will generate an error; on OS X, they're just ignored 
4622                  * if not applicable for the context. 
4624                 CFDictionaryRemoveValue(result
, kSecReturnData
); 
4625                 CFDictionaryRemoveValue(result
, kSecReturnAttributes
); 
4626                 CFDictionaryRemoveValue(result
, kSecReturnRef
); 
4627                 CFDictionaryRemoveValue(result
, kSecReturnPersistentRef
); 
4631                 /* Searching on data is not supported. */ 
4632                 CFDictionaryRemoveValue(result
, kSecValueData
); 
4636         /* Searching on access lists is not supported */ 
4637         CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4641                 /* Remove kSecMatchSearchList (value is array of SecKeychainRef); 
4642                  * cannot specify a keychain search list on iOS 
4644                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4646                 /* Remove kSecUseKeychain (value is a SecKeychainRef); 
4647                  * cannot specify a keychain on iOS 
4649                 CFDictionaryRemoveValue(result
, kSecUseKeychain
); 
4651                 /* Potentially translate kSecAttrAccess (value is a SecAccessRef), 
4652                  * unless kSecAttrAccessGroup has already been specified. 
4654                 SecAccessRef access 
= (SecAccessRef
) CFDictionaryGetValue(result
, kSecAttrAccess
); 
4655                 CFStringRef accessGroup 
= (CFStringRef
) CFDictionaryGetValue(result
, kSecAttrAccessGroup
); 
4656                 if (access 
!= NULL 
&& accessGroup 
== NULL
) { 
4657                         /* Translate "InternetAccounts" application group to an access group */ 
4658                         if (errSecSuccess 
== SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) { 
4659                                 /* The caller is a valid member of the application group. */ 
4660                                 CFStringRef groupName 
= CFSTR("appleaccount"); 
4661                                 CFTypeRef value 
= CFDictionaryGetValue(result
, kSecAttrAuthenticationType
); 
4662                                 if (value 
&& CFEqual(value
, kSecAttrAuthenticationTypeHTMLForm
)) { 
4663                                         groupName 
= CFSTR("com.apple.cfnetwork"); 
4665                                 CFDictionarySetValue(result
, kSecAttrAccessGroup
, groupName
); 
4668                 CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4670                 /* If item is specified by direct reference, and this is an iOS search, 
4671                  * replace it with a persistent reference, if it was recorded inside ItemImpl. 
4673                 CFTypeRef directRef 
= CFDictionaryGetValue(result
, kSecValueRef
); 
4674                 if (directRef 
!= NULL
) { 
4675                         CFTypeID typeID 
= CFGetTypeID(directRef
); 
4676                         if ((typeID 
!= SecKeyGetTypeID() || SecKeyIsCDSAKey((SecKeyRef
)directRef
)) && 
4677                                 (typeID 
!= SecCertificateGetTypeID() || SecCertificateIsItemImplInstance((SecCertificateRef
)directRef
)) && 
4678                                 (typeID 
!= SecIdentityGetTypeID())) { 
4679                                 CFDataRef persistentRef 
= _SecItemGetPersistentReference(directRef
); 
4680                                 if (persistentRef
) { 
4681                                         CFDictionarySetValue(result
, kSecValuePersistentRef
, persistentRef
); 
4682                                         CFDictionaryRemoveValue(result
, kSecValueRef
); 
4687                 /* If item is specified by persistent reference, and this is an iOS search, 
4688                  * remove the synchronizable attribute as it will be rejected by secd. 
4690                 CFTypeRef persistentRef 
= CFDictionaryGetValue(result
, kSecValuePersistentRef
); 
4691                 if (persistentRef
) { 
4692                         CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4695                 /* Remove kSecAttrModificationDate; this should never be used as criteria 
4696                  * for a search, or to add/modify an item. (If we are cloning an item 
4697                  * and want to keep its modification date, we don't call this function.) 
4698                  * It turns out that some clients are using the full attributes dictionary 
4699                  * returned by SecItemCopyMatching as a query to find the same item later, 
4700                  * which won't work once the item is updated. 
4702                 CFDictionaryRemoveValue(result
, kSecAttrModificationDate
); 
4704         /* Find all intermediate certificates in OSX keychain and append them in to the kSecMatchIssuers. 
4705          * This is required because secd cannot do query in to the OSX keychain 
4707         CFTypeRef matchIssuers 
= CFDictionaryGetValue(result
, kSecMatchIssuers
); 
4708         if (matchIssuers 
&& CFGetTypeID(matchIssuers
) == CFArrayGetTypeID()) { 
4709             CFArrayRef newMatchIssuers 
= _CopyMatchingIssuers((CFArrayRef
)matchIssuers
); 
4710             if (newMatchIssuers
) { 
4711                 CFDictionarySetValue(result
, kSecMatchIssuers
, newMatchIssuers
); 
4712                 CFRelease(newMatchIssuers
); 
4717                 /* iOS doesn't add the class attribute, so we must do it here. */ 
4719                         CFDictionarySetValue(result
, kSecClass
, itemClass
); 
4721                 /* Remove attributes which are not part of the OS X database schema. */ 
4722                 CFDictionaryRemoveValue(result
, kSecAttrAccessible
); 
4723                 CFDictionaryRemoveValue(result
, kSecAttrAccessControl
); 
4724                 CFDictionaryRemoveValue(result
, kSecAttrAccessGroup
); 
4725                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4726                 CFDictionaryRemoveValue(result
, kSecAttrTombstone
); 
4729     /* This attribute is consumed by the bridge itself. */ 
4730     CFDictionaryRemoveValue(result
, kSecUseDataProtectionKeychain
); 
4731 #pragma clang diagnostic push 
4732 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
4733     // Also remove deprecated symbol in case your CFDict is derpy 
4734     CFDictionaryRemoveValue(result
, kSecAttrNoLegacy
); 
4735 #pragma clang diagnostic pop 
4743 _CopyMatchingIssuers(CFArrayRef matchIssuers
) { 
4744     CFMutableArrayRef result 
= NULL
; 
4745     CFMutableDictionaryRef query 
= NULL
; 
4746     CFMutableDictionaryRef policyProperties 
= NULL
; 
4747     SecPolicyRef policy 
= NULL
; 
4748     CFTypeRef matchedCertificates 
= NULL
; 
4750     require_quiet(policyProperties 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), out
); 
4751     CFDictionarySetValue(policyProperties
, kSecPolicyKU_KeyCertSign
, kCFBooleanTrue
); 
4752     require_quiet(policy 
= SecPolicyCreateWithProperties(kSecPolicyAppleX509Basic
, policyProperties
), out
); 
4754     require_quiet(query 
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
), out
); 
4755     CFDictionarySetValue(query
, kSecClass
, kSecClassCertificate
); 
4756     CFDictionarySetValue(query
, kSecMatchIssuers
, matchIssuers
); 
4757     CFDictionarySetValue(query
, kSecMatchLimit
, kSecMatchLimitAll
); 
4758     CFDictionarySetValue(query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4759     CFDictionarySetValue(query
, kSecUseCertificatesWithMatchIssuers
, kCFBooleanTrue
); 
4760     CFDictionarySetValue(query
, kSecMatchPolicy
, policy
); 
4762     if (SecItemCopyMatching_osx(query
, &matchedCertificates
) == errSecSuccess 
&& CFGetTypeID(matchedCertificates
) == CFArrayGetTypeID()) { 
4763         require_quiet(result 
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, (CFArrayRef
)matchedCertificates
), out
); 
4764         for(CFIndex i 
= 0; i 
< CFArrayGetCount((CFArrayRef
)matchedCertificates
); ++i
) { 
4765             CFDictionaryRef attributes 
= (CFDictionaryRef
)CFArrayGetValueAtIndex((CFArrayRef
)matchedCertificates
, i
); 
4766             CFTypeRef subject 
= CFDictionaryGetValue(attributes
, kSecAttrSubject
); 
4767             if (!CFArrayContainsValue(result
, CFRangeMake(0, CFArrayGetCount(result
)), subject
)) { 
4768                 CFArrayAppendValue(result
, subject
); 
4774     CFReleaseSafe(query
); 
4775     CFReleaseSafe(policyProperties
); 
4776     CFReleaseSafe(policy
); 
4777     CFReleaseSafe(matchedCertificates
); 
4783 SecItemMergeResults(bool can_target_ios
, OSStatus status_ios
, CFTypeRef result_ios
, 
4784                                         bool can_target_osx
, OSStatus status_osx
, CFTypeRef result_osx
, 
4785                                         CFTypeRef 
*result
) { 
4786         // When querying both keychains and iOS keychain fails because of missing 
4787         // entitlements, completely ignore iOS keychain result.  This is to keep 
4788         // backward compatibility with applications which know nothing about iOS keychain 
4789         // and use SecItem API to access OSX keychain which does not need any entitlements. 
4790         if (can_target_osx 
&& can_target_ios 
&& status_ios 
== errSecMissingEntitlement
) { 
4791                 can_target_ios 
= false; 
4794         if (can_target_osx 
&& can_target_ios
) { 
4795                 // If both keychains were targetted, examine returning statuses and decide what to do. 
4796                 if (status_ios 
!= errSecSuccess
) { 
4797                         // iOS keychain failed to produce results because of some error, go with results from OSX keychain. 
4798             // Since iOS keychain queries will fail without a keychain-access-group or proper entitlements, SecItemCopyMatching 
4799             // calls against the OSX keychain API that should return errSecItemNotFound will return nonsense from the iOS keychain. 
4800                         AssignOrReleaseResult(result_osx
, result
); 
4802                 } else if (status_osx 
!= errSecSuccess
) { 
4803                         if (status_osx 
!= errSecItemNotFound
) { 
4804                                 // OSX failed to produce results with some failure mode (else than not_found), but iOS produced results. 
4805                                 // We have to either return OSX failure result and discard iOS results, or vice versa.  For now, we just 
4806                                 // ignore OSX error and return just iOS results. 
4807                                 secitemlog(LOG_NOTICE
, "SecItemMergeResults: osx_result=%d, ignoring it, iOS succeeded fine", status_osx
); 
4810                         // OSX failed to produce results, but we have success from iOS keychain; go with results from iOS keychain. 
4811                         AssignOrReleaseResult(result_ios
, result
); 
4812                         return errSecSuccess
; 
4814                         // Both searches succeeded, merge results. 
4815                         if (result 
!= NULL
) { 
4816                                 CFTypeID id_osx 
= (result_osx
) ? CFGetTypeID(result_osx
) : 0; 
4817                                 CFTypeID id_ios 
= (result_ios
) ? CFGetTypeID(result_ios
) : 0; 
4818                                 CFTypeID id_array 
= CFArrayGetTypeID(); 
4819                                 if ((id_osx 
== id_array
) && (id_ios 
== id_array
)) { 
4820                                         // Fold the arrays into one. 
4821                                         *result 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4822                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_ios
, 
4823                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_ios
))); 
4824                                         CFArrayAppendArray((CFMutableArrayRef
)*result
, (CFArrayRef
)result_osx
, 
4825                                                                            CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_osx
))); 
4827                                         // Result type is not an array, so only one match can be returned. 
4828                                         *result 
= (id_ios
) ? result_ios 
: result_osx
; 
4829                                         CFRetainSafe(*result
); 
4832                         CFReleaseSafe(result_osx
); 
4833                         CFReleaseSafe(result_ios
); 
4834                         return errSecSuccess
; 
4836         } else if (can_target_ios
) { 
4837                 // Only iOS keychain was targetted. 
4838                 AssignOrReleaseResult(result_ios
, result
); 
4840         } else if (can_target_osx
) { 
4841                 // Only OSX keychain was targetted. 
4842                 AssignOrReleaseResult(result_osx
, result
); 
4845                 // Query could not run at all? 
4851 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef 
*result
) 
4853     os_activity_t activity 
= os_activity_create("SecItemCopyMatching", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4854     os_activity_scope(activity
); 
4855     os_release(activity
); 
4860         secitemshow(query
, "SecItemCopyMatching query:"); 
4862         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4863         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4864         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
4865         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
4866         if (status 
!= errSecSuccess
) { 
4870         if (can_target_ios
) { 
4871                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4872                         CFDictionaryGetValue(query
, kSecClass
), true, false, false, false, true, true); 
4874                         status_ios 
= errSecParam
; 
4877                         status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4878                         CFRelease(attrs_ios
); 
4880                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_ios result: %d", status_ios
); 
4883         if (can_target_osx
) { 
4884                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4885                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, false, true, true); 
4887                         status_osx 
= errSecParam
; 
4890                         status_osx 
= SecItemCopyMatching_osx(attrs_osx
, &result_osx
); 
4891                         CFRelease(attrs_osx
); 
4893                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_osx result: %d", status_osx
); 
4896         status 
= SecItemMergeResults(can_target_ios
, status_ios
, result_ios
, 
4897                                                                  can_target_osx
, status_osx
, result_osx
, result
); 
4898         secitemlog(LOG_NOTICE
, "SecItemCopyMatching result: %d", status
); 
4903 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
4905     os_activity_t activity 
= os_activity_create("SecItemAdd", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4906     os_activity_scope(activity
); 
4907     os_release(activity
); 
4915         secitemshow(attributes
, "SecItemAdd attrs:"); 
4917         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4918         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
4919         OSStatus status 
= SecItemCategorizeQuery(attributes
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
4920         if (status 
!= errSecSuccess
) { 
4924         // SecItemAdd cannot be really done on both keychains.  In order to keep backward compatibility 
4925         // with existing applications, we prefer to add items into legacy keychain and fallback 
4926         // into iOS (modern) keychain only when the query is not suitable for legacy keychain. 
4927         if (!can_target_osx
) { 
4928                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(attributes
, 
4929                         NULL
, true, true, false, false, false, false); 
4931                         status 
= errSecParam
; 
4933             status 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4934                         CFRelease(attrs_ios
); 
4936                 secitemlog(LOG_NOTICE
, "SecItemAdd_ios result: %d", status
); 
4937                 AssignOrReleaseResult(result_ios
, result
); 
4940                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(attributes
, 
4941                     NULL
, false, false, true, false, false, false); 
4943                         status 
= errSecParam
; 
4945                         status 
= SecItemAdd_osx(attrs_osx
, &result_osx
); 
4946                         CFRelease(attrs_osx
); 
4948                 secitemlog(LOG_NOTICE
, "SecItemAdd_osx result: %d", status
); 
4949                 AssignOrReleaseResult(result_osx
, result
); 
4955 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
4957     os_activity_t activity 
= os_activity_create("SecItemUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
4958     os_activity_scope(activity
); 
4959     os_release(activity
); 
4961         if (!query 
|| !attributesToUpdate
) { 
4964         secitemshow(query
, "SecItemUpdate query:"); 
4965         secitemshow(attributesToUpdate
, "SecItemUpdate attrs:"); 
4967         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4968         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
4969         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
4970         if (status 
!= errSecSuccess
) { 
4975      * If the user have explicity opted in to UseDataProtectionKeychain, then don't touch the legacy keychain at all 
4976      * ie don't move the item back to legacy keychain if you remove sync=1 or the inverse. 
4978     if (useDataProtectionKeychainFlag
) { 
4979         CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4980             CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4982             status_ios 
= errSecParam
; 
4984             status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4985             CFRelease(attrs_ios
); 
4987         secitemlog(LOG_NOTICE
, "SecItemUpdate(ios only) result: %d", status_ios
); 
4991         if (can_target_ios
) { 
4992                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4993                         CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4995                         status_ios 
= errSecParam
; 
4998             if (SecItemHasSynchronizableUpdate(true, attributesToUpdate
)) { 
4999                 status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
5001                 status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
5003                         CFRelease(attrs_ios
); 
5005                 secitemlog(LOG_NOTICE
, "SecItemUpdate_ios result: %d", status_ios
); 
5008         if (can_target_osx
) { 
5009                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
5010                     CFDictionaryGetValue(query
, kSecClass
), false, false, true, true, true, true); 
5012                         status_osx 
= errSecParam
; 
5015                         if (SecItemHasSynchronizableUpdate(false, attributesToUpdate
)) 
5016                                 status_osx 
= SecItemChangeSynchronizability(attrs_osx
, attributesToUpdate
, true); 
5018                                 status_osx 
= SecItemUpdate_osx(attrs_osx
, attributesToUpdate
); 
5020                         CFRelease(attrs_osx
); 
5022                 secitemlog(LOG_NOTICE
, "SecItemUpdate_osx result: %d", status_osx
); 
5025         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
5026                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
5027         secitemlog(LOG_NOTICE
, "SecItemUpdate result: %d", status
); 
5032 SecItemDelete(CFDictionaryRef query
) 
5034     os_activity_t activity 
= os_activity_create("SecItemDelete", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_DEFAULT
); 
5035     os_activity_scope(activity
); 
5036     os_release(activity
); 
5041         secitemshow(query
, "SecItemDelete query:"); 
5043         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
5044         bool can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
; 
5045         OSStatus status 
= SecItemCategorizeQuery(query
, can_target_ios
, can_target_osx
, useDataProtectionKeychainFlag
); 
5046         if (status 
!= errSecSuccess
) { 
5050         if (can_target_ios
) { 
5051                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
5052                         NULL
, true, true, false, true, true, true); 
5054                         status_ios 
= errSecParam
; 
5056             status_ios 
= SecItemDelete_ios(attrs_ios
); 
5057                         CFRelease(attrs_ios
); 
5059                 secitemlog(LOG_NOTICE
, "SecItemDelete_ios result: %d", status_ios
); 
5062         if (can_target_osx
) { 
5063                 CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
5064                     NULL
, false, false, true, true, true, true); 
5066                         status_osx 
= errSecParam
; 
5068                         status_osx 
= SecItemDelete_osx(attrs_osx
); 
5069                         CFRelease(attrs_osx
); 
5071                 secitemlog(LOG_NOTICE
, "SecItemDelete_osx result: %d", status_osx
); 
5074         status 
= SecItemMergeResults(can_target_ios
, status_ios
, NULL
, 
5075                                                                  can_target_osx
, status_osx
, NULL
, NULL
); 
5076         secitemlog(LOG_NOTICE
, "SecItemCopyDelete result: %d", status
); 
5081 SecItemUpdateTokenItems(CFTypeRef tokenID
, CFArrayRef tokenItemsAttributes
) 
5083         OSStatus status 
= SecItemUpdateTokenItems_ios(tokenID
, tokenItemsAttributes
); 
5084         secitemlog(LOG_NOTICE
, "SecItemUpdateTokenItems_ios result: %d", status
); 
5089 SecItemCopyMatching_osx( 
5090         CFDictionaryRef query
, 
5093         if (!query 
|| !result
) 
5098         CFAllocatorRef allocator 
= CFGetAllocator(query
); 
5099         CFIndex matchCount 
= 0; 
5100         CFMutableArrayRef itemArray 
= NULL
; 
5101         SecKeychainItemRef item 
= NULL
; 
5102         SecIdentityRef identity 
= NULL
; 
5103         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5105         // validate input query parameters and create the search reference 
5106         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(query
, &status
); 
5107         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5109         // find the next match until we hit maxMatches, or no more matches found 
5110         while ( !(!itemParams
->returnAllMatches 
&& matchCount 
>= itemParams
->maxMatches
) && 
5111                         SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == errSecSuccess
) { 
5113                 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
)) 
5114                         continue; // move on to next item 
5116                 ++matchCount
; // we have a match 
5118                 tmpStatus 
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
); 
5119                 if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5127                         CFRelease(identity
); 
5132         if (status 
== errSecSuccess
) 
5133                 status 
= (matchCount 
> 0) ? errSecSuccess 
: errSecItemNotFound
; 
5136         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5140         _FreeSecItemParams(itemParams
); 
5146 SecItemCopyDisplayNames( 
5148         CFArrayRef 
*displayNames
) 
5152         Required(displayNames
); 
5154     return errSecUnimplemented
; 
5160         CFDictionaryRef attributes
, 
5168         CFAllocatorRef allocator 
= CFGetAllocator(attributes
); 
5169         CFMutableArrayRef itemArray 
= NULL
; 
5170         SecKeychainItemRef item 
= NULL
; 
5171         OSStatus tmpStatus
, status 
= errSecSuccess
; 
5173         // validate input attribute parameters 
5174         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(attributes
, &status
); 
5175         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
5177         // currently, we don't support adding SecIdentityRef items (an aggregate item class), 
5178         // since the private key should already be in a keychain by definition. We could support 
5179         // this as a copy operation for the private key if a different keychain is specified, 
5180         // but in any case it should try to add the certificate. See <rdar://8317887>. 
5181         require_action(!itemParams
->returnIdentity
, error_exit
, status 
= errSecItemInvalidValue
); 
5183         if (itemParams
->useItems 
== NULL
) { 
5185                 require_action(itemParams
->itemData 
== NULL 
|| CFGetTypeID(itemParams
->itemData
) == CFDataGetTypeID(), 
5186                                            error_exit
, status 
= errSecItemInvalidValue
); 
5188                 // create a single keychain item specified by the input attributes 
5189                 status 
= SecKeychainItemCreateFromContent(itemParams
->itemClass
, 
5190                         itemParams
->attrList
, 
5191                         (itemParams
->itemData
) ? (UInt32
)CFDataGetLength(itemParams
->itemData
) : 0, 
5192                         (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
, 
5193                         itemParams
->keychain
, 
5196                 require_noerr(status
, error_exit
); 
5198                 // return results (if requested) 
5200                         itemParams
->maxMatches 
= 1; // in case kSecMatchLimit was set to > 1 
5201                         tmpStatus 
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5202                         if (tmpStatus 
&& (status 
== errSecSuccess
)) 
5208                 // add multiple items which are specified in the itemParams->useItems array. 
5209                 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain. 
5210                 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain. 
5211                 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain. 
5213                 OSStatus aggregateStatus 
= errSecSuccess
; 
5214                 CFIndex ix
, count 
= CFArrayGetCount(itemParams
->useItems
); 
5215                 itemParams
->maxMatches 
= (count 
> 1) ? (int)count 
: 2; // force results to always be returned as an array 
5216                 for (ix
=0; ix 
< count
; ix
++) { 
5217                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
); 
5219                                 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) { 
5220                                         // SecCertificateRef item 
5221                                         tmpStatus 
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
); 
5222                                         if (!tmpStatus 
&& result
) { 
5223                                                 tmpStatus 
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5225                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5227                                 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) { 
5229                                         SecKeychainRef itemKeychain 
= NULL
; 
5230                                         tmpStatus 
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
); 
5231                                         if (tmpStatus 
== errSecSuccess
) { 
5232                                                 // key was in a keychain, so we can attempt to copy it 
5233                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5234                                                 tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5235                                                 if (!tmpStatus 
&& result
) { 
5236                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5239                                                         CFRelease(itemCopy
); 
5243                                                 // key was not in any keychain, so must be imported 
5244                                                 SecKeychainItemRef keyItem 
= NULL
; 
5245                                                 tmpStatus 
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
); 
5246                                                 if (!tmpStatus 
&& result
) { 
5247                                                         tmpStatus 
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5254                                                 CFRelease(itemKeychain
); 
5256                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5258                                 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) { 
5259                                         // SecKeychainItemRef item 
5260                                         SecKeychainItemRef itemCopy 
= NULL
; 
5261                                         tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5262                                         if (!tmpStatus 
&& result
) { 
5263                                                 tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5266                                                 CFRelease(itemCopy
); 
5268                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5270                                 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) { 
5271                                         // CFDataRef item (persistent reference) 
5272                                         SecKeychainItemRef realItem 
= NULL
; 
5273                                         tmpStatus 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
); 
5274                                         if (tmpStatus 
== errSecSuccess
) { 
5275                                                 // persistent reference resolved to a keychain item, so we can attempt to copy it 
5276                                                 SecKeychainItemRef itemCopy 
= NULL
; 
5277                                                 tmpStatus 
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
5278                                                 if (!tmpStatus 
&& result
) { 
5279                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
5282                                                         CFRelease(itemCopy
); 
5286                                                 CFRelease(realItem
); 
5288                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
5291                 } // end of itemList array loop 
5292                 status 
= aggregateStatus
; 
5293         } // end processing multiple items 
5296         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
5300         _FreeSecItemParams(itemParams
); 
5307         CFDictionaryRef query
, 
5308         CFDictionaryRef attributesToUpdate
) 
5310         if (!query 
|| !attributesToUpdate
) 
5313         // run the provided query to get a list of items to update 
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                         status 
= _UpdateKeychainItem(anItem
, attributesToUpdate
); 
5334                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
); 
5346         CFDictionaryRef query
) 
5351         // run the provided query to get a list of items to delete 
5352         CFTypeRef results 
= NULL
; 
5353         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
5354         if (status 
!= errSecSuccess
) 
5355                 return status
; // nothing was matched, or the query was bad 
5357         CFArrayRef items 
= NULL
; 
5358         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
5359                 items 
= (CFArrayRef
) results
; 
5362                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
5366         OSStatus result 
= errSecSuccess
; 
5367         CFIndex ix
, count 
= CFArrayGetCount(items
); 
5368         for (ix
=0; ix 
< count
; ix
++) { 
5369                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
5371                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) { 
5372                                 status 
= _DeleteIdentity((SecIdentityRef
)anItem
); 
5375                                 status 
= _DeleteKeychainItem(anItem
); 
5377                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
);