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
);