2  * Copyright (c) 2006-2013 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 void secitemlog(int priority
, const char *format
, ...) 
  75         if (priority 
< LOG_NOTICE
) // log warnings and errors 
  79                 va_start(list
, format
); 
  80                 vsyslog(priority
, format
, list
); 
  85 static void secitemshow(CFTypeRef obj
, const char *context
) 
  88         CFStringRef desc 
= CFCopyDescription(obj
); 
  91         CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc
), kCFStringEncodingUTF8
) + 1; 
  92         char* buffer 
= (char*) malloc(length
); 
  94                 Boolean converted 
= CFStringGetCString(desc
, buffer
, length
, kCFStringEncodingUTF8
); 
  96                         const char *prefix 
= (context
) ? context 
: ""; 
  97                         const char *separator 
= (context
) ? " " : ""; 
  98                         secitemlog(LOG_NOTICE
, "%s%s%s", prefix
, separator
, buffer
); 
 107 #define CFDataGetBytePtrVoid CFDataGetBytePtr 
 109 #pragma mark SecItem private utility functions 
 111 /******************************************************************************/ 
 113 struct ProtocolAttributeInfo 
{ 
 114         const CFTypeRef 
*protocolValue
; 
 115         SecProtocolType protocolType
; 
 118 static ProtocolAttributeInfo gProtocolTypes
[] = { 
 119         { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP 
}, 
 120         { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount 
}, 
 121         { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP 
}, 
 122         { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC 
}, 
 123         { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP 
}, 
 124         { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3 
}, 
 125         { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP 
}, 
 126         { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS 
}, 
 127         { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP 
}, 
 128         { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP 
}, 
 129         { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk 
}, 
 130         { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP 
}, 
 131         { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet 
}, 
 132         { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH 
}, 
 133         { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS 
}, 
 134         { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS 
}, 
 135         { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy 
}, 
 136         { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy 
}, 
 137         { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy 
}, 
 138         { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB 
}, 
 139         { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP 
}, 
 140         { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy 
}, 
 141         { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP 
}, 
 142         { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC 
}, 
 143         { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP 
}, 
 144         { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS 
}, 
 145         { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS 
}, 
 146         { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS 
}, 
 147         { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS 
}, 
 148         { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS 
}, 
 149         { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S 
} 
 152 static const int kNumberOfProtocolTypes 
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
); 
 155  * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType. 
 157 static SecProtocolType
 
 158 _SecProtocolTypeForSecAttrProtocol( 
 161         SecProtocolType result 
= kSecProtocolTypeAny
; 
 163         if (protocol 
!= NULL
) { 
 165                 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 166                         if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) { 
 167                                 result 
= gProtocolTypes
[count
].protocolType
; 
 177  * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol. 
 180 _SecAttrProtocolForSecProtocolType( 
 181         SecProtocolType protocolType
) 
 183         CFTypeRef result 
= NULL
; 
 185         for (count
=0; count
<kNumberOfProtocolTypes
; count
++) { 
 186                 if (gProtocolTypes
[count
].protocolType 
== protocolType
) { 
 187                         result 
= *(gProtocolTypes
[count
].protocolValue
); 
 196 /******************************************************************************/ 
 198 struct AuthenticationAttributeInfo 
{ 
 199         const CFTypeRef 
*authValue
; 
 200         SecAuthenticationType authType
; 
 203 static AuthenticationAttributeInfo gAuthTypes
[] = { 
 204         { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM 
}, 
 205         { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN 
}, 
 206         { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA 
}, 
 207         { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA 
}, 
 208         { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic 
}, 
 209         { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest 
}, 
 210         { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm 
}, 
 211         { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault 
} 
 214 static const int kNumberOfAuthenticationTypes 
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
); 
 217  * _SecAuthenticationTypeForSecAttrAuthenticationType converts a 
 218  * SecAttrAuthenticationType to a SecAuthenticationType. 
 220 static SecAuthenticationType
 
 221 _SecAuthenticationTypeForSecAttrAuthenticationType( 
 222         CFTypeRef authenticationType
) 
 224         SecAuthenticationType result 
= kSecAuthenticationTypeAny
; 
 226         if (authenticationType 
!= NULL
) { 
 228                 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 229                         if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) { 
 230                                 result 
= gAuthTypes
[count
].authType
; 
 240  * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType 
 241  * to a SecAttrAuthenticationType. 
 244 _SecAttrAuthenticationTypeForSecAuthenticationType( 
 245         SecAuthenticationType authenticationType
) 
 247         CFTypeRef result 
= NULL
; 
 249         for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) { 
 250                 if (gAuthTypes
[count
].authType 
== authenticationType
) { 
 251                         result 
= *(gAuthTypes
[count
].authValue
); 
 260 /******************************************************************************/ 
 262 struct KeyAlgorithmInfo 
{ 
 263         const CFTypeRef 
*keyType
; 
 267 static KeyAlgorithmInfo gKeyTypes
[] = { 
 268         { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA 
}, 
 269         { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA 
}, 
 270         { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES 
}, 
 271         { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES 
}, 
 272         { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES 
}, 
 273         { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4 
}, 
 274         { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2 
}, 
 275         { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST 
}, 
 276         { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA 
}, 
 277         { &kSecAttrKeyTypeEC
, CSSM_ALGID_ECDSA 
} 
 280 static const int kNumberOfKeyTypes 
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
); 
 283 static UInt32 
_SecAlgorithmTypeFromSecAttrKeyType( 
 284         CFTypeRef keyTypeRef
) 
 286         UInt32 keyAlgValue 
= 0; 
 287         if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
)) 
 291         for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) { 
 292                 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) { 
 293                         keyAlgValue 
= gKeyTypes
[ix
].keyValue
; 
 298         //%%%TODO try to convert the input string to a number here 
 304 enum ItemRepresentation
 
 306         kStringRepresentation
, 
 308         kNumberRepresentation
, 
 309         kBooleanRepresentation
, 
 314 struct InternalAttributeListInfo
 
 317         const CFTypeRef 
*newItemType
; 
 318         ItemRepresentation itemRepresentation
; 
 322 static InternalAttributeListInfo gGenericPasswordAttributes
[] = 
 324         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 325         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 326         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 327         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 328         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 329         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 330         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 331         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 332         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 333         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 334         { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation 
}, 
 335         { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation 
} 
 338 static const int kNumberOfGenericPasswordAttributes 
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 341 static InternalAttributeListInfo gInternetPasswordAttributes
[] = 
 343         { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation 
}, 
 344         { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation 
}, 
 345         { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation 
}, 
 346         { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation 
}, 
 347         { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 348         { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation 
}, // UInt32, a.k.a. FourCharCode 
 349         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 350         { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation 
}, 
 351         { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation 
}, 
 352         { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation 
}, 
 353         { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation 
}, 
 354         { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation 
}, 
 355         { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation 
}, // maps from UInt32 value to string constant 
 356         { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation 
}, 
 357         { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation 
} 
 360 static const int kNumberOfInternetPasswordAttributes 
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
); 
 363 static InternalAttributeListInfo gCertificateAttributes
[] = 
 365         { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation 
}, 
 366         { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation 
}, 
 367         { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation 
}, 
 368         { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation 
}, 
 369         { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation 
}, 
 370         { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation 
}, 
 371         { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation 
}, 
 372         { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation 
} 
 375 static const int kNumberOfCertificateAttributes 
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
); 
 378 static InternalAttributeListInfo gKeyAttributes
[] = 
 380     { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation 
}, // key class maps from UInt32 value to string constant 
 381     { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation 
}, // note that "print name" maps to the user-visible label 
 382 //  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation }, 
 383     { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation 
}, 
 384 //  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 385 //  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 386     { 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 
 387     { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation 
}, 
 388 //  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key 
 389     { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation 
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES) 
 390     { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation 
}, 
 391     { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation 
}, 
 392 //  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 393 //  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation }, 
 394 //  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 395 //  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 396 //  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 397 //  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 398     { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation 
}, 
 399     { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation 
}, 
 400     { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation 
}, 
 401     { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation 
}, 
 402     { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation 
}, 
 403 //  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 404 //  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation }, 
 405     { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation 
}, 
 406     { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation 
} 
 409 static const int kNumberOfKeyAttributes 
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
); 
 412 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
) 
 416                 case kStringRepresentation
: 
 418                         if (CFStringGetTypeID() != CFGetTypeID(value
)) { 
 422                         CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 423                         char* buffer 
= (char*) malloc(maxLength
); 
 424                         Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 426                                 length 
= (UInt32
)strlen(buffer
); 
 436                 case kDataRepresentation
: 
 438                         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 439                 // We may have a string here, since the key label may be a GUID for the symmetric keys 
 440                 CFIndex maxLength 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1; 
 441                 char* buffer 
= (char*) malloc(maxLength
); 
 442                 Boolean converted 
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
); 
 444                     length 
= (UInt32
)strlen(buffer
); 
 454                         if (CFDataGetTypeID() != CFGetTypeID(value
)) { 
 458                         length 
= (UInt32
)CFDataGetLength((CFDataRef
) value
); 
 459                         uint8_t* buffer 
= (uint8_t*) malloc(length
); 
 460                         CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
); 
 464                 case kNumberRepresentation
: 
 466                         if (CFNumberGetTypeID() != CFGetTypeID(value
)) { 
 470                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 471                         Boolean converted 
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
); 
 473                                 length 
= sizeof(uint32_t); 
 483                 case kBooleanRepresentation
: 
 485                         if (CFBooleanGetTypeID() != CFGetTypeID(value
)) { 
 489                         uint32_t* buffer 
= (uint32_t*) malloc(sizeof(uint32_t)); 
 490                         *buffer 
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
 491                         length 
= sizeof(uint32_t); 
 495                 case kDateRepresentation
: 
 497                         if (CFDateGetTypeID() != CFGetTypeID(value
)) { 
 501                         char* buffer 
= (char*) calloc(1, 32); // max length of a CSSM date string 
 502                         CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
); 
 503                         length 
= (UInt32
)strlen(buffer
); 
 517 _ConvertNewFormatToOldFormat( 
 518         CFAllocatorRef allocator
, 
 519         const InternalAttributeListInfo
* info
, 
 521         CFDictionaryRef dictionaryRef
, 
 522         SecKeychainAttributeList
* &attrList
 
 525         // get the keychain attributes array from the data item 
 526         // here's the problem.  On the one hand, we have a dictionary that is purported to contain 
 527         // attributes for our type.  On the other hand, the dictionary may contain items we don't support, 
 528         // and we therefore don't know how many attributes we will have unless we count them first 
 531         attrList 
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
)); 
 533         // make storage to extract the dictionary items 
 534         CFIndex itemsInDictionary 
= CFDictionaryGetCount(dictionaryRef
); 
 535         CFTypeRef keys
[itemsInDictionary
]; 
 536         CFTypeRef values
[itemsInDictionary
]; 
 538         CFTypeRef 
*keysPtr 
= keys
; 
 539         CFTypeRef 
*valuesPtr 
= values
; 
 541         CFDictionaryGetKeysAndValues(dictionaryRef
, keys
, values
); 
 543         // count the number of items we are interested in 
 547         // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that 
 548         // we don't pay the price for this twice 
 549         SecKeychainAttrType tags
[itemsInDictionary
]; 
 550         ItemRepresentation types
[itemsInDictionary
]; 
 552         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 554                 CFTypeRef key 
= keysPtr
[i
]; 
 557                 for (j 
= 0; j 
< infoNumItems
; ++j
) 
 559                         if (CFEqual(*(info
[j
].newItemType
), key
)) 
 561                                 tags
[i
] = info
[j
].oldItemType
; 
 562                                 types
[i
] = info
[j
].itemRepresentation
; 
 568                 if (j 
>= infoNumItems
) 
 570                         // if we got here, we aren't interested in this item. 
 575         // now we can make the result array 
 576         attrList
->count 
= (UInt32
)count
; 
 577         attrList
->attr 
= (SecKeychainAttribute
*) malloc(sizeof(SecKeychainAttribute
) * count
); 
 579         // fill out the array 
 580         int resultPointer 
= 0; 
 581         for (i 
= 0; i 
< itemsInDictionary
; ++i
) 
 583                 if (values
[i
] != NULL
) 
 585                         attrList
->attr
[resultPointer
].tag 
= tags
[i
]; 
 587                         // we have to clone the data pointer.  The caller will need to make sure to throw these away 
 588                         // with _FreeAttrList when it is done... 
 589                         attrList
->attr
[resultPointer
].data 
= CloneDataByType(types
[i
], valuesPtr
[i
], attrList
->attr
[resultPointer
].length
); 
 594         return errSecSuccess
; 
 600 _ConvertOldFormatToNewFormat( 
 601         CFAllocatorRef allocator
, 
 602         const InternalAttributeListInfo
* info
, 
 604         SecKeychainItemRef itemRef
, 
 605         CFMutableDictionaryRef
& dictionaryRef
) 
 607         SecKeychainAttributeList list
; 
 608         list
.count 
= infoNumItems
; 
 609         list
.attr 
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
)); 
 611         // fill out the array.  We only need to fill in the tags, since calloc zeros what it returns 
 613         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 615                 list
.attr
[i
].tag 
= info
[i
].oldItemType
; 
 618         OSStatus result 
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
); 
 619         if (result 
!= errSecSuccess
) 
 621                 dictionaryRef 
= NULL
; 
 626         // create the dictionary 
 627         dictionaryRef 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 630         for (i 
= 0; i 
< infoNumItems
; ++i
) 
 632                 if (list
.attr
[i
].data 
== NULL
) 
 635                 switch (info
[i
].itemRepresentation
) 
 637                         case kStringRepresentation
: 
 639                                 CFStringRef stringRef
; 
 640                                 if (info
[i
].oldItemType 
== kSecKeyKeyClass
) { 
 641                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 642                                         uint32_t keyRecordValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 643                                         bool retainString 
= true; 
 644                                         switch (keyRecordValue
) { 
 645                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 646                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 648                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 649                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 651                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 652                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 655                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
); 
 659                                                 if (retainString
) CFRetain(stringRef
); 
 660                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 661                                                 CFRelease(stringRef
); 
 664                                 else if (info
[i
].oldItemType 
== kSecKeyKeyType
) { 
 665                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 666                                         uint32_t keyAlgValue 
= *((uint32_t*)list
.attr
[i
].data
); 
 667                                         bool retainString 
= true; 
 668                                         switch (keyAlgValue
) { 
 669                                                 case CSSM_ALGID_RSA 
: 
 670                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 672                                                 case CSSM_ALGID_DSA 
: 
 673                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 675                                                 case CSSM_ALGID_AES 
: 
 676                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 678                                                 case CSSM_ALGID_DES 
: 
 679                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 681                                                 case CSSM_ALGID_3DES 
: 
 682                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 684                                                 case CSSM_ALGID_RC4 
: 
 685                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 687                                                 case CSSM_ALGID_RC2 
: 
 688                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 690                                                 case CSSM_ALGID_CAST 
: 
 691                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 693                                                 case CSSM_ALGID_ECDSA 
: 
 694                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 697                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
); 
 698                                                         retainString 
= false; 
 702                                                 if (retainString
) CFRetain(stringRef
); 
 703                                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 704                                                 CFRelease(stringRef
); 
 708                                         // normal case: attribute contains a string 
 709                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 710                                         if (stringRef 
== NULL
) 
 711                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 712                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 713                                         CFRelease(stringRef
); 
 718                         case kDataRepresentation
: 
 720                 if ((info
[i
].oldItemType 
== kSecKeyLabel
) && (list
.attr
[i
].length 
== kUUIDStringLength
)) { 
 721                                         // It's possible that there could be a string here because the key label may have a UUID 
 722                                         CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
); 
 723                                         if (stringRef 
== NULL
) 
 724                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 725                                         CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
); 
 726                                         CFRelease(stringRef
); 
 729                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
); 
 731                     dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
 732                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
); 
 737                         case kNumberRepresentation
: 
 739                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
); 
 740                                 if (numberRef 
== NULL
) 
 741                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
 742                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
); 
 743                                 CFRelease(numberRef
); 
 747                         case kBooleanRepresentation
: 
 749                                 uint32_t value 
= *((uint32_t*)list
.attr
[i
].data
); 
 750                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
 751                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
); 
 755                         case kDateRepresentation
: 
 757                                 CFDateRef dateRef 
= NULL
; 
 758                                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
); 
 760                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
 761                                 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
); 
 769         SecKeychainItemFreeContent(&list
, NULL
); 
 779  * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the 
 780  * attributes of item. 
 783 _CreateAttributesDictionaryFromGenericPasswordItem( 
 784         CFAllocatorRef allocator
, 
 785         SecKeychainItemRef item
, 
 786         CFDictionaryRef 
*dictionary
) 
 788         // do the basic allocations 
 789         CFMutableDictionaryRef dict 
= NULL
; 
 790         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
); 
 791         if (result 
== errSecSuccess
) // did we complete OK 
 793                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
); 
 804  * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the 
 805  * attributes of item. 
 808 _CreateAttributesDictionaryFromCertificateItem( 
 809         CFAllocatorRef allocator
, 
 810         SecKeychainItemRef item
, 
 811         CFDictionaryRef 
*dictionary
) 
 813         // do the basic allocations 
 814         CFMutableDictionaryRef dict 
= NULL
; 
 815         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
); 
 816         if (result 
== errSecSuccess
) // did we complete OK 
 818                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
); 
 823         return errSecSuccess
; 
 827  * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the 
 828  * attributes of item. 
 831 _CreateAttributesDictionaryFromKeyItem( 
 832         CFAllocatorRef allocator
, 
 833         SecKeychainItemRef item
, 
 834         CFDictionaryRef 
*dictionary
) 
 837 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails. 
 838 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and 
 839 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent. 
 842                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 845         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 847         // do the basic allocations 
 848         CFMutableDictionaryRef dict 
= NULL
; 
 849         OSStatus result 
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
); 
 850         if (result 
== errSecSuccess
) // did we complete OK 
 852                 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
 857         return errSecSuccess
; 
 860         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 862         SecItemClass itemClass 
= 0; 
 864         SecKeychainAttributeList 
*attrList 
= NULL
; 
 865         SecKeychainAttributeInfo 
*info 
= NULL
; 
 866         SecKeychainRef keychain 
= NULL
; 
 868         OSStatus status 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
 870                 goto error_exit
; // item must have an itemClass 
 875     case kSecInternetPasswordItemClass
: 
 876                 itemID 
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
; 
 878     case kSecGenericPasswordItemClass
: 
 879                 itemID 
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
; 
 881     case 'ashp': /* kSecAppleSharePasswordItemClass */ 
 882                 itemID 
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
; 
 889         status 
= SecKeychainItemCopyKeychain(item
, &keychain
); 
 891                 goto error_exit
; // item must have a keychain, so we can get the attribute info for it 
 894         status 
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
); 
 896                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 899         status 
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
); 
 901                 goto error_exit
; // unable to get the attribute info (i.e. database schema) 
 904         for (ix 
= 0; ix 
< info
->count
; ++ix
) 
 906                 SecKeychainAttribute 
*attribute 
= &attrList
->attr
[ix
]; 
 907                 if (!attribute
->length 
&& !attribute
->data
) 
 910                 UInt32 j
, count 
= kNumberOfKeyAttributes
; 
 911                 InternalAttributeListInfo 
*intInfo 
= NULL
; 
 912                 for (j
=0; j
<count
; j
++) { 
 913                         if (gKeyAttributes
[j
].oldItemType 
== info
->tag
[ix
]) { 
 914                                 intInfo 
= &gKeyAttributes
[j
]; 
 921                 switch (intInfo
->itemRepresentation
) 
 923                         case kStringRepresentation
: 
 925                                 CFStringRef stringRef
; 
 926                                 if (intInfo
->oldItemType 
== kSecKeyKeyClass
) { 
 927                                         // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant 
 928                                         UInt32 keyRecordValue 
= *((UInt32
*)attribute
->data
); 
 929                                         bool retainString 
= true; 
 930                                         switch (keyRecordValue
) { 
 931                                                 case CSSM_DL_DB_RECORD_PUBLIC_KEY 
: 
 932                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPublic
; 
 934                                                 case CSSM_DL_DB_RECORD_PRIVATE_KEY
: 
 935                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassPrivate
; 
 937                                                 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
: 
 938                                                         stringRef 
= (CFStringRef
) kSecAttrKeyClassSymmetric
; 
 941                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyRecordValue
); 
 945                                                 if (retainString
) CFRetain(stringRef
); 
 946                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 947                                                 CFRelease(stringRef
); 
 950                                 else if (intInfo
->oldItemType 
== kSecKeyKeyType
) { 
 951                                         // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant 
 952                                         UInt32 keyAlgValue 
= *((UInt32
*)attribute
->data
); 
 953                                         bool retainString 
= true; 
 954                                         switch (keyAlgValue
) { 
 955                                                 case CSSM_ALGID_RSA 
: 
 956                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRSA
; 
 958                                                 case CSSM_ALGID_DSA 
: 
 959                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDSA
; 
 961                                                 case CSSM_ALGID_AES 
: 
 962                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeAES
; 
 964                                                 case CSSM_ALGID_DES 
: 
 965                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeDES
; 
 967                                                 case CSSM_ALGID_3DES 
: 
 968                                                         stringRef 
= (CFStringRef
) kSecAttrKeyType3DES
; 
 970                                                 case CSSM_ALGID_RC4 
: 
 971                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC4
; 
 973                                                 case CSSM_ALGID_RC2 
: 
 974                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeRC2
; 
 976                                                 case CSSM_ALGID_CAST 
: 
 977                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeCAST
; 
 979                                                 case CSSM_ALGID_ECDSA 
: 
 980                                                         stringRef 
= (CFStringRef
) kSecAttrKeyTypeEC
; 
 983                                                         stringRef 
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%u"), (unsigned int)keyAlgValue
); 
 984                                                         retainString 
= false; 
 988                                                 if (retainString
) CFRetain(stringRef
); 
 989                                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 990                                                 CFRelease(stringRef
); 
 994                                         // normal case: attribute contains a string 
 995                                         stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
 996                                         if (stringRef 
== NULL
) 
 997                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
 998                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
 999                                         CFRelease(stringRef
); 
1004                         case kDataRepresentation
: 
1006                 if ((intInfo
->oldItemType 
== kSecKeyLabel
) && (attribute
->length 
== kUUIDStringLength
)) { 
1007                                         // It's possible that there could be a string here because the key label may have a UUID 
1008                     CFStringRef stringRef 
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
); 
1009                                         if (stringRef 
== NULL
) 
1010                                                 stringRef 
= (CFStringRef
) CFRetain(kCFNull
); 
1011                                         CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
); 
1012                                         CFRelease(stringRef
); 
1016                                 CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
); 
1017                                 if (dataRef 
== NULL
) 
1018                                         dataRef 
= (CFDataRef
) CFRetain(kCFNull
); 
1019                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
); 
1024                         case kNumberRepresentation
: 
1026                                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
); 
1027                                 if (numberRef 
== NULL
) 
1028                                         numberRef 
= (CFNumberRef
) CFRetain(kCFNull
); 
1029                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
); 
1030                                 CFRelease(numberRef
); 
1034                         case kBooleanRepresentation
: 
1036                                 UInt32 value 
= *((UInt32
*)attribute
->data
); 
1037                                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1038                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
); 
1042                         case kDateRepresentation
: 
1044                                 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here 
1045                                 CFDateRef dateRef 
= NULL
; 
1046                                 if (dateRef 
== NULL
) 
1047                                         dateRef 
= (CFDateRef
) CFRetain(kCFNull
); 
1048                                 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
); 
1055         CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
); 
1060                 SecKeychainItemFreeAttributesAndData(attrList
, NULL
); 
1063                 SecKeychainFreeAttributeInfo(info
); 
1066                 CFRelease(keychain
); 
1075  * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the 
1076  * attributes of item. 
1079 _CreateAttributesDictionaryFromInternetPasswordItem( 
1080         CFAllocatorRef allocator
, 
1081         SecKeychainItemRef item
, 
1082         CFDictionaryRef 
*dictionary
) 
1085         SecKeychainAttribute attr
[] = { 
1086                 { kSecServerItemAttr
, 0, NULL 
},                /* [0] server */ 
1087                 { kSecSecurityDomainItemAttr
, 0, NULL 
},        /* [1] securityDomain */ 
1088                 { kSecAccountItemAttr
, 0, NULL 
},               /* [2] account */ 
1089                 { kSecPathItemAttr
, 0, NULL 
},                  /* [3] path */ 
1090                 { kSecPortItemAttr
, 0, NULL 
},                  /* [4] port */ 
1091                 { kSecProtocolItemAttr
, 0, NULL 
},              /* [5] protocol */ 
1092                 { kSecAuthenticationTypeItemAttr
, 0, NULL 
},    /* [6] authenticationType */ 
1093                 { kSecCommentItemAttr
, 0, NULL 
},               /* [7] comment */ 
1094                 { kSecDescriptionItemAttr
, 0, NULL 
},           /* [8] description */ 
1095                 { kSecLabelItemAttr
, 0, NULL 
},                 /* [9] label */ 
1096                 { kSecCreationDateItemAttr
, 0, NULL 
},  /* [10] creation date */ 
1097                 { kSecModDateItemAttr
, 0, NULL 
},               /* [11] modification date */ 
1098                 { kSecCreatorItemAttr
, 0, NULL 
},               /* [12] creator */ 
1099                 { kSecTypeItemAttr
, 0, NULL 
},                  /* [13] type */ 
1100                 { kSecInvisibleItemAttr
, 0, NULL 
},             /* [14] invisible */ 
1101                 { kSecNegativeItemAttr
, 0, NULL 
},              /* [15] negative */ 
1103         SecKeychainAttributeList attrList 
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr 
}; 
1106         CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1107         CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2]; 
1111         // copy the item's attributes 
1112         status 
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
); 
1113         require_noerr(status
, SecKeychainItemCopyContent_failed
); 
1118         keys
[numValues
] = kSecClass
; 
1119         values
[numValues
] = kSecClassInternetPassword
; 
1122         // add kSecAttrServer 
1123         if ( attrList
.attr
[0].length 
> 0 ) { 
1124                 keys
[numValues
] = kSecAttrServer
; 
1125                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
); 
1126                 if ( values
[numValues
] != NULL 
) { 
1131         // add kSecAttrSecurityDomain 
1132         if ( attrList
.attr
[1].length 
> 0 ) { 
1133                 keys
[numValues
] = kSecAttrSecurityDomain
; 
1134                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
); 
1135                 if ( values
[numValues
] != NULL 
) { 
1140         // add kSecAttrAccount 
1141         if ( attrList
.attr
[2].length 
> 0 ) { 
1142                 keys
[numValues
] = kSecAttrAccount
; 
1143                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
); 
1144                 if ( values
[numValues
] != NULL 
) { 
1150         if ( attrList
.attr
[3].length 
> 0 ) { 
1151                 keys
[numValues
] = kSecAttrPath
; 
1152                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
); 
1153                 if ( values
[numValues
] != NULL 
) { 
1159         if ( attrList
.attr
[4].length 
> 0 ) { 
1160                 keys
[numValues
] = kSecAttrPort
; 
1161                 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
); 
1162                 if ( values
[numValues
] != NULL 
) { 
1167         // add kSecAttrProtocol 
1168         if ( attrList
.attr
[5].length 
> 0 ) { 
1169                 keys
[numValues
] = kSecAttrProtocol
; 
1170                 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
); 
1171                 if ( values
[numValues
] != NULL 
) { 
1172                         CFRetain(values
[numValues
]); 
1177         // add kSecAttrAuthenticationType 
1178         if ( attrList
.attr
[6].length 
> 0 ) { 
1179                 keys
[numValues
] = kSecAttrAuthenticationType
; 
1180                 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType(*(SecProtocolType
*)attrList
.attr
[6].data
); 
1181                 if ( values
[numValues
] != NULL 
) { 
1182                         CFRetain(values
[numValues
]); 
1187         // add kSecAttrComment 
1188         if ( attrList
.attr
[7].length 
> 0 ) { 
1189                 keys
[numValues
] = kSecAttrComment
; 
1190                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
); 
1191                 if ( values
[numValues
] != NULL 
) { 
1196         // add kSecAttrDescription 
1197         if ( attrList
.attr
[8].length 
> 0 ) { 
1198                 keys
[numValues
] = kSecAttrDescription
; 
1199                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
); 
1200                 if ( values
[numValues
] != NULL 
) { 
1205         // add kSecAttrLabel 
1206         if ( attrList
.attr
[9].length 
> 0 ) { 
1207                 keys
[numValues
] = kSecAttrLabel
; 
1208                 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8 
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
); 
1209                 if ( values
[numValues
] != NULL 
) { 
1214         // add kSecAttrCreationDate 
1215         if ( attrList
.attr
[10].length 
> 0 ) { 
1216                 CFDateRef creationDate 
= NULL
; 
1217                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
); 
1218                 keys
[numValues
] = kSecAttrCreationDate
; 
1219                 values
[numValues
] = creationDate
; 
1220                 if ( values
[numValues
] != NULL 
) { 
1225         // add kSecAttrModificationDate 
1226         if ( attrList
.attr
[11].length 
> 0 ) { 
1227                 CFDateRef modDate 
= NULL
; 
1228                 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
); 
1229                 keys
[numValues
] = kSecAttrModificationDate
; 
1230                 values
[numValues
] = modDate
; 
1231                 if ( values
[numValues
] != NULL 
) { 
1236         // add kSecCreatorItemAttr 
1237         if ( attrList
.attr
[12].length 
> 0 ) { 
1238                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
); 
1239                 keys
[numValues
] = kSecAttrCreator
; 
1240                 values
[numValues
] = numberRef
; 
1241                 if ( values
[numValues
] != NULL 
) { 
1242                         CFRetain(values
[numValues
]); 
1247         // add kSecTypeItemAttr 
1248         if ( attrList
.attr
[13].length 
> 0 ) { 
1249                 CFNumberRef numberRef 
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
); 
1250                 keys
[numValues
] = kSecAttrType
; 
1251                 values
[numValues
] = numberRef
; 
1252                 if ( values
[numValues
] != NULL 
) { 
1253                         CFRetain(values
[numValues
]); 
1258         // add kSecInvisibleItemAttr 
1259         if ( attrList
.attr
[14].length 
> 0 ) { 
1260                 uint32_t value 
= *((uint32_t*)attrList
.attr
[14].data
); 
1261                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1262                 keys
[numValues
] = kSecAttrIsInvisible
; 
1263                 values
[numValues
] = boolRef
; 
1264                 if ( values
[numValues
] != NULL 
) { 
1265                         CFRetain(values
[numValues
]); 
1270         // add kSecNegativeItemAttr 
1271         if ( attrList
.attr
[15].length 
> 0 ) { 
1272                 uint32_t value 
= *((uint32_t*)attrList
.attr
[15].data
); 
1273                 CFBooleanRef boolRef 
= (value
) ? kCFBooleanTrue 
: kCFBooleanFalse
; 
1274                 keys
[numValues
] = kSecAttrIsNegative
; 
1275                 values
[numValues
] = boolRef
; 
1276                 if ( values
[numValues
] != NULL 
) { 
1277                         CFRetain(values
[numValues
]); 
1282         // create the dictionary 
1283         *dictionary 
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
1285         // release the values added to the dictionary 
1286         for ( index 
= 0; index 
< numValues
; ++index 
) 
1288                 CFRelease(values
[index
]); 
1291         // and free the attributes 
1292         (void) SecKeychainItemFreeContent(&attrList
, NULL
); 
1294 SecKeychainItemCopyContent_failed
: 
1301  * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the 
1302  * attributes of the specified item class and item. 
1305 _CreateAttributesDictionaryFromItem( 
1306         CFAllocatorRef allocator
, 
1307         SecItemClass itemClass
, 
1308         SecKeychainItemRef item
, 
1309         CFDictionaryRef 
*dictionary
) 
1313                 case kSecInternetPasswordItemClass
: 
1314                         return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
); 
1316                 case kSecGenericPasswordItemClass
: 
1317                         return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
); 
1319                 case kSecCertificateItemClass
: 
1320                         return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
); 
1322                 case kSecPublicKeyItemClass
: 
1323                 case kSecPrivateKeyItemClass
: 
1324                 case kSecSymmetricKeyItemClass
: 
1325                         return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
); 
1336  * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList 
1337  * by the _CreateSecKeychainAttributeListFromDictionary function. 
1341         SecKeychainAttributeList 
*attrListPtr
) 
1345         if ( attrListPtr 
!= NULL 
) { 
1346                 if ( attrListPtr
->attr 
!= NULL 
) { 
1347                         // free any attribute data 
1348                         for ( index 
= 0; index 
< attrListPtr
->count
; ++index 
) { 
1349                                 free(attrListPtr
->attr
[index
].data
); 
1351                         // free the attribute array 
1352                         free(attrListPtr
->attr
); 
1354                 // free the attribute list 
1360  * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by 
1361  * attr using the data and tag parameters. 
1363  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1364  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1367 _CFDataCreateAttribute( 
1369         SecKeychainAttrType tag
, 
1370         SecKeychainAttributePtr attr
) 
1372         OSStatus status 
= errSecSuccess
; 
1375         // set the attribute tag 
1378         // determine the attribute length 
1379         attr
->length 
= (UInt32
) CFDataGetLength(data
); 
1380         range 
= CFRangeMake(0, (CFIndex
)attr
->length
); 
1382         // allocate memory for the attribute bytes 
1383         attr
->data 
= malloc(attr
->length
); 
1384         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1386         // get the attribute bytes 
1387         CFDataGetBytes(data
, range
, (UInt8 
*)attr
->data
); 
1395  * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by 
1396  * attr using the string and tag parameters. 
1398  * The memory for the SecKeychainAttribute's data field is allocated with malloc 
1399  * and must be released by the caller (this is normally done by calling _FreeAttrList). 
1402 _CFStringCreateAttribute( 
1404         SecKeychainAttrType tag
, 
1405         SecKeychainAttributePtr attr
) 
1407         OSStatus status 
= errSecSuccess
; 
1410         // set the attribute tag 
1413         // determine the attribute length 
1414         range 
= CFRangeMake(0, CFStringGetLength(string
)); 
1415         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex 
*)&attr
->length
); 
1417         // allocate memory for the attribute bytes 
1418         attr
->data 
= malloc(attr
->length
); 
1419         require_action(attr
->data 
!= NULL
, malloc_failed
, status 
= errSecBufferTooSmall
); 
1421         // get the attribute bytes 
1422         CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8 
*)attr
->data
, attr
->length
, NULL
); 
1431  * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1432  * from the attribute key/values in attrDictionary. 
1434  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1435  * must be freed by the caller with _FreeAttrList() 
1438 _CreateSecKeychainGenericPasswordAttributeListFromDictionary( 
1439         CFDictionaryRef attrDictionary
, 
1440         SecKeychainAttributeList 
**attrList
) 
1442         return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
); 
1447  * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList 
1448  * from the attribute key/values in attrDictionary. 
1450  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1451  * must be freed by the caller with _FreeAttrList() 
1454 _CreateSecKeychainCertificateAttributeListFromDictionary( 
1455         CFDictionaryRef attrDictionary
, 
1456         SecKeychainAttributeList 
**attrList
) 
1458         return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
); 
1463  * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList 
1464  * from the attribute key/values in attrDictionary. 
1466  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1467  * must be freed by the caller with _FreeAttrList() 
1470 _CreateSecKeychainKeyAttributeListFromDictionary( 
1471         CFDictionaryRef attrDictionary
, 
1472         SecKeychainAttributeList 
**attrList
) 
1475         //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug 
1476         return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
); 
1478         // explicitly build attribute list for supported key attributes 
1479         // NOTE: this code supports only MaxSecKeyAttributes (15) attributes 
1480         const int MaxSecKeyAttributes 
= 15; 
1484         SecKeychainAttributeList 
*attrListPtr
; 
1486         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1487         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1489         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
)); 
1490         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1492         // [0] get the kSecKeyKeyClass value 
1493         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) { 
1494                 UInt32 keyRecordValue 
= 0; 
1495                 if (CFEqual(kSecAttrKeyClassPublic
, value
)) 
1496                         keyRecordValue 
= CSSM_DL_DB_RECORD_PUBLIC_KEY
; 
1497                 else if (CFEqual(kSecAttrKeyClassPrivate
, value
)) 
1498                         keyRecordValue 
= CSSM_DL_DB_RECORD_PRIVATE_KEY
; 
1499                 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
)) 
1500                         keyRecordValue 
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
; 
1502                 // only use this attribute if we recognize the value! 
1503                 if (keyRecordValue 
!= 0) { 
1504                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1505                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1507                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyClass
; 
1508                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1509                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
; 
1511                         ++attrListPtr
->count
; 
1515         // [1] get the kSecKeyPrintName string 
1516         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) { 
1517                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1518                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1520                 ++attrListPtr
->count
; 
1523         // [2] get the kSecKeyPermanent boolean 
1524         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) { 
1525                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1526                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1528                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyPermanent
; 
1529                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1530                 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1532                 ++attrListPtr
->count
; 
1535         // [3] get the kSecKeyLabel string 
1536         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) { 
1537         if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1538             status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1539         else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1540             status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1542             status 
= errSecParam
; 
1544                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1546                 ++attrListPtr
->count
; 
1549         // [4] get the kSecKeyApplicationTag data 
1550         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) { 
1551                 if (CFStringGetTypeID() == CFGetTypeID(value
)) 
1552                         status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1553                 else if (CFDataGetTypeID() == CFGetTypeID(value
)) 
1554                         status 
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1556                         status 
= errSecParam
; 
1558                 require_noerr_quiet(status
, CFDataCreateAttribute_failed
); 
1559                 ++attrListPtr
->count
; 
1562         // [5] get the kSecKeyKeyType number 
1563         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) { 
1564                 UInt32 keyAlgValue 
= _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType
); 
1565                 if (keyAlgValue 
!= 0) { 
1566                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1567                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1569                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeyType
; 
1570                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1571                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
; 
1573                         ++attrListPtr
->count
; 
1577         // [6] get the kSecKeyKeySizeInBits number 
1578         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) { 
1579                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1580                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1581                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1583                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyKeySizeInBits
; 
1584                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1585                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1587                         ++attrListPtr
->count
; 
1591         // [7] get the kSecKeyEffectiveKeySize number 
1592         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) { 
1593                 if (CFNumberGetTypeID() == CFGetTypeID(value
)) { 
1594                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1595                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1597                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEffectiveKeySize
; 
1598                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1599                         CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1601                         ++attrListPtr
->count
; 
1605         // [8] get the kSecKeyEncrypt boolean 
1606         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) { 
1607                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1608                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1609                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1611                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyEncrypt
; 
1612                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1613                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1615                         ++attrListPtr
->count
; 
1619         // [9] get the kSecKeyDecrypt boolean 
1620         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) { 
1621                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1622                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1623                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1625                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDecrypt
; 
1626                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1627                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1629                         ++attrListPtr
->count
; 
1633         // [10] get the kSecKeyDerive boolean 
1634         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) { 
1635                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1636                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1637                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1639                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyDerive
; 
1640                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1641                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1643                         ++attrListPtr
->count
; 
1647         // [11] get the kSecKeySign boolean 
1648         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) { 
1649                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1650                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1651                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1653                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeySign
; 
1654                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1655                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1657                         ++attrListPtr
->count
; 
1661         // [12] get the kSecKeyVerify boolean 
1662         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) { 
1663                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1664                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1665                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1667                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyVerify
; 
1668                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1669                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1671                         ++attrListPtr
->count
; 
1675         // [13] get the kSecKeyWrap boolean 
1676         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) { 
1677                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1678                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1679                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1681                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyWrap
; 
1682                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1683                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1685                         ++attrListPtr
->count
; 
1689         // [14] get the kSecKeyUnwrap boolean 
1690         if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) { 
1691                 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) { 
1692                         attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1693                         require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_number_failed
, status 
= errSecBufferTooSmall
); 
1695                         attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecKeyUnwrap
; 
1696                         attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1697                         *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0; 
1699                         ++attrListPtr
->count
; 
1703         // return the pointer to the attrList 
1704         *attrList 
= attrListPtr
; 
1706         return ( errSecSuccess 
); 
1710 malloc_number_failed
: 
1711 CFDataCreateAttribute_failed
: 
1712 CFStringCreateAttribute_failed
: 
1713 malloc_attrPtr_failed
: 
1715         // free any attributes 
1716         _FreeAttrList(attrListPtr
); 
1718 calloc_attrListPtr_failed
: 
1720         return ( errSecBufferTooSmall 
); 
1725 static CFTypeRef 
copyNumber(CFTypeRef obj
) 
1730     CFTypeID tid 
= CFGetTypeID(obj
); 
1731     if (tid 
== CFNumberGetTypeID()) 
1737     if (tid 
== CFBooleanGetTypeID()) 
1739         SInt32 value 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
1740         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1743     if (tid 
== CFStringGetTypeID()) 
1745         SInt32 value 
= CFStringGetIntValue((CFStringRef
)obj
); 
1746         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value
); 
1747         /* If a string converted to an int isn't equal to the int printed as 
1748          a string, return a NULL instead. */ 
1749         if (!CFEqual(t
, obj
)) 
1755         return CFNumberCreate(0, kCFNumberSInt32Type
, &value
); 
1761  * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList 
1762  * from the attribute key/values in attrDictionary. 
1764  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1765  * must be freed by the caller with _FreeAttrList() 
1768 _CreateSecKeychainInternetPasswordAttributeListFromDictionary( 
1769         CFDictionaryRef attrDictionary
, 
1770         SecKeychainAttributeList 
**attrList
) 
1772         // explicitly build attribute list for supported key attributes 
1773         // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes 
1774         const int MaxSecKeychainAttributes 
= 14; 
1778         SecKeychainAttributeList 
*attrListPtr
; 
1780         attrListPtr 
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
)); 
1781         require_action(attrListPtr 
!= NULL
, calloc_attrListPtr_failed
, status 
= errSecBufferTooSmall
); 
1783         attrListPtr
->attr 
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
)); 
1784         require_action(attrListPtr
->attr 
!= NULL
, malloc_attrPtr_failed
, status 
= errSecBufferTooSmall
); 
1787         // [0] get the serverName string 
1788         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) { 
1789                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1790                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1792                 ++attrListPtr
->count
; 
1795         // [1] get the securityDomain string 
1796         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) { 
1797                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1798                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1800                 ++attrListPtr
->count
; 
1803         // [2] get the accountName string 
1804         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) { 
1805                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1806                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1808                 ++attrListPtr
->count
; 
1811         // [3] get the path string 
1812         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) { 
1813                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1814                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1816                 ++attrListPtr
->count
; 
1819         // [4] get the port number 
1820         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) { 
1821                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt16
)); 
1822                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1824         CFTypeRef num 
= copyNumber(value
); 
1825                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1826                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecPortItemAttr
; 
1827                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt16
); 
1828                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1831                 ++attrListPtr
->count
; 
1834         // [5] get the protocol 
1835         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) { 
1836                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecProtocolType
)); 
1837                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_protocol_failed
, status 
= errSecBufferTooSmall
); 
1839                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecProtocolItemAttr
; 
1840                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecProtocolType
); 
1841                 *(SecProtocolType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
); 
1843                 ++attrListPtr
->count
; 
1846         // [6] get the authenticationType 
1847         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) { 
1848                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(SecAuthenticationType
)); 
1849                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_authenticationType_failed
, status 
= errSecBufferTooSmall
); 
1851                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecAuthenticationTypeItemAttr
; 
1852                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(SecAuthenticationType
); 
1853                 *(SecAuthenticationType 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
); 
1855                 ++attrListPtr
->count
; 
1858         // [7] get the comment string 
1859         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) { 
1860                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1861                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1863                 ++attrListPtr
->count
; 
1866         // [8] get the description string 
1867         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) { 
1868                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1869                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1871                 ++attrListPtr
->count
; 
1874         // [9] get the label string 
1875         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) { 
1876                 status 
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]); 
1877                 require_noerr_quiet(status
, CFStringCreateAttribute_failed
); 
1879                 ++attrListPtr
->count
; 
1882         // [10] get the creator code 
1883         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) { 
1884                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1885                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1887         CFTypeRef num 
= copyNumber(value
); 
1888                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1889                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecCreatorItemAttr
; 
1890                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1891                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1894                 ++attrListPtr
->count
; 
1897         // [11] get the type code 
1898         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) { 
1899                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1900                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1902         CFTypeRef num 
= copyNumber(value
); 
1903                 require_action(num 
!= NULL
, CFStringCreateAttribute_failed
, status 
= errSecParam
); 
1904                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecTypeItemAttr
; 
1905                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1906                 CFNumberGetValue((CFNumberRef
)num
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
); 
1909                 ++attrListPtr
->count
; 
1912         // [12] get the invisible flag 
1913         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) { 
1914                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1915                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1917                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecInvisibleItemAttr
; 
1918                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1919                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1921                 ++attrListPtr
->count
; 
1924         // [13] get the negative flag 
1925         if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) { 
1926                 attrListPtr
->attr
[attrListPtr
->count
].data 
= malloc(sizeof(UInt32
)); 
1927                 require_action(attrListPtr
->attr
[attrListPtr
->count
].data 
!= NULL
, malloc_port_failed
, status 
= errSecBufferTooSmall
); 
1929                 attrListPtr
->attr
[attrListPtr
->count
].tag 
= kSecNegativeItemAttr
; 
1930                 attrListPtr
->attr
[attrListPtr
->count
].length 
= sizeof(UInt32
); 
1931                 *(UInt32 
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0; 
1933                 ++attrListPtr
->count
; 
1936         // return the pointer to the attrList 
1937         *attrList 
= attrListPtr
; 
1939         return ( errSecSuccess 
); 
1943 malloc_authenticationType_failed
: 
1944 malloc_protocol_failed
: 
1946 CFStringCreateAttribute_failed
: 
1947 malloc_attrPtr_failed
: 
1949         // free any attributes 
1950         _FreeAttrList(attrListPtr
); 
1952 calloc_attrListPtr_failed
: 
1954         return ( errSecBufferTooSmall 
); 
1959  * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList 
1960  * from the attribute key/values in attrDictionary for the specified item class. 
1962  * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList 
1963  * must be freed by the caller with _FreeAttrList() 
1966 _CreateSecKeychainAttributeListFromDictionary( 
1967         CFDictionaryRef attrDictionary
, 
1968         SecItemClass itemClass
, 
1969         SecKeychainAttributeList 
**attrList
) 
1973                 case kSecInternetPasswordItemClass
: 
1974                         return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1976                 case kSecGenericPasswordItemClass
: 
1977                         return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
); 
1979                 case kSecCertificateItemClass
: 
1980                         return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
); 
1982                 case kSecPublicKeyItemClass
: 
1983                 case kSecPrivateKeyItemClass
: 
1984                 case kSecSymmetricKeyItemClass
: 
1985                         return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
); 
1995  * _AppNameFromSecTrustedApplication attempts to pull the name of the 
1996  * application/tool from the SecTrustedApplicationRef. 
1999 _AppNameFromSecTrustedApplication( 
2000         CFAllocatorRef alloc
, 
2001         SecTrustedApplicationRef appRef
) 
2005         CFDataRef appDataRef
; 
2009         // get the data for item's application/tool 
2010         status 
= SecTrustedApplicationCopyData(appRef
, &appDataRef
); 
2011         if ( status 
== errSecSuccess 
) { 
2014                 // convert it to a CFString potentially containing the path 
2015                 path 
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
); 
2016                 if ( path 
!= NULL 
) { 
2017                         // the path has to start with a "/" and cannot contain "://" 
2018                         if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location 
== kCFNotFound
) ) { 
2019                                 CFRange nameRange
, compRg
; 
2021                                 nameRange 
= CFRangeMake(0, CFStringGetLength(path
)); 
2023                                 // remove the trailing slashes (if any) 
2024                                 while ( (nameRange
.length 
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length 
- 1) == '/') ) { 
2025                                         nameRange
.length 
--; 
2028                                 if ( nameRange
.length 
> 0 ) { 
2029                                         // find last slash and adjust nameRange be everything after it 
2030                                         if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) { 
2031                                                 nameRange
.length 
= nameRange
.location 
+ nameRange
.length 
- (compRg
.location 
+ 1); 
2032                                                 nameRange
.location 
= compRg
.location 
+ 1; 
2035                                         result 
= CFStringCreateWithSubstring(alloc
, path
, nameRange
); 
2040                 CFRelease(appDataRef
); 
2046 /* (This function really belongs in SecIdentity.cpp!) 
2048  * Returns the public key item corresponding to the identity, if it exists in 
2049  * the same keychain as the private key. Note that the public key might not 
2050  * exist in the same keychain (e.g. if the identity was imported via PKCS12), 
2051  * in which case it will not be found. 
2054 _SecIdentityCopyPublicKey( 
2055         SecIdentityRef identityRef
, 
2056         SecKeyRef 
*publicKeyRef
) 
2060         SecKeychainAttribute attr 
= { kSecKeyLabel
, 0, NULL 
}; 
2061         SecKeychainAttributeList attrList 
= { 1, &attr 
}; 
2062         SecKeychainAttributeList 
*keyAttrList 
= NULL
; 
2063         SecKeychainAttributeInfo 
*info 
= NULL
; 
2064         SecKeychainSearchRef search 
= NULL
; 
2065         SecKeychainRef keychain 
= NULL
; 
2066         SecKeychainItemRef privateKey 
= NULL
; 
2067         SecKeychainItemRef publicKey 
= NULL
; 
2069         status 
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef 
*)&privateKey
); 
2071                 goto error_exit
; // identity must have a private key 
2073         status 
= SecKeychainItemCopyKeychain(privateKey
, &keychain
); 
2075                 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it 
2077         status 
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
); 
2079                 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys 
2081         status 
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
); 
2083                 goto error_exit
; // unable to get the key label attribute for the private key 
2086         // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching 
2087         for (count 
= 0; count 
< keyAttrList
->count
; count
++) { 
2088                 if (keyAttrList
->attr
[count
].tag 
== kSecKeyLabel
) { 
2089                         attr
.length 
= keyAttrList
->attr
[count
].length
; 
2090                         attr
.data 
= keyAttrList
->attr
[count
].data
; 
2094         if (!attr
.length 
|| !attr
.data
) { 
2095                 status 
= errSecNoSuchAttr
; 
2096                 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel 
2098         status 
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
); 
2100                 goto error_exit
; // unable to create the search reference 
2102         status 
= SecKeychainSearchCopyNext(search
, &publicKey
); 
2104                 goto error_exit
; // unable to find the public key 
2108                 *publicKeyRef 
= (SecKeyRef
)publicKey
; 
2110                 CFRelease(publicKey
); 
2113         if (status 
!= errSecSuccess
) { 
2115                         *publicKeyRef 
= NULL
; 
2117                         CFRelease(publicKey
); 
2123                 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
); 
2126                 SecKeychainFreeAttributeInfo(info
); 
2129                 CFRelease(keychain
); 
2132                 CFRelease(privateKey
); 
2139  * Deletes a keychain item if the current application/tool is the only application/tool 
2140  * with decrypt access to that keychain item. If more than one application/tool 
2141  * has decrypt access to the keychain item, the item is left on the keychain. 
2143  * TBD: If more than one app/tool has access to the keychain item, we should remove 
2144  * the current app/tool's decrypt access. There's no easy way to do that with 
2145  * current keychain APIs without bringing up the security UI. 
2148 _SafeSecKeychainItemDelete( 
2149         SecKeychainItemRef itemRef
) 
2152         SecAccessRef access
; 
2156         CFStringRef description
; 
2157         CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
; 
2159         SecItemClass itemClass
; 
2160         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2161         if (!status 
&& (itemClass 
== kSecCertificateItemClass 
|| itemClass 
== kSecPublicKeyItemClass
)) { 
2162                 // the item doesn't have any access controls, so delete it normally 
2163                 return SecKeychainItemDelete(itemRef
); 
2166         // skip access control checking for web form passwords: <rdar://10957301> 
2167         // This permits Safari to manage the removal of all web form passwords, 
2168         // regardless of whether they are shared by multiple applications. 
2169         if (itemClass 
== kSecInternetPasswordItemClass
) { 
2170                 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr 
}; 
2171                 SecKeychainAttributeInfo attrInfo 
= { 1, tags
, NULL 
}; 
2172                 SecKeychainAttributeList 
*attrs 
= NULL
; 
2173                 status 
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
); 
2174                 if (!status 
&& attrs
) { 
2175                         bool webFormPassword 
= (attrs
->attr
[0].length 
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4))); 
2176                         SecKeychainItemFreeAttributesAndData(attrs
, NULL
); 
2177                         if (webFormPassword
) { 
2178                                 return SecKeychainItemDelete(itemRef
); 
2183         // copy the access of the keychain item 
2184         status 
= SecKeychainItemCopyAccess(itemRef
, &access
); 
2185         require_noerr(status
, SecKeychainItemCopyAccessFailed
); 
2187         // copy the decrypt access control lists -- this is what has access to the keychain item 
2188         status 
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
); 
2189         require_noerr(status
, SecAccessCopySelectedACLListFailed
); 
2190         require_quiet(aclList 
!= NULL
, noACLList
); 
2192         // get the access control list 
2193         acl 
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0); 
2194         require_quiet(acl 
!= NULL
, noACL
); 
2196         // copy the application list, description, and CSSM prompt selector for a given access control list entry 
2197         status 
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
); 
2198         require_noerr(status
, SecACLCopySimpleContentsFailed
); 
2199         require_quiet(appList 
!= NULL
, noAppList
); 
2201         // does only a single application/tool have decrypt access to this item? 
2202         if ( CFArrayGetCount(appList
) == 1 ) { 
2203                 SecTrustedApplicationRef itemAppRef
, currentAppRef
; 
2204                 CFStringRef itemAppName
, currentAppName
; 
2206                 // get SecTrustedApplicationRef for item's application/tool 
2207                 itemAppRef 
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, 0); 
2208                 require(itemAppRef 
!= NULL
, noItemAppRef
); 
2210                 // copy the name out 
2211                 itemAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
); 
2212                 require(itemAppName 
!= NULL
, noAppName
); 
2214                 // create SecTrustedApplicationRef for current application/tool 
2215                 status 
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
); 
2216                 require((status 
== errSecSuccess
) && (currentAppRef 
!= NULL
), SecTrustedApplicationCreateFromPathFailed
); 
2218                 // copy the name out 
2219                 currentAppName 
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
); 
2220                 require(currentAppName 
!= NULL
, noCurrentAppName
); 
2222                 // compare the current application/tool's name to this item's application/tool's name to see if we own the decrypt access 
2223                 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo 
) { 
2224                         // delete the keychain item 
2225                         SecKeychainItemDelete(itemRef
); 
2228                 CFRelease(currentAppName
); 
2230                 CFRelease(currentAppRef
); 
2231         SecTrustedApplicationCreateFromPathFailed
: 
2232                 CFRelease(itemAppName
); 
2238         if ( description 
) { 
2239                 CFRelease(description
); 
2243 SecACLCopySimpleContentsFailed
: 
2247 SecAccessCopySelectedACLListFailed
: 
2249 SecKeychainItemCopyAccessFailed
: 
2255 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
) 
2257         // This function updates a single keychain item, which may be specified as 
2258         // a reference, persistent reference or attribute dictionary, with the 
2259         // attributes provided. 
2261         OSStatus status 
= errSecSuccess
; 
2266         SecItemClass itemClass
; 
2267         SecAccessRef access 
= NULL
; 
2268         SecKeychainAttributeList 
*changeAttrList 
= NULL
; 
2269         SecKeychainItemRef itemToUpdate 
= NULL
; 
2270         CFDataRef theData 
= NULL
; 
2271         CFTypeID itemType 
= CFGetTypeID(item
); 
2273         // validate input item (must be convertible to a SecKeychainItemRef) 
2274         if (SecKeychainItemGetTypeID() == itemType 
|| 
2275                 SecCertificateGetTypeID() == itemType 
|| 
2276                 SecKeyGetTypeID() == itemType
) { 
2277                 // item is already a reference, retain it 
2278                 itemToUpdate 
= (SecKeychainItemRef
) CFRetain(item
); 
2280         else if (CFDataGetTypeID() == itemType
) { 
2281                 // item is a persistent reference, must convert it 
2282                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
); 
2284         else if (CFDictionaryGetTypeID() == itemType
) { 
2285                 // item is a dictionary 
2286                 CFTypeRef value 
= NULL
; 
2287                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2288                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2289                         itemToUpdate 
= (SecKeychainItemRef
) CFRetain(value
); 
2291                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2292                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2293                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
); 
2296         else if (SecIdentityGetTypeID() == itemType
) { 
2297                 // item is a certificate + private key; since we can't really change the 
2298                 // certificate's attributes, assume we want to update the private key 
2299                 status 
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
); 
2301         require_action(itemToUpdate 
!= NULL
, update_failed
, status 
= errSecInvalidItemRef
); 
2302         require_noerr(status
, update_failed
); 
2304         status 
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
); 
2305         require_noerr(status
, update_failed
); 
2307         // build changeAttrList from changedAttributes dictionary 
2310                 case kSecInternetPasswordItemClass
: 
2312                         status 
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2313                         require_noerr(status
, update_failed
); 
2317                 case kSecGenericPasswordItemClass
: 
2319                         status 
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2320                         require_noerr(status
, update_failed
); 
2324                 case kSecCertificateItemClass
: 
2326                         status 
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2327                         require_noerr(status
, update_failed
); 
2331                 case kSecPublicKeyItemClass
: 
2332                 case kSecPrivateKeyItemClass
: 
2333                 case kSecSymmetricKeyItemClass
: 
2335                         status 
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
); 
2336                         require_noerr(status
, update_failed
); 
2341         // (if the caller is not updating the password, this value will be NULL) 
2342         theData 
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
); 
2343         if (theData 
!= NULL
) { 
2344                 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status 
= errSecParam
); 
2347         status 
= SecKeychainItemModifyContent(itemToUpdate
, 
2348                                 (changeAttrList
->count 
== 0) ? NULL 
: changeAttrList
, 
2349                                 (theData 
!= NULL
) ? (UInt32
)CFDataGetLength(theData
) : 0, 
2350                                 (theData 
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
); 
2352         // one more thing... update access? 
2353         if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) { 
2354                 status 
= SecKeychainItemSetAccess(itemToUpdate
, access
); 
2359                 CFRelease(itemToUpdate
); 
2360         _FreeAttrList(changeAttrList
); 
2365 _DeleteKeychainItem(CFTypeRef item
) 
2367         // This function deletes a single keychain item, which may be specified as 
2368         // a reference, persistent reference or attribute dictionary. It will not 
2369         // delete non-keychain items or aggregate items (such as a SecIdentityRef); 
2370         // it is assumed that the caller will pass identity components separately. 
2372         OSStatus status 
= errSecSuccess
; 
2377         SecKeychainItemRef itemToDelete 
= NULL
; 
2378         CFTypeID itemType 
= CFGetTypeID(item
); 
2379         if (SecKeychainItemGetTypeID() == itemType 
|| 
2380                 SecCertificateGetTypeID() == itemType 
|| 
2381                 SecKeyGetTypeID() == itemType
) { 
2382                 // item is already a reference, retain it 
2383                 itemToDelete 
= (SecKeychainItemRef
) CFRetain(item
); 
2385         else if (CFDataGetTypeID() == itemType
) { 
2386                 // item is a persistent reference, must convert it 
2387                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
); 
2389         else if (CFDictionaryGetTypeID() == itemType
) { 
2390                 // item is a dictionary 
2391                 CFTypeRef value 
= NULL
; 
2392                 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) { 
2393                         // kSecValueRef value is a SecKeychainItemRef, retain it 
2394                         itemToDelete 
= (SecKeychainItemRef
) CFRetain(value
); 
2396                 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) { 
2397                         // kSecValuePersistentRef value is a persistent reference, must convert it 
2398                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
); 
2404                         status 
= _SafeSecKeychainItemDelete(itemToDelete
); 
2406                 CFRelease(itemToDelete
); 
2413 _DeleteIdentity(SecIdentityRef identity
) 
2415         OSStatus status
, result 
= errSecSuccess
; 
2416         SecKeyRef privateKey 
= NULL
; 
2417         SecCertificateRef certificate 
= NULL
; 
2419         status 
= SecIdentityCopyPrivateKey(identity
, &privateKey
); 
2421                 SecKeyRef publicKey 
= NULL
; 
2422                 status 
= _SecIdentityCopyPublicKey(identity
, &publicKey
); 
2424                         status 
= _DeleteKeychainItem(publicKey
); 
2425                         CFRelease(publicKey
); 
2427                 status 
= _DeleteKeychainItem(privateKey
); 
2430         if (privateKey
) CFRelease(privateKey
); 
2431         if (status
) result 
= status
; 
2433         status 
= SecIdentityCopyCertificate(identity
, &certificate
); 
2435                 status 
= _DeleteKeychainItem(certificate
); 
2438         if (certificate
) CFRelease(certificate
); 
2439         if (status
) result 
= status
; 
2445 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
) 
2447         // This function is used when atomically processing multiple items, 
2448         // where an overall error result must be returned for the entire operation. 
2449         // When newStatus is something other than errSecSuccess, we want to keep the "most 
2450         // interesting" status (which usually will be newStatus, unless curStatus is 
2451         // already set; in that case, newStatus can trump curStatus only by being 
2452         // something different than baseStatus.) 
2454         OSStatus result 
= curStatus
; 
2456         if (newStatus 
!= errSecSuccess
) { 
2458                 if (curStatus 
!= errSecSuccess
) { 
2459                         result 
= (newStatus 
!= baseStatus
) ? newStatus 
: curStatus
; 
2466 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
) 
2468         // CFDictionaryApplierFunction 
2469         // This function just takes the given key/value pair, 
2470         // and adds it to another dictionary supplied in the context argument. 
2472         CFMutableDictionaryRef dict 
= *((CFMutableDictionaryRef
*) context
); 
2474                 CFDictionaryAddValue(dict
, key
, value
); 
2478 static CFStringCompareFlags
 
2479 _StringCompareFlagsFromQuery(CFDictionaryRef query
) 
2482         CFStringCompareFlags flags 
= 0; 
2483         if (!query
) return flags
; 
2485         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) || 
2486                 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2487                 flags 
|= kCFCompareAnchored
; 
2489         if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
)) 
2490                 flags 
|= kCFCompareBackwards
; 
2492         if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2493                 flags 
|= kCFCompareCaseInsensitive
; 
2495         if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2496                 flags 
|= kCFCompareDiacriticInsensitive
; 
2498         if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2499                 flags 
|= kCFCompareWidthInsensitive
; 
2505 _CssmKeyUsageFromQuery(CFDictionaryRef query
) 
2508         uint32 keyUsage 
= 0; 
2509         if (!query
) return keyUsage
; 
2511         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2512                 keyUsage 
|= CSSM_KEYUSE_ENCRYPT
; 
2514         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2515                 keyUsage 
|= CSSM_KEYUSE_DECRYPT
; 
2517         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2518                 keyUsage 
|= CSSM_KEYUSE_SIGN
; 
2520         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2521                 keyUsage 
|= CSSM_KEYUSE_VERIFY
; 
2523         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2524                 keyUsage 
|= CSSM_KEYUSE_WRAP
; 
2526         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2527                 keyUsage 
|= CSSM_KEYUSE_UNWRAP
; 
2529         if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
)) 
2530                 keyUsage 
|= CSSM_KEYUSE_DERIVE
; 
2536 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean 
*isIdentity
) 
2538         SecItemClass itemClass 
= (SecItemClass
) 0; 
2539         if (isIdentity
) *isIdentity 
= false; 
2541         if (CFEqual(item
, kSecClassGenericPassword
)) { 
2542                 itemClass 
= kSecGenericPasswordItemClass
; 
2544         else if (CFEqual(item
, kSecClassInternetPassword
)) { 
2545                 itemClass 
= kSecInternetPasswordItemClass
; 
2547         else if (CFEqual(item
, kSecClassCertificate
)) { 
2548                 itemClass 
= kSecCertificateItemClass
; 
2550         else if (CFEqual(item
, kSecClassIdentity
)) { 
2551                 // will perform a certificate lookup 
2552                 itemClass 
= kSecCertificateItemClass
; 
2553                 if (isIdentity
) *isIdentity 
= true; 
2555         else if (CFEqual(item
, kSecClassKey
)) { 
2556                 // examine second parameter to determine type of key 
2557                 if (!keyClass 
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) { 
2558                         itemClass 
= kSecSymmetricKeyItemClass
; 
2560                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) { 
2561                         itemClass 
= kSecPublicKeyItemClass
; 
2563                 else if (keyClass 
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) { 
2564                         itemClass 
= kSecPrivateKeyItemClass
; 
2572 _ItemClassFromItemList(CFArrayRef itemList
) 
2574         // Given a list of items (standard or persistent references), 
2575         // determine whether they all have the same item class. Returns 
2576         // the item class, or 0 if multiple classes in list. 
2577         SecItemClass result 
= 0; 
2578         CFIndex index
, count 
= (itemList
) ? CFArrayGetCount(itemList
) : 0; 
2579         for (index
=0; index 
< count
; index
++) { 
2580                 CFTypeRef item 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemList
, index
); 
2582                         SecKeychainItemRef itemRef 
= NULL
; 
2584                         if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
2585                                 // persistent reference, resolve first 
2586                                 status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemRef
); 
2589                                 itemRef 
= (SecKeychainItemRef
) CFRetain(item
); 
2592                                 SecItemClass itemClass 
= 0; 
2593                                 CFTypeID itemTypeID 
= CFGetTypeID(itemRef
); 
2594                                 if (itemTypeID 
== SecIdentityGetTypeID() || itemTypeID 
== SecCertificateGetTypeID()) { 
2595                                         // Identities and certificates have the same underlying item class 
2596                                         itemClass 
= kSecCertificateItemClass
; 
2598                                 else if (itemTypeID 
== SecKeychainItemGetTypeID()) { 
2599                                         // Reference to item in a keychain 
2600                                         status 
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
2602                                 else if (itemTypeID 
== SecKeyGetTypeID()) { 
2603                                         // SecKey that isn't stored in a keychain 
2604                                         // %%% will need to change this code when SecKey is no longer CSSM-based %%% 
2605                                         const CSSM_KEY 
*cssmKey
; 
2606                                         status 
= SecKeyGetCSSMKey((SecKeyRef
)itemRef
, &cssmKey
); 
2607                                         if (status 
== errSecSuccess
) { 
2608                                                 if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PUBLIC_KEY
) 
2609                                                         itemClass 
= kSecPublicKeyItemClass
; 
2610                                                 else if (cssmKey
->KeyHeader
.KeyClass 
== CSSM_KEYCLASS_PRIVATE_KEY
) 
2611                                                         itemClass 
= kSecPrivateKeyItemClass
; 
2613                                                         itemClass 
= kSecSymmetricKeyItemClass
; 
2617                                 if (itemClass 
!= 0) { 
2618                                         if (result 
!= 0 && result 
!= itemClass
) { 
2619                                                 return 0; // different item classes in list; bail out 
2629 // SecItemParams contains a validated set of input parameters, as well as a 
2630 // search reference and attribute list built from those parameters. It is 
2631 // designed to be allocated with _CreateSecItemParamsFromDictionary, and 
2632 // freed with _FreeSecItemParams. 
2634 struct SecItemParams 
{ 
2635         CFDictionaryRef query
;                          // caller-supplied query 
2636         int numResultTypes
;                                     // number of result types requested 
2637         int maxMatches
;                                         // max number of matches to return 
2638         uint32 keyUsage
;                                        // key usage(s) requested 
2639         Boolean returningAttributes
;            // true if returning attributes dictionary 
2640         Boolean returningData
;                          // true if returning item's data 
2641         Boolean returningRef
;                           // true if returning item reference 
2642         Boolean returningPersistentRef
;         // true if returing a persistent reference 
2643         Boolean returnAllMatches
;                       // true if we should return all matches 
2644         Boolean returnIdentity
;                         // true if we are returning a SecIdentityRef 
2645         Boolean trustedOnly
;                            // true if we only return trusted certs 
2646         Boolean issuerAndSNToMatch
;                     // true if both issuer and SN were provided 
2647         SecItemClass itemClass
;                         // item class for this query 
2648         SecPolicyRef policy
;                            // value for kSecMatchPolicy (may be NULL) 
2649         SecKeychainRef keychain
;                        // value for kSecUseKeychain (may be NULL) 
2650         CFArrayRef useItems
;                            // value for kSecUseItemList (may be NULL) 
2651         CFArrayRef itemList
;                            // value for kSecMatchItemList (may be NULL) 
2652         CFTypeRef searchList
;                           // value for kSecMatchSearchList (may be NULL) 
2653         CFTypeRef matchLimit
;                           // value for kSecMatchLimit (may be NULL) 
2654         CFTypeRef emailAddrToMatch
;                     // value for kSecMatchEmailAddressIfPresent (may be NULL) 
2655         CFTypeRef validOnDate
;                          // value for kSecMatchValidOnDate (may be NULL) 
2656         CFTypeRef keyClass
;                                     // value for kSecAttrKeyClass (may be NULL) 
2657         CFTypeRef service
;                                      // value for kSecAttrService (may be NULL) 
2658         CFTypeRef issuer
;                                       // value for kSecAttrIssuer (may be NULL) 
2659         CFTypeRef serialNumber
;                         // value for kSecAttrSerialNumber (may be NULL) 
2660         CFTypeRef search
;                                       // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef) 
2661         CFTypeRef assumedKeyClass
;                      // if no kSecAttrKeyClass provided, holds the current class we're searching for 
2662         CFIndex itemListIndex
;                          // if no search reference but we have itemList, holds index of next item to return 
2663         SecKeychainAttributeList 
*attrList
;     // attribute list for this query 
2664         SecAccessRef access
;                            // access reference (for SecItemAdd only, not used to find items) 
2665         CFDataRef itemData
;                                     // item data (for SecItemAdd only, not used to find items) 
2666         CFTypeRef itemRef
;                                      // item reference (to find, add, update or delete, depending on context) 
2667         SecIdentityRef identityRef
;                     // identity reference (input as kSecValueRef) 
2668         CFDataRef itemPersistentRef
;            // item persistent reference (to find, add, update or delete, depending on context) 
2672 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
) 
2674         if (!dict 
|| !key 
|| !value 
|| !expectedTypeID
) 
2677         if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) { 
2678                 // value was not provided for this key (not an error!) 
2681         else if (!(*value
)) { 
2682                 // provided value is NULL (also not an error!) 
2683                 return errSecSuccess
; 
2686                 CFTypeID actualTypeID 
= CFGetTypeID(*value
); 
2687                 if (!((expectedTypeID 
== actualTypeID
) || (altTypeID 
&& altTypeID 
== actualTypeID
))) { 
2688                         // provided value does not have the expected (or alternate) CF type ID 
2689                         if ((expectedTypeID 
== SecKeychainItemGetTypeID()) && 
2690                                 (actualTypeID 
== SecKeyGetTypeID() || actualTypeID 
== SecCertificateGetTypeID())) { 
2691                                 // provided value is a "floating" reference which is not yet in a keychain 
2693                                 return errSecSuccess
; 
2695                         return errSecItemInvalidValue
; 
2698                         // provided value is OK; retain it 
2702         return errSecSuccess
; 
2706 _FreeSecItemParams(SecItemParams 
*itemParams
) 
2711         if (itemParams
->query
) CFRelease(itemParams
->query
); 
2712         if (itemParams
->policy
) CFRelease(itemParams
->policy
); 
2713         if (itemParams
->keychain
) CFRelease(itemParams
->keychain
); 
2714         if (itemParams
->useItems
) CFRelease(itemParams
->useItems
); 
2715         if (itemParams
->itemList
) CFRelease(itemParams
->itemList
); 
2716         if (itemParams
->searchList
) CFRelease(itemParams
->searchList
); 
2717         if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
); 
2718         if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
); 
2719         if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
); 
2720         if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
); 
2721         if (itemParams
->service
) CFRelease(itemParams
->service
); 
2722         if (itemParams
->issuer
) CFRelease(itemParams
->issuer
); 
2723         if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
); 
2724         if (itemParams
->search
) CFRelease(itemParams
->search
); 
2725         if (itemParams
->access
) CFRelease(itemParams
->access
); 
2726         if (itemParams
->itemData
) CFRelease(itemParams
->itemData
); 
2727         if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
); 
2728         if (itemParams
->identityRef
) CFRelease(itemParams
->identityRef
); 
2729         if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
); 
2731         _FreeAttrList(itemParams
->attrList
); 
2736 static SecItemParams
* 
2737 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus 
*error
) 
2740         CFTypeRef value 
= NULL
; 
2741         SecItemParams 
*itemParams 
= (SecItemParams 
*) malloc(sizeof(SecItemParams
)); 
2743         require_action(itemParams 
!= NULL
, error_exit
, status 
= errSecAllocate
); 
2744         require_action(dict 
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status 
= errSecParam
); 
2746         memset(itemParams
, 0, sizeof(SecItemParams
)); 
2747         itemParams
->query 
= (CFDictionaryRef
) CFRetain(dict
); 
2749         // validate input search parameters 
2750         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
); 
2751         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2752         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
); 
2753         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
); 
2754         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
); 
2755         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
); 
2757         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
); 
2758         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
); 
2760         // validate a subset of input attributes (used to create an appropriate search reference) 
2761         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
); 
2762         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
); 
2763         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
); 
2764         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
); 
2766         // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items 
2767         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
); 
2769         // validate item references 
2770         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit
); 
2771         if (itemParams
->itemRef 
&& (CFGetTypeID(itemParams
->itemRef
) == SecIdentityGetTypeID())) { 
2772                 itemParams
->identityRef 
= (SecIdentityRef
)itemParams
->itemRef
; 
2773                 itemParams
->itemRef 
= NULL
; 
2774                 SecIdentityCopyCertificate(itemParams
->identityRef
, (SecCertificateRef 
*)&itemParams
->itemRef
); 
2776         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
); 
2777         if (itemParams
->itemRef 
|| itemParams
->itemPersistentRef
) { 
2778                 // Caller is trying to add or find an item by reference. 
2779                 // The supported method for doing that is to provide a kSecUseItemList array 
2780                 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al, 
2781                 // so add the item reference to those arrays here. 
2782                 if (itemParams
->useItems
) { 
2783                         CFArrayRef tmpItems 
= itemParams
->useItems
; 
2784                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
2785                         CFRelease(tmpItems
); 
2787                         itemParams
->useItems 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2789                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
); 
2790                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
); 
2792                 if (itemParams
->itemList
) { 
2793                         CFArrayRef tmpItems 
= itemParams
->itemList
; 
2794                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
); 
2795                         CFRelease(tmpItems
); 
2797                         itemParams
->itemList 
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
2799                 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
); 
2800                 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
); 
2803         // must have an explicit item class, unless one of the following is true: 
2804         //   - we have an item list to add or search (kSecUseItemList) 
2805         //   - we have an item reference or persistent reference for the thing we want to look up 
2806         // Note that both of these cases will set itemParams->useItems. 
2807         // If we have an item list to match (kSecMatchItemList), that still requires an item class, 
2808         // so we can perform a search and see if the results match items in the list. 
2810         if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
) { 
2811                 require_action(false, error_exit
, status 
= errSecItemClassMissing
); 
2814                 itemParams
->itemClass 
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
); 
2815                 if (itemParams
->itemClass 
== kSecSymmetricKeyItemClass 
&& !itemParams
->keyClass
) { 
2816                         itemParams
->assumedKeyClass 
= kSecAttrKeyClassSymmetric
; // no key class specified, so start with symmetric key class; will search the others later 
2818                 require_action(!(itemParams
->itemClass 
== 0 && !itemParams
->useItems
), error_exit
, status 
= errSecItemClassMissing
); 
2821         itemParams
->keyUsage 
= _CssmKeyUsageFromQuery(dict
); 
2822         itemParams
->trustedOnly 
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
2823         itemParams
->issuerAndSNToMatch 
= (itemParams
->issuer 
!= NULL 
&& itemParams
->serialNumber 
!= NULL
); 
2825         // other input attributes, used for SecItemAdd but not for finding items 
2826         require_noerr(status 
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
2827         if (itemParams
->access 
== NULL
) { 
2828                 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>) 
2829                 require_noerr(status 
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
); 
2832         // determine how to return the result 
2833         itemParams
->numResultTypes 
= 0; 
2834         itemParams
->returningRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
2835         if (itemParams
->returningRef
) ++itemParams
->numResultTypes
; 
2836         itemParams
->returningPersistentRef 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
2837         if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
; 
2838         itemParams
->returningAttributes 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
2839         if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
; 
2840         itemParams
->returningData 
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value 
&& CFEqual(kCFBooleanTrue
, value
); 
2841         if (itemParams
->returningData
) ++itemParams
->numResultTypes
; 
2843         // default is kSecReturnRef if no result types were specified 
2844         if (!itemParams
->numResultTypes
) { 
2845                 itemParams
->returningRef 
= TRUE
; 
2846                 itemParams
->numResultTypes 
= 1; 
2849         // determine if one, some or all matches should be returned (default is kSecMatchLimitOne) 
2850         itemParams
->maxMatches 
= 1; 
2851         itemParams
->returnAllMatches 
= FALSE
; 
2852         if (itemParams
->matchLimit
) { 
2853                 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
2854                         itemParams
->returnAllMatches 
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
); 
2856                 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) { 
2857                         CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
); 
2858                         require_action(!(itemParams
->maxMatches 
< 0), error_exit
, status 
= errSecMatchLimitUnsupported
); 
2861         if (itemParams
->returnAllMatches
) { 
2862                 itemParams
->maxMatches 
= INT32_MAX
; 
2863                 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each) 
2864                 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass 
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
) 
2865                         status 
= errSecReturnDataUnsupported
; 
2866                 require_noerr(status
, error_exit
); 
2869         // 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 
2870         if (itemParams
->useItems
) { 
2871                 if (itemParams
->itemClass 
== 0) { 
2872                         itemParams
->itemClass 
= _ItemClassFromItemList(itemParams
->useItems
); 
2874                 status 
= errSecSuccess
; 
2875                 goto error_exit
; // all done here 
2878         // build a SecKeychainAttributeList from the query dictionary for the specified item class 
2879         require_noerr(status 
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
); 
2881         // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef) 
2882         if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) { 
2883                 // searching for certificates by email address 
2884                 char *nameBuf 
= (char*)malloc(MAXPATHLEN
); 
2886                         status 
= errSecAllocate
; 
2888                 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) { 
2889                         status 
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
); 
2892                         status 
= errSecItemInvalidValue
; 
2894                 if (nameBuf
) free(nameBuf
); 
2896         else if ((itemParams
->itemClass 
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) { 
2897                 // searching for certificates by issuer and serial number 
2898                 status 
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
, 
2899                                 (CFDataRef
)itemParams
->issuer
, 
2900                                 (CFDataRef
)itemParams
->serialNumber
, 
2901                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
2903         else if (itemParams
->returnIdentity 
&& itemParams
->policy
) { 
2904                 // searching for identities by policy 
2905                 status 
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
, 
2906                                 (CFStringRef
)itemParams
->service
, 
2907                                 itemParams
->keyUsage
, 
2908                                 itemParams
->searchList
, 
2909                                 itemParams
->trustedOnly
, 
2910                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
2912         else if (itemParams
->returnIdentity
) { 
2913                 // searching for identities 
2914                 status 
= SecIdentitySearchCreate(itemParams
->searchList
, 
2915                                 itemParams
->keyUsage
, 
2916                                 (SecIdentitySearchRef
*)&itemParams
->search
); 
2919                 // normal keychain item search 
2920                 status 
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
, 
2921                                 itemParams
->itemClass
, 
2922                                 (itemParams
->attrList
->count 
== 0) ? NULL 
: itemParams
->attrList
, 
2923                                 (SecKeychainSearchRef
*)&itemParams
->search
); 
2928                 _FreeSecItemParams(itemParams
); 
2941         SecKeychainRef keychainRef
, 
2942         SecAccessRef accessRef
, 
2943         SecKeychainAttributeList 
*attrList
, 
2944         SecKeychainItemRef 
*outItemRef
) 
2948                 // We must specify the access, since a free-floating key won't have one yet by default 
2949                 SecPointer
<Access
> access
; 
2951                         access 
= Access::required(accessRef
); 
2954                         CFStringRef descriptor 
= NULL
; 
2956                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
2957                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
2958                                         if (attr
.tag 
== kSecKeyPrintName
) { 
2959                                                 descriptor 
= CFStringCreateWithBytes(NULL
, (const UInt8 
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
); 
2964                         if (descriptor 
== NULL
) { 
2965                                 descriptor 
= (CFStringRef
) CFRetain(CFSTR("<unknown>")); 
2967                         access 
= new Access(cfString(descriptor
)); 
2968                         CFRelease(descriptor
); 
2971                 KeyItem 
*key 
= KeyItem::required(keyRef
); 
2972                 Item item 
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
); 
2974                         *outItemRef 
= item
->handle(); 
2980 _CanIgnoreLeafStatusCodes(CSSM_TP_APPLE_EVIDENCE_INFO 
*evidence
) 
2982         /* Check for ignorable status codes in leaf certificate's evidence */ 
2983         Boolean result 
= true; 
2985         for (i
=0; i 
< evidence
->NumStatusCodes
; i
++) { 
2986                 CSSM_RETURN scode 
= evidence
->StatusCodes
[i
]; 
2987                 if (scode 
== CSSMERR_APPLETP_INVALID_CA
) { 
2988                         // the TP has rejected this CA cert because it's in the leaf position 
2991                 else if (ignorableRevocationStatusCode(scode
)) { 
3003 _FilterWithPolicy(SecPolicyRef policy
, CFDateRef date
, SecCertificateRef cert
) 
3005         CFDictionaryRef props 
= NULL
; 
3006         CFArrayRef keychains 
= NULL
; 
3007         CFArrayRef anchors 
= NULL
; 
3008         CFArrayRef certs 
= NULL
; 
3009         CFArrayRef chain 
= NULL
; 
3010         SecTrustRef trust 
= NULL
; 
3012         SecTrustResultType      trustResult
; 
3013         CSSM_TP_APPLE_EVIDENCE_INFO 
*evidence 
= NULL
; 
3014         Boolean needChain 
= false; 
3016         if (!policy 
|| !cert
) return errSecParam
; 
3018         certs 
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
); 
3019         status 
= SecTrustCreateWithCertificates(certs
, policy
, &trust
); 
3020         if(status
) goto cleanup
; 
3022         /* Set evaluation date, if specified (otherwise current date is implied) */ 
3023         if (date 
&& (CFGetTypeID(date
) == CFDateGetTypeID())) { 
3024                 status 
= SecTrustSetVerifyDate(trust
, date
); 
3025                 if(status
) goto cleanup
; 
3028         /* Check whether this is the X509 Basic policy, which means chain building */ 
3029         props 
= SecPolicyCopyProperties(policy
); 
3031                 CFTypeRef oid 
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
); 
3032                 if (oid 
&& CFEqual(oid
, kSecPolicyAppleX509Basic
)) { 
3038                 /* To make the evaluation as lightweight as possible, specify an empty array 
3039                  * of keychains which will be searched for certificates. 
3041                 keychains 
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
); 
3042                 status 
= SecTrustSetKeychains(trust
, keychains
); 
3043                 if(status
) goto cleanup
; 
3045                 /* To make the evaluation as lightweight as possible, specify an empty array 
3046                  * of trusted anchors. 
3048                 anchors 
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
); 
3049                 status 
= SecTrustSetAnchorCertificates(trust
, anchors
); 
3050                 if(status
) goto cleanup
; 
3053         /* All parameters are locked and loaded, ready to evaluate! */ 
3054         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3055         if(status
) goto cleanup
; 
3057         /* If we didn't provide trust anchors or a way to look for them, 
3058          * the evaluation will fail with kSecTrustResultRecoverableTrustFailure. 
3059          * However, we can tell whether the policy evaluation succeeded by 
3060          * looking at the per-cert status codes in the returned evidence. 
3062         status 
= SecTrustGetResult(trust
, &trustResult
, &chain
, &evidence
); 
3063         if(status
) goto cleanup
; 
3065         if (!(trustResult 
== kSecTrustResultProceed 
|| 
3066                   trustResult 
== kSecTrustResultUnspecified 
|| 
3067                   trustResult 
== kSecTrustResultRecoverableTrustFailure
)) { 
3068                 /* The evaluation failed in a non-recoverable way */ 
3069                 status 
= errSecCertificateCannotOperate
; 
3073         /* If there are no per-cert policy status codes, 
3074          * and the cert has not expired, consider it valid for the policy. 
3076         if((evidence 
!= NULL
) && _CanIgnoreLeafStatusCodes(evidence
) && 
3077            ((evidence
[0].StatusBits 
& CSSM_CERT_STATUS_EXPIRED
) == 0) && 
3078            ((evidence
[0].StatusBits 
& CSSM_CERT_STATUS_NOT_VALID_YET
) == 0)) { 
3079                 status 
= errSecSuccess
; 
3082                 status 
= errSecCertificateCannotOperate
; 
3086         if(props
) CFRelease(props
); 
3087         if(chain
) CFRelease(chain
); 
3088         if(anchors
) CFRelease(anchors
); 
3089         if(keychains
) CFRelease(keychains
); 
3090         if(certs
) CFRelease(certs
); 
3091         if(trust
) CFRelease(trust
); 
3097 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
) 
3099         if (!validOnDate 
|| !cert
) return errSecParam
; 
3101         CFAbsoluteTime at
, nb
, na
; 
3102         if (CFGetTypeID(validOnDate
) == CFDateGetTypeID()) 
3103                 at 
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
); 
3105                 at 
= CFAbsoluteTimeGetCurrent(); 
3107         OSStatus status 
= errSecSuccess
; 
3108         nb 
= SecCertificateNotValidBefore(cert
); 
3109         na 
= SecCertificateNotValidAfter(cert
); 
3111         if (nb 
== 0 || na 
== 0 || nb 
== na
) 
3112                 status 
= errSecCertificateCannotOperate
; 
3114                 status 
= errSecCertificateNotValidYet
; 
3116                 status 
= errSecCertificateExpired
; 
3122 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
) 
3124         if (!cert
) return errSecParam
; 
3125         if (!trustedOnly
) return errSecSuccess
; 
3127         CFArrayRef certArray 
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
); 
3128         SecPolicyRef policy 
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
); 
3129         OSStatus status 
= (policy 
== NULL
) ? errSecPolicyNotFound 
: errSecSuccess
; 
3132                 SecTrustRef trust 
= NULL
; 
3133                 status 
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
); 
3135                         SecTrustResultType trustResult
; 
3136                         status 
= SecTrustEvaluate(trust
, &trustResult
); 
3138                                 if (!(trustResult 
== kSecTrustResultProceed 
|| trustResult 
== kSecTrustResultUnspecified
)) { 
3139                                         status 
= (trustResult 
== kSecTrustResultDeny
) ? errSecTrustSettingDeny 
: errSecNotTrusted
; 
3147                 CFRelease(certArray
); 
3153 static SecKeychainItemRef
 
3154 CopyResolvedKeychainItem(CFTypeRef item
) 
3156         SecKeychainItemRef kcItem 
= NULL
; 
3159                 if (CFGetTypeID(item
) == CFDataGetTypeID()) { 
3160                         // persistent reference, resolve first 
3161                         status 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &kcItem
); 
3165                         kcItem 
= (SecKeychainItemRef
) CFRetain(item
); 
3168                         // ask for the item's class: 
3169                         // will return an error if the item has been deleted 
3170                         SecItemClass itemClass
; 
3171                         SecKeychainItemRef certRef 
= NULL
; 
3172                         if (CFGetTypeID(kcItem
) == SecIdentityGetTypeID()) { 
3173                                 status 
= SecIdentityCopyCertificate((SecIdentityRef
)kcItem
, (SecCertificateRef 
*)&certRef
); 
3175                         status 
= SecKeychainItemCopyAttributesAndData((certRef
) ? certRef 
: kcItem
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3189 UpdateKeychainSearchAndCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3191         // This function refreshes the search parameters in the specific case where 
3192         // the caller is searching for kSecClassKey items but did not provide the 
3193         // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and 
3194         // we must perform separate searches to obtain all results. 
3196         OSStatus status 
= errSecItemNotFound
; 
3197         if (!params 
|| !params
->assumedKeyClass 
|| !params
->query 
|| !item
) 
3200         // Free the previous search reference and attribute list. 
3202                 CFRelease(params
->search
); 
3203         params
->search 
= NULL
; 
3204         _FreeAttrList(params
->attrList
); 
3205         params
->attrList 
= NULL
; 
3207         // Make a copy of the query dictionary so we can set the key class parameter. 
3208         CFMutableDictionaryRef dict 
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
); 
3209         CFRelease(params
->query
); 
3210         params
->query 
= dict
; 
3211         CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
); 
3213         // Determine the current item class for this search, and the next assumed key class. 
3214         if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) { 
3215                 params
->itemClass 
= kSecSymmetricKeyItemClass
; 
3216                 params
->assumedKeyClass 
= kSecAttrKeyClassPublic
; 
3217         } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) { 
3218                 params
->itemClass 
= kSecPublicKeyItemClass
; 
3219                 params
->assumedKeyClass 
= kSecAttrKeyClassPrivate
; 
3221                 params
->itemClass 
= kSecPrivateKeyItemClass
; 
3222                 params
->assumedKeyClass 
= NULL
; 
3225         // Rebuild the attribute list for the new key class. 
3226         if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == errSecSuccess
) { 
3227                 // Create a new search reference for the new attribute list. 
3228                 if (SecKeychainSearchCreateFromAttributes(params
->searchList
, 
3230                         (params
->attrList
->count 
== 0) ? NULL 
: params
->attrList
, 
3231                         (SecKeychainSearchRef
*)¶ms
->search
) == errSecSuccess
) { 
3232                         // Return the first matching item from the new search. 
3233                         // We won't come back here again until there are no more matching items for this search. 
3234                         status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
); 
3242 SecItemSearchCopyNext(SecItemParams 
*params
, CFTypeRef 
*item
) 
3244         // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef. 
3245         // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter, 
3246         // depending on the type of search reference. 
3249         CFTypeRef search 
= (params
) ? params
->search 
: NULL
; 
3250         CFTypeID typeID 
= (search
) ? CFGetTypeID(search
) : 0; 
3251         if (typeID 
== SecIdentitySearchGetTypeID()) { 
3252                 status 
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
); 
3254         else if (typeID 
== SecKeychainSearchGetTypeID()) { 
3255                 status 
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
); 
3256                 // Check if we need to refresh the search for the next key class 
3257                 while (status 
== errSecItemNotFound 
&& params
->assumedKeyClass 
!= NULL
) 
3258                         status 
= UpdateKeychainSearchAndCopyNext(params
, item
); 
3260         else if (typeID 
== 0 && (params
->useItems 
|| params
->itemList
)) { 
3261                 // No search available, but there is an item list available. 
3262                 // Return the next candidate item from the caller's item list 
3263                 CFArrayRef itemList 
= (params
->useItems
) ? params
->useItems 
: params
->itemList
; 
3264                 CFIndex count 
= CFArrayGetCount(itemList
); 
3265                 *item 
= (CFTypeRef
) NULL
; 
3266                 if (params
->itemListIndex 
< count
) { 
3267                         *item 
= (CFTypeRef
)CFArrayGetValueAtIndex(itemList
, params
->itemListIndex
++); 
3269                                 // Potentially resolve persistent item references here, and 
3270                                 // verify the item reference we're about to hand back is still 
3271                                 // valid (it could have been deleted from the keychain while 
3272                                 // our query was holding onto the itemList). 
3273                                 *item 
= CopyResolvedKeychainItem(*item
); 
3274                                 if (*item 
&& (CFGetTypeID(*item
) == SecIdentityGetTypeID())) { 
3275                                         // Persistent reference resolved to an identity, so return that type. 
3276                                         params
->returnIdentity 
= true; 
3280                 status 
= (*item
) ? errSecSuccess 
: errSecItemNotFound
; 
3283                 status 
= errSecItemNotFound
; 
3289 FilterCandidateItem(CFTypeRef 
*item
, SecItemParams 
*itemParams
, SecIdentityRef 
*identity
) 
3291         if (!item 
|| *item 
== NULL 
|| !itemParams
) 
3292                 return errSecItemNotFound
; 
3295         CFStringRef commonName 
= NULL
; 
3296         SecIdentityRef foundIdentity 
= NULL
; 
3297         if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) { 
3298                 // we found a SecIdentityRef, rather than a SecKeychainItemRef; 
3299                 // replace the found "item" with its associated certificate (which is the 
3300                 // item we actually want for purposes of getting attributes, data, or a 
3301                 // persistent data reference), and return the identity separately. 
3302                 SecCertificateRef certificate
; 
3303                 status 
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
); 
3304                 if (itemParams
->returnIdentity
) { 
3305                         foundIdentity 
= (SecIdentityRef
) *item
; 
3307                                 *identity 
= foundIdentity
; 
3313                 *item 
= (CFTypeRef
)certificate
; 
3316         CFDictionaryRef query 
= itemParams
->query
; 
3318         if (itemParams
->itemClass 
== kSecCertificateItemClass
) { 
3319                 // perform string comparisons first 
3320                 CFStringCompareFlags flags 
= _StringCompareFlagsFromQuery(query
); 
3321                 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
; 
3322                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
)) 
3323                         nameContains 
= NULL
; 
3324                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
)) 
3326                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
)) 
3328                 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
)) 
3330                 if (nameContains 
|| nameStarts 
|| nameEnds 
|| nameExact
) { 
3331                         status 
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
); 
3332                         if (status 
|| !commonName
) goto filterOut
; 
3335                         CFRange range 
= CFStringFind(commonName
, nameContains
, flags
); 
3336                         if (range
.length 
< 1) 
3338                         // certificate item contains string; proceed to next check 
3341                         CFRange range 
= CFStringFind(commonName
, nameStarts
, flags
); 
3342                         if (range
.length 
< 1 || range
.location 
> 1) 
3344                         // certificate item starts with string; proceed to next check 
3347                         CFRange range 
= CFStringFind(commonName
, nameEnds
, flags
); 
3348                         if (range
.length 
< 1 || range
.location 
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
))) 
3350                         // certificate item ends with string; proceed to next check 
3353                         CFRange range 
= CFStringFind(commonName
, nameExact
, flags
); 
3354                         if (range
.length 
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
))) 
3356                         // certificate item exactly matches string; proceed to next check 
3358                 if (itemParams
->returnIdentity
) { 
3359                         // if we already found and returned the identity, we can skip this 
3360                         if (!foundIdentity
) { 
3361                                 status 
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
); 
3362                                 if (status
) goto filterOut
; 
3364                         // certificate item is part of an identity; proceed to next check 
3366                 if (itemParams
->policy
) { 
3367                         status 
= _FilterWithPolicy(itemParams
->policy
, (CFDateRef
)itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3368                         if (status
) goto filterOut
; 
3369                         // certificate item is valid for specified policy (and optionally specified date) 
3371                 if (itemParams
->validOnDate
) { 
3372                         status 
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
); 
3373                         if (status
) goto filterOut
; 
3374                         // certificate item is valid for specified date 
3376                 if (itemParams
->trustedOnly
) { 
3377                         // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search, 
3378                         // their trust has already been validated and we can skip this part. 
3379                         if (!(foundIdentity 
&& itemParams
->returnIdentity 
&& itemParams
->policy
)) { 
3380                                 status 
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
); 
3381                                 if (status
) goto filterOut
; 
3383                         // certificate item is trusted on this system 
3386         if (itemParams
->itemList
) { 
3387                 Boolean foundMatch 
= FALSE
; 
3388                 CFIndex idx
, count 
= CFArrayGetCount(itemParams
->itemList
); 
3389                 for (idx
=0; idx
<count
; idx
++) { 
3390                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
); 
3391                         SecKeychainItemRef realItem 
= NULL
; 
3392                         SecCertificateRef aCert 
= NULL
; 
3393                         if (anItem 
== NULL
) { 
3396                         if (CFDataGetTypeID() == CFGetTypeID(anItem
) && 
3397                                 errSecSuccess 
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) { 
3400                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) && 
3401                                 errSecSuccess 
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) { 
3404                         if (CFEqual(anItem
, (CFTypeRef
) *item
)) { 
3411                                 CFRelease(realItem
); 
3417                 if (!foundMatch
) goto filterOut
; 
3418                 // item was found on provided list 
3421         if (foundIdentity 
&& !identity
) { 
3422                 CFRelease(foundIdentity
); 
3425                 CFRelease(commonName
); 
3428         // if we get here, consider the item a match 
3429         return errSecSuccess
; 
3433                 CFRelease(commonName
); 
3437         if (foundIdentity
) { 
3438                 CFRelease(foundIdentity
); 
3443         return errSecItemNotFound
; 
3447 AddItemResults(SecKeychainItemRef item
, 
3448         SecIdentityRef identity
, 
3449         SecItemParams 
*itemParams
, 
3450         CFAllocatorRef allocator
, 
3451         CFMutableArrayRef 
*items
, 
3454         // Given a found item (which may also be an identity), this function adds 
3455         // the requested result types (specified in itemParams) to the appropriate 
3456         // container as follows: 
3458         // 1. If there is only one result type (numResultTypes == 1) and only one 
3459         //    match requested (maxMatches == 1), set *result directly. 
3461         // 2. If there are multiple result types (numResultTypes > 1), and only one 
3462         //    match requested (maxMatches == 1), add each result type to itemDict 
3463         //    and set itemDict as the value of *result. 
3465         // 3. If there is only one result type (numResultTypes == 1) and multiple 
3466         //    possible matches (maxMatches > 1), add the result type to *items 
3467         //    and set *items as the value of *result. 
3469         // 4. If there are multiple result types (numResultTypes > 1) and multiple 
3470         //    possible matches (maxMatches > 1), add each result type to itemDict, 
3471         //    add itemDict to *items, and set *items as the value of *result. 
3473         // Note that we allocate *items if needed. 
3475         if (!item 
|| !itemParams 
|| !result
) 
3478         if (itemParams
->maxMatches 
> 1) { 
3479                 // if we can return more than one item, we must have an array 
3482                 else if (*items 
== NULL
) 
3483                         *items 
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
3486         OSStatus tmpStatus
, status 
= errSecSuccess
; 
3487         CFMutableArrayRef itemArray 
= (items
) ? *items 
: NULL
; 
3488         CFMutableDictionaryRef itemDict 
= NULL
; 
3489         if (itemParams
->numResultTypes 
> 1) { 
3490                 // if we're returning more than one result type, each item we return must be a dictionary 
3491                 itemDict 
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
3494         if (itemParams
->returningRef
) { 
3495                 const void* itemRef 
= (identity
) ? (const void*)identity 
: (const void*)item
; 
3497                         CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
); 
3499                 else if (itemArray
) { 
3500                         CFArrayAppendValue(itemArray
, itemRef
); 
3503                         *result 
= CFRetain((CFTypeRef
)itemRef
); 
3507         if (itemParams
->returningPersistentRef
) { 
3508                 CFDataRef persistentRef
; 
3509                 SecKeychainItemRef tmpItem 
= item
; 
3510                 if (itemParams
->identityRef
) { 
3511                         tmpItem 
= (SecKeychainItemRef
)itemParams
->identityRef
; 
3513                 tmpStatus 
= SecKeychainItemCreatePersistentReference(tmpItem
, &persistentRef
); 
3514                 if (tmpStatus 
== errSecSuccess
) { 
3516                                 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
); 
3518                         else if (itemArray
) { 
3519                                 CFArrayAppendValue(itemArray
, persistentRef
); 
3522                                 *result 
= CFRetain(persistentRef
); 
3524                         CFRelease(persistentRef
); 
3526                 else if (status 
== errSecSuccess
) { 
3531         if (itemParams
->returningData
) { 
3534                 tmpStatus 
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
); 
3535                 if (tmpStatus 
== errSecSuccess
) { 
3536                         CFDataRef dataRef 
= CFDataCreate(allocator
, (UInt8 
*)data
, length
); 
3538                                 CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
); 
3540                         else if (itemArray
) { 
3541                                 CFArrayAppendValue(itemArray
, dataRef
); 
3544                                 *result 
= CFRetain(dataRef
); 
3547                         (void) SecKeychainItemFreeContent(NULL
, data
); 
3549                 else if (status 
== errSecSuccess
) { 
3554         if (itemParams
->returningAttributes
) { 
3555                 CFDictionaryRef attrsDict 
= NULL
; 
3556                 SecItemClass itemClass
; 
3557                 // since we have an item, allow its actual class to override the query-specified item class 
3558                 tmpStatus 
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
); 
3560                         itemClass 
= itemParams
->itemClass
; 
3562                 tmpStatus 
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
); 
3565                                 // add all keys and values from attrsDict to the item dictionary 
3566                                 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
); 
3568                         else if (itemArray
) { 
3569                                 CFArrayAppendValue(itemArray
, attrsDict
); 
3572                                 *result 
= CFRetain(attrsDict
); 
3574                         CFRelease(attrsDict
); 
3576                 if (tmpStatus 
&& (status 
== errSecSuccess
)) { 
3583                         CFArrayAppendValue(itemArray
, itemDict
); 
3584                         CFRelease(itemDict
); 
3585                         *result 
= itemArray
; 
3591         else if (itemArray
) { 
3592                 *result 
= itemArray
; 
3598 CFDataRef 
_SecItemGetPersistentReference(CFTypeRef raw_item
) 
3601                 Item item 
= ItemImpl::required((SecKeychainItemRef
)raw_item
); 
3602                 return item
->getPersistentRef(); 
3608 /******************************************************************************/ 
3609 #pragma mark SecItem API functions 
3610 /******************************************************************************/ 
3613 // Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error. 
3615 static SInt32 
readNumber(CFTypeRef obj
) { 
3616     CFTypeID tid 
= CFGetTypeID(obj
); 
3618     if (tid 
== CFNumberGetTypeID()) { 
3619         CFNumberGetValue((CFNumberRef
)obj
, kCFNumberSInt32Type
, &v
); 
3621     } else if (tid 
== CFBooleanGetTypeID()) { 
3622         v 
= CFBooleanGetValue((CFBooleanRef
)obj
); 
3624     } else if (tid 
== CFStringGetTypeID()) { 
3625         v 
= CFStringGetIntValue((CFStringRef
)obj
); 
3626         CFStringRef t 
= CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v
); 
3627         /* If a string converted to an int isn't equal to the int printed as 
3628          a string, return a CFStringRef instead. */ 
3629         if (!CFEqual(t
, obj
)) { 
3640 // Function to ensure the syncable keychain is unlocked. 
3641 // Currently, this means unlocking the login keychain, 
3642 // which will also unlock the keybag as a side effect. 
3644 static OSStatus 
SecItemUnlockSynchronizableKeychain() 
3646         SecKeychainRef keychain 
= NULL
; 
3647         OSStatus status 
= SecKeychainCopyLogin(&keychain
); 
3649                 status 
= SecKeychainUnlock(keychain
, 0, NULL
, false); 
3651         CFReleaseSafe(keychain
); 
3656 // Function to check whether the kSecAttrSynchronizable flag is set in the query. 
3658 static Boolean 
SecItemSynchronizable(CFDictionaryRef query
) 
3660         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
3661         Boolean result 
= (value 
&& readNumber(value
)); 
3667 // Function to check whether the kSecAttrSynchronizable flag is set in the query, 
3668 // and has the special value of kSecAttrSynchronizableAny. 
3670 static Boolean 
SecItemSynchronizableAny(CFDictionaryRef query
) 
3672         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecAttrSynchronizable
); 
3674                 return (CFGetTypeID(value
) == CFStringGetTypeID() && 
3675                                 CFEqual(value
, kSecAttrSynchronizableAny
)); 
3681 // Function to check whether the kSecAttrSynchronizable attribute is being updated. 
3683 static Boolean 
SecItemHasSynchronizableUpdate(Boolean synchronizable
, CFDictionaryRef changes
) 
3685         CFTypeRef newValue 
= CFDictionaryGetValue(changes
, kSecAttrSynchronizable
); 
3689         Boolean new_sync 
= readNumber(newValue
); 
3690         Boolean old_sync 
= synchronizable
; 
3692         return (old_sync 
!= new_sync
); 
3696 // Returns true if keychain syncing is globally enabled. 
3698 static Boolean 
SecItemSyncEnabled() 
3700         static dispatch_once_t onceToken
; 
3701         static Boolean syncEnabled 
= true; 
3703         //sudo defaults write /Library/Preferences/com.apple.security SecItemSynchronizable -bool YES 
3704         dispatch_once(&onceToken
, ^{ 
3705                         CFTypeRef sync 
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
); 
3707                         if (sync 
&& CFGetTypeID(sync
) == CFBooleanGetTypeID()) { 
3708                         syncEnabled 
= CFBooleanGetValue((CFBooleanRef
)sync
); 
3717 // Function to check whether a synchronizable persistent reference was provided. 
3719 static Boolean 
SecItemHasSynchronizablePersistentReference(CFDictionaryRef query
) 
3721         CFTypeRef value 
= CFDictionaryGetValue(query
, kSecValuePersistentRef
); 
3723                 /* Synchronizable persistent ref consists of the sqlite rowid and 4-byte class value */ 
3724                 const CFIndex kSynchronizablePersistentRefLength 
= sizeof(int64_t) + 4; 
3725                 return (CFGetTypeID(value
) == CFDataGetTypeID() && 
3726                                 CFDataGetLength((CFDataRef
)value
) == kSynchronizablePersistentRefLength
); 
3732 // Function to apply changes to a mutable dictionary. 
3733 // (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction) 
3735 static void SecItemApplyChanges(const void *key
, const void *value
, void *context
) 
3737         CFMutableDictionaryRef dict 
= (CFMutableDictionaryRef
) context
; 
3740         CFDictionarySetValue(dict
, key
, value
); 
3744 // Function to change matching items from non-syncable to syncable 
3745 // (if toSyncable is true), otherwise from syncable to non-syncable. 
3746 // This currently moves items between keychain containers. 
3748 static OSStatus 
SecItemChangeSynchronizability(CFDictionaryRef query
, CFDictionaryRef changes
, Boolean toSyncable
) 
3750         // Note: the input query dictionary is a mutable copy of the query originally 
3751         // provided by the caller as the first parameter to SecItemUpdate. It may not 
3752         // specify returning attributes or data, but we will need both to make a copy. 
3754         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnRef
); 
3755         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnPersistentRef
); 
3756         CFDictionaryRemoveValue((CFMutableDictionaryRef
)query
, kSecReturnData
); 
3757         CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnAttributes
, kCFBooleanTrue
); 
3758         if (NULL 
== CFDictionaryGetValue(changes
, kSecValueData
)) 
3759                 CFDictionarySetValue((CFMutableDictionaryRef
)query
, kSecReturnData
, kCFBooleanTrue
); 
3764                 status 
= SecItemCopyMatching_osx(query
, &result
); 
3766                 status 
= SecItemCopyMatching_ios(query
, &result
); 
3771                 return errSecItemNotFound
; 
3773         CFMutableArrayRef items
; 
3774         if (CFGetTypeID(result
) != CFArrayGetTypeID()) { 
3775                 items 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
3776                 CFArrayAppendValue(items
, result
); 
3780                 items 
= (CFMutableArrayRef
)result
; 
3783         CFIndex idx
, count 
= (items
) ? CFArrayGetCount(items
) : 0; 
3784         int priority 
= LOG_DEBUG
; 
3786         for (idx 
= 0; idx 
< count
; idx
++) { 
3787                 CFDictionaryRef dict 
= (CFDictionaryRef
) CFArrayGetValueAtIndex(items
, idx
); 
3788                 CFMutableDictionaryRef item 
= (CFMutableDictionaryRef
) 
3789                         SecItemCopyTranslatedAttributes(dict
, 
3790                                 CFDictionaryGetValue(query
, kSecClass
), 
3791                                 (toSyncable
) ? true : false /*iOSOut*/, 
3792                                 true /*pruneMatch*/, 
3794                                 true /*pruneReturn*/, 
3795                                 false /*pruneData*/, 
3796                                 (toSyncable
) ? true : false /*pruneAccess*/); 
3797                 // hold onto the query before applying changes, in case the item already exists. 
3798                 // note that we cannot include the creation or modification dates from our 
3799                 // found item in this query, as they may not match the item in the other keychain. 
3800                 CFMutableDictionaryRef itemQuery 
= CFDictionaryCreateMutableCopy(NULL
, 0, item
); 
3801                 CFDictionaryRemoveValue(itemQuery
, kSecAttrCreationDate
); 
3802                 CFDictionaryRemoveValue(itemQuery
, kSecAttrModificationDate
); 
3803                 // apply changes to the item dictionary that we will pass to SecItemAdd 
3804                 CFDictionaryApplyFunction(changes
, SecItemApplyChanges
, item
); 
3806                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
3807                         status 
= SecItemAdd_ios(item
, NULL
); 
3808                         secitemlog(priority
, "ChangeSync: SecItemAdd_ios=%d", status
); 
3809                         if (errSecDuplicateItem 
== status
) { 
3810                                 // find and apply changes to the existing syncable item. 
3811                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
3812                                 status 
= SecItemUpdate_ios(itemQuery
, changes
); 
3813                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_ios=%d", status
); 
3815                         if (errSecSuccess 
== status
) { 
3816                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
3817                                 status 
= SecItemDelete_osx(itemQuery
); 
3818                                 secitemlog(priority
, "ChangeSync: SecItemDelete_osx=%d", status
); 
3822                         CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
3823                         status 
= SecItemAdd_osx(item
, NULL
); 
3824                         secitemlog(priority
, "ChangeSync: SecItemAdd_osx=%d", status
); 
3825                         if (errSecDuplicateItem 
== status
) { 
3826                                 // find and apply changes to the existing non-syncable item. 
3827                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanFalse
); 
3828                                 status 
= SecItemUpdate_osx(itemQuery
, changes
); 
3829                                 secitemlog(priority
, "ChangeSync: SecItemUpdate_osx=%d", status
); 
3831                         if (errSecSuccess 
== status
) { 
3832                                 CFDictionarySetValue(itemQuery
, kSecAttrSynchronizable
, kCFBooleanTrue
); 
3833                                 status 
= SecItemDelete_ios(itemQuery
); 
3834                                 secitemlog(priority
, "ChangeSync: SecItemDelete_ios=%d", status
); 
3837                 CFReleaseSafe(item
); 
3838                 CFReleaseSafe(itemQuery
); 
3842         CFReleaseSafe(items
); 
3851 SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes
) { 
3852         CFTypeRef ref 
= NULL
; 
3853         CFStringRef key_class_string 
= (CFStringRef
)CFDictionaryGetValue(refAttributes
, kSecClass
); 
3854         SecItemClass key_class
; 
3855         bool key_class_found 
= false; 
3857         if (CFEqual(key_class_string
, kSecClassGenericPassword
)) { 
3858                 key_class 
= kSecGenericPasswordItemClass
; 
3859                 key_class_found 
= true; 
3861         if (CFEqual(key_class_string
, kSecClassInternetPassword
)) { 
3862                 key_class 
= kSecInternetPasswordItemClass
; 
3863                 key_class_found 
= true; 
3866         if (key_class_found
) { 
3867                 // we carry v_Data around here so the *_ios calls can find it and locate 
3868                 // their own data.   Putting things in the attribute list doesn't help as 
3869                 // the osx keychainitem and item calls bail when they don't see a keychain 
3870                 // object.   If we need to make them work we either have to bridge them, or 
3871                 // find a way to craft a workable keychain object.   #if'ed code left below 
3872                 // in case we need to go down that path. 
3874                 struct SecKeychainAttributeList 
*attrs 
= (struct SecKeychainAttributeList 
*)malloc(sizeof(struct SecKeychainAttributeList
) + sizeof(struct SecKeychainAttribute
) * 0); 
3875                 attrs
->attr 
= (struct SecKeychainAttribute 
*)(attrs 
+ 1); 
3879                 // The C++ string objects need to last at least as long as the attr struct. 
3882                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("mdat")); 
3884                         attrs
->attr
[attrs
->count
].tag 
= kSecModDateItemAttr
; 
3885                         // XXX need to convert to YYYYMMDDhhmmSSZ 
3886                         attrs
->attr
[attrs
->count
].data 
= (void*)"19690223140232Z"; 
3887                         attrs
->attr
[attrs
->count
].length 
= strlen((char*)(attrs
->attr
[attrs
->count
].data
)); 
3890                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("cdat")); 
3892                         attrs
->attr
[attrs
->count
].tag 
= kSecCreationDateItemAttr
; 
3893                         // XXX need to convert to YYYYMMDDhhmmSSZ 
3894                         attrs
->attr
[attrs
->count
].data 
= (void*)"19690223140232Z"; 
3895                         attrs
->attr
[attrs
->count
].length 
= strlen((char*)(attrs
->attr
[attrs
->count
].data
)); 
3899                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("acct")); 
3901                         attrs
->attr
[attrs
->count
].tag 
= kSecAccountItemAttr
; 
3902                         account 
= cfString((CFStringRef
)v
); 
3903                         attrs
->attr
[attrs
->count
].data 
= (void*)(account
.c_str()); 
3904                         attrs
->attr
[attrs
->count
].length 
= account
.length(); 
3908                 // class isn't treated as an attribute by the creation API 
3910                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("svce")); 
3912                         attrs
->attr
[attrs
->count
].tag 
= kSecServiceItemAttr
; 
3913                         account 
= cfString((CFStringRef
)v
); 
3914                         attrs
->attr
[attrs
->count
].data 
= (void*)(account
.c_str()); 
3915                         attrs
->attr
[attrs
->count
].length 
= account
.length(); 
3919                 v 
= CFDictionaryGetValue(refAttributes
, CFSTR("acct")); 
3921                         attrs
->attr
[attrs
->count
].tag 
= kSecLabelItemAttr
; 
3922                         account 
= cfString((CFStringRef
)v
); 
3923                         attrs
->attr
[attrs
->count
].data 
= (void*)(account
.c_str()); 
3924                         attrs
->attr
[attrs
->count
].length 
= account
.length(); 
3928                 Item item 
= Item(key_class
, attrs
, 0, ""); 
3929                 ItemImpl 
*real_item 
= item
.get(); 
3930                 v 
= CFDictionaryGetValue(refAttributes
, kSecValuePersistentRef
); 
3932                         real_item
->setPersistentRef((CFDataRef
)v
); 
3934                 ref 
= real_item
->handle(); 
3936                 // keys, certs, identities are not currently sync'able. 
3943  * SecItemValidateAppleApplicationGroupAccess determines if the caller 
3944  * is a member of the specified application group, and is signed by Apple. 
3947 SecItemValidateAppleApplicationGroupAccess(CFStringRef group
) 
3949         SecTrustedApplicationRef app 
= NULL
; 
3950         SecRequirementRef requirement 
= NULL
; 
3951         SecCodeRef code 
= NULL
; 
3952         OSStatus status 
= errSecParam
; 
3955                 CFIndex length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(group
), kCFStringEncodingUTF8
) + 1; 
3956                 char* buffer 
= (char*) malloc(length
); 
3958                         if (CFStringGetCString(group
, buffer
, length
, kCFStringEncodingUTF8
)) { 
3959                                 status 
= SecTrustedApplicationCreateApplicationGroup(buffer
, NULL
, &app
); 
3963                         status 
= errSecMemoryError
; 
3967                 status 
= SecTrustedApplicationCopyRequirement(app
, &requirement
); 
3970                 status 
= SecCodeCopySelf(kSecCSDefaultFlags
, &code
); 
3973                 status 
= SecCodeCheckValidity(code
, kSecCSDefaultFlags
, requirement
); 
3976         CFReleaseSafe(code
); 
3977         CFReleaseSafe(requirement
); 
3983  * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary 
3984  * and attempts to return a sanitized copy for passing to the underlying 
3985  * platform-specific implementation code. 
3987  * If iOSOut is true, one or more translations may apply: 
3988  *   - SecKeychain refs are removed, since there aren't multiple keychains 
3989  *   - SecPolicy refs are removed, since they can't be externalized 
3990  *   - SecAccess refs are removed, and potentially translated to entitlements 
3992  * If pruneMatch is true, kSecMatch* attributes are removed; this avoids 
3993  * parameter errors due to strict input checks in secd, which only permits 
3994  * these constants for calls to SecItemCopyMatching. 
3996  * If pruneSync is true, the kSecAttrSynchronizable attribute is removed. 
3997  * This permits a query to be reused for non-synchronizable items, or to 
3998  * resolve a search based on a persistent item reference for iOS. 
4000  * If pruneReturn is true, kSecReturn* attributes are removed; this avoids 
4001  * parameter errors due to strict input checks in secd, which do not permit 
4002  * these constants for calls to SecItemUpdate. 
4005 SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict
, CFTypeRef itemClass
, 
4006         bool iOSOut
, bool pruneMatch
, bool pruneSync
, bool pruneReturn
, bool pruneData
, bool pruneAccess
) 
4008         CFMutableDictionaryRef result 
= CFDictionaryCreateMutableCopy(NULL
, 0, inOSXDict
); 
4009         if (result 
== NULL
) { 
4014                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4018                 /* Match constants are only supported on iOS for SecItemCopyMatching, 
4019                  * and will generate an error if passed to other SecItem API functions; 
4020                  * on OS X, they're just ignored if not applicable for the context. 
4022                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4023                 CFDictionaryRemoveValue(result
, kSecMatchItemList
); 
4024                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4025                 CFDictionaryRemoveValue(result
, kSecMatchIssuers
); 
4026                 CFDictionaryRemoveValue(result
, kSecMatchEmailAddressIfPresent
); 
4027                 CFDictionaryRemoveValue(result
, kSecMatchSubjectContains
); 
4028                 CFDictionaryRemoveValue(result
, kSecMatchCaseInsensitive
); 
4029                 CFDictionaryRemoveValue(result
, kSecMatchTrustedOnly
); 
4030                 CFDictionaryRemoveValue(result
, kSecMatchValidOnDate
); 
4031                 CFDictionaryRemoveValue(result
, kSecMatchLimit
); 
4032                 CFDictionaryRemoveValue(result
, kSecMatchLimitOne
); 
4033                 CFDictionaryRemoveValue(result
, kSecMatchLimitAll
); 
4037                 /* Return constants are not supported on iOS for SecItemUpdate, 
4038                  * where they will generate an error; on OS X, they're just ignored 
4039                  * if not applicable for the context. 
4041                 CFDictionaryRemoveValue(result
, kSecReturnData
); 
4042                 CFDictionaryRemoveValue(result
, kSecReturnAttributes
); 
4043                 CFDictionaryRemoveValue(result
, kSecReturnRef
); 
4044                 CFDictionaryRemoveValue(result
, kSecReturnPersistentRef
); 
4048                 /* Searching on data is not supported. */ 
4049                 CFDictionaryRemoveValue(result
, kSecValueData
); 
4053         /* Searching on access lists is not supported */ 
4054         CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4058                 /* Remove kSecMatchSearchList (value is array of SecKeychainRef); 
4059                  * cannot specify a keychain search list on iOS 
4061                 CFDictionaryRemoveValue(result
, kSecMatchSearchList
); 
4063                 /* Remove kSecUseKeychain (value is a SecKeychainRef); 
4064                  * cannot specify a keychain on iOS 
4066                 CFDictionaryRemoveValue(result
, kSecUseKeychain
); 
4068                 /* Remove kSecMatchPolicy (value is a SecPolicyRef); 
4069                  * TODO: need a way to externalize and restore a policy instance 
4071                 CFDictionaryRemoveValue(result
, kSecMatchPolicy
); 
4073                 /* Potentially translate kSecAttrAccess (value is a SecAccessRef), 
4074                  * unless kSecAttrAccessGroup has already been specified. 
4076                 SecAccessRef access 
= (SecAccessRef
) CFDictionaryGetValue(result
, kSecAttrAccess
); 
4077                 CFStringRef accessGroup 
= (CFStringRef
) CFDictionaryGetValue(result
, kSecAttrAccessGroup
); 
4078                 if (access 
!= NULL 
&& accessGroup 
== NULL
) { 
4079                         /* Translate "InternetAccounts" application group to an access group */ 
4080                         if (errSecSuccess 
== SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) { 
4081                                 /* The caller is a valid member of the application group. */ 
4082                                 CFStringRef groupName 
= CFSTR("appleaccount"); 
4083                                 CFTypeRef value 
= CFDictionaryGetValue(result
, kSecAttrAuthenticationType
); 
4084                                 if (value 
&& CFEqual(value
, kSecAttrAuthenticationTypeHTMLForm
)) { 
4085                                         groupName 
= CFSTR("com.apple.cfnetwork"); 
4087                                 CFDictionarySetValue(result
, kSecAttrAccessGroup
, groupName
); 
4090                 CFDictionaryRemoveValue(result
, kSecAttrAccess
); 
4092                 /* If item is specified by direct reference, and this is an iOS search, 
4093                  * replace it with a persistent reference. 
4095         CFTypeRef directRef 
= CFDictionaryGetValue(result
, kSecValueRef
); 
4097                         CFDataRef persistentRef 
= _SecItemGetPersistentReference(directRef
); 
4098                         if (persistentRef
) { 
4099                 CFDictionarySetValue(result
, kSecValuePersistentRef
, persistentRef
); 
4101                         CFDictionaryRemoveValue(result
, kSecValueRef
); 
4104                 /* If item is specified by persistent reference, and this is an iOS search, 
4105                  * remove the synchronizable attribute as it will be rejected by secd. 
4107                 CFTypeRef persistentRef 
= CFDictionaryGetValue(result
, kSecValuePersistentRef
); 
4108                 if (persistentRef
) { 
4109                         CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4112                 /* Remove kSecAttrModificationDate; this should never be used as criteria 
4113                  * for a search, or to add/modify an item. (If we are cloning an item 
4114                  * and want to keep its modification date, we don't call this function.) 
4115                  * It turns out that some clients are using the full attributes dictionary 
4116                  * returned by SecItemCopyMatching as a query to find the same item later, 
4117                  * which won't work once the item is updated. 
4119                 CFDictionaryRemoveValue(result
, kSecAttrModificationDate
); 
4122                 /* iOS doesn't add the class attribute, so we must do it here. */ 
4124                         CFDictionarySetValue(result
, kSecClass
, itemClass
); 
4126                 /* Remove attributes which are not part of the OS X database schema. */ 
4127                 CFDictionaryRemoveValue(result
, kSecAttrAccessible
); 
4128                 CFDictionaryRemoveValue(result
, kSecAttrAccessGroup
); 
4129                 CFDictionaryRemoveValue(result
, kSecAttrSynchronizable
); 
4130                 CFDictionaryRemoveValue(result
, kSecAttrTombstone
); 
4137  * SecItemCopyMergedResults takes two input objects, which may be containers, 
4138  * and returns a retained object which merges the results. Merging depends on the 
4139  * result type. If each result is valid and is not an array, then only one match was 
4140  * requested; in that case, the syncable (ios) match is preferred. 
4142  * FIXME: There are some edge cases still to deal with; e.g. if the OSX search specified a 
4143  * particular keychain to search, we do not want to merge in any IOS results. Also, may need 
4144  * to filter out duplicates if two items differ only in the sync attribute. 
4147 SecItemCopyMergedResults(CFDictionaryRef query
, CFTypeRef result_osx
, CFTypeRef result_ios
) 
4149         CFTypeID id_osx 
= (result_osx
) ? CFGetTypeID(result_osx
) : 0; 
4150         CFTypeID id_ios 
= (result_ios
) ? CFGetTypeID(result_ios
) : 0; 
4151         CFTypeID id_array 
= CFArrayGetTypeID(); 
4152         if ((id_osx 
== id_array
) && (id_ios 
== id_array
)) { 
4153                 // Fold the arrays into one. 
4154                 CFMutableArrayRef results 
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
); 
4155                 CFArrayAppendArray(results
, (CFArrayRef
)result_ios
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_ios
))); 
4156                 CFArrayAppendArray(results
, (CFArrayRef
)result_osx
, CFRangeMake(0, CFArrayGetCount((CFArrayRef
)result_osx
))); 
4159         // Result type is not an array, so only one match can be returned. 
4160         return (id_ios
) ? CFRetain(result_ios
) : CFRetain(result_osx
); 
4167 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef 
*result
) 
4169         secitemlog(LOG_NOTICE
, "SecItemCopyMatching"); 
4173         secitemshow(query
, "SecItemCopyMatching query:"); 
4175         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4176         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4177         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4178         Boolean search_ios 
= SecItemSynchronizable(query
); 
4179         Boolean merge_search 
= SecItemSynchronizableAny(query
); 
4180         Boolean persistref_ios 
= SecItemHasSynchronizablePersistentReference(query
); 
4182         if (sync_enabled 
&& (merge_search 
|| persistref_ios 
|| search_ios
)) { 
4183                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4184                         CFDictionaryGetValue(query
, kSecClass
), true, false, false, false, true, true); 
4186                         status_ios 
= errSecParam
; 
4189             SecItemUnlockSynchronizableKeychain(); 
4190             status_ios 
= SecItemCopyMatching_ios(attrs_ios
, &result_ios
); 
4191                         CFRelease(attrs_ios
); 
4193                 secitemlog(LOG_NOTICE
, "SecItemCopyMatching_ios result: %d", status_ios
); 
4194                 if (!merge_search 
|| persistref_ios
) { 
4195                         AssignOrReleaseResult(result_ios
, result
); 
4196                         return status_ios
; // no need to search non-syncable keychains 
4200         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4201                 CFDictionaryGetValue(query
, kSecClass
), false, false, true, false, true, true); 
4203                 status_osx 
= errSecParam
; 
4206                 status_osx 
= SecItemCopyMatching_osx(attrs_osx
, &result_osx
); 
4207                 CFRelease(attrs_osx
); 
4209         secitemlog(LOG_NOTICE
, "SecItemCopyMatching_osx result: %d", status_osx
); 
4211         // If one of the searches failed to occur or produce results, we can eliminate it 
4212         if (result_ios 
== NULL
) { 
4213                 AssignOrReleaseResult(result_osx
, result
); 
4214                 return status_osx
; // we can only have non-syncable results 
4216         if (result_osx 
== NULL
) { 
4217                 AssignOrReleaseResult(result_ios
, result
); 
4218                 return status_ios
; // we can only have syncable results 
4221         // If we get here, need to merge results 
4222         CFTypeRef result_merged 
= SecItemCopyMergedResults(query
, result_osx
, result_ios
); 
4223         CFReleaseSafe(result_osx
); 
4224         CFReleaseSafe(result_ios
); 
4225         AssignOrReleaseResult(result_merged
, result
); 
4227         if (status_osx 
== status_ios
) { 
4228                 return status_osx
; // both searches produced the same result 
4230         else if (!status_osx 
|| !status_ios
) { 
4231                 return errSecSuccess
; // one of the searches succeeded 
4233         else if (status_osx 
== errSecItemNotFound
) { 
4234                 return status_ios
; // this failure was more interesting 
4240 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef 
*result
) 
4242         secitemlog(LOG_NOTICE
, "SecItemAdd"); 
4249         secitemshow(attributes
, "SecItemAdd attrs:"); 
4251         OSStatus status_osx
, status_ios
; 
4252         CFTypeRef result_osx 
= NULL
, result_ios 
= NULL
; 
4253         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4254         Boolean add_ios 
= SecItemSynchronizable(attributes
); 
4256         if (sync_enabled 
&& add_ios
) { 
4257                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(attributes
, 
4258                         NULL
, true, true, false, false, false, false); 
4260                         status_ios 
= errSecParam
; 
4263             SecItemUnlockSynchronizableKeychain(); 
4264             status_ios 
= SecItemAdd_ios(attrs_ios
, &result_ios
); 
4265                         CFRelease(attrs_ios
); 
4267                 secitemlog(LOG_NOTICE
, "SecItemAdd_ios result: %d", status_ios
); 
4269                         *result 
= result_ios
; 
4271                         CFReleaseSafe(result_ios
); 
4275         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(attributes
, 
4276                 NULL
, false, false, true, false, false, false); 
4278                 status_osx 
= errSecParam
; 
4281                 status_osx 
= SecItemAdd_osx(attrs_osx
, &result_osx
); 
4282                 CFRelease(attrs_osx
); 
4284         secitemlog(LOG_NOTICE
, "SecItemAdd_osx result: %d", status_osx
); 
4286                 *result 
= result_osx
; 
4288                 CFReleaseSafe(result_osx
); 
4293 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
) 
4295         secitemlog(LOG_NOTICE
, "SecItemUpdate"); 
4296         if (!query 
|| !attributesToUpdate
) { 
4299         secitemshow(query
, "SecItemUpdate query:"); 
4300         secitemshow(attributesToUpdate
, "SecItemUpdate attrs:"); 
4302         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4303         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4304         Boolean search_ios 
= SecItemSynchronizable(query
); 
4305         Boolean merge_search 
= SecItemSynchronizableAny(query
); 
4306         Boolean persistref_ios 
= SecItemHasSynchronizablePersistentReference(query
); 
4308         if (sync_enabled 
&& (merge_search 
|| persistref_ios 
|| search_ios
)) { 
4309                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4310                         CFDictionaryGetValue(query
, kSecClass
), true, true, false, true, true, true); 
4312                         status_ios 
= errSecParam
; 
4315                         SecItemUnlockSynchronizableKeychain(); 
4316             if (SecItemHasSynchronizableUpdate(true, attributesToUpdate
)) 
4317                 status_ios 
= SecItemChangeSynchronizability(attrs_ios
, attributesToUpdate
, false); 
4319                 status_ios 
= SecItemUpdate_ios(attrs_ios
, attributesToUpdate
); 
4320                         CFRelease(attrs_ios
); 
4322                 secitemlog(LOG_NOTICE
, "SecItemUpdate_ios result: %d", status_ios
); 
4323                 if (!merge_search 
|| persistref_ios
) 
4327         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4328                 CFDictionaryGetValue(query
, kSecClass
), false, false, true, true, true, true); 
4330                 status_osx 
= errSecParam
; 
4333                 if (SecItemHasSynchronizableUpdate(false, attributesToUpdate
)) 
4334                         status_osx 
= SecItemChangeSynchronizability(attrs_osx
, attributesToUpdate
, true); 
4336                         status_osx 
= SecItemUpdate_osx(attrs_osx
, attributesToUpdate
); 
4338                 CFRelease(attrs_osx
); 
4340         secitemlog(LOG_NOTICE
, "SecItemUpdate_osx result: %d", status_osx
); 
4342                 // Harmonize the result of the update attempts. 
4343                 if (status_osx 
== status_ios
) { 
4344                         // both updates produced the same result 
4347                 else if (!status_osx 
|| !status_ios
) { 
4348                         // one of the updates succeeded, but the other failed 
4349                         if (status_osx 
== errSecItemNotFound 
|| status_ios 
== errSecItemNotFound
) 
4350                                 return errSecSuccess
; // item only found in one keychain 
4352                                 return (status_osx
) ? status_osx 
: status_ios
; // return the error 
4354                 else if (status_osx 
== errSecItemNotFound
) { 
4355                         // both updates failed, status_ios failure is more interesting 
4356                         // since the item was actually found 
4364 SecItemDelete(CFDictionaryRef query
) 
4366         secitemlog(LOG_NOTICE
, "SecItemDelete"); 
4370         secitemshow(query
, "SecItemDelete query:"); 
4372         OSStatus status_osx 
= errSecItemNotFound
, status_ios 
= errSecItemNotFound
; 
4373         Boolean sync_enabled 
= SecItemSyncEnabled(); 
4374         Boolean search_ios 
= SecItemSynchronizable(query
); 
4375         Boolean merge_search 
= SecItemSynchronizableAny(query
); 
4376         Boolean persistref_ios 
= SecItemHasSynchronizablePersistentReference(query
); 
4378         if (sync_enabled 
&& (merge_search 
|| persistref_ios 
|| search_ios
)) { 
4379                 CFDictionaryRef attrs_ios 
= SecItemCopyTranslatedAttributes(query
, 
4380                         NULL
, true, true, false, true, true, true); 
4382                         status_ios 
= errSecParam
; 
4385             SecItemUnlockSynchronizableKeychain(); 
4386             status_ios 
= SecItemDelete_ios(attrs_ios
); 
4387                         CFRelease(attrs_ios
); 
4389                 secitemlog(LOG_NOTICE
, "SecItemDelete_ios result: %d", status_ios
); 
4390                 if (!merge_search 
|| persistref_ios
) 
4394         CFDictionaryRef attrs_osx 
= SecItemCopyTranslatedAttributes(query
, 
4395                 NULL
, false, false, true, true, true, true); 
4397                 status_osx 
= errSecParam
; 
4400                 status_osx 
= SecItemDelete_osx(attrs_osx
); 
4401                 CFRelease(attrs_osx
); 
4403         secitemlog(LOG_NOTICE
, "SecItemDelete_osx result: %d", status_osx
); 
4406                 // Harmonize the result of the delete attempts. 
4407                 if (status_osx 
== status_ios
) { 
4408                         // both deletes produced the same result 
4411                 else if (!status_osx 
|| !status_ios
) { 
4412                         // one of the deletes succeeded, but the other failed 
4413                         if (status_osx 
== errSecItemNotFound 
|| status_ios 
== errSecItemNotFound
) 
4414                                 return errSecSuccess
; // item only found in one keychain 
4416                                 return (status_osx
) ? status_osx 
: status_ios
; // return the error 
4418                 else if (status_osx 
== errSecItemNotFound
) { 
4419                         // both deletes failed, status_ios failure is more interesting 
4420                         // since the item was actually found 
4428 SecItemCopyMatching_osx( 
4429         CFDictionaryRef query
, 
4432         if (!query 
|| !result
) 
4437         CFAllocatorRef allocator 
= CFGetAllocator(query
); 
4438         CFIndex matchCount 
= 0; 
4439         CFMutableArrayRef itemArray 
= NULL
; 
4440         SecKeychainItemRef item 
= NULL
; 
4441         SecIdentityRef identity 
= NULL
; 
4442         OSStatus tmpStatus
, status 
= errSecSuccess
; 
4444         // validate input query parameters and create the search reference 
4445         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(query
, &status
); 
4446         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
4448         // find the next match until we hit maxMatches, or no more matches found 
4449         while ( !(!itemParams
->returnAllMatches 
&& matchCount 
>= itemParams
->maxMatches
) && 
4450                         SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == errSecSuccess
) { 
4452                 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
)) 
4453                         continue; // move on to next item 
4455                 ++matchCount
; // we have a match 
4457                 tmpStatus 
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
); 
4458                 if (tmpStatus 
&& (status 
== errSecSuccess
)) 
4466                         CFRelease(identity
); 
4471         if (status 
== errSecSuccess
) 
4472                 status 
= (matchCount 
> 0) ? errSecSuccess 
: errSecItemNotFound
; 
4475         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
4479         _FreeSecItemParams(itemParams
); 
4485 SecItemCopyDisplayNames( 
4487         CFArrayRef 
*displayNames
) 
4491         Required(displayNames
); 
4493     return errSecUnimplemented
; 
4499         CFDictionaryRef attributes
, 
4507         CFAllocatorRef allocator 
= CFGetAllocator(attributes
); 
4508         CFMutableArrayRef itemArray 
= NULL
; 
4509         SecKeychainItemRef item 
= NULL
; 
4510         OSStatus tmpStatus
, status 
= errSecSuccess
; 
4512         // validate input attribute parameters 
4513         SecItemParams 
*itemParams 
= _CreateSecItemParamsFromDictionary(attributes
, &status
); 
4514         require_action(itemParams 
!= NULL
, error_exit
, itemParams 
= NULL
); 
4516         // currently, we don't support adding SecIdentityRef items (an aggregate item class), 
4517         // since the private key should already be in a keychain by definition. We could support 
4518         // this as a copy operation for the private key if a different keychain is specified, 
4519         // but in any case it should try to add the certificate. See <rdar://8317887>. 
4520         require_action(!itemParams
->returnIdentity
, error_exit
, status 
= errSecItemInvalidValue
); 
4522         if (!itemParams
->useItems
) { 
4523                 // create a single keychain item specified by the input attributes 
4524                 status 
= SecKeychainItemCreateFromContent(itemParams
->itemClass
, 
4525                         itemParams
->attrList
, 
4526                         (itemParams
->itemData
) ? (UInt32
)CFDataGetLength(itemParams
->itemData
) : 0, 
4527                         (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
, 
4528                         itemParams
->keychain
, 
4531                 require_noerr(status
, error_exit
); 
4533                 // return results (if requested) 
4535                         itemParams
->maxMatches 
= 1; // in case kSecMatchLimit was set to > 1 
4536                         tmpStatus 
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4537                         if (tmpStatus 
&& (status 
== errSecSuccess
)) 
4543                 // add multiple items which are specified in the itemParams->useItems array. 
4544                 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain. 
4545                 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain. 
4546                 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain. 
4548                 OSStatus aggregateStatus 
= errSecSuccess
; 
4549                 CFIndex ix
, count 
= CFArrayGetCount(itemParams
->useItems
); 
4550                 itemParams
->maxMatches 
= (count 
> 1) ? (int)count 
: 2; // force results to always be returned as an array 
4551                 for (ix
=0; ix 
< count
; ix
++) { 
4552                         CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
); 
4554                                 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) { 
4555                                         // SecCertificateRef item 
4556                                         tmpStatus 
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
); 
4557                                         if (!tmpStatus 
&& result
) { 
4558                                                 tmpStatus 
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4560                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4562                                 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) { 
4564                                         SecKeychainRef itemKeychain 
= NULL
; 
4565                                         tmpStatus 
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
); 
4566                                         if (tmpStatus 
== errSecSuccess
) { 
4567                                                 // key was in a keychain, so we can attempt to copy it 
4568                                                 SecKeychainItemRef itemCopy 
= NULL
; 
4569                                                 tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
4570                                                 if (!tmpStatus 
&& result
) { 
4571                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4574                                                         CFRelease(itemCopy
); 
4578                                                 // key was not in any keychain, so must be imported 
4579                                                 SecKeychainItemRef keyItem 
= NULL
; 
4580                                                 tmpStatus 
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
); 
4581                                                 if (!tmpStatus 
&& result
) { 
4582                                                         tmpStatus 
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4589                                                 CFRelease(itemKeychain
); 
4591                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4593                                 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) { 
4594                                         // SecKeychainItemRef item 
4595                                         SecKeychainItemRef itemCopy 
= NULL
; 
4596                                         tmpStatus 
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
4597                                         if (!tmpStatus 
&& result
) { 
4598                                                 tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4601                                                 CFRelease(itemCopy
); 
4603                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4605                                 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) { 
4606                                         // CFDataRef item (persistent reference) 
4607                                         SecKeychainItemRef realItem 
= NULL
; 
4608                                         tmpStatus 
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
); 
4609                                         if (tmpStatus 
== errSecSuccess
) { 
4610                                                 // persistent reference resolved to a keychain item, so we can attempt to copy it 
4611                                                 SecKeychainItemRef itemCopy 
= NULL
; 
4612                                                 tmpStatus 
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
); 
4613                                                 if (!tmpStatus 
&& result
) { 
4614                                                         tmpStatus 
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
); 
4617                                                         CFRelease(itemCopy
); 
4621                                                 CFRelease(realItem
); 
4623                                         aggregateStatus 
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
); 
4626                 } // end of itemList array loop 
4627                 status 
= aggregateStatus
; 
4628         } // end processing multiple items 
4631         if (status 
!= errSecSuccess 
&& result 
!= NULL 
&& *result 
!= NULL
) { 
4635         _FreeSecItemParams(itemParams
); 
4642         CFDictionaryRef query
, 
4643         CFDictionaryRef attributesToUpdate
) 
4645         if (!query 
|| !attributesToUpdate
) 
4648         // run the provided query to get a list of items to update 
4649         CFTypeRef results 
= NULL
; 
4650         OSStatus status 
= SecItemCopyMatching(query
, &results
); 
4651         if (status 
!= errSecSuccess
) 
4652                 return status
; // nothing was matched, or the query was bad 
4654         CFArrayRef items 
= NULL
; 
4655         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
4656                 items 
= (CFArrayRef
) results
; 
4659                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
4663         OSStatus result 
= errSecSuccess
; 
4664         CFIndex ix
, count 
= CFArrayGetCount(items
); 
4665         for (ix
=0; ix 
< count
; ix
++) { 
4666                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
4668                         status 
= _UpdateKeychainItem(anItem
, attributesToUpdate
); 
4669                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
); 
4681         CFDictionaryRef query
) 
4686         // run the provided query to get a list of items to delete 
4687         CFTypeRef results 
= NULL
; 
4688         OSStatus status 
= SecItemCopyMatching_osx(query
, &results
); 
4689         if (status 
!= errSecSuccess
) 
4690                 return status
; // nothing was matched, or the query was bad 
4692         CFArrayRef items 
= NULL
; 
4693         if (CFArrayGetTypeID() == CFGetTypeID(results
)) { 
4694                 items 
= (CFArrayRef
) results
; 
4697                 items 
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
); 
4701         OSStatus result 
= errSecSuccess
; 
4702         CFIndex ix
, count 
= CFArrayGetCount(items
); 
4703         for (ix
=0; ix 
< count
; ix
++) { 
4704                 CFTypeRef anItem 
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
); 
4706                         if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) { 
4707                                 status 
= _DeleteIdentity((SecIdentityRef
)anItem
); 
4710                                 status 
= _DeleteKeychainItem(anItem
); 
4712                         result 
= _UpdateAggregateStatus(status
, result
, errSecSuccess
);