2  * Copyright (c) 2006-2015 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  24 #include "SecBridge.h" 
  25 #include "SecInternal.h" 
  26 #include <CoreFoundation/CoreFoundation.h> 
  27 #include <security_utilities/cfutilities.h> 
  28 #include <Security/SecBase.h> 
  29 #include <Security/SecKeychainItem.h> 
  30 #include <Security/SecCertificate.h> 
  31 #include <sys/param.h> 
  32 #include "cssmdatetime.h" 
  34 #include "SecItemPriv.h" 
  35 #include "SecIdentitySearchPriv.h" 
  36 #include "SecKeychainPriv.h" 
  37 #include "SecCertificatePriv.h" 
  38 #include "SecCertificatePrivP.h" 
  39 #include "TrustAdditions.h" 
  41 #include <AssertMacros.h> 
  44 #include <Security/SecTrustedApplication.h> 
  45 #include <Security/SecTrustedApplicationPriv.h> 
  46 #include <Security/SecCode.h> 
  47 #include <Security/SecCodePriv.h> 
  48 #include <Security/SecRequirement.h> 
  50 const uint8_t kUUIDStringLength 
= 36; 
  52 OSStatus 
SecItemAdd_osx(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  53 OSStatus 
SecItemCopyMatching_osx(CFDictionaryRef query
, CFTypeRef 
*result
); 
  54 OSStatus 
SecItemUpdate_osx(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  55 OSStatus 
SecItemDelete_osx(CFDictionaryRef query
); 
  58 OSStatus 
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef 
*result
); 
  59 OSStatus 
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef 
*result
); 
  60 OSStatus 
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
); 
  61 OSStatus 
SecItemDelete_ios(CFDictionaryRef query
); 
  63 CFTypeRef 
SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
); 
  64 CFTypeRef 
SecItemCopyMergedResults(CFDictionaryRef query
, CFTypeRef result_osx
, CFTypeRef result_ios
); 
  65 OSStatus 
SecItemValidateAppleApplicationGroupAccess(CFStringRef group
); 
  66 CFDictionaryRef 
SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
  67         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
); 
  70 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
); 
  72 static void secitemlog(int priority
, const char *format
, ...) 
  77         if (priority 
< LOG_NOTICE
) // log warnings and errors 
  81                 va_start(list
, format
); 
  82                 vsyslog(priority
, format
, list
); 
  87 static void secitemshow(CFTypeRef obj
, const char *context
) 
  90         CFStringRef desc 
= CFCopyDescription(obj
); 
  93         CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1; 
  94         char* buffer 
= (char*) malloc(length
); 
  96                 Boolean converted 
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
); 
  98                         const char *prefix 
= (context
) ? context 
: ""; 
  99                         const char *separator 
= (context
) ? " " : ""; 
 100                         secitemlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
); 
 109 #define CFDataGetBytePtrVoid CFDataGetBytePtr 
 111 #pragma mark SecItem private utility functions 
 113 /******************************************************************************/ 
 115 struct ProtocolAttributeInfo 
{ 
 116         const CFStringRef 
*protocolValue
; 
 117         SecProtocolType protocolType
; 
 120 static ProtocolAttributeInfo gProtocolTypes
[] = { 
 121         { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP 
}, 
 122         { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount 
}, 
 123         { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP 
}, 
 124         { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC 
}, 
 125         { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP 
}, 
 126         { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3 
}, 
 127         { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP 
}, 
 128         { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS 
}, 
 129         { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP 
}, 
 130         { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP 
}, 
 131         { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk 
}, 
 132         { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP 
}, 
 133         { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet 
}, 
 134         { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH 
}, 
 135         { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS 
}, 
 136         { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS 
}, 
 137         { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy 
}, 
 138         { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy 
}, 
 139         { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy 
}, 
 140         { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB 
}, 
 141         { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP 
}, 
 142         { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy 
}, 
 143         { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP 
}, 
 144         { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC 
}, 
 145         { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP 
}, 
 146         { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS 
}, 
 147         { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS 
}, 
 148         { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS 
}, 
 149         { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS 
}, 
 150         { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS 
}, 
 151         { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S 
} 
 154 static const int kNumberOfProtocolTypes 
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
); 
 157  * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType. 
 159 static SecProtocolType
 
 160 _SecProtocolTypeForSecAttrProtocol( 
 163         SecProtocolType result 
= kSecProtocolTypeAny
; 
 165         if (protocol 
!= NULL
) { 
 167                 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 168                         if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) { 
 169                                 result 
= gProtocolTypes
[count
].protocolType
; 
 179  * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol. 
 182 _SecAttrProtocolForSecProtocolType( 
 183         SecProtocolType protocolType
) 
 185         CFTypeRef result 
= NULL
; 
 187         for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 188                 if (gProtocolTypes
[count
].protocolType 
== protocolType
) { 
 189                         result 
= *(gProtocolTypes
[count
].protocolValue
); 
 198 /******************************************************************************/ 
 200 struct AuthenticationAttributeInfo 
{ 
 201         const CFStringRef 
*authValue
; 
 202         SecAuthenticationType authType
; 
 205 static AuthenticationAttributeInfo gAuthTypes
[] = { 
 206         { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM 
}, 
 207         { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN 
}, 
 208         { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA 
}, 
 209         { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA 
}, 
 210         { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic 
}, 
 211         { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest 
}, 
 212         { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm 
}, 
 213         { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault 
} 
 216 static const int kNumberOfAuthenticationTypes 
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
); 
 219  * _SecAuthenticationTypeForSecAttrAuthenticationType converts a 
 220  * SecAttrAuthenticationType to a SecAuthenticationType. 
 222 static SecAuthenticationType
 
 223 _SecAuthenticationTypeForSecAttrAuthenticationType( 
 224         CFTypeRef authenticationType
) 
 226         SecAuthenticationType result 
= kSecAuthenticationTypeAny
; 
 228         if (authenticationType 
!= NULL
) { 
 230                 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 231                         if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) { 
 232                                 result 
= gAuthTypes
[count
].authType
; 
 242  * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType 
 243  * to a SecAttrAuthenticationType. 
 246 _SecAttrAuthenticationTypeForSecAuthenticationType( 
 247         SecAuthenticationType authenticationType
) 
 249         CFTypeRef result 
= NULL
; 
 251         for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 252                 if (gAuthTypes
[count
].authType 
== authenticationType
) { 
 253                         result 
= *(gAuthTypes
[count
].authValue
); 
 262 /******************************************************************************/ 
 264 struct KeyAlgorithmInfo 
{ 
 265         const CFStringRef 
*keyType
; 
 269 static KeyAlgorithmInfo gKeyTypes
[] = { 
 270         { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA 
}, 
 271         { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA 
}, 
 272         { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES 
}, 
 273         { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES 
}, 
 274         { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES 
}, 
 275         { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4 
}, 
 276         { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2 
}, 
 277         { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST 
}, 
 278         { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA 
}, 
 279         { &kSecAttrKeyTypeEC
, CSSM_ALGID_ECDSA 
} 
 282 static const int kNumberOfKeyTypes 
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
); 
 285 static UInt32 
_SecAlgorithmTypeFromSecAttrKeyType( 
 286         CFTypeRef keyTypeRef
) 
 288         UInt32 keyAlgValue 
= 0; 
 289         if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
)) 
 293         for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) { 
 294                 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) { 
 295                         keyAlgValue 
= gKeyTypes
[ix
].keyValue
; 
 300         //%%%TODO try to convert the input string to a number here 
 306 enum ItemRepresentation
 
 308         kStringRepresentation
, 
 310         kNumberRepresentation
, 
 311         kBooleanRepresentation
, 
 316 struct InternalAttributeListInfo
 
 319         const CFStringRef 
*newItemType
; 
 320         ItemRepresentation itemRepresentation
; 
 324 static InternalAttributeListInfo gGenericPasswordAttributes
[] = 
 326         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 327         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 328         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 329         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 330         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 331         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 332         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 333         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 334         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 335         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 336         { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation 
}, 
 337         { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation 
} 
 340 static const int kNumberOfGenericPasswordAttributes 
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 343 static InternalAttributeListInfo gInternetPasswordAttributes
[] = 
 345         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 346         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 347         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 348         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 349         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 350         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 351         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 352         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 353         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 354         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 355         { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation 
}, 
 356         { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation 
}, 
 357         { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation 
}, // maps from UInt32 value to string constant 
 358         { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation 
}, 
 359         { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation 
} 
 362 static const int kNumberOfInternetPasswordAttributes 
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 365 static InternalAttributeListInfo gCertificateAttributes
[] = 
 367         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 368         { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation 
}, 
 369         { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation 
}, 
 370         { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation 
}, 
 371         { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation 
}, 
 372         { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation 
}, 
 373         { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation 
}, 
 374         { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation 
} 
 377 static const int kNumberOfCertificateAttributes 
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
); 
 380 static InternalAttributeListInfo gKeyAttributes
[] = 
 382     { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation 
}, // key class maps from UInt32 value to string constant 
 383     { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation 
}, // note that "print name" maps to the user-visible label 
 384 //  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation }, 
 385     { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation 
}, 
 386 //  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 387 //  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 388     { 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 
 389     { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation 
}, 
 390 //  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key 
 391     { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation 
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES) 
 392     { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation 
}, 
 393     { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation 
}, 
 394 //  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 395 //  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 396 //  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 397 //  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 398 //  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 399 //  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 400     { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation 
}, 
 401     { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation 
}, 
 402     { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation 
}, 
 403     { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation 
}, 
 404     { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation 
}, 
 405 //  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 406 //  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 407     { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation 
}, 
 408     { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation 
} 
 411 static const int kNumberOfKeyAttributes 
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
); 
 414 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
) 
 418                 case kStringRepresentation
: 
 420                         if (CFStringGetTypeID() != CFGetTypeID(value
)) { 
 424                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 425                         char* buffer 
= (char*) malloc(maxLength
); 
 426                         Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 428                                 length 
= (UInt32
)strlen(buffer
); 
 438                 case kDataRepresentation
: 
 440                         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 441                 // We may have a string here, since the key label may be a GUID for the symmetric keys 
 442                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 443                 char* buffer 
= (char*) malloc(maxLength
); 
 444                 Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 446                     length 
= (UInt32
)strlen(buffer
); 
 456                         if (CFDataGetTypeID() != CFGetTypeID(value
)) { 
 460                         length 
= (UInt32
)CFDataGetLength((CFDataRef
) value
); 
 461                         uint8_t* buffer 
= (uint8_t*) malloc(length
); 
 462                         CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
); 
 466                 case kNumberRepresentation
: 
 468                         if (CFNumberGetTypeID() != CFGetTypeID(value
)) { 
 472                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 473                         Boolean converted 
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
); 
 475                                 length 
= sizeof(uint32_t); 
 485                 case kBooleanRepresentation
: 
 487                         if (CFBooleanGetTypeID() != CFGetTypeID(value
)) { 
 491                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 492                         *buffer 
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
 493                         length 
= sizeof(uint32_t); 
 497                 case kDateRepresentation
: 
 499                         if (CFDateGetTypeID() != CFGetTypeID(value
)) { 
 503                         char* buffer 
= (char*) calloc(1, 32); // max length of a CSSM date string 
 504                         CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
); 
 505                         length 
= (UInt32
)strlen(buffer
); 
 519 _ConvertNewFormatToOldFormat( 
 520         CFAllocatorRef allocator
, 
 521         const InternalAttributeListInfo
* info
, 
 523         CFDictionaryRef dictionaryRef
, 
 524         SecKeychainAttributeList
* &attrList
 
 527         // get the keychain attributes array from the data item 
 528         // here's the problem.  On the one hand, we have a dictionary that is purported to contain 
 529         // attributes for our type.  On the other hand, the dictionary may contain items we don't support, 
 530         // and we therefore don't know how many attributes we will have unless we count them first 
 533         attrList 
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
)); 
 535         // make storage to extract the dictionary items 
 536         CFIndex itemsInDictionary 
= CFDictionaryGetCount(dictionaryRef
); 
 537         CFTypeRef keys
[itemsInDictionary
]; 
 538         CFTypeRef values
[itemsInDictionary
]; 
 540         CFTypeRef 
*keysPtr 
= keys
; 
 541         CFTypeRef 
*valuesPtr 
= values
; 
 543         CFDictionaryGetKeysAndValues(dictionaryRef
, keys
, values
); 
 545         // count the number of items we are interested in 
 549         // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that 
 550         // we don't pay the price for this twice 
 551         SecKeychainAttrType tags
[itemsInDictionary
]; 
 552         ItemRepresentation types
[itemsInDictionary
]; 
 554         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 556                 CFTypeRef key 
= keysPtr
[i
]; 
 559                 for (j 
= 0; j 
< infoNumItems
; ++j
) 
 561                         if (CFEqual(*(info
[j
].newItemType
), key
)) 
 563                                 tags
[i
] = info
[j
].oldItemType
; 
 564                                 types
[i
] = info
[j
].itemRepresentation
; 
 570                 if (j 
>= infoNumItems
) 
 572                         // if we got here, we aren't interested in this item. 
 577         // now we can make the result array 
 578         attrList
->count 
= (UInt32
)count
; 
 579         attrList
->attr 
= (SecKeychainAttribute
*) malloc(sizeof(SecKeychainAttribute
) * count
); 
 581         // fill out the array 
 582         int resultPointer 
= 0; 
 583         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 585                 if (values
[i
] != NULL
) 
 587                         attrList
->attr
[resultPointer
].tag 
= tags
[i
]; 
 589                         // we have to clone the data pointer.  The caller will need to make sure to throw these away 
 590                         // with _FreeAttrList when it is done... 
 591                         attrList
->attr
[resultPointer
].data 
= CloneDataByType(types
[i
], valuesPtr
[i
], attrList
->attr
[resultPointer
].length
); 
 596         return errSecSuccess
; 
 602 _ConvertOldFormatToNewFormat( 
 603         CFAllocatorRef allocator
, 
 604         const InternalAttributeListInfo
* info
, 
 606         SecKeychainItemRef itemRef
, 
 607         CFMutableDictionaryRef
& dictionaryRef
) 
 609         SecKeychainAttributeList list
; 
 610         list
.count 
= infoNumItems
; 
 611         list
.attr 
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
)); 
 613         // fill out the array.  We only need to fill in the tags, since calloc zeros what it returns 
 615         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 617                 list
.attr
[i
].tag 
= info
[i
].oldItemType
; 
 620         OSStatus result 
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
); 
 621         if (result 
!= errSecSuccess
) 
 623                 dictionaryRef 
= NULL
; 
 628         // create the dictionary 
 629         dictionaryRef 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 632         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 634                 if (list
.attr
[i
].data 
== NULL
) 
 637                 switch (info
[i
].itemRepresentation
) 
 639                         case kStringRepresentation
: 
 641                                 CFStringRef stringRef
; 
 642                                 if (info
[i
].oldItemType 
== kSecKeyKeyClass
) { 
 643                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 644                                         uint32_t keyRecordValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 645                                         bool retainString 
= true; 
 646                                         switch (keyRecordValue
) { 
 647                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 648                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 650                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 651                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 653                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 654                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 657                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
); 
 661                                                 if (retainString
) CFRetain(stringRef
); 
 662                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 663                                                 CFRelease(stringRef
); 
 666                                 else if (info
[i
].oldItemType 
== kSecKeyKeyType
) { 
 667                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 668                                         uint32_t keyAlgValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 669                                         bool retainString 
= true; 
 670                                         switch (keyAlgValue
) { 
 671                                                 case CSSM_ALGID_RSA 
: 
 672                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 674                                                 case CSSM_ALGID_DSA 
: 
 675                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 677                                                 case CSSM_ALGID_AES 
: 
 678                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 680                                                 case CSSM_ALGID_DES 
: 
 681                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 683                                                 case CSSM_ALGID_3DES 
: 
 684                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 686                                                 case CSSM_ALGID_RC4 
: 
 687                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 689                                                 case CSSM_ALGID_RC2 
: 
 690                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 692                                                 case CSSM_ALGID_CAST 
: 
 693                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 695                                                 case CSSM_ALGID_ECDSA 
: 
 696                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 699                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
); 
 700                                                         retainString 
= false; 
 704                                                 if (retainString
) CFRetain(stringRef
); 
 705                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 706                                                 CFRelease(stringRef
); 
 710                                         // normal case: attribute contains a string 
 711                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 712                                         if (stringRef 
== NULL
) 
 713                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 714                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 715                                         CFRelease(stringRef
); 
 720                         case kDataRepresentation
: 
 722                 if ((info
[i
].oldItemType 
== kSecKeyLabel
) && (list
.attr
[i
].length 
== kUUIDStringLength
)) { 
 723                                         // It's possible that there could be a string here because the key label may have a UUID 
 724                                         CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 725                                         if (stringRef 
== NULL
) 
 726                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 727                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 728                                         CFRelease(stringRef
); 
 731                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
); 
 733                     dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
 734                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
); 
 739                         case kNumberRepresentation
: 
 741                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
); 
 742                                 if (numberRef 
== NULL
) 
 743                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
 744                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
); 
 745                                 CFRelease(numberRef
); 
 749                         case kBooleanRepresentation
: 
 751                                 uint32_t value 
= *((uint32_t*)list
.attr
[i
].data
); 
 752                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
 753                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
); 
 757                         case kDateRepresentation
: 
 759                                 CFDateRef dateRef 
= NULL
; 
 760                                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
); 
 762                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
 763                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
); 
 771         SecKeychainItemFreeContent(&list
, NULL
); 
 781  * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the 
 782  * attributes of item. 
 785 _CreateAttributesDictionaryFromGenericPasswordItem( 
 786         CFAllocatorRef allocator
, 
 787         SecKeychainItemRef item
, 
 788         CFDictionaryRef 
*dictionary
) 
 790         // do the basic allocations 
 791         CFMutableDictionaryRef dict 
= NULL
; 
 792         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
); 
 793         if (result 
== errSecSuccess
) // did we complete OK 
 795                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
); 
 806  * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the 
 807  * attributes of item. 
 810 _CreateAttributesDictionaryFromCertificateItem( 
 811         CFAllocatorRef allocator
, 
 812         SecKeychainItemRef item
, 
 813         CFDictionaryRef 
*dictionary
) 
 815         // do the basic allocations 
 816         CFMutableDictionaryRef dict 
= NULL
; 
 817         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
); 
 818         if (result 
== errSecSuccess
) // did we complete OK 
 820                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
); 
 825         return errSecSuccess
; 
 829  * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the 
 830  * attributes of item. 
 833 _CreateAttributesDictionaryFromKeyItem( 
 834         CFAllocatorRef allocator
, 
 835         SecKeychainItemRef item
, 
 836         CFDictionaryRef 
*dictionary
) 
 839 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails. 
 840 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and 
 841 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent. 
 844                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 847         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 849         // do the basic allocations 
 850         CFMutableDictionaryRef dict 
= NULL
; 
 851         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
); 
 852         if (result 
== errSecSuccess
) // did we complete OK 
 854                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
 859         return errSecSuccess
; 
 862         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 864         SecItemClass itemClass 
= 0; 
 866         SecKeychainAttributeList 
*attrList 
= NULL
; 
 867         SecKeychainAttributeInfo 
*info 
= NULL
; 
 868         SecKeychainRef keychain 
= NULL
; 
 870         OSStatus status 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
 872                 goto error_exit
; // item must have an itemClass 
 877     case kSecInternetPasswordItemClass
: 
 878                 itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
 880     case kSecGenericPasswordItemClass
: 
 881                 itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
 883     case 'ashp': /* kSecAppleSharePasswordItemClass */ 
 884                 itemID 
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
; 
 891         status 
= SecKeychainItemCopyKeychain(item
, &keychain
); 
 893                 goto error_exit
; // item must have a keychain, so we can get the attribute info for it 
 896         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
 898                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 901         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 903                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 906         for (ix 
= 0; ix 
< info
->count
; ++ix
) 
 908                 SecKeychainAttribute 
*attribute 
= &attrList
->attr
[ix
]; 
 909                 if (!attribute
->length 
&& !attribute
->data
) 
 912                 UInt32 j
, count 
= kNumberOfKeyAttributes
; 
 913                 InternalAttributeListInfo 
*intInfo 
= NULL
; 
 914                 for (j
=0; j
<count
; j
++) { 
 915                         if (gKeyAttributes
[j
].oldItemType 
== info
->tag
[ix
]) { 
 916                                 intInfo 
= &gKeyAttributes
[j
]; 
 923                 switch (intInfo
->itemRepresentation
) 
 925                         case kStringRepresentation
: 
 927                                 CFStringRef stringRef
; 
 928                                 if (intInfo
->oldItemType 
== kSecKeyKeyClass
) { 
 929                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 930                                         UInt32 keyRecordValue 
= *((UInt32
*)attribute
->data
); 
 931                                         bool retainString 
= true; 
 932                                         switch (keyRecordValue
) { 
 933                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 934                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 936                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 937                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 939                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 940                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 943                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyRecordValue
); 
 947                                                 if (retainString
) CFRetain(stringRef
); 
 948                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 949                                                 CFRelease(stringRef
); 
 952                                 else if (intInfo
->oldItemType 
== kSecKeyKeyType
) { 
 953                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 954                                         UInt32 keyAlgValue 
= *((UInt32
*)attribute
->data
); 
 955                                         bool retainString 
= true; 
 956                                         switch (keyAlgValue
) { 
 957                                                 case CSSM_ALGID_RSA 
: 
 958                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 960                                                 case CSSM_ALGID_DSA 
: 
 961                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 963                                                 case CSSM_ALGID_AES 
: 
 964                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 966                                                 case CSSM_ALGID_DES 
: 
 967                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 969                                                 case CSSM_ALGID_3DES 
: 
 970                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 972                                                 case CSSM_ALGID_RC4 
: 
 973                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 975                                                 case CSSM_ALGID_RC2 
: 
 976                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 978                                                 case CSSM_ALGID_CAST 
: 
 979                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 981                                                 case CSSM_ALGID_ECDSA 
: 
 982                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 985                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyAlgValue
); 
 986                                                         retainString 
= false; 
 990                                                 if (retainString
) CFRetain(stringRef
); 
 991                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 992                                                 CFRelease(stringRef
); 
 996                                         // normal case: attribute contains a string 
 997                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
 998                                         if (stringRef 
== NULL
) 
 999                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1000                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1001                                         CFRelease(stringRef
); 
1006                         case kDataRepresentation
: 
1008                 if ((intInfo
->oldItemType 
== kSecKeyLabel
) && (attribute
->length 
== kUUIDStringLength
)) { 
1009                                         // It's possible that there could be a string here because the key label may have a UUID 
1010                     CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1011                                         if (stringRef 
== NULL
) 
1012                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1013                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1014                                         CFRelease(stringRef
); 
1018                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
); 
1019                                 if (dataRef 
== NULL
) 
1020                                         dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
1021                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
); 
1026                         case kNumberRepresentation
: 
1028                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
); 
1029                                 if (numberRef 
== NULL
) 
1030                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
1031                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
); 
1032                                 CFRelease(numberRef
); 
1036                         case kBooleanRepresentation
: 
1038                                 UInt32 value 
= *((UInt32
*)attribute
->data
); 
1039                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1040                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
); 
1044                         case kDateRepresentation
: 
1046                                 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here 
1047                                 CFDateRef dateRef 
= NULL
; 
1048                                 if (dateRef 
== NULL
) 
1049                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
1050                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
); 
1057         CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
1062                 SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
1065                 SecKeychainFreeAttributeInfo(info
); 
1068                 CFRelease(keychain
); 
1077  * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the 
1078  * attributes of item. 
1081 _CreateAttributesDictionaryFromInternetPasswordItem( 
1082         CFAllocatorRef allocator
, 
1083         SecKeychainItemRef item
, 
1084         CFDictionaryRef 
*dictionary
) 
1087         SecKeychainAttribute attr
[] = { 
1088                 { kSecServerItemAttr
, 0, NULL 
},                /* [0] server */ 
1089                 { kSecSecurityDomainItemAttr
, 0, NULL 
},        /* [1] securityDomain */ 
1090                 { kSecAccountItemAttr
, 0, NULL 
},               /* [2] account */ 
1091                 { kSecPathItemAttr
, 0, NULL 
},                  /* [3] path */ 
1092                 { kSecPortItemAttr
, 0, NULL 
},                  /* [4] port */ 
1093                 { kSecProtocolItemAttr
, 0, NULL 
},              /* [5] protocol */ 
1094                 { kSecAuthenticationTypeItemAttr
, 0, NULL 
},    /* [6] authenticationType */ 
1095                 { kSecCommentItemAttr
, 0, NULL 
},               /* [7] comment */ 
1096                 { kSecDescriptionItemAttr
, 0, NULL 
},           /* [8] description */ 
1097                 { kSecLabelItemAttr
, 0, NULL 
},                 /* [9] label */ 
1098                 { kSecCreationDateItemAttr
, 0, NULL 
},  /* [10] creation date */ 
1099                 { kSecModDateItemAttr
, 0, NULL 
},               /* [11] modification date */ 
1100                 { kSecCreatorItemAttr
, 0, NULL 
},               /* [12] creator */ 
1101                 { kSecTypeItemAttr
, 0, NULL 
},                  /* [13] type */ 
1102                 { kSecInvisibleItemAttr
, 0, NULL 
},             /* [14] invisible */ 
1103                 { kSecNegativeItemAttr
, 0, NULL 
},              /* [15] negative */ 
1105         SecKeychainAttributeList attrList 
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr 
}; 
1108         CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1109         CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1113         // copy the item's attributes 
1114         status 
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
); 
1115         require_noerr(status
, SecKeychainItemCopyContent_failed
); 
1120         keys
[numValues
] = kSecClass
; 
1121         values
[numValues
] = kSecClassInternetPassword
; 
1124         // add kSecAttrServer 
1125         if ( attrList
.attr
[0].length 
> 0 ) { 
1126                 keys
[numValues
] = kSecAttrServer
; 
1127                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
); 
1128                 if ( values
[numValues
] != NULL 
) { 
1133         // add kSecAttrSecurityDomain 
1134         if ( attrList
.attr
[1].length 
> 0 ) { 
1135                 keys
[numValues
] = kSecAttrSecurityDomain
; 
1136                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
); 
1137                 if ( values
[numValues
] != NULL 
) { 
1142         // add kSecAttrAccount 
1143         if ( attrList
.attr
[2].length 
> 0 ) { 
1144                 keys
[numValues
] = kSecAttrAccount
; 
1145                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
); 
1146                 if ( values
[numValues
] != NULL 
) { 
1152         if ( attrList
.attr
[3].length 
> 0 ) { 
1153                 keys
[numValues
] = kSecAttrPath
; 
1154                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
); 
1155                 if ( values
[numValues
] != NULL 
) { 
1161         if ( attrList
.attr
[4].length 
> 0 ) { 
1162                 keys
[numValues
] = kSecAttrPort
; 
1163                 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
); 
1164                 if ( values
[numValues
] != NULL 
) { 
1169         // add kSecAttrProtocol 
1170         if ( attrList
.attr
[5].length 
> 0 ) { 
1171                 keys
[numValues
] = kSecAttrProtocol
; 
1172                 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
); 
1173                 if ( values
[numValues
] != NULL 
) { 
1174                         CFRetain(values
[numValues
]); 
1179         // add kSecAttrAuthenticationType 
1180         if ( attrList
.attr
[6].length 
> 0 ) { 
1181                 keys
[numValues
] = kSecAttrAuthenticationType
; 
1182                 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType(*(SecProtocolType
*)attrList
.attr
[6].data
); 
1183                 if ( values
[numValues
] != NULL 
) { 
1184                         CFRetain(values
[numValues
]); 
1189         // add kSecAttrComment 
1190         if ( attrList
.attr
[7].length 
> 0 ) { 
1191                 keys
[numValues
] = kSecAttrComment
; 
1192                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
); 
1193                 if ( values
[numValues
] != NULL 
) { 
1198         // add kSecAttrDescription 
1199         if ( attrList
.attr
[8].length 
> 0 ) { 
1200                 keys
[numValues
] = kSecAttrDescription
; 
1201                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
); 
1202                 if ( values
[numValues
] != NULL 
) { 
1207         // add kSecAttrLabel 
1208         if ( attrList
.attr
[9].length 
> 0 ) { 
1209                 keys
[numValues
] = kSecAttrLabel
; 
1210                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
); 
1211                 if ( values
[numValues
] != NULL 
) { 
1216         // add kSecAttrCreationDate 
1217         if ( attrList
.attr
[10].length 
> 0 ) { 
1218                 CFDateRef creationDate 
= NULL
; 
1219                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
); 
1220                 keys
[numValues
] = kSecAttrCreationDate
; 
1221                 values
[numValues
] = creationDate
; 
1222                 if ( values
[numValues
] != NULL 
) { 
1227         // add kSecAttrModificationDate 
1228         if ( attrList
.attr
[11].length 
> 0 ) { 
1229                 CFDateRef modDate 
= NULL
; 
1230                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
); 
1231                 keys
[numValues
] = kSecAttrModificationDate
; 
1232                 values
[numValues
] = modDate
; 
1233                 if ( values
[numValues
] != NULL 
) { 
1238         // add kSecCreatorItemAttr 
1239         if ( attrList
.attr
[12].length 
> 0 ) { 
1240                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
); 
1241                 keys
[numValues
] = kSecAttrCreator
; 
1242                 values
[numValues
] = numberRef
; 
1243                 if ( values
[numValues
] != NULL 
) { 
1244                         CFRetain(values
[numValues
]); 
1249         // add kSecTypeItemAttr 
1250         if ( attrList
.attr
[13].length 
> 0 ) { 
1251                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
); 
1252                 keys
[numValues
] = kSecAttrType
; 
1253                 values
[numValues
] = numberRef
; 
1254                 if ( values
[numValues
] != NULL 
) { 
1255                         CFRetain(values
[numValues
]); 
1260         // add kSecInvisibleItemAttr 
1261         if ( attrList
.attr
[14].length 
> 0 ) { 
1262                 uint32_t value 
= *((uint32_t*)attrList
.attr
[14].data
); 
1263                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1264                 keys
[numValues
] = kSecAttrIsInvisible
; 
1265                 values
[numValues
] = boolRef
; 
1266                 if ( values
[numValues
] != NULL 
) { 
1267                         CFRetain(values
[numValues
]); 
1272         // add kSecNegativeItemAttr 
1273         if ( attrList
.attr
[15].length 
> 0 ) { 
1274                 uint32_t value 
= *((uint32_t*)attrList
.attr
[15].data
); 
1275                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1276                 keys
[numValues
] = kSecAttrIsNegative
; 
1277                 values
[numValues
] = boolRef
; 
1278                 if ( values
[numValues
] != NULL 
) { 
1279                         CFRetain(values
[numValues
]); 
1284         // create the dictionary 
1285         *dictionary 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1287         // release the values added to the dictionary 
1288         for ( index 
= 0; index 
< numValues
; ++index 
) 
1290                 CFRelease(values
[index
]); 
1293         // and free the attributes 
1294         (void) SecKeychainItemFreeContent(&attrList
, NULL
); 
1296 SecKeychainItemCopyContent_failed
: 
1303  * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the 
1304  * attributes of the specified item class and item. 
1307 _CreateAttributesDictionaryFromItem( 
1308         CFAllocatorRef allocator
, 
1309         SecItemClass itemClass
, 
1310         SecKeychainItemRef item
, 
1311         CFDictionaryRef 
*dictionary
) 
1315                 case kSecInternetPasswordItemClass
: 
1316                         return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
); 
1318                 case kSecGenericPasswordItemClass
: 
1319                         return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
); 
1321                 case kSecCertificateItemClass
: 
1322                         return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
); 
1324                 case kSecPublicKeyItemClass
: 
1325                 case kSecPrivateKeyItemClass
: 
1326                 case kSecSymmetricKeyItemClass
: 
1327                         return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
); 
1338  * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList 
1339  * by the _CreateSecKeychainAttributeListFromDictionary function. 
1343         SecKeychainAttributeList 
*attrListPtr
) 
1347         if ( attrListPtr 
!= NULL 
) { 
1348                 if ( attrListPtr
->attr 
!= NULL 
) { 
1349                         // free any attribute data 
1350                         for ( index 
= 0; index 
< attrListPtr
->count
; ++index 
) { 
1351                                 free(attrListPtr
->attr
[index
].data
); 
1353                         // free the attribute array 
1354                         free(attrListPtr
->attr
); 
1356                 // free the attribute list 
1362  * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by 
1363  * attr using the data and tag parameters. 
1365  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1366  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1369 _CFDataCreateAttribute( 
1371         SecKeychainAttrType tag
, 
1372         SecKeychainAttributePtr attr
) 
1374         OSStatus status 
= errSecSuccess
; 
1377         // set the attribute tag 
1380         // determine the attribute length 
1381         attr
->length 
= (UInt32
) CFDataGetLength(data
); 
1382         range 
= CFRangeMake(0, (CFIndex
)attr
->length
); 
1384         // allocate memory for the attribute bytes 
1385         attr
->data 
= malloc(attr
->length
); 
1386         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1388         // get the attribute bytes 
1389         CFDataGetBytes(data
, range
, (UInt8 
*)attr
->data
); 
1397  * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by 
1398  * attr using the string and tag parameters. 
1400  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1401  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1404 _CFStringCreateAttribute( 
1406         SecKeychainAttrType tag
, 
1407         SecKeychainAttributePtr attr
) 
1409         OSStatus status 
= errSecSuccess
; 
1412         // set the attribute tag 
1415         // determine the attribute length 
1416         range 
= CFRangeMake(0, CFStringGetLength(string
)); 
1417         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex 
*)&attr
->length
); 
1419         // allocate memory for the attribute bytes 
1420         attr
->data 
= malloc(attr
->length
); 
1421         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1423         // get the attribute bytes 
1424         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8 
*)attr
->data
, attr
->length
, NULL
); 
1433  * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1434  * from the attribute key/values in attrDictionary. 
1436  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1437  * must be freed by the caller with _FreeAttrList() 
1440 _CreateSecKeychainGenericPasswordAttributeListFromDictionary( 
1441         CFDictionaryRef attrDictionary
, 
1442         SecKeychainAttributeList 
**attrList
) 
1444         return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
); 
1449  * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList 
1450  * from the attribute key/values in attrDictionary. 
1452  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1453  * must be freed by the caller with _FreeAttrList() 
1456 _CreateSecKeychainCertificateAttributeListFromDictionary( 
1457         CFDictionaryRef attrDictionary
, 
1458         SecKeychainAttributeList 
**attrList
) 
1460         return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
); 
1465  * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList 
1466  * from the attribute key/values in attrDictionary. 
1468  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1469  * must be freed by the caller with _FreeAttrList() 
1472 _CreateSecKeychainKeyAttributeListFromDictionary( 
1473         CFDictionaryRef attrDictionary
, 
1474         SecKeychainAttributeList 
**attrList
) 
1477         //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug 
1478         return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
); 
1480         // explicitly build attribute list for supported key attributes 
1481         // NOTE: this code supports only MaxSecKeyAttributes (15) attributes 
1482         const int MaxSecKeyAttributes 
= 15; 
1486         SecKeychainAttributeList 
*attrListPtr
; 
1488         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1489         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1491         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
)); 
1492         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1494         // [0] get the kSecKeyKeyClass value 
1495         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) { 
1496                 UInt32 keyRecordValue 
= 0; 
1497                 if (CFEqual(kSecAttrKeyClassPublic
, value
)) 
1498                         keyRecordValue 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
1499                 else if (CFEqual(kSecAttrKeyClassPrivate
, value
)) 
1500                         keyRecordValue 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
1501                 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
)) 
1502                         keyRecordValue 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
1504                 // only use this attribute if we recognize the value! 
1505                 if (keyRecordValue 
!= 0) { 
1506                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1507                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1509                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyClass
; 
1510                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1511                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
; 
1513                         ++attrListPtr
->count
; 
1517         // [1] get the kSecKeyPrintName string 
1518         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) { 
1519                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1520                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1522                 ++attrListPtr
->count
; 
1525         // [2] get the kSecKeyPermanent boolean 
1526         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) { 
1527                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1528                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1530                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyPermanent
; 
1531                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1532                 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1534                 ++attrListPtr
->count
; 
1537         // [3] get the kSecKeyLabel string 
1538         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) { 
1539         if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1540             status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1541         else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1542             status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1544             status 
= errSecParam
; 
1546                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1548                 ++attrListPtr
->count
; 
1551         // [4] get the kSecKeyApplicationTag data 
1552         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) { 
1553                 if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1554                         status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1555                 else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1556                         status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1558                         status 
= errSecParam
; 
1560                 require_noerr_quiet(status
, CFDataCreateAttribute_failed
); 
1561                 ++attrListPtr
->count
; 
1564         // [5] get the kSecKeyKeyType number 
1565         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) { 
1566                 UInt32 keyAlgValue 
= _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType
); 
1567                 if (keyAlgValue 
!= 0) { 
1568                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1569                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1571                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyType
; 
1572                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1573                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
; 
1575                         ++attrListPtr
->count
; 
1579         // [6] get the kSecKeyKeySizeInBits number 
1580         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) { 
1581                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1582                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1583                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1585                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeySizeInBits
; 
1586                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1587                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1589                         ++attrListPtr
->count
; 
1593         // [7] get the kSecKeyEffectiveKeySize number 
1594         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) { 
1595                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1596                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1597                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1599                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEffectiveKeySize
; 
1600                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1601                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1603                         ++attrListPtr
->count
; 
1607         // [8] get the kSecKeyEncrypt boolean 
1608         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) { 
1609                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1610                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1611                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1613                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEncrypt
; 
1614                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1615                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1617                         ++attrListPtr
->count
; 
1621         // [9] get the kSecKeyDecrypt boolean 
1622         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) { 
1623                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1624                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1625                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1627                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDecrypt
; 
1628                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1629                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1631                         ++attrListPtr
->count
; 
1635         // [10] get the kSecKeyDerive boolean 
1636         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) { 
1637                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1638                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1639                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1641                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDerive
; 
1642                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1643                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1645                         ++attrListPtr
->count
; 
1649         // [11] get the kSecKeySign boolean 
1650         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) { 
1651                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1652                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1653                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1655                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeySign
; 
1656                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1657                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1659                         ++attrListPtr
->count
; 
1663         // [12] get the kSecKeyVerify boolean 
1664         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) { 
1665                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1666                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1667                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1669                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyVerify
; 
1670                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1671                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1673                         ++attrListPtr
->count
; 
1677         // [13] get the kSecKeyWrap boolean 
1678         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) { 
1679                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1680                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1681                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1683                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyWrap
; 
1684                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1685                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1687                         ++attrListPtr
->count
; 
1691         // [14] get the kSecKeyUnwrap boolean 
1692         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) { 
1693                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1694                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1695                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1697                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyUnwrap
; 
1698                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1699                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1701                         ++attrListPtr
->count
; 
1705         // return the pointer to the attrList 
1706         *attrList 
= attrListPtr
; 
1708         return ( errSecSuccess 
); 
1712 malloc_number_failed
: 
1713 CFDataCreateAttribute_failed
: 
1714 CFStringCreateAttribute_failed
: 
1715 malloc_attrPtr_failed
: 
1717         // free any attributes 
1718         _FreeAttrList(attrListPtr
); 
1720 calloc_attrListPtr_failed
: 
1722         return ( errSecBufferTooSmall 
); 
1727 static CFTypeRef 
copyNumber(CFTypeRef obj
) 
1732     CFTypeID tid 
= CFGetTypeID(obj
); 
1733     if (tid 
== CFNumberGetTypeID()) 
1739     if (tid 
== CFBooleanGetTypeID()) 
1741         SInt32 value 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
1742         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1745     if (tid 
== CFStringGetTypeID()) 
1747         SInt32 value 
= CFStringGetIntValue((CFStringRef
)obj
); 
1748         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value
); 
1749         /* If a string converted to an int isn't equal to the int printed as 
1750          a string, return a NULL instead. */ 
1751         if (!CFEqual(t
, obj
)) 
1757         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1763  * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1764  * from the attribute key/values in attrDictionary. 
1766  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1767  * must be freed by the caller with _FreeAttrList() 
1770 _CreateSecKeychainInternetPasswordAttributeListFromDictionary( 
1771         CFDictionaryRef attrDictionary
, 
1772         SecKeychainAttributeList 
**attrList
) 
1774         // explicitly build attribute list for supported key attributes 
1775         // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes 
1776         const int MaxSecKeychainAttributes 
= 14; 
1780         SecKeychainAttributeList 
*attrListPtr
; 
1782         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1783         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1785         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
)); 
1786         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1789         // [0] get the serverName string 
1790         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) { 
1791                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1792                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1794                 ++attrListPtr
->count
; 
1797         // [1] get the securityDomain string 
1798         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) { 
1799                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1800                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1802                 ++attrListPtr
->count
; 
1805         // [2] get the accountName string 
1806         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) { 
1807                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1808                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1810                 ++attrListPtr
->count
; 
1813         // [3] get the path string 
1814         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) { 
1815                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1816                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1818                 ++attrListPtr
->count
; 
1821         // [4] get the port number 
1822         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) { 
1823                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt16
)); 
1824                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1826         CFTypeRef num 
= copyNumber(value
); 
1827                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1828                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecPortItemAttr
; 
1829                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt16
); 
1830                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1833                 ++attrListPtr
->count
; 
1836         // [5] get the protocol 
1837         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) { 
1838                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecProtocolType
)); 
1839                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_protocol_failed
, status 
= errSecBufferTooSmall
); 
1841                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecProtocolItemAttr
; 
1842                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecProtocolType
); 
1843                 *(SecProtocolType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
); 
1845                 ++attrListPtr
->count
; 
1848         // [6] get the authenticationType 
1849         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) { 
1850                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecAuthenticationType
)); 
1851                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_authenticationType_failed
, status 
= errSecBufferTooSmall
); 
1853                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecAuthenticationTypeItemAttr
; 
1854                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecAuthenticationType
); 
1855                 *(SecAuthenticationType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
); 
1857                 ++attrListPtr
->count
; 
1860         // [7] get the comment string 
1861         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) { 
1862                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1863                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1865                 ++attrListPtr
->count
; 
1868         // [8] get the description string 
1869         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) { 
1870                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1871                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1873                 ++attrListPtr
->count
; 
1876         // [9] get the label string 
1877         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) { 
1878                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1879                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1881                 ++attrListPtr
->count
; 
1884         // [10] get the creator code 
1885         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) { 
1886                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1887                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1889         CFTypeRef num 
= copyNumber(value
); 
1890                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1891                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecCreatorItemAttr
; 
1892                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1893                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1896                 ++attrListPtr
->count
; 
1899         // [11] get the type code 
1900         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) { 
1901                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1902                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1904         CFTypeRef num 
= copyNumber(value
); 
1905                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1906                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecTypeItemAttr
; 
1907                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1908                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1911                 ++attrListPtr
->count
; 
1914         // [12] get the invisible flag 
1915         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) { 
1916                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1917                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1919                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecInvisibleItemAttr
; 
1920                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1921                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1923                 ++attrListPtr
->count
; 
1926         // [13] get the negative flag 
1927         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) { 
1928                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1929                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1931                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecNegativeItemAttr
; 
1932                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1933                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1935                 ++attrListPtr
->count
; 
1938         // return the pointer to the attrList 
1939         *attrList 
= attrListPtr
; 
1941         return ( errSecSuccess 
); 
1945 malloc_authenticationType_failed
: 
1946 malloc_protocol_failed
: 
1948 CFStringCreateAttribute_failed
: 
1949 malloc_attrPtr_failed
: 
1951         // free any attributes 
1952         _FreeAttrList(attrListPtr
); 
1954 calloc_attrListPtr_failed
: 
1956         return ( errSecBufferTooSmall 
); 
1961  * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList 
1962  * from the attribute key/values in attrDictionary for the specified item class. 
1964  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1965  * must be freed by the caller with _FreeAttrList() 
1968 _CreateSecKeychainAttributeListFromDictionary( 
1969         CFDictionaryRef attrDictionary
, 
1970         SecItemClass itemClass
, 
1971         SecKeychainAttributeList 
**attrList
) 
1975                 case kSecInternetPasswordItemClass
: 
1976                         return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1978                 case kSecGenericPasswordItemClass
: 
1979                         return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1981                 case kSecCertificateItemClass
: 
1982                         return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
); 
1984                 case kSecPublicKeyItemClass
: 
1985                 case kSecPrivateKeyItemClass
: 
1986                 case kSecSymmetricKeyItemClass
: 
1987                         return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
); 
1997  * _AppNameFromSecTrustedApplication attempts to pull the name of the 
1998  * application/tool from the SecTrustedApplicationRef. 
2001 _AppNameFromSecTrustedApplication( 
2002         CFAllocatorRef alloc
, 
2003         SecTrustedApplicationRef appRef
) 
2007         CFDataRef appDataRef
; 
2011         // get the data for item's application/tool 
2012         status 
= SecTrustedApplicationCopyData(appRef
, &appDataRef
); 
2013         if ( status 
== errSecSuccess 
) { 
2016                 // convert it to a CFString potentially containing the path 
2017                 path 
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
); 
2018                 if ( path 
!= NULL 
) { 
2019                         // the path has to start with a "/" and cannot contain "://" 
2020                         if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location 
== kCFNotFound
) ) { 
2021                                 CFRange nameRange
, compRg
; 
2023                                 nameRange 
= CFRangeMake(0, CFStringGetLength(path
)); 
2025                                 // remove the trailing slashes (if any) 
2026                                 while ( (nameRange
.length 
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length 
- 1) == '/') ) { 
2027                                         nameRange
.length 
--; 
2030                                 if ( nameRange
.length 
> 0 ) { 
2031                                         // find last slash and adjust nameRange to be everything after it 
2032                                         if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) { 
2033                                                 nameRange
.length 
= nameRange
.location 
+ nameRange
.length 
- (compRg
.location 
+ 1); 
2034                                                 nameRange
.location 
= compRg
.location 
+ 1; 
2037                                         result 
= CFStringCreateWithSubstring(alloc
, path
, nameRange
); 
2042                 CFRelease(appDataRef
); 
2048 /* (This function really belongs in SecIdentity.cpp!) 
2050  * Returns the public key item corresponding to the identity, if it exists in 
2051  * the same keychain as the private key. Note that the public key might not 
2052  * exist in the same keychain (e.g. if the identity was imported via PKCS12), 
2053  * in which case it will not be found. 
2056 _SecIdentityCopyPublicKey( 
2057         SecIdentityRef identityRef
, 
2058         SecKeyRef 
*publicKeyRef
) 
2062         SecKeychainAttribute attr 
= { kSecKeyLabel
, 0, NULL 
}; 
2063         SecKeychainAttributeList attrList 
= { 1, &attr 
}; 
2064         SecKeychainAttributeList 
*keyAttrList 
= NULL
; 
2065         SecKeychainAttributeInfo 
*info 
= NULL
; 
2066         SecKeychainSearchRef search 
= NULL
; 
2067         SecKeychainRef keychain 
= NULL
; 
2068         SecKeychainItemRef privateKey 
= NULL
; 
2069         SecKeychainItemRef publicKey 
= NULL
; 
2071         status 
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef 
*)&privateKey
); 
2073                 goto error_exit
; // identity must have a private key 
2075         status 
= SecKeychainItemCopyKeychain(privateKey
, &keychain
); 
2077                 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it 
2079         status 
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
); 
2081                 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys 
2083         status 
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
); 
2085                 goto error_exit
; // unable to get the key label attribute for the private key 
2088         // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching 
2089         for (count 
= 0; count 
< keyAttrList
->count
; count
++) { 
2090                 if (keyAttrList
->attr
[count
].tag 
== kSecKeyLabel
) { 
2091                         attr
.length 
= keyAttrList
->attr
[count
].length
; 
2092                         attr
.data 
= keyAttrList
->attr
[count
].data
; 
2096         if (!attr
.length 
|| !attr
.data
) { 
2097                 status 
= errSecNoSuchAttr
; 
2098                 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel 
2100         status 
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
); 
2102                 goto error_exit
; // unable to create the search reference 
2104         status 
= SecKeychainSearchCopyNext(search
, &publicKey
); 
2106                 goto error_exit
; // unable to find the public key 
2110                 *publicKeyRef 
= (SecKeyRef
)publicKey
; 
2112                 CFRelease(publicKey
); 
2115         if (status 
!= errSecSuccess
) { 
2117                         *publicKeyRef 
= NULL
; 
2119                         CFRelease(publicKey
); 
2125                 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
); 
2128                 SecKeychainFreeAttributeInfo(info
); 
2131                 CFRelease(keychain
); 
2134                 CFRelease(privateKey
); 
2141  * Deletes a keychain item if the current application/tool is the only application/tool 
2142  * with decrypt access to that keychain item. If more than one application/tool 
2143  * has decrypt access to the keychain item, the item is left on the keychain. 
2145  * TBD: If more than one app/tool has access to the keychain item, we should remove 
2146  * the current app/tool's decrypt access. There's no easy way to do that with 
2147  * current keychain APIs without bringing up the security UI. 
2150 _SafeSecKeychainItemDelete( 
2151         SecKeychainItemRef itemRef
) 
2154         SecAccessRef access 
= NULL
; 
2155         CFArrayRef aclList 
= NULL
; 
2156         SecACLRef acl 
= NULL
; 
2157         CFArrayRef appList 
= NULL
; 
2158         CFStringRef description 
= NULL
; 
2159         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
2160         CFIndex idx
, count 
= 0; 
2161         SecTrustedApplicationRef currentAppRef 
= NULL
; 
2162         CFStringRef itemAppName 
= NULL
, currentAppName 
= NULL
; 
2164         SecItemClass itemClass 
= (SecItemClass
)0; 
2165         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2166         if (!(itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2167                 // only perform the access control safety check on deletion of password credentials; 
2168                 // if the item is of some other type, delete it normally. 
2169                 return SecKeychainItemDelete(itemRef
); 
2172         // skip access control checking for web form passwords: <rdar://10957301> 
2173         // This permits Safari to manage the removal of all web form passwords, 
2174         // regardless of whether they are shared by multiple applications. 
2175         if (itemClass 
== kSecInternetPasswordItemClass
) { 
2176                 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr 
}; 
2177                 SecKeychainAttributeInfo attrInfo 
= { 1, tags
, NULL 
}; 
2178                 SecKeychainAttributeList 
*attrs 
= NULL
; 
2179                 status 
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
); 
2180                 if (!status 
&& attrs
) { 
2181                         bool webFormPassword 
= (attrs
->attr
[0].length 
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4))); 
2182                         SecKeychainItemFreeAttributesAndData(attrs
, NULL
); 
2183                         if (webFormPassword
) { 
2184                                 return SecKeychainItemDelete(itemRef
); 
2189         // copy the access of the keychain item 
2190         status 
= SecKeychainItemCopyAccess(itemRef
, &access
); 
2191         require_noerr(status
, finish
); 
2192         require_quiet(access 
!= NULL
, finish
); 
2194         // copy the decrypt access control lists -- this is what has access to the keychain item 
2195         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
2196         require_noerr(status
, finish
); 
2197         require_quiet(aclList 
!= NULL
, finish
); 
2199         // get the access control list 
2200         acl 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
2201         require_quiet(acl 
!= NULL
, finish
); 
2203         // copy the application list, description, and CSSM prompt selector for a given access control list entry 
2204         status 
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
); 
2205         require_noerr(status
, finish
); 
2206         require_quiet(appList 
!= NULL
, finish
); 
2208         // does the calling application/tool have decrypt access to this item? 
2209         count 
= CFArrayGetCount(appList
); 
2210         for ( idx 
= 0; idx 
< count
; idx
++ ) { 
2211                 // get SecTrustedApplicationRef for this entry 
2212                 SecTrustedApplicationRef itemAppRef 
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, idx
); 
2213                 require_quiet(itemAppRef 
!= NULL
, finish
); 
2215                 // copy the name out 
2216                 CFReleaseSafe(itemAppName
); 
2217                 itemAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
); 
2218                 if (itemAppName 
== NULL
) { 
2220                          * If there is no app name, it's probably because it's not an appname 
2221                          * in the ACE but an entitlement/info.plist based rule instead; 
2222                          * just let the caller have it. */ 
2227                 // create SecTrustedApplicationRef for current application/tool 
2228                 CFReleaseSafe(currentAppRef
); 
2229                 status 
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
); 
2230                 require_noerr(status
, finish
); 
2231                 require_quiet(currentAppRef 
!= NULL
, finish
); 
2233                 // copy the name out 
2234                 CFReleaseSafe(currentAppName
); 
2235                 currentAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
); 
2236                 require_quiet(currentAppName 
!= NULL
, finish
); 
2238                 // compare the names to see if we own the decrypt access 
2239                 // TBD: validation of membership in an application group 
2240                 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo 
) { 
2248         CFReleaseSafe(currentAppName
); 
2249         CFReleaseSafe(itemAppName
); 
2250         CFReleaseSafe(currentAppRef
); 
2251         CFReleaseSafe(description
); 
2252         CFReleaseSafe(appList
); 
2253         CFReleaseSafe(aclList
); 
2254         CFReleaseSafe(access
); 
2256         if ((count 
== 0) || (status 
== errSecVerifyFailed
)) { 
2257                 // no "owners" remain in the ACL list (or unable to get ACL) 
2258                 status 
= SecKeychainItemDelete(itemRef
); 
2260                 // caller is not the "owner" of the item 
2261                 status 
= errSecInvalidOwnerEdit
; 
2268 _ReplaceKeychainItem( 
2269         SecKeychainItemRef itemToUpdate
, 
2270         SecKeychainAttributeList 
*changeAttrList
, 
2275         SecItemClass itemClass
; 
2276         SecKeychainAttributeInfo 
*info 
= NULL
; 
2277         SecKeychainAttributeList 
*attrList 
= NULL
; 
2278         SecKeychainAttributeList newAttrList 
= { 0, NULL
}; 
2279         SecKeychainRef keychain 
= NULL
; 
2280         SecKeychainItemRef newItem 
= NULL
; 
2282         int priority 
= LOG_DEBUG
; 
2283         const char *format 
= "ReplaceKeychainItem (%d) error %d"; 
2285         // get existing item's keychain 
2286         status 
= SecKeychainItemCopyKeychain(itemToUpdate
, &keychain
); 
2287         if (status
) { secitemlog(priority
, format
, 1, (int)status
); } 
2288         require_noerr(status
, replace_failed
); 
2290         // get attribute info (i.e. database schema) for the item class 
2291         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2292         if (status
) { secitemlog(priority
, format
, 2, (int)status
); } 
2293         require_noerr(status
, replace_failed
); 
2297                 case kSecInternetPasswordItemClass
: 
2298                         itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
2300                 case kSecGenericPasswordItemClass
: 
2301                         itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
2307         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
2308         if (status
) { secitemlog(priority
, format
, 3, (int)status
); } 
2310         // get item's existing attributes (but not data!) 
2311         status 
= SecKeychainItemCopyAttributesAndData(itemToUpdate
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
2312         if (status
) { secitemlog(priority
, format
, 4, (int)status
); } 
2313         require(attrList 
!= NULL
, replace_failed
); 
2315         // move aside the item by changing a primary attribute 
2316     // (currently only for passwords) 
2317         if (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
) { 
2318                 CFUUIDRef uuid 
= CFUUIDCreate(kCFAllocatorDefault
); 
2319                 CFStringRef uuidStr 
= (uuid
) ? CFUUIDCreateString(kCFAllocatorDefault
, uuid
) : CFSTR("MOVED"); 
2320                 CFReleaseSafe(uuid
); 
2322                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(uuidStr
), kCFStringEncodingUTF8
) + 1; 
2323                         char* buffer 
= (char*) malloc(maxLength
); 
2325                                 if (CFStringGetCString(uuidStr
, buffer
, maxLength
, kCFStringEncodingUTF8
)) { 
2326                                         UInt32 length 
= (UInt32
)strlen(buffer
); 
2327                                         SecKeychainAttribute attrs
[] = { { kSecAccountItemAttr
, length
, (char*)buffer 
}, }; 
2328                                         SecKeychainAttributeList updateAttrList 
= { sizeof(attrs
) / sizeof(attrs
[0]), attrs 
}; 
2329                                         status 
= SecKeychainItemModifyAttributesAndData(itemToUpdate
, &updateAttrList
, 0, NULL
); 
2330                                         if (status
) { secitemlog(priority
, format
, 5, (int)status
); } 
2331                                         if (status 
== errSecVerifyFailed
) { 
2332                                                 // still unable to change attrs? delete unconditionally here 
2333                                                 status 
= SecKeychainItemDelete(itemToUpdate
); 
2334                                                 if (status
) { secitemlog(priority
, format
, 6, (int)status
); } 
2339                         CFReleaseSafe(uuidStr
); 
2342         require_noerr(status
, replace_failed
); 
2344         // make attribute list for new item (the data is still owned by attrList) 
2345         newAttrList
.count 
= attrList
->count
; 
2346         newAttrList
.attr 
= (SecKeychainAttribute 
*) malloc(sizeof(SecKeychainAttribute
) * attrList
->count
); 
2348         for (i
=0, newCount
=0; i 
< attrList
->count
; i
++) { 
2349                 if (attrList
->attr
[i
].length 
> 0) { 
2350                         newAttrList
.attr
[newCount
++] = attrList
->attr
[i
]; 
2352                         // debugging code to log item attributes 
2353                         SecKeychainAttrType tag 
= attrList
->attr
[i
].tag
; 
2354                         SecKeychainAttrType htag
=(SecKeychainAttrType
)OSSwapConstInt32(tag
); 
2355                         char tmp
[sizeof(SecKeychainAttrType
) + 1]; 
2356                         char tmpdata
[attrList
->attr
[i
].length 
+ 1]; 
2357                         memcpy(tmp
, &htag
, sizeof(SecKeychainAttrType
)); 
2358                         tmp
[sizeof(SecKeychainAttrType
)]=0; 
2359                         memcpy(tmpdata
, attrList
->attr
[i
].data
, attrList
->attr
[i
].length
); 
2360                         tmpdata
[attrList
->attr
[i
].length
]=0; 
2361                         secitemlog(priority
, "item attr '%s' = %d bytes: \"%s\"", 
2362                                 tmp
, (int)attrList
->attr
[i
].length
, tmpdata
); 
2366         newAttrList
.count 
= newCount
; 
2368         // create new item in the same keychain 
2369         status 
= SecKeychainItemCreateFromContent(itemClass
, &newAttrList
, 
2370                 (UInt32
)((itemData
) ? CFDataGetLength(itemData
) : 0), 
2371                 (const void *)((itemData
) ? CFDataGetBytePtr(itemData
) : NULL
), 
2372                 keychain
, NULL
, &newItem
); 
2373         if (status
) { secitemlog(priority
, format
, 7, (int)status
); } 
2374         require_noerr(status
, replace_failed
); 
2376         // delete the old item unconditionally once new item exists 
2377         status 
= SecKeychainItemDelete(itemToUpdate
); 
2379         // update the new item with changed attributes, if any 
2380         status 
= (changeAttrList
) ? SecKeychainItemModifyContent(newItem
, changeAttrList
, 0, NULL
) : errSecSuccess
; 
2381         if (status
) { secitemlog(priority
, format
, 8, (int)status
); } 
2382         if (status 
== errSecSuccess
) { 
2383                 // say the item already exists, because it does now. <rdar://19063674> 
2384                 status 
= errSecDuplicateItem
; 
2388         if (newAttrList
.attr
) { 
2389                 free(newAttrList
.attr
); 
2392         SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
2395         SecKeychainFreeAttributeInfo(info
); 
2397         CFReleaseSafe(newItem
); 
2398         CFReleaseSafe(keychain
); 
2404 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
) 
2406         // This function updates a single keychain item, which may be specified as 
2407         // a reference, persistent reference or attribute dictionary, with the 
2408         // attributes provided. 
2410         OSStatus status 
= errSecSuccess
; 
2415         SecItemClass itemClass
; 
2416         SecAccessRef access 
= NULL
; 
2417         SecKeychainAttributeList 
*changeAttrList 
= NULL
; 
2418         SecKeychainItemRef itemToUpdate 
= NULL
; 
2419         CFDataRef theData 
= NULL
; 
2420         CFTypeID itemType 
= CFGetTypeID(item
); 
2422         // validate input item (must be convertible to a SecKeychainItemRef) 
2423         if (SecKeychainItemGetTypeID() == itemType 
|| 
2424                 SecCertificateGetTypeID() == itemType 
|| 
2425                 SecKeyGetTypeID() == itemType
) { 
2426                 // item is already a reference, retain it 
2427                 itemToUpdate 
= (SecKeychainItemRef
) CFRetain(item
); 
2429         else if (CFDataGetTypeID() == itemType
) { 
2430                 // item is a persistent reference, must convert it 
2431                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
); 
2433         else if (CFDictionaryGetTypeID() == itemType
) { 
2434                 // item is a dictionary 
2435                 CFTypeRef value 
= NULL
; 
2436                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2437                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2438                         itemToUpdate 
= (SecKeychainItemRef
) CFRetain(value
); 
2440                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2441                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2442                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
); 
2445         else if (SecIdentityGetTypeID() == itemType
) { 
2446                 // item is a certificate + private key; since we can't really change the 
2447                 // certificate's attributes, assume we want to update the private key 
2448                 status 
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
); 
2450         require_action(itemToUpdate 
!= NULL
, update_failed
, status 
= errSecInvalidItemRef
); 
2451         require_noerr(status
, update_failed
); 
2453         status 
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
); 
2454         require_noerr(status
, update_failed
); 
2456         // build changeAttrList from changedAttributes dictionary 
2459                 case kSecInternetPasswordItemClass
: 
2461                         status 
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2462                         require_noerr(status
, update_failed
); 
2466                 case kSecGenericPasswordItemClass
: 
2468                         status 
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2469                         require_noerr(status
, update_failed
); 
2473                 case kSecCertificateItemClass
: 
2475                         status 
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2476                         require_noerr(status
, update_failed
); 
2480                 case kSecPublicKeyItemClass
: 
2481                 case kSecPrivateKeyItemClass
: 
2482                 case kSecSymmetricKeyItemClass
: 
2484                         status 
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2485                         require_noerr(status
, update_failed
); 
2490         // (if the caller is not updating the password, this value will be NULL) 
2491         theData 
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
); 
2492         if (theData 
!= NULL
) { 
2493                 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status 
= errSecParam
); 
2496         status 
= SecKeychainItemModifyContent(itemToUpdate
, 
2497                                 (changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2498                                 (theData 
!= NULL
) ? (UInt32
)CFDataGetLength(theData
) : 0, 
2499                                 (theData 
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
); 
2500         require_noerr(status
, update_failed
); 
2502         // one more thing... update access? 
2503         if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) { 
2504                 status 
= SecKeychainItemSetAccess(itemToUpdate
, access
); 
2508         if (status 
== errSecVerifyFailed 
&& 
2509                 (itemClass 
== kSecInternetPasswordItemClass 
|| itemClass 
== kSecGenericPasswordItemClass
)) { 
2510                 // if we got a cryptographic failure updating a password item, it needs to be replaced 
2511                 status 
= _ReplaceKeychainItem(itemToUpdate
, 
2512                                         (changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2516                 CFRelease(itemToUpdate
); 
2517         _FreeAttrList(changeAttrList
); 
2522 _DeleteKeychainItem(CFTypeRef item
) 
2524         // This function deletes a single keychain item, which may be specified as 
2525         // a reference, persistent reference or attribute dictionary. It will not 
2526         // delete non-keychain items or aggregate items (such as a SecIdentityRef); 
2527         // it is assumed that the caller will pass identity components separately. 
2529         OSStatus status 
= errSecSuccess
; 
2534         SecKeychainItemRef itemToDelete 
= NULL
; 
2535         CFTypeID itemType 
= CFGetTypeID(item
); 
2536         if (SecKeychainItemGetTypeID() == itemType 
|| 
2537                 SecCertificateGetTypeID() == itemType 
|| 
2538                 SecKeyGetTypeID() == itemType
) { 
2539                 // item is already a reference, retain it 
2540                 itemToDelete 
= (SecKeychainItemRef
) CFRetain(item
); 
2542         else if (CFDataGetTypeID() == itemType
) { 
2543                 // item is a persistent reference, must convert it 
2544                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
); 
2546         else if (CFDictionaryGetTypeID() == itemType
) { 
2547                 // item is a dictionary 
2548                 CFTypeRef value 
= NULL
; 
2549                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2550                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2551                         itemToDelete 
= (SecKeychainItemRef
) CFRetain(value
); 
2553                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2554                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2555                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
); 
2561                         status 
= _SafeSecKeychainItemDelete(itemToDelete
); 
2563                 CFRelease(itemToDelete
); 
2570 _DeleteIdentity(SecIdentityRef identity
) 
2572         OSStatus status
, result 
= errSecSuccess
; 
2573         SecKeyRef privateKey 
= NULL
; 
2574         SecCertificateRef certificate 
= NULL
; 
2576         status 
= SecIdentityCopyPrivateKey(identity
, &privateKey
); 
2578                 SecKeyRef publicKey 
= NULL
; 
2579                 status 
= _SecIdentityCopyPublicKey(identity
, &publicKey
); 
2581                         status 
= _DeleteKeychainItem(publicKey
); 
2582                         CFRelease(publicKey
); 
2584                 status 
= _DeleteKeychainItem(privateKey
); 
2587         if (privateKey
) CFRelease(privateKey
); 
2588         if (status
) result 
= status
; 
2590         status 
= SecIdentityCopyCertificate(identity
, &certificate
); 
2592                 status 
= _DeleteKeychainItem(certificate
); 
2595         if (certificate
) CFRelease(certificate
); 
2596         if (status
) result 
= status
; 
2602 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
) 
2604         // This function is used when atomically processing multiple items, 
2605         // where an overall error result must be returned for the entire operation. 
2606         // When newStatus is something other than errSecSuccess, we want to keep the "most 
2607         // interesting" status (which usually will be newStatus, unless curStatus is 
2608         // already set; in that case, newStatus can trump curStatus only by being 
2609         // something different than baseStatus.) 
2611         OSStatus result 
= curStatus
; 
2613         if (newStatus 
!= errSecSuccess
) { 
2615                 if (curStatus 
!= errSecSuccess
) { 
2616                         result 
= (newStatus 
!= baseStatus
) ? newStatus 
: curStatus
; 
2623 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
) 
2625         // CFDictionaryApplierFunction 
2626         // This function just takes the given key/value pair, 
2627         // and adds it to another dictionary supplied in the context argument. 
2629         CFMutableDictionaryRef dict 
= *((CFMutableDictionaryRef
*) context
); 
2631                 CFDictionaryAddValue(dict
, key
, value
); 
2635 static CFStringCompareFlags
 
2636 _StringCompareFlagsFromQuery(CFDictionaryRef query
) 
2639         CFStringCompareFlags flags 
= 0; 
2640         if (!query
) return flags
; 
2642         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) || 
2643                 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2644                 flags 
|= kCFCompareAnchored
; 
2646         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2647                 flags 
|= kCFCompareBackwards
; 
2649         if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2650                 flags 
|= kCFCompareCaseInsensitive
; 
2652         if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2653                 flags 
|= kCFCompareDiacriticInsensitive
; 
2655         if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2656                 flags 
|= kCFCompareWidthInsensitive
; 
2662 _CssmKeyUsageFromQuery(CFDictionaryRef query
) 
2665         uint32 keyUsage 
= 0; 
2666         if (!query
) return keyUsage
; 
2668         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2669                 keyUsage 
|= CSSM_KEYUSE_ENCRYPT
; 
2671         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2672                 keyUsage 
|= CSSM_KEYUSE_DECRYPT
; 
2674         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2675                 keyUsage 
|= CSSM_KEYUSE_SIGN
; 
2677         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2678                 keyUsage 
|= CSSM_KEYUSE_VERIFY
; 
2680         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2681                 keyUsage 
|= CSSM_KEYUSE_WRAP
; 
2683         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2684                 keyUsage 
|= CSSM_KEYUSE_UNWRAP
; 
2686         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2687                 keyUsage 
|= CSSM_KEYUSE_DERIVE
; 
2693 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean 
*isIdentity
) 
2695         SecItemClass itemClass 
= (SecItemClass
) 0; 
2696         if (isIdentity
) *isIdentity 
= false; 
2698         if (CFEqual(item
, kSecClassGenericPassword
)) { 
2699                 itemClass 
= kSecGenericPasswordItemClass
; 
2701         else if (CFEqual(item
, kSecClassInternetPassword
)) { 
2702                 itemClass 
= kSecInternetPasswordItemClass
; 
2704         else if (CFEqual(item
, kSecClassCertificate
)) { 
2705                 itemClass 
= kSecCertificateItemClass
; 
2707         else if (CFEqual(item
, kSecClassIdentity
)) { 
2708                 // will perform a certificate lookup 
2709                 itemClass 
= kSecCertificateItemClass
; 
2710                 if (isIdentity
) *isIdentity 
= true; 
2712         else if (CFEqual(item
, kSecClassKey
)) { 
2713                 // examine second parameter to determine type of key 
2714                 if (!keyClass 
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) { 
2715                         itemClass 
= kSecSymmetricKeyItemClass
; 
2717                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) { 
2718                         itemClass 
= kSecPublicKeyItemClass
; 
2720                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) { 
2721                         itemClass 
= kSecPrivateKeyItemClass
; 
2729 _ItemClassFromItemList(CFArrayRef itemList
) 
2731         // Given a list of items (standard or persistent references), 
2732         // determine whether they all have the same item class. Returns 
2733         // the item class, or 0 if multiple classes in list. 
2734         SecItemClass result 
= 0; 
2735         CFIndex index
, count 
= (itemList
) ? CFArrayGetCount(itemList
) : 0; 
2736         for (index
=0; index 
< count
; index
++) { 
2737                 CFTypeRef item 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemList
, index
); 
2739                         SecKeychainItemRef itemRef 
= NULL
; 
2741                         if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
2742                                 // persistent reference, resolve first 
2743                                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemRef
); 
2746                                 itemRef 
= (SecKeychainItemRef
) CFRetain(item
); 
2749                                 SecItemClass itemClass 
= 0; 
2750                                 CFTypeID itemTypeID 
= CFGetTypeID(itemRef
); 
2751                                 if (itemTypeID 
== SecIdentityGetTypeID() || itemTypeID 
== SecCertificateGetTypeID()) { 
2752                                         // Identities and certificates have the same underlying item class 
2753                                         itemClass 
= kSecCertificateItemClass
; 
2755                                 else if (itemTypeID 
== SecKeychainItemGetTypeID()) { 
2756                                         // Reference to item in a keychain 
2757                                         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2759                                 else if (itemTypeID 
== SecKeyGetTypeID()) { 
2760                                         // SecKey that isn't stored in a keychain 
2761                                         // %%% will need to change this code when SecKey is no longer CSSM-based %%% 
2762                                         const CSSM_KEY 
*cssmKey
; 
2763                                         status 
= SecKeyGetCSSMKey((SecKeyRef
)itemRef
, &cssmKey
); 
2764                                         if (status 
== errSecSuccess
) { 
2765                                                 if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) 
2766                                                         itemClass 
= kSecPublicKeyItemClass
; 
2767                                                 else if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY
) 
2768                                                         itemClass 
= kSecPrivateKeyItemClass
; 
2770                                                         itemClass 
= kSecSymmetricKeyItemClass
; 
2774                                 if (itemClass 
!= 0) { 
2775                                         if (result 
!= 0 && result 
!= itemClass
) { 
2776                                                 return 0; // different item classes in list; bail out 
2786 // SecItemParams contains a validated set of input parameters, as well as a 
2787 // search reference and attribute list built from those parameters. It is 
2788 // designed to be allocated with _CreateSecItemParamsFromDictionary, and 
2789 // freed with _FreeSecItemParams. 
2791 struct SecItemParams 
{ 
2792         CFDictionaryRef query
;                          // caller-supplied query 
2793         int numResultTypes
;                                     // number of result types requested 
2794         int maxMatches
;                                         // max number of matches to return 
2795         uint32 keyUsage
;                                        // key usage(s) requested 
2796         Boolean returningAttributes
;            // true if returning attributes dictionary 
2797         Boolean returningData
;                          // true if returning item's data 
2798         Boolean returningRef
;                           // true if returning item reference 
2799         Boolean returningPersistentRef
;         // true if returing a persistent reference 
2800         Boolean returnAllMatches
;                       // true if we should return all matches 
2801         Boolean returnIdentity
;                         // true if we are returning a SecIdentityRef 
2802         Boolean trustedOnly
;                            // true if we only return trusted certs 
2803         Boolean issuerAndSNToMatch
;                     // true if both issuer and SN were provided 
2804         SecItemClass itemClass
;                         // item class for this query 
2805         SecPolicyRef policy
;                            // value for kSecMatchPolicy (may be NULL) 
2806         SecKeychainRef keychain
;                        // value for kSecUseKeychain (may be NULL) 
2807         CFArrayRef useItems
;                            // value for kSecUseItemList (may be NULL) 
2808         CFArrayRef itemList
;                            // value for kSecMatchItemList (may be NULL) 
2809         CFTypeRef searchList
;                           // value for kSecMatchSearchList (may be NULL) 
2810         CFTypeRef matchLimit
;                           // value for kSecMatchLimit (may be NULL) 
2811         CFTypeRef emailAddrToMatch
;                     // value for kSecMatchEmailAddressIfPresent (may be NULL) 
2812         CFTypeRef validOnDate
;                          // value for kSecMatchValidOnDate (may be NULL) 
2813         CFTypeRef keyClass
;                                     // value for kSecAttrKeyClass (may be NULL) 
2814         CFTypeRef service
;                                      // value for kSecAttrService (may be NULL) 
2815         CFTypeRef issuer
;                                       // value for kSecAttrIssuer (may be NULL) 
2816         CFTypeRef serialNumber
;                         // value for kSecAttrSerialNumber (may be NULL) 
2817         CFTypeRef search
;                                       // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) 
2818         CFTypeRef assumedKeyClass
;                      // if no kSecAttrKeyClass provided, holds the current class we're searching for 
2819         CFIndex itemListIndex
;                          // if no search reference but we have itemList, holds index of next item to return 
2820         SecKeychainAttributeList 
*attrList
;     // attribute list for this query 
2821         SecAccessRef access
;                            // access reference (for SecItemAdd only, not used to find items) 
2822         CFDataRef itemData
;                                     // item data (for SecItemAdd only, not used to find items) 
2823         CFTypeRef itemRef
;                                      // item reference (to find, add, update or delete, depending on context) 
2824         SecIdentityRef identityRef
;                     // identity reference (input as kSecValueRef) 
2825         CFDataRef itemPersistentRef
;            // item persistent reference (to find, add, update or delete, depending on context) 
2826         Boolean isPCSItem
;                                      // true if this query is for a Protected Cloud Storage item 
2830 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
) 
2832         if (!dict 
|| !key 
|| !value 
|| !expectedTypeID
) 
2835         if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) { 
2836                 // value was not provided for this key (not an error!) 
2839         else if (!(*value
)) { 
2840                 // provided value is NULL (also not an error!) 
2841                 return errSecSuccess
; 
2844                 CFTypeID actualTypeID 
= CFGetTypeID(*value
); 
2845                 if (!((expectedTypeID 
== actualTypeID
) || (altTypeID 
&& altTypeID 
== actualTypeID
))) { 
2846                         // provided value does not have the expected (or alternate) CF type ID 
2847                         if ((expectedTypeID 
== SecKeychainItemGetTypeID()) && 
2848                                 (actualTypeID 
== SecKeyGetTypeID() || actualTypeID 
== SecCertificateGetTypeID())) { 
2849                                 // provided value is a "floating" reference which is not yet in a keychain 
2851                                 return errSecSuccess
; 
2853                         return errSecItemInvalidValue
; 
2856                         // provided value is OK; retain it 
2860         return errSecSuccess
; 
2864 _EnsureUserDefaultKeychainIsSearched(SecItemParams 
*itemParams
) 
2867         CFArrayRef tmpList 
= (CFArrayRef
) itemParams
->searchList
; 
2869                 // search list exists; make it mutable 
2870                 itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2873                 // no search list; start with default list 
2874                 status 
= SecKeychainCopySearchList(&tmpList
); 
2875                 if (!status 
&& tmpList
) { 
2876                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpList
); 
2880                         itemParams
->searchList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2884         SecKeychainRef userKeychain 
= NULL
; 
2885         status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2886         if (!status 
&& userKeychain
) { 
2887                 if (!CFArrayContainsValue((CFArrayRef
)itemParams
->searchList
, 
2888                         CFRangeMake(0, CFArrayGetCount((CFArrayRef
)itemParams
->searchList
)), userKeychain
)) { 
2889                         // user's default keychain isn't currently in the search list, so append it 
2890                         CFArrayAppendValue((CFMutableArrayRef
)itemParams
->searchList
, userKeychain
); 
2892                 CFRelease(userKeychain
); 
2897 _EnsureUserDefaultKeychainIsTargeted(SecItemParams 
*itemParams
) 
2899         if (itemParams
->keychain
) { 
2900                 return; // keychain is already explicitly specified, assume it's correct 
2902         SecKeychainRef userKeychain 
= NULL
; 
2903         OSStatus status 
= SecKeychainCopyDomainDefault(kSecPreferencesDomainUser
, &userKeychain
); 
2904         if (!status 
&& userKeychain
) { 
2905                 itemParams
->keychain 
= userKeychain
; 
2910 _FreeSecItemParams(SecItemParams 
*itemParams
) 
2915         if (itemParams
->query
) CFRelease(itemParams
->query
); 
2916         if (itemParams
->policy
) CFRelease(itemParams
->policy
); 
2917         if (itemParams
->keychain
) CFRelease(itemParams
->keychain
); 
2918         if (itemParams
->useItems
) CFRelease(itemParams
->useItems
); 
2919         if (itemParams
->itemList
) CFRelease(itemParams
->itemList
); 
2920         if (itemParams
->searchList
) CFRelease(itemParams
->searchList
); 
2921         if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
); 
2922         if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
); 
2923         if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
); 
2924         if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
); 
2925         if (itemParams
->service
) CFRelease(itemParams
->service
); 
2926         if (itemParams
->issuer
) CFRelease(itemParams
->issuer
); 
2927         if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
); 
2928         if (itemParams
->search
) CFRelease(itemParams
->search
); 
2929         if (itemParams
->access
) CFRelease(itemParams
->access
); 
2930         if (itemParams
->itemData
) CFRelease(itemParams
->itemData
); 
2931         if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
); 
2932         if (itemParams
->identityRef
) CFRelease(itemParams
->identityRef
); 
2933         if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
); 
2935         _FreeAttrList(itemParams
->attrList
); 
2940 static SecItemParams
* 
2941 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus 
*error
) 
2944         CFTypeRef value 
= NULL
; 
2945         SecItemParams 
*itemParams 
= (SecItemParams 
*) malloc(sizeof(SecItemParams
)); 
2947         require_action(itemParams 
!= NULL
, error_exit
, status 
= errSecAllocate
); 
2948         require_action(dict 
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status 
= errSecParam
); 
2950         memset(itemParams
, 0, sizeof(SecItemParams
)); 
2951         itemParams
->query 
= (CFDictionaryRef
) CFRetain(dict
); 
2953         // validate input search parameters 
2954         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
); 
2955         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2956         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2957         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
2958         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
); 
2959         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
); 
2961         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
); 
2962         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
); 
2964         // validate a subset of input attributes (used to create an appropriate search reference) 
2965         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
); 
2966         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
); 
2967         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
); 
2968         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
); 
2970         if (itemParams
->service 
&& CFStringHasPrefix((CFStringRef
)itemParams
->service
, CFSTR("ProtectedCloudStorage"))) { 
2971                 itemParams
->isPCSItem 
= true; 
2972                 if (!SecItemSynchronizable(dict
)) { 
2973                         _EnsureUserDefaultKeychainIsSearched(itemParams
); // for SecItemCopyMatching, SecItemUpdate, SecItemDelete 
2974                         _EnsureUserDefaultKeychainIsTargeted(itemParams
); // for SecItemAdd 
2978         // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items 
2979         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
); 
2981         // validate item references 
2982         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit
); 
2983         if (itemParams
->itemRef 
&& (CFGetTypeID(itemParams
->itemRef
) == SecIdentityGetTypeID())) { 
2984                 itemParams
->identityRef 
= (SecIdentityRef
)itemParams
->itemRef
; 
2985                 itemParams
->itemRef 
= NULL
; 
2986                 SecIdentityCopyCertificate(itemParams
->identityRef
, (SecCertificateRef 
*)&itemParams
->itemRef
); 
2988         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
); 
2989         if (itemParams
->itemRef 
|| itemParams
->itemPersistentRef
) { 
2990                 // Caller is trying to add or find an item by reference. 
2991                 // The supported method for doing that is to provide a kSecUseItemList array 
2992                 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al, 
2993                 // so add the item reference to those arrays here. 
2994                 if (itemParams
->useItems
) { 
2995                         CFArrayRef tmpItems 
= itemParams
->useItems
; 
2996                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
2997                         CFRelease(tmpItems
); 
2999                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3001                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
); 
3002                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
); 
3004                 if (itemParams
->itemList
) { 
3005                         CFArrayRef tmpItems 
= itemParams
->itemList
; 
3006                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
3007                         CFRelease(tmpItems
); 
3009                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3011                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
); 
3012                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
); 
3015         // must have an explicit item class, unless one of the following is true: 
3016         //   - we have an item list to add or search (kSecUseItemList) 
3017         //   - we have an item reference or persistent reference for the thing we want to look up 
3018         // Note that both of these cases will set itemParams->useItems. 
3019         // If we have an item list to match (kSecMatchItemList), that still requires an item class, 
3020         // so we can perform a search and see if the results match items in the list. 
3022         if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
) { 
3023                 require_action(false, error_exit
, status 
= errSecItemClassMissing
); 
3026                 itemParams
->itemClass 
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
); 
3027                 if (itemParams
->itemClass 
== kSecSymmetricKeyItemClass 
&& !itemParams
->keyClass
) { 
3028             // no key class specified, so start with symmetric key class; will search the others later in UpdateKeychainSearchAndCopyNext 
3029             itemParams
->itemClass 
= kSecSymmetricKeyItemClass
; 
3030             itemParams
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3032                 require_action(!(itemParams
->itemClass 
== 0 && !itemParams
->useItems
), error_exit
, status 
= errSecItemClassMissing
); 
3035         itemParams
->keyUsage 
= _CssmKeyUsageFromQuery(dict
); 
3036         itemParams
->trustedOnly 
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3037         itemParams
->issuerAndSNToMatch 
= (itemParams
->issuer 
!= NULL 
&& itemParams
->serialNumber 
!= NULL
); 
3039         // other input attributes, used for SecItemAdd but not for finding items 
3040         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3041         if (itemParams
->access 
== NULL
) { 
3042                 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>) 
3043                 require_noerr(status 
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
3046         // determine how to return the result 
3047         itemParams
->numResultTypes 
= 0; 
3048         itemParams
->returningRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3049         if (itemParams
->returningRef
) ++itemParams
->numResultTypes
; 
3050         itemParams
->returningPersistentRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3051         if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
; 
3052         itemParams
->returningAttributes 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3053         if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
; 
3054         itemParams
->returningData 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
3055         if (itemParams
->returningData
) ++itemParams
->numResultTypes
; 
3057         // default is kSecReturnRef if no result types were specified 
3058         if (!itemParams
->numResultTypes
) { 
3059                 itemParams
->returningRef 
= TRUE
; 
3060                 itemParams
->numResultTypes 
= 1; 
3063         // determine if one, some or all matches should be returned (default is kSecMatchLimitOne) 
3064         itemParams
->maxMatches 
= 1; 
3065         itemParams
->returnAllMatches 
= FALSE
; 
3066         if (itemParams
->matchLimit
) { 
3067                 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3068                         itemParams
->returnAllMatches 
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
); 
3070                 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
3071                         CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
); 
3072                         require_action(!(itemParams
->maxMatches 
< 0), error_exit
, status 
= errSecMatchLimitUnsupported
); 
3075         if (itemParams
->returnAllMatches
) { 
3076                 itemParams
->maxMatches 
= INT32_MAX
; 
3077                 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each) 
3078                 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass 
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
) 
3079                         status 
= errSecReturnDataUnsupported
; 
3080                 require_noerr(status
, error_exit
); 
3083         // if we already have an item list (to add or find items in), we don't need an item class, attribute list or a search reference 
3084         if (itemParams
->useItems
) { 
3085                 if (itemParams
->itemClass 
== 0) { 
3086                         itemParams
->itemClass 
= _ItemClassFromItemList(itemParams
->useItems
); 
3088                 status 
= errSecSuccess
; 
3089                 goto error_exit
; // all done here 
3092         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
3093         require_noerr(status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
); 
3095     // if policy is a SMIME policy, copy email address in policy into emailAddrToMatch parameter 
3096     if(itemParams
->policy
) { 
3097         CFDictionaryRef policyDict 
= SecPolicyCopyProperties(itemParams
->policy
); 
3098         CFStringRef oidStr 
= (CFStringRef
) CFDictionaryGetValue(policyDict
, kSecPolicyOid
); 
3099         if(oidStr 
&& CFStringCompare(kSecPolicyAppleSMIME
,oidStr
,0) == 0) { 
3100             require_noerr(status 
= _ValidateDictionaryEntry(policyDict
, kSecPolicyName
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
3102         CFRelease(policyDict
); 
3105         // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) 
3106         if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) { 
3107                 // searching for certificates by email address 
3108                 char *nameBuf 
= (char*)malloc(MAXPATHLEN
); 
3110                         status 
= errSecAllocate
; 
3112                 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) { 
3113                         status 
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
); 
3116                         status 
= errSecItemInvalidValue
; 
3118                 if (nameBuf
) free(nameBuf
); 
3120         else if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) { 
3121                 // searching for certificates by issuer and serial number 
3122                 status 
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
, 
3123                                 (CFDataRef
)itemParams
->issuer
, 
3124                                 (CFDataRef
)itemParams
->serialNumber
, 
3125                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3127         else if (itemParams
->returnIdentity 
&& itemParams
->policy
) { 
3128                 // searching for identities by policy 
3129                 status 
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
, 
3130                                 (CFStringRef
)itemParams
->service
, 
3131                                 itemParams
->keyUsage
, 
3132                                 itemParams
->searchList
, 
3133                                 itemParams
->trustedOnly
, 
3134                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3136         else if (itemParams
->returnIdentity
) { 
3137                 // searching for identities 
3138                 status 
= SecIdentitySearchCreate(itemParams
->searchList
, 
3139                                 itemParams
->keyUsage
, 
3140                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
3143                 // normal keychain item search 
3144                 status 
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
, 
3145                                 itemParams
->itemClass
, 
3146                                 (itemParams
->attrList
->count 
== 0) ? NULL 
: itemParams
->attrList
, 
3147                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
3152                 _FreeSecItemParams(itemParams
); 
3165         SecKeychainRef keychainRef
, 
3166         SecAccessRef accessRef
, 
3167         SecKeychainAttributeList 
*attrList
, 
3168         SecKeychainItemRef 
*outItemRef
) 
3172                 // We must specify the access, since a free-floating key won't have one yet by default 
3173                 SecPointer
<Access
> access
; 
3175                         access 
= Access::required(accessRef
); 
3178                         CFStringRef descriptor 
= NULL
; 
3180                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
3181                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
3182                                         if (attr
.tag 
== kSecKeyPrintName
) { 
3183                                                 descriptor 
= CFStringCreateWithBytes(NULL
, (const UInt8 
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
); 
3188                         if (descriptor 
== NULL
) { 
3189                                 descriptor 
= (CFStringRef
) CFRetain(CFSTR("<unknown>")); 
3191                         access 
= new Access(cfString(descriptor
)); 
3192                         CFRelease(descriptor
); 
3195                 KeyItem 
*key 
= KeyItem::required(keyRef
); 
3196                 Item item 
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
); 
3198                         *outItemRef 
= item
->handle(); 
3205 _CanIgnoreLeafStatusCodes(CSSM_TP_APPLE_EVIDENCE_INFO 
*evidence
) 
3207         /* Check for ignorable status codes in leaf certificate's evidence */ 
3208         Boolean result 
= true; 
3210         for (i
=0; i 
< evidence
->NumStatusCodes
; i
++) { 
3211                 CSSM_RETURN scode 
= evidence
->StatusCodes
[i
]; 
3212                 if (scode 
== CSSMERR_APPLETP_INVALID_CA
) { 
3213                         // the TP has rejected this CA cert because it's in the leaf position 
3216                 else if (ignorableRevocationStatusCode(scode
)) { 
3229 _FilterWithPolicy(SecPolicyRef policy
, CFDateRef date
, SecCertificateRef cert
) 
3231         CFDictionaryRef props 
= NULL
; 
3232         CFArrayRef keychains 
= NULL
; 
3233         CFArrayRef anchors 
= NULL
; 
3234         CFArrayRef certs 
= NULL
; 
3235         CFArrayRef chain 
= NULL
; 
3236         SecTrustRef trust 
= NULL
; 
3238         SecTrustResultType      trustResult
; 
3239         CSSM_TP_APPLE_EVIDENCE_INFO 
*evidence 
= NULL
; 
3240         Boolean needChain 
= false; 
3242         if (!policy 
|| !cert
) return errSecParam
; 
3244         certs 
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
); 
3245         status 
= SecTrustCreateWithCertificates(certs
, policy
, &trust
); 
3246         if(status
) goto cleanup
; 
3248         /* Set evaluation date, if specified (otherwise current date is implied) */ 
3249         if (date 
&& (CFGetTypeID(date
) == CFDateGetTypeID())) { 
3250                 status 
= SecTrustSetVerifyDate(trust
, date
); 
3251                 if(status
) goto cleanup
; 
3254         /* Check whether this is the X509 Basic policy, which means chain building */ 
3255         props 
= SecPolicyCopyProperties(policy
); 
3257                 CFTypeRef oid 
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
); 
3258                 if (oid 
&& CFEqual(oid
, kSecPolicyAppleX509Basic
)) { 
3264                 /* To make the evaluation as lightweight as possible, specify an empty array 
3265                  * of keychains which will be searched for certificates. 
3267                 keychains 
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
); 
3268                 status 
= SecTrustSetKeychains(trust
, keychains
); 
3269                 if(status
) goto cleanup
; 
3271                 /* To make the evaluation as lightweight as possible, specify an empty array 
3272                  * of trusted anchors. 
3274                 anchors 
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
); 
3275                 status 
= SecTrustSetAnchorCertificates(trust
, anchors
); 
3276                 if(status
) goto cleanup
; 
3279         /* All parameters are locked and loaded, ready to evaluate! */ 
3280         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3281         if(status
) goto cleanup
; 
3283         /* If we didn't provide trust anchors or a way to look for them, 
3284          * the evaluation will fail with kSecTrustResultRecoverableTrustFailure. 
3285          * However, we can tell whether the policy evaluation succeeded by 
3286          * looking at the per-cert status codes in the returned evidence. 
3288         status 
= SecTrustGetResult(trust
, &trustResult
, &chain
, &evidence
); 
3289         if(status
) goto cleanup
; 
3291         if (!(trustResult 
== kSecTrustResultProceed 
|| 
3292                   trustResult 
== kSecTrustResultUnspecified 
|| 
3293                   trustResult 
== kSecTrustResultRecoverableTrustFailure
)) { 
3294                 /* The evaluation failed in a non-recoverable way */ 
3295                 status 
= errSecCertificateCannotOperate
; 
3299         /* If there are no per-cert policy status codes, 
3300          * and the cert has not expired, consider it valid for the policy. 
3304                 (void)SecTrustGetCssmResultCode(trust
, &status
); 
3306         if((evidence 
!= NULL
) && _CanIgnoreLeafStatusCodes(evidence
) && 
3307            ((evidence
[0].StatusBits 
& CSSM_CERT_STATUS_EXPIRED
) == 0) && 
3308            ((evidence
[0].StatusBits 
& CSSM_CERT_STATUS_NOT_VALID_YET
) == 0)) { 
3309                 status 
= errSecSuccess
; 
3313                 status 
= errSecCertificateCannotOperate
; 
3317         if(props
) CFRelease(props
); 
3318         if(chain
) CFRelease(chain
); 
3319         if(anchors
) CFRelease(anchors
); 
3320         if(keychains
) CFRelease(keychains
); 
3321         if(certs
) CFRelease(certs
); 
3322         if(trust
) CFRelease(trust
); 
3328 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
) 
3330         if (!validOnDate 
|| !cert
) return errSecParam
; 
3332         CFAbsoluteTime at
, nb
, na
; 
3333         if (CFGetTypeID(validOnDate
) == CFDateGetTypeID()) 
3334                 at 
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
); 
3336                 at 
= CFAbsoluteTimeGetCurrent(); 
3338         OSStatus status 
= errSecSuccess
; 
3339         nb 
= SecCertificateNotValidBefore(cert
); 
3340         na 
= SecCertificateNotValidAfter(cert
); 
3342         if (nb 
== 0 || na 
== 0 || nb 
== na
) 
3343                 status 
= errSecCertificateCannotOperate
; 
3345                 status 
= errSecCertificateNotValidYet
; 
3347                 status 
= errSecCertificateExpired
; 
3353 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
) 
3355         if (!cert
) return errSecParam
; 
3356         if (!trustedOnly
) return errSecSuccess
; 
3358         CFArrayRef certArray 
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
); 
3359         SecPolicyRef policy 
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
); 
3360         OSStatus status 
= (policy 
== NULL
) ? errSecPolicyNotFound 
: errSecSuccess
; 
3363                 SecTrustRef trust 
= NULL
; 
3364                 status 
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
); 
3366                         SecTrustResultType trustResult
; 
3367                         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3369                                 if (!(trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
)) { 
3370                                         status 
= (trustResult 
== kSecTrustResultDeny
) ? errSecTrustSettingDeny 
: errSecNotTrusted
; 
3378                 CFRelease(certArray
); 
3384 static SecKeychainItemRef
 
3385 CopyResolvedKeychainItem(CFTypeRef item
) 
3387         SecKeychainItemRef kcItem 
= NULL
; 
3390                 if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
3391                         // persistent reference, resolve first 
3392                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &kcItem
); 
3396                         kcItem 
= (SecKeychainItemRef
) CFRetain(item
); 
3399                         // ask for the item's class: 
3400                         // will return an error if the item has been deleted 
3401                         SecItemClass itemClass
; 
3402                         SecKeychainItemRef certRef 
= NULL
; 
3403                         if (CFGetTypeID(kcItem
) == SecIdentityGetTypeID()) { 
3404                                 status 
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
, (SecCertificateRef 
*)&certRef
); 
3407                                 // can't call SecKeychainItemCopyAttributesAndData on a SecCertificateRef 
3408                                 itemClass 
= kSecCertificateItemClass
; 
3411                                 status 
= SecKeychainItemCopyAttributesAndData(kcItem
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3426 UpdateKeychainSearchAndCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3428         // This function refreshes the search parameters in the specific case where 
3429         // the caller is searching for kSecClassKey items but did not provide the 
3430         // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and 
3431         // we must perform separate searches to obtain all results. 
3433         OSStatus status 
= errSecItemNotFound
; 
3434         if (!params 
|| !params
->assumedKeyClass 
|| !params
->query 
|| !item
) 
3437         // Free the previous search reference and attribute list. 
3439                 CFRelease(params
->search
); 
3440         params
->search 
= NULL
; 
3441         _FreeAttrList(params
->attrList
); 
3442         params
->attrList 
= NULL
; 
3444         // Make a copy of the query dictionary so we can set the key class parameter. 
3445         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
); 
3446         CFRelease(params
->query
); 
3447         params
->query 
= dict
; 
3448         CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
); 
3450         // Determine the current item class for this search, and the next assumed key class. 
3451         if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) { 
3452                 params
->itemClass 
= kSecSymmetricKeyItemClass
; 
3453                 params
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3454         } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) { 
3455                 params
->itemClass 
= kSecPublicKeyItemClass
; 
3456                 params
->assumedKeyClass 
= kSecAttrKeyClassPrivate
; 
3458                 params
->itemClass 
= kSecPrivateKeyItemClass
; 
3459                 params
->assumedKeyClass 
= NULL
; 
3462         // Rebuild the attribute list for the new key class. 
3463         if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == errSecSuccess
) { 
3464                 // Create a new search reference for the new attribute list. 
3465                 if (SecKeychainSearchCreateFromAttributes(params
->searchList
, 
3467                         (params
->attrList
->count 
== 0) ? NULL 
: params
->attrList
, 
3468                         (SecKeychainSearchRef
*)¶ms
->search
) == errSecSuccess
) { 
3469                         // Return the first matching item from the new search. 
3470                         // We won't come back here again until there are no more matching items for this search. 
3471                         status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
); 
3479 SecItemSearchCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3481         // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef. 
3482         // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter, 
3483         // depending on the type of search reference. 
3486         CFTypeRef search 
= (params
) ? params
->search 
: NULL
; 
3487         CFTypeID typeID 
= (search
) ? CFGetTypeID(search
) : 0; 
3488         if (typeID 
== SecIdentitySearchGetTypeID()) { 
3489                 status 
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
); 
3491         else if (typeID 
== SecKeychainSearchGetTypeID()) { 
3492                 status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
); 
3493                 // Check if we need to refresh the search for the next key class 
3494                 while (status 
== errSecItemNotFound 
&& params
->assumedKeyClass 
!= NULL
) 
3495                         status 
= UpdateKeychainSearchAndCopyNext(params
, item
); 
3497         else if (typeID 
== 0 && (params
->useItems 
|| params
->itemList
)) { 
3498                 // No search available, but there is an item list available. 
3499                 // Return the next candidate item from the caller's item list 
3500                 CFArrayRef itemList 
= (params
->useItems
) ? params
->useItems 
: params
->itemList
; 
3501                 CFIndex count 
= CFArrayGetCount(itemList
); 
3502                 *item 
= (CFTypeRef
) NULL
; 
3503                 if (params
->itemListIndex 
< count
) { 
3504                         *item 
= (CFTypeRef
)CFArrayGetValueAtIndex(itemList
, params
->itemListIndex
++); 
3506                                 // Potentially resolve persistent item references here, and 
3507                                 // verify the item reference we're about to hand back is still 
3508                                 // valid (it could have been deleted from the keychain while 
3509                                 // our query was holding onto the itemList). 
3510                                 *item 
= CopyResolvedKeychainItem(*item
); 
3511                                 if (*item 
&& (CFGetTypeID(*item
) == SecIdentityGetTypeID())) { 
3512                                         // Persistent reference resolved to an identity, so return that type. 
3513                                         params
->returnIdentity 
= true; 
3517                 status 
= (*item
) ? errSecSuccess 
: errSecItemNotFound
; 
3520                 status 
= errSecItemNotFound
; 
3526 FilterCandidateItem(CFTypeRef 
*item
, SecItemParams 
*itemParams
, SecIdentityRef 
*identity
) 
3528         if (!item 
|| *item 
== NULL 
|| !itemParams
) 
3529                 return errSecItemNotFound
; 
3532         CFStringRef commonName 
= NULL
; 
3533         SecIdentityRef foundIdentity 
= NULL
; 
3534         if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) { 
3535                 // we found a SecIdentityRef, rather than a SecKeychainItemRef; 
3536                 // replace the found "item" with its associated certificate (which is the 
3537                 // item we actually want for purposes of getting attributes, data, or a 
3538                 // persistent data reference), and return the identity separately. 
3539                 SecCertificateRef certificate
; 
3540                 status 
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
); 
3541                 if (itemParams
->returnIdentity
) { 
3542                         foundIdentity 
= (SecIdentityRef
) *item
; 
3544                                 *identity 
= foundIdentity
; 
3550                 *item 
= (CFTypeRef
)certificate
; 
3553         CFDictionaryRef query 
= itemParams
->query
; 
3555         if (itemParams
->itemClass 
== kSecCertificateItemClass
) { 
3556                 // perform string comparisons first 
3557                 CFStringCompareFlags flags 
= _StringCompareFlagsFromQuery(query
); 
3558                 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
; 
3559                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
)) 
3560                         nameContains 
= NULL
; 
3561                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
)) 
3563                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
)) 
3565                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
)) 
3567                 if (nameContains 
|| nameStarts 
|| nameEnds 
|| nameExact
) { 
3568                         status 
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
); 
3569                         if (status 
|| !commonName
) goto filterOut
; 
3572                         CFRange range 
= CFStringFind(commonName
, nameContains
, flags
); 
3573                         if (range
.length 
< 1) 
3575                         // certificate item contains string; proceed to next check 
3578                         CFRange range 
= CFStringFind(commonName
, nameStarts
, flags
); 
3579                         if (range
.length 
< 1 || range
.location 
> 1) 
3581                         // certificate item starts with string; proceed to next check 
3584                         CFRange range 
= CFStringFind(commonName
, nameEnds
, flags
); 
3585                         if (range
.length 
< 1 || range
.location 
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
))) 
3587                         // certificate item ends with string; proceed to next check 
3590                         CFRange range 
= CFStringFind(commonName
, nameExact
, flags
); 
3591                         if (range
.length 
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
))) 
3593                         // certificate item exactly matches string; proceed to next check 
3595                 if (itemParams
->returnIdentity
) { 
3596                         // if we already found and returned the identity, we can skip this 
3597                         if (!foundIdentity
) { 
3598                                 status 
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
); 
3599                                 if (status
) goto filterOut
; 
3601                         // certificate item is part of an identity; proceed to next check 
3603                 if (itemParams
->policy
) { 
3604                         status 
= _FilterWithPolicy(itemParams
->policy
, (CFDateRef
)itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3605                         if (status
) goto filterOut
; 
3606                         // certificate item is valid for specified policy (and optionally specified date) 
3608                 if (itemParams
->validOnDate
) { 
3609                         status 
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3610                         if (status
) goto filterOut
; 
3611                         // certificate item is valid for specified date 
3613                 if (itemParams
->trustedOnly
) { 
3614                         // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search, 
3615                         // their trust has already been validated and we can skip this part. 
3616                         if (!(foundIdentity 
&& itemParams
->returnIdentity 
&& itemParams
->policy
)) { 
3617                                 status 
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
); 
3618                                 if (status
) goto filterOut
; 
3620                         // certificate item is trusted on this system 
3623         if (itemParams
->itemList
) { 
3624                 Boolean foundMatch 
= FALSE
; 
3625                 CFIndex idx
, count 
= CFArrayGetCount(itemParams
->itemList
); 
3626                 for (idx
=0; idx
<count
; idx
++) { 
3627                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
); 
3628                         SecKeychainItemRef realItem 
= NULL
; 
3629                         SecCertificateRef aCert 
= NULL
; 
3630                         if (anItem 
== NULL
) { 
3633                         if (CFDataGetTypeID() == CFGetTypeID(anItem
) && 
3634                                 errSecSuccess 
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) { 
3637                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) && 
3638                                 errSecSuccess 
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) { 
3641                         if (CFEqual(anItem
, (CFTypeRef
) *item
)) { 
3648                                 CFRelease(realItem
); 
3654                 if (!foundMatch
) goto filterOut
; 
3655                 // item was found on provided list 
3658         if (foundIdentity 
&& !identity
) { 
3659                 CFRelease(foundIdentity
); 
3662                 CFRelease(commonName
); 
3665         // if we get here, consider the item a match 
3666         return errSecSuccess
; 
3670                 CFRelease(commonName
); 
3674         if (foundIdentity
) { 
3675                 CFRelease(foundIdentity
); 
3680         return errSecItemNotFound
; 
3684 AddItemResults(SecKeychainItemRef item
, 
3685         SecIdentityRef identity
, 
3686         SecItemParams 
*itemParams
, 
3687         CFAllocatorRef allocator
, 
3688         CFMutableArrayRef 
*items
, 
3691         // Given a found item (which may also be an identity), this function adds 
3692         // the requested result types (specified in itemParams) to the appropriate 
3693         // container as follows: 
3695         // 1. If there is only one result type (numResultTypes == 1) and only one 
3696         //    match requested (maxMatches == 1), set *result directly. 
3698         // 2. If there are multiple result types (numResultTypes > 1), and only one 
3699         //    match requested (maxMatches == 1), add each result type to itemDict 
3700         //    and set itemDict as the value of *result. 
3702         // 3. If there is only one result type (numResultTypes == 1) and multiple 
3703         //    possible matches (maxMatches > 1), add the result type to *items 
3704         //    and set *items as the value of *result. 
3706         // 4. If there are multiple result types (numResultTypes > 1) and multiple 
3707         //    possible matches (maxMatches > 1), add each result type to itemDict, 
3708         //    add itemDict to *items, and set *items as the value of *result. 
3710         // Note that we allocate *items if needed. 
3712         if (!item 
|| !itemParams 
|| !result
) 
3715         if (itemParams
->maxMatches 
> 1) { 
3716                 // if we can return more than one item, we must have an array 
3719                 else if (*items 
== NULL
) 
3720                         *items 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
3723         OSStatus tmpStatus
, status 
= errSecSuccess
; 
3724         CFMutableArrayRef itemArray 
= (items
) ? *items 
: NULL
; 
3725         CFMutableDictionaryRef itemDict 
= NULL
; 
3726         if (itemParams
->numResultTypes 
> 1) { 
3727                 // if we're returning more than one result type, each item we return must be a dictionary 
3728                 itemDict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
3731         if (itemParams
->returningRef
) { 
3732                 const void* itemRef 
= (identity
) ? (const void*)identity 
: (const void*)item
; 
3734                         CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
); 
3736                 else if (itemArray
) { 
3737                         CFArrayAppendValue(itemArray
, itemRef
); 
3740                         *result 
= CFRetain((CFTypeRef
)itemRef
); 
3744         if (itemParams
->returningPersistentRef
) { 
3745                 CFDataRef persistentRef
; 
3746                 SecKeychainItemRef tmpItem 
= item
; 
3747                 if (itemParams
->identityRef
) { 
3748                         tmpItem 
= (SecKeychainItemRef
)itemParams
->identityRef
; 
3750                 tmpStatus 
= SecKeychainItemCreatePersistentReference(tmpItem
, &persistentRef
); 
3751                 if (tmpStatus 
== errSecSuccess
) { 
3753                                 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
); 
3755                         else if (itemArray
) { 
3756                                 CFArrayAppendValue(itemArray
, persistentRef
); 
3759                                 *result 
= CFRetain(persistentRef
); 
3761                         CFRelease(persistentRef
); 
3763                 else if (status 
== errSecSuccess
) { 
3768         if (itemParams
->returningData
) { 
3769                 // Use SecCertificateCopyData if we have a SecCertificateRef item. 
3770                 // Note that a SecCertificateRef may not actually be a SecKeychainItem, 
3771                 // in which case SecKeychainItemCopyContent will not obtain its data. 
3773                 if (CFGetTypeID(item
) == SecCertificateGetTypeID()) { 
3774                         CFDataRef dataRef 
= SecCertificateCopyData((SecCertificateRef
)item
); 
3777                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3779                                 else if (itemArray
) { 
3780                                         CFArrayAppendValue(itemArray
, dataRef
); 
3783                                         *result 
= CFRetain(dataRef
); 
3786                                 status 
= errSecSuccess
; 
3789                                 status 
= errSecAllocate
; 
3795                         tmpStatus 
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
); 
3796                         if (tmpStatus 
== errSecSuccess
) { 
3797                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8 
*)data
, length
); 
3799                                         CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3801                                 else if (itemArray
) { 
3802                                         CFArrayAppendValue(itemArray
, dataRef
); 
3805                                         *result 
= CFRetain(dataRef
); 
3808                                 (void) SecKeychainItemFreeContent(NULL
, data
); 
3810                         else if (status 
== errSecSuccess
) { 
3816         if (itemParams
->returningAttributes
) { 
3817                 CFDictionaryRef attrsDict 
= NULL
; 
3818                 SecItemClass itemClass
; 
3819                 // since we have an item, allow its actual class to override the query-specified item class 
3820                 tmpStatus 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3822                         itemClass 
= itemParams
->itemClass
; 
3824                 tmpStatus 
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
); 
3827                                 // add all keys and values from attrsDict to the item dictionary 
3828                                 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
); 
3830                         else if (itemArray
) { 
3831                                 CFArrayAppendValue(itemArray
, attrsDict
); 
3834                                 *result 
= CFRetain(attrsDict
); 
3836                         CFRelease(attrsDict
); 
3838                 if (tmpStatus 
&& (status 
== errSecSuccess
)) { 
3845                         CFArrayAppendValue(itemArray
, itemDict
); 
3846                         CFRelease(itemDict
); 
3847                         *result 
= itemArray
; 
3853         else if (itemArray
) { 
3854                 *result 
= itemArray
; 
3860 CFDataRef 
_SecItemGetPersistentReference(CFTypeRef raw_item
) 
3863                 Item item 
= ItemImpl::required((SecKeychainItemRef
)raw_item
); 
3864                 return item
->getPersistentRef(); 
3870 /******************************************************************************/ 
3871 #pragma mark SecItem API functions 
3872 /******************************************************************************/ 
3875 // Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error. 
3877 static SInt32 
readNumber(CFTypeRef obj
) { 
3878     CFTypeID tid 
= CFGetTypeID(obj
); 
3880     if (tid 
== CFNumberGetTypeID()) { 
3881         CFNumberGetValue((CFNumberRef
)obj
, kCFNumberSInt32Type
, &v
); 
3883     } else if (tid 
== CFBooleanGetTypeID()) { 
3884         v 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
3886     } else if (tid 
== CFStringGetTypeID()) { 
3887         v 
= CFStringGetIntValue((CFStringRef
)obj
); 
3888         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v
); 
3889         /* If a string converted to an int isn't equal to the int printed as 
3890          a string, return a CFStringRef instead. */ 
3891         if (!CFEqual(t
, obj
)) { 
3902 // Function to ensure the syncable keychain is unlocked. 
3903 // Currently, this means unlocking the login keychain, 
3904 // which will also unlock the keybag as a side effect. 
3906 static OSStatus 
SecItemUnlockSynchronizableKeychain() 
3908         SecKeychainRef keychain 
= NULL
; 
3909         OSStatus status 
= SecKeychainCopyLogin(&keychain
); 
3911                 status 
= SecKeychainUnlock(keychain
, 0, NULL
, false); 
3913         CFReleaseSafe(keychain
); 
3918 // Function to check whether the kSecAttrSynchronizable flag is set in the query. 
3920 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
) 
3922         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
3923         Boolean result 
= (value 
&& readNumber(value
)); 
3929 // Function to check whether the kSecAttrNoLegacy flag is set in the query. 
3931 static Boolean 
SecItemNoLegacy(CFDictionaryRef query
) 
3933     CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrNoLegacy
); 
3934     Boolean result 
= (value 
&& readNumber(value
)); 
3940 // Function to check whether the kSecAttrSynchronizable flag is set in the query, 
3941 // and has the special value of kSecAttrSynchronizableAny. 
3943 static Boolean 
SecItemSynchronizableAny(CFDictionaryRef query
) 
3945         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
3947                 return (CFGetTypeID(value
) == CFStringGetTypeID() && 
3948                                 CFEqual(value
, kSecAttrSynchronizableAny
)); 
3954 // Function to check whether the kSecAttrSynchronizable attribute is being updated. 
3956 static Boolean 
SecItemHasSynchronizableUpdate(Boolean synchronizable
, CFDictionaryRef changes
) 
3958         CFTypeRef newValue 
= CFDictionaryGetValue(changes
, kSecAttrSynchronizable
); 
3962         Boolean new_sync 
= readNumber(newValue
); 
3963         Boolean old_sync 
= synchronizable
; 
3965         return (old_sync 
!= new_sync
); 
3969 // Returns true if keychain syncing is globally enabled. 
3971 static Boolean 
SecItemSyncEnabled() 
3973         static dispatch_once_t onceToken
; 
3974         static Boolean syncEnabled 
= true; 
3976         //sudo defaults write /Library/Preferences/com.apple.security SecItemSynchronizable -bool YES 
3977         dispatch_once(&onceToken
, ^{ 
3978                         CFTypeRef sync 
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
); 
3980                         if (sync 
&& CFGetTypeID(sync
) == CFBooleanGetTypeID()) { 
3981                         syncEnabled 
= CFBooleanGetValue((CFBooleanRef
)sync
); 
3990 // Function to check whether a synchronizable persistent reference was provided. 
3992 static Boolean 
SecItemHasSynchronizablePersistentReference(CFDictionaryRef query
) 
3994         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
3996                 /* Synchronizable persistent ref consists of the sqlite rowid and 4-byte class value */ 
3997                 const CFIndex kSynchronizablePersistentRefLength 
= sizeof(int64_t) + 4; 
3998                 return (CFGetTypeID(value
) == CFDataGetTypeID() && 
3999                                 CFDataGetLength((CFDataRef
)value
) == kSynchronizablePersistentRefLength
); 
4005 // Function to apply changes to a mutable dictionary. 
4006 // (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction) 
4008 static void SecItemApplyChanges(const void *key
, const void *value
, void *context
) 
4010         CFMutableDictionaryRef dict 
= (CFMutableDictionaryRef
) context
; 
4013         CFDictionarySetValue(dict
, key
, value
); 
4017 // Function to change matching items from non-syncable to syncable 
4018 // (if toSyncable is true), otherwise from syncable to non-syncable. 
4019 // This currently moves items between keychain containers. 
4021 static OSStatus 
SecItemChangeSynchronizability(CFDictionaryRef query
, CFDictionaryRef changes
, Boolean toSyncable
) 
4023         // Note: the input query dictionary is a mutable copy of the query originally 
4024         // provided by the caller as the first parameter to SecItemUpdate. It may not 
4025         // specify returning attributes or data, but we will need both to make a copy. 
4027         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnRef
); 
4028         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnPersistentRef
); 
4029         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnData
); 
4030         CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnAttributes
, kCFBooleanTrue
); 
4031         if (NULL 
== CFDictionaryGetValue(changes
, kSecValueData
)) 
4032                 CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnData
, kCFBooleanTrue
); 
4037                 status 
= SecItemCopyMatching_osx(query
, &result
); 
4039                 status 
= SecItemCopyMatching_ios(query
, &result
); 
4044                 return errSecItemNotFound
; 
4046         CFMutableArrayRef items
; 
4047         if (CFGetTypeID(result
) != CFArrayGetTypeID()) { 
4048                 items 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4049                 CFArrayAppendValue(items
, result
); 
4053                 items 
= (CFMutableArrayRef
)result
; 
4056         CFIndex idx
, count 
= (items
) ? CFArrayGetCount(items
) : 0; 
4057         int priority 
= LOG_DEBUG
; 
4059         for (idx 
= 0; idx 
< count
; idx
++) { 
4060                 CFDictionaryRef dict 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(items
, idx
); 
4061                 CFMutableDictionaryRef item 
= (CFMutableDictionaryRef
) 
4062                         SecItemCopyTranslatedAttributes(dict
, 
4063                                 CFDictionaryGetValue(query
, kSecClass
), 
4064                                 (toSyncable
) ? true : false /*iOSOut*/, 
4065                                 true /*pruneMatch*/, 
4067                                 true /*pruneReturn*/, 
4068                                 false /*pruneData*/, 
4069                                 (toSyncable
) ? true : false /*pruneAccess*/); 
4070                 // hold onto the query before applying changes, in case the item already exists. 
4071                 // note that we cannot include the creation or modification dates from our 
4072                 // found item in this query, as they may not match the item in the other keychain. 
4073                 CFMutableDictionaryRef itemQuery 
= CFDictionaryCreateMutableCopy(NULL
, 0, item
); 
4074                 CFDictionaryRemoveValue(itemQuery
, kSecAttrCreationDate
); 
4075                 CFDictionaryRemoveValue(itemQuery
, kSecAttrModificationDate
); 
4076                 // apply changes to the item dictionary that we will pass to SecItemAdd 
4077                 CFDictionaryApplyFunction(changes
, SecItemApplyChanges
, item
); 
4079                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4080                         status 
= SecItemAdd_ios(item
, NULL
); 
4081                         secitemlog(priority
, "ChangeSync: SecItemAdd_ios=%d", status
); 
4082                         if (errSecDuplicateItem 
== status
) { 
4083                                 // find and apply changes to the existing syncable item. 
4084                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4085                                 status 
= SecItemUpdate_ios(itemQuery
, changes
); 
4086                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_ios=%d", status
); 
4088                         if (errSecSuccess 
== status
) { 
4089                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4090                                 status 
= SecItemDelete_osx(itemQuery
); 
4091                                 secitemlog(priority
, "ChangeSync: SecItemDelete_osx=%d", status
); 
4095                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4096                         status 
= SecItemAdd_osx(item
, NULL
); 
4097                         secitemlog(priority
, "ChangeSync: SecItemAdd_osx=%d", status
); 
4098                         if (errSecDuplicateItem 
== status
) { 
4099                                 // find and apply changes to the existing non-syncable item. 
4100                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
4101                                 status 
= SecItemUpdate_osx(itemQuery
, changes
); 
4102                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_osx=%d", status
); 
4104                         if (errSecSuccess 
== status
) { 
4105                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
4106                                 status 
= SecItemDelete_ios(itemQuery
); 
4107                                 secitemlog(priority
, "ChangeSync: SecItemDelete_ios=%d", status
); 
4110                 CFReleaseSafe(item
); 
4111                 CFReleaseSafe(itemQuery
); 
4115         CFReleaseSafe(items
); 
4124 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) { 
4125         CFTypeRef ref 
= NULL
; 
4126         CFStringRef key_class_string 
= (CFStringRef
)CFDictionaryGetValue(refAttributes
, kSecClass
); 
4127         SecItemClass key_class
; 
4128         bool key_class_found 
= false; 
4130         if (CFEqual(key_class_string
, kSecClassGenericPassword
)) { 
4131                 key_class 
= kSecGenericPasswordItemClass
; 
4132                 key_class_found 
= true; 
4134         if (CFEqual(key_class_string
, kSecClassInternetPassword
)) { 
4135                 key_class 
= kSecInternetPasswordItemClass
; 
4136                 key_class_found 
= true; 
4139         if (key_class_found
) { 
4140                 // we carry v_Data around here so the *_ios calls can find it and locate 
4141                 // their own data.   Putting things in the attribute list doesn't help as 
4142                 // the osx keychainitem and item calls bail when they don't see a keychain 
4143                 // object.   If we need to make them work we either have to bridge them, or 
4144                 // find a way to craft a workable keychain object.   #if'ed code left below 
4145                 // in case we need to go down that path. 
4147                 struct SecKeychainAttributeList 
*attrs 
= (struct SecKeychainAttributeList 
*)malloc(sizeof(struct SecKeychainAttributeList
) + sizeof(struct SecKeychainAttribute
) * 0); 
4148                 attrs
->attr 
= (struct SecKeychainAttribute 
*)(attrs 
+ 1); 
4152                 // The C++ string objects need to last at least as long as the attr struct. 
4155                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("mdat")); 
4157                         attrs
->attr
[attrs
->count
].tag 
= kSecModDateItemAttr
; 
4158                         // XXX need to convert to YYYYMMDDhhmmSSZ 
4159                         attrs
->attr
[attrs
->count
].data 
= (void*)"19690223140232Z"; 
4160                         attrs
->attr
[attrs
->count
].length 
= strlen((char*)(attrs
->attr
[attrs
->count
].data
)); 
4163                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("cdat")); 
4165                         attrs
->attr
[attrs
->count
].tag 
= kSecCreationDateItemAttr
; 
4166                         // XXX need to convert to YYYYMMDDhhmmSSZ 
4167                         attrs
->attr
[attrs
->count
].data 
= (void*)"19690223140232Z"; 
4168                         attrs
->attr
[attrs
->count
].length 
= strlen((char*)(attrs
->attr
[attrs
->count
].data
)); 
4172                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("acct")); 
4174                         attrs
->attr
[attrs
->count
].tag 
= kSecAccountItemAttr
; 
4175                         account 
= cfString((CFStringRef
)v
); 
4176                         attrs
->attr
[attrs
->count
].data 
= (void*)(account
.c_str()); 
4177                         attrs
->attr
[attrs
->count
].length 
= account
.length(); 
4181                 // class isn't treated as an attribute by the creation API 
4183                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("svce")); 
4185                         attrs
->attr
[attrs
->count
].tag 
= kSecServiceItemAttr
; 
4186                         account 
= cfString((CFStringRef
)v
); 
4187                         attrs
->attr
[attrs
->count
].data 
= (void*)(account
.c_str()); 
4188                         attrs
->attr
[attrs
->count
].length 
= account
.length(); 
4192                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("acct")); 
4194                         attrs
->attr
[attrs
->count
].tag 
= kSecLabelItemAttr
; 
4195                         account 
= cfString((CFStringRef
)v
); 
4196                         attrs
->attr
[attrs
->count
].data 
= (void*)(account
.c_str()); 
4197                         attrs
->attr
[attrs
->count
].length 
= account
.length(); 
4201                 Item item 
= Item(key_class
, attrs
, 0, ""); 
4202                 ItemImpl 
*real_item 
= item
.get(); 
4203                 v 
= CFDictionaryGetValue(refAttributes
, kSecValuePersistentRef
); 
4205                         real_item
->setPersistentRef((CFDataRef
)v
); 
4207                 ref 
= real_item
->handle(); 
4209                 // keys, certs, identities are not currently sync'able. 
4216  * SecItemValidateAppleApplicationGroupAccess determines if the caller 
4217  * is a member of the specified application group, and is signed by Apple. 
4220 SecItemValidateAppleApplicationGroupAccess(CFStringRef group
) 
4222         SecTrustedApplicationRef app 
= NULL
; 
4223         SecRequirementRef requirement 
= NULL
; 
4224         SecCodeRef code 
= NULL
; 
4225         OSStatus status 
= errSecParam
; 
4228                 CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(group
), kCFStringEncodingUTF8
) + 1; 
4229                 char* buffer 
= (char*) malloc(length
); 
4231                         if (CFStringGetCString(group
, buffer
, length
, kCFStringEncodingUTF8
)) { 
4232                                 status 
= SecTrustedApplicationCreateApplicationGroup(buffer
, NULL
, &app
); 
4236                         status 
= errSecMemoryError
; 
4240                 status 
= SecTrustedApplicationCopyRequirement(app
, &requirement
); 
4243                 status 
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
); 
4246                 status 
= SecCodeCheckValidity(code
, kSecCSDefaultFlags
, requirement
); 
4249         CFReleaseSafe(code
); 
4250         CFReleaseSafe(requirement
); 
4256  * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary 
4257  * and attempts to return a sanitized copy for passing to the underlying 
4258  * platform-specific implementation code. 
4260  * If iOSOut is true, one or more translations may apply: 
4261  *   - SecKeychain refs are removed, since there aren't multiple keychains 
4262  *   - SecPolicy refs are removed, since they can't be externalized 
4263  *   - SecAccess refs are removed, and potentially translated to entitlements 
4265  * If pruneMatch is true, kSecMatch* attributes are removed; this avoids 
4266  * parameter errors due to strict input checks in secd, which only permits 
4267  * these constants for calls to SecItemCopyMatching. 
4269  * If pruneSync is true, the kSecAttrSynchronizable attribute is removed. 
4270  * This permits a query to be reused for non-synchronizable items, or to 
4271  * resolve a search based on a persistent item reference for iOS. 
4273  * If pruneReturn is true, kSecReturn* attributes are removed; this avoids 
4274  * parameter errors due to strict input checks in secd, which do not permit 
4275  * these constants for calls to SecItemUpdate. 
4278 SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
4279         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
) 
4281         CFMutableDictionaryRef result 
= CFDictionaryCreateMutableCopy(NULL
, 0, inOSXDict
); 
4282         if (result 
== NULL
) { 
4287                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4291                 /* Match constants are only supported on iOS for SecItemCopyMatching, 
4292                  * and will generate an error if passed to other SecItem API functions; 
4293                  * on OS X, they're just ignored if not applicable for the context. 
4295                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4296                 CFDictionaryRemoveValue(result
, kSecMatchItemList
); 
4297                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4298                 CFDictionaryRemoveValue(result
, kSecMatchIssuers
); 
4299                 CFDictionaryRemoveValue(result
, kSecMatchEmailAddressIfPresent
); 
4300                 CFDictionaryRemoveValue(result
, kSecMatchSubjectContains
); 
4301                 CFDictionaryRemoveValue(result
, kSecMatchCaseInsensitive
); 
4302                 CFDictionaryRemoveValue(result
, kSecMatchTrustedOnly
); 
4303                 CFDictionaryRemoveValue(result
, kSecMatchValidOnDate
); 
4304                 CFDictionaryRemoveValue(result
, kSecMatchLimit
); 
4305                 CFDictionaryRemoveValue(result
, kSecMatchLimitOne
); 
4306                 CFDictionaryRemoveValue(result
, kSecMatchLimitAll
); 
4310                 /* Return constants are not supported on iOS for SecItemUpdate, 
4311                  * where they will generate an error; on OS X, they're just ignored 
4312                  * if not applicable for the context. 
4314                 CFDictionaryRemoveValue(result
, kSecReturnData
); 
4315                 CFDictionaryRemoveValue(result
, kSecReturnAttributes
); 
4316                 CFDictionaryRemoveValue(result
, kSecReturnRef
); 
4317                 CFDictionaryRemoveValue(result
, kSecReturnPersistentRef
); 
4321                 /* Searching on data is not supported. */ 
4322                 CFDictionaryRemoveValue(result
, kSecValueData
); 
4326         /* Searching on access lists is not supported */ 
4327         CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4331                 /* Remove kSecMatchSearchList (value is array of SecKeychainRef); 
4332                  * cannot specify a keychain search list on iOS 
4334                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4336                 /* Remove kSecUseKeychain (value is a SecKeychainRef); 
4337                  * cannot specify a keychain on iOS 
4339                 CFDictionaryRemoveValue(result
, kSecUseKeychain
); 
4341                 /* Remove kSecMatchPolicy (value is a SecPolicyRef); 
4342                  * TODO: need a way to externalize and restore a policy instance 
4344                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4346                 /* Potentially translate kSecAttrAccess (value is a SecAccessRef), 
4347                  * unless kSecAttrAccessGroup has already been specified. 
4349                 SecAccessRef access 
= (SecAccessRef
) CFDictionaryGetValue(result
, kSecAttrAccess
); 
4350                 CFStringRef accessGroup 
= (CFStringRef
) CFDictionaryGetValue(result
, kSecAttrAccessGroup
); 
4351                 if (access 
!= NULL 
&& accessGroup 
== NULL
) { 
4352                         /* Translate "InternetAccounts" application group to an access group */ 
4353                         if (errSecSuccess 
== SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) { 
4354                                 /* The caller is a valid member of the application group. */ 
4355                                 CFStringRef groupName 
= CFSTR("appleaccount"); 
4356                                 CFTypeRef value 
= CFDictionaryGetValue(result
, kSecAttrAuthenticationType
); 
4357                                 if (value 
&& CFEqual(value
, kSecAttrAuthenticationTypeHTMLForm
)) { 
4358                                         groupName 
= CFSTR("com.apple.cfnetwork"); 
4360                                 CFDictionarySetValue(result
, kSecAttrAccessGroup
, groupName
); 
4363                 CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4365                 /* If item is specified by direct reference, and this is an iOS search, 
4366                  * replace it with a persistent reference. 
4368         CFTypeRef directRef 
= CFDictionaryGetValue(result
, kSecValueRef
); 
4370                         CFDataRef persistentRef 
= _SecItemGetPersistentReference(directRef
); 
4371                         if (persistentRef
) { 
4372                 CFDictionarySetValue(result
, kSecValuePersistentRef
, persistentRef
); 
4374                         CFDictionaryRemoveValue(result
, kSecValueRef
); 
4377                 /* If item is specified by persistent reference, and this is an iOS search, 
4378                  * remove the synchronizable attribute as it will be rejected by secd. 
4380                 CFTypeRef persistentRef 
= CFDictionaryGetValue(result
, kSecValuePersistentRef
); 
4381                 if (persistentRef
) { 
4382                         CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4385                 /* Remove kSecAttrModificationDate; this should never be used as criteria 
4386                  * for a search, or to add/modify an item. (If we are cloning an item 
4387                  * and want to keep its modification date, we don't call this function.) 
4388                  * It turns out that some clients are using the full attributes dictionary 
4389                  * returned by SecItemCopyMatching as a query to find the same item later, 
4390                  * which won't work once the item is updated. 
4392                 CFDictionaryRemoveValue(result
, kSecAttrModificationDate
); 
4395                 /* iOS doesn't add the class attribute, so we must do it here. */ 
4397                         CFDictionarySetValue(result
, kSecClass
, itemClass
); 
4399                 /* Remove attributes which are not part of the OS X database schema. */ 
4400                 CFDictionaryRemoveValue(result
, kSecAttrAccessible
); 
4401                 CFDictionaryRemoveValue(result
, kSecAttrAccessGroup
); 
4402                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4403                 CFDictionaryRemoveValue(result
, kSecAttrTombstone
); 
4406     /* This attribute is consumed by the bridge itself. */ 
4407     CFDictionaryRemoveValue(result
, kSecAttrNoLegacy
); 
4413  * SecItemCopyMergedResults takes two input objects, which may be containers, 
4414  * and returns a retained object which merges the results. Merging depends on the 
4415  * result type. If each result is valid and is not an array, then only one match was 
4416  * requested; in that case, the syncable (ios) match is preferred. 
4418  * FIXME: There are some edge cases still to deal with; e.g. if the OSX search specified a 
4419  * particular keychain to search, we do not want to merge in any IOS results. Also, may need 
4420  * to filter out duplicates if two items differ only in the sync attribute. 
4423 SecItemCopyMergedResults(CFDictionaryRef query
, CFTypeRef result_osx
, CFTypeRef result_ios
) 
4425         CFTypeID id_osx 
= (result_osx
) ? CFGetTypeID(result_osx
) : 0; 
4426         CFTypeID id_ios 
= (result_ios
) ? CFGetTypeID(result_ios
) : 0; 
4427         CFTypeID id_array 
= CFArrayGetTypeID(); 
4428         if ((id_osx 
== id_array
) && (id_ios 
== id_array
)) { 
4429                 // Fold the arrays into one. 
4430                 CFMutableArrayRef results 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4431                 CFArrayAppendArray(results
, (CFArrayRef
)result_ios
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_ios
))); 
4432                 CFArrayAppendArray(results
, (CFArrayRef
)result_osx
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_osx
))); 
4435         // Result type is not an array, so only one match can be returned. 
4436         return (id_ios
) ? CFRetain(result_ios
) : CFRetain(result_osx
); 
4443 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef 
*result
) 
4445         secitemlog(LOG_NOTICE
, "SecItemCopyMatching"); 
4449         secitemshow(query
, "SecItemCopyMatching query:"); 
4451         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4452         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4453         Boolean ios_only 
= SecItemNoLegacy(query
); 
4454         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4455         Boolean search_ios 
= SecItemSynchronizable(query
); 
4456         Boolean merge_search 
= SecItemSynchronizableAny(query
); 
4457         Boolean persistref_ios 
= SecItemHasSynchronizablePersistentReference(query
); 
4459         if (ios_only 
|| (sync_enabled 
&& (merge_search 
|| persistref_ios 
|| search_ios
))) { 
4460                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4461                         CFDictionaryGetValue(query
, kSecClass
), true, false, false, false, true, true); 
4463                         status_ios 
= errSecParam
; 
4466             SecItemUnlockSynchronizableKeychain(); 
4467             status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4468                         CFRelease(attrs_ios
); 
4470                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_ios result: %d", status_ios
); 
4471                 if (ios_only 
|| !merge_search 
|| persistref_ios
) { 
4472                         AssignOrReleaseResult(result_ios
, result
); 
4473                         return status_ios
; // no need to search non-syncable keychains 
4477         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4478                 CFDictionaryGetValue(query
, kSecClass
), false, false, true, false, true, true); 
4480                 status_osx 
= errSecParam
; 
4483                 status_osx 
= SecItemCopyMatching_osx(attrs_osx
, &result_osx
); 
4484                 CFRelease(attrs_osx
); 
4486         secitemlog(LOG_NOTICE
, "SecItemCopyMatching_osx result: %d", status_osx
); 
4488         // If one of the searches failed to occur or produce results, we can eliminate it 
4489         if (result_ios 
== NULL
) { 
4490                 AssignOrReleaseResult(result_osx
, result
); 
4491                 return status_osx
; // we can only have non-syncable results 
4493         if (result_osx 
== NULL
) { 
4494                 AssignOrReleaseResult(result_ios
, result
); 
4495                 return status_ios
; // we can only have syncable results 
4498         // If we get here, need to merge results 
4499         CFTypeRef result_merged 
= SecItemCopyMergedResults(query
, result_osx
, result_ios
); 
4500         CFReleaseSafe(result_osx
); 
4501         CFReleaseSafe(result_ios
); 
4502         AssignOrReleaseResult(result_merged
, result
); 
4504         if (status_osx 
== status_ios
) { 
4505                 return status_osx
; // both searches produced the same result 
4507         else if (!status_osx 
|| !status_ios
) { 
4508                 return errSecSuccess
; // one of the searches succeeded 
4510         else if (status_osx 
== errSecItemNotFound
) { 
4511                 return status_ios
; // this failure was more interesting 
4517 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
4519         secitemlog(LOG_NOTICE
, "SecItemAdd"); 
4526         secitemshow(attributes
, "SecItemAdd attrs:"); 
4528         OSStatus status_osx
, status_ios
; 
4529         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4530         Boolean ios_only 
= SecItemNoLegacy(attributes
); 
4531         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4532         Boolean add_ios 
= SecItemSynchronizable(attributes
); 
4534         if (ios_only 
|| (sync_enabled 
&& add_ios
)) { 
4535                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(attributes
, 
4536                         NULL
, true, true, false, false, false, false); 
4538                         status_ios 
= errSecParam
; 
4541             SecItemUnlockSynchronizableKeychain(); 
4542             status_ios 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4543                         CFRelease(attrs_ios
); 
4545                 secitemlog(LOG_NOTICE
, "SecItemAdd_ios result: %d", status_ios
); 
4547                         *result 
= result_ios
; 
4549                         CFReleaseSafe(result_ios
); 
4553         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(attributes
, 
4554                 NULL
, false, false, true, false, false, false); 
4556                 status_osx 
= errSecParam
; 
4559                 status_osx 
= SecItemAdd_osx(attrs_osx
, &result_osx
); 
4560                 CFRelease(attrs_osx
); 
4562         secitemlog(LOG_NOTICE
, "SecItemAdd_osx result: %d", status_osx
); 
4564                 *result 
= result_osx
; 
4566                 CFReleaseSafe(result_osx
); 
4571 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
4573         secitemlog(LOG_NOTICE
, "SecItemUpdate"); 
4574         if (!query 
|| !attributesToUpdate
) { 
4577         secitemshow(query
, "SecItemUpdate query:"); 
4578         secitemshow(attributesToUpdate
, "SecItemUpdate attrs:"); 
4580         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4581         Boolean ios_only 
= SecItemNoLegacy(query
); 
4582         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4583         Boolean search_ios 
= SecItemSynchronizable(query
); 
4584         Boolean merge_search 
= SecItemSynchronizableAny(query
); 
4585         Boolean persistref_ios 
= SecItemHasSynchronizablePersistentReference(query
); 
4587         if (ios_only 
|| (sync_enabled 
&& (merge_search 
|| persistref_ios 
|| search_ios
))) { 
4588                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4589                         CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4591                         status_ios 
= errSecParam
; 
4594                         SecItemUnlockSynchronizableKeychain(); 
4595             if (SecItemHasSynchronizableUpdate(true, attributesToUpdate
)) 
4596                 status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
4598                 status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4599                         CFRelease(attrs_ios
); 
4601                 secitemlog(LOG_NOTICE
, "SecItemUpdate_ios result: %d", status_ios
); 
4602                 if (ios_only 
|| !merge_search 
|| persistref_ios
) 
4606         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4607                 CFDictionaryGetValue(query
, kSecClass
), false, false, true, true, true, true); 
4609                 status_osx 
= errSecParam
; 
4612                 if (SecItemHasSynchronizableUpdate(false, attributesToUpdate
)) 
4613                         status_osx 
= SecItemChangeSynchronizability(attrs_osx
, attributesToUpdate
, true); 
4615                         status_osx 
= SecItemUpdate_osx(attrs_osx
, attributesToUpdate
); 
4617                 CFRelease(attrs_osx
); 
4619         secitemlog(LOG_NOTICE
, "SecItemUpdate_osx result: %d", status_osx
); 
4621                 // Harmonize the result of the update attempts. 
4622                 if (status_osx 
== status_ios
) { 
4623                         // both updates produced the same result 
4626                 else if (!status_osx 
|| !status_ios
) { 
4627                         // one of the updates succeeded, but the other failed 
4628                         if (status_osx 
== errSecItemNotFound 
|| status_ios 
== errSecItemNotFound
) 
4629                                 return errSecSuccess
; // item only found in one keychain 
4631                                 return (status_osx
) ? status_osx 
: status_ios
; // return the error 
4633                 else if (status_osx 
== errSecItemNotFound
) { 
4634                         // both updates failed, status_ios failure is more interesting 
4635                         // since the item was actually found 
4643 SecItemDelete(CFDictionaryRef query
) 
4645         secitemlog(LOG_NOTICE
, "SecItemDelete"); 
4649         secitemshow(query
, "SecItemDelete query:"); 
4651         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4652         Boolean ios_only 
= SecItemNoLegacy(query
); 
4653         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4654         Boolean search_ios 
= SecItemSynchronizable(query
); 
4655         Boolean merge_search 
= SecItemSynchronizableAny(query
); 
4656         Boolean persistref_ios 
= SecItemHasSynchronizablePersistentReference(query
); 
4658         if (ios_only 
|| (sync_enabled 
&& (merge_search 
|| persistref_ios 
|| search_ios
))) { 
4659                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4660                         NULL
, true, true, false, true, true, true); 
4662                         status_ios 
= errSecParam
; 
4665             SecItemUnlockSynchronizableKeychain(); 
4666             status_ios 
= SecItemDelete_ios(attrs_ios
); 
4667                         CFRelease(attrs_ios
); 
4669                 secitemlog(LOG_NOTICE
, "SecItemDelete_ios result: %d", status_ios
); 
4670                 if (ios_only 
|| !merge_search 
|| persistref_ios
) 
4674         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4675                 NULL
, false, false, true, true, true, true); 
4677                 status_osx 
= errSecParam
; 
4680                 status_osx 
= SecItemDelete_osx(attrs_osx
); 
4681                 CFRelease(attrs_osx
); 
4683         secitemlog(LOG_NOTICE
, "SecItemDelete_osx result: %d", status_osx
); 
4686                 // Harmonize the result of the delete attempts. 
4687                 if (status_osx 
== status_ios
) { 
4688                         // both deletes produced the same result 
4691                 else if (!status_osx 
|| !status_ios
) { 
4692                         // one of the deletes succeeded, but the other failed 
4693                         if (status_osx 
== errSecItemNotFound 
|| status_ios 
== errSecItemNotFound
) 
4694                                 return errSecSuccess
; // item only found in one keychain 
4696                                 return (status_osx
) ? status_osx 
: status_ios
; // return the error 
4698                 else if (status_osx 
== errSecItemNotFound
) { 
4699                         // both deletes failed, status_ios failure is more interesting 
4700                         // since the item was actually found 
4708 SecItemCopyMatching_osx( 
4709         CFDictionaryRef query
, 
4712         if (!query 
|| !result
) 
4717         CFAllocatorRef allocator 
= CFGetAllocator(query
); 
4718         CFIndex matchCount 
= 0; 
4719         CFMutableArrayRef itemArray 
= NULL
; 
4720         SecKeychainItemRef item 
= NULL
; 
4721         SecIdentityRef identity 
= NULL
; 
4722         OSStatus tmpStatus
, status 
= errSecSuccess
; 
4724         // validate input query parameters and create the search reference 
4725         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(query
, &status
); 
4726         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
4728         // find the next match until we hit maxMatches, or no more matches found 
4729         while ( !(!itemParams
->returnAllMatches 
&& matchCount 
>= itemParams
->maxMatches
) && 
4730                         SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == errSecSuccess
) { 
4732                 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
)) 
4733                         continue; // move on to next item 
4735                 ++matchCount
; // we have a match 
4737                 tmpStatus 
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
); 
4738                 if (tmpStatus 
&& (status 
== errSecSuccess
)) 
4746                         CFRelease(identity
); 
4751         if (status 
== errSecSuccess
) 
4752                 status 
= (matchCount 
> 0) ? errSecSuccess 
: errSecItemNotFound
; 
4755         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
4759         _FreeSecItemParams(itemParams
); 
4765 SecItemCopyDisplayNames( 
4767         CFArrayRef 
*displayNames
) 
4771         Required(displayNames
); 
4773     return errSecUnimplemented
; 
4779         CFDictionaryRef attributes
, 
4787         CFAllocatorRef allocator 
= CFGetAllocator(attributes
); 
4788         CFMutableArrayRef itemArray 
= NULL
; 
4789         SecKeychainItemRef item 
= NULL
; 
4790         OSStatus tmpStatus
, status 
= errSecSuccess
; 
4792         // validate input attribute parameters 
4793         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(attributes
, &status
); 
4794         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
4796         // currently, we don't support adding SecIdentityRef items (an aggregate item class), 
4797         // since the private key should already be in a keychain by definition. We could support 
4798         // this as a copy operation for the private key if a different keychain is specified, 
4799         // but in any case it should try to add the certificate. See <rdar://8317887>. 
4800         require_action(!itemParams
->returnIdentity
, error_exit
, status 
= errSecItemInvalidValue
); 
4802         if (!itemParams
->useItems
) { 
4803                 // create a single keychain item specified by the input attributes 
4804                 status 
= SecKeychainItemCreateFromContent(itemParams
->itemClass
, 
4805                         itemParams
->attrList
, 
4806                         (itemParams
->itemData
) ? (UInt32
)CFDataGetLength(itemParams
->itemData
) : 0, 
4807                         (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
, 
4808                         itemParams
->keychain
, 
4811                 require_noerr(status
, error_exit
); 
4813                 // return results (if requested) 
4815                         itemParams
->maxMatches 
= 1; // in case kSecMatchLimit was set to > 1 
4816                         tmpStatus 
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4817                         if (tmpStatus 
&& (status 
== errSecSuccess
)) 
4823                 // add multiple items which are specified in the itemParams->useItems array. 
4824                 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain. 
4825                 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain. 
4826                 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain. 
4828                 OSStatus aggregateStatus 
= errSecSuccess
; 
4829                 CFIndex ix
, count 
= CFArrayGetCount(itemParams
->useItems
); 
4830                 itemParams
->maxMatches 
= (count 
> 1) ? (int)count 
: 2; // force results to always be returned as an array 
4831                 for (ix
=0; ix 
< count
; ix
++) { 
4832                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
); 
4834                                 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) { 
4835                                         // SecCertificateRef item 
4836                                         tmpStatus 
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
); 
4837                                         if (!tmpStatus 
&& result
) { 
4838                                                 tmpStatus 
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4840                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4842                                 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) { 
4844                                         SecKeychainRef itemKeychain 
= NULL
; 
4845                                         tmpStatus 
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
); 
4846                                         if (tmpStatus 
== errSecSuccess
) { 
4847                                                 // key was in a keychain, so we can attempt to copy it 
4848                                                 SecKeychainItemRef itemCopy 
= NULL
; 
4849                                                 tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
4850                                                 if (!tmpStatus 
&& result
) { 
4851                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4854                                                         CFRelease(itemCopy
); 
4858                                                 // key was not in any keychain, so must be imported 
4859                                                 SecKeychainItemRef keyItem 
= NULL
; 
4860                                                 tmpStatus 
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
); 
4861                                                 if (!tmpStatus 
&& result
) { 
4862                                                         tmpStatus 
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4869                                                 CFRelease(itemKeychain
); 
4871                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4873                                 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) { 
4874                                         // SecKeychainItemRef item 
4875                                         SecKeychainItemRef itemCopy 
= NULL
; 
4876                                         tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
4877                                         if (!tmpStatus 
&& result
) { 
4878                                                 tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4881                                                 CFRelease(itemCopy
); 
4883                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4885                                 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) { 
4886                                         // CFDataRef item (persistent reference) 
4887                                         SecKeychainItemRef realItem 
= NULL
; 
4888                                         tmpStatus 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
); 
4889                                         if (tmpStatus 
== errSecSuccess
) { 
4890                                                 // persistent reference resolved to a keychain item, so we can attempt to copy it 
4891                                                 SecKeychainItemRef itemCopy 
= NULL
; 
4892                                                 tmpStatus 
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
4893                                                 if (!tmpStatus 
&& result
) { 
4894                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4897                                                         CFRelease(itemCopy
); 
4901                                                 CFRelease(realItem
); 
4903                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4906                 } // end of itemList array loop 
4907                 status 
= aggregateStatus
; 
4908         } // end processing multiple items 
4911         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
4915         _FreeSecItemParams(itemParams
); 
4922         CFDictionaryRef query
, 
4923         CFDictionaryRef attributesToUpdate
) 
4925         if (!query 
|| !attributesToUpdate
) 
4928         // run the provided query to get a list of items to update 
4929         CFTypeRef results 
= NULL
; 
4930         OSStatus status 
= SecItemCopyMatching(query
, &results
); 
4931         if (status 
!= errSecSuccess
) 
4932                 return status
; // nothing was matched, or the query was bad 
4934         CFArrayRef items 
= NULL
; 
4935         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
4936                 items 
= (CFArrayRef
) results
; 
4939                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
4943         OSStatus result 
= errSecSuccess
; 
4944         CFIndex ix
, count 
= CFArrayGetCount(items
); 
4945         for (ix
=0; ix 
< count
; ix
++) { 
4946                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
4948                         status 
= _UpdateKeychainItem(anItem
, attributesToUpdate
); 
4949                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
); 
4961         CFDictionaryRef query
) 
4966         // run the provided query to get a list of items to delete 
4967         CFTypeRef results 
= NULL
; 
4968         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
4969         if (status 
!= errSecSuccess
) 
4970                 return status
; // nothing was matched, or the query was bad 
4972         CFArrayRef items 
= NULL
; 
4973         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
4974                 items 
= (CFArrayRef
) results
; 
4977                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
4981         OSStatus result 
= errSecSuccess
; 
4982         CFIndex ix
, count 
= CFArrayGetCount(items
); 
4983         for (ix
=0; ix 
< count
; ix
++) { 
4984                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
4986                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) { 
4987                                 status 
= _DeleteIdentity((SecIdentityRef
)anItem
); 
4990                                 status 
= _DeleteKeychainItem(anItem
); 
4992                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
);