2 * Copyright (c) 2006-2010,2012 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "SecBridge.h"
25 #include <security_utilities/cfutilities.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <Security/SecKeychainItem.h>
28 #include <Security/SecCertificate.h>
29 #include <sys/param.h>
30 #include "cssmdatetime.h"
32 #include "SecItemPriv.h"
33 #include "SecIdentitySearchPriv.h"
34 #include "SecCertificatePriv.h"
35 #include "SecCertificatePrivP.h"
36 #include "TrustAdditions.h"
38 #include <AssertMacros.h>
40 OSStatus
SecItemAdd_osx(CFDictionaryRef attributes
, CFTypeRef
*result
);
41 OSStatus
SecItemCopyMatching_osx(CFDictionaryRef query
, CFTypeRef
*result
);
42 OSStatus
SecItemUpdate_osx(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
);
43 OSStatus
SecItemDelete_osx(CFDictionaryRef query
);
46 OSStatus
SecItemAdd_ios(CFDictionaryRef attributes
, CFTypeRef
*result
);
47 OSStatus
SecItemCopyMatching_ios(CFDictionaryRef query
, CFTypeRef
*result
);
48 OSStatus
SecItemUpdate_ios(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
);
49 OSStatus
SecItemDelete_ios(CFDictionaryRef query
);
53 #define CFDataGetBytePtrVoid CFDataGetBytePtr
55 #pragma mark SecItem private utility functions
57 /******************************************************************************/
59 struct ProtocolAttributeInfo
{
60 const CFTypeRef
*protocolValue
;
61 SecProtocolType protocolType
;
64 static ProtocolAttributeInfo gProtocolTypes
[] = {
65 { &kSecAttrProtocolFTP
, kSecProtocolTypeFTP
},
66 { &kSecAttrProtocolFTPAccount
, kSecProtocolTypeFTPAccount
},
67 { &kSecAttrProtocolHTTP
, kSecProtocolTypeHTTP
},
68 { &kSecAttrProtocolIRC
, kSecProtocolTypeIRC
},
69 { &kSecAttrProtocolNNTP
, kSecProtocolTypeNNTP
},
70 { &kSecAttrProtocolPOP3
, kSecProtocolTypePOP3
},
71 { &kSecAttrProtocolSMTP
, kSecProtocolTypeSMTP
},
72 { &kSecAttrProtocolSOCKS
, kSecProtocolTypeSOCKS
},
73 { &kSecAttrProtocolIMAP
, kSecProtocolTypeIMAP
},
74 { &kSecAttrProtocolLDAP
, kSecProtocolTypeLDAP
},
75 { &kSecAttrProtocolAppleTalk
, kSecProtocolTypeAppleTalk
},
76 { &kSecAttrProtocolAFP
, kSecProtocolTypeAFP
},
77 { &kSecAttrProtocolTelnet
, kSecProtocolTypeTelnet
},
78 { &kSecAttrProtocolSSH
, kSecProtocolTypeSSH
},
79 { &kSecAttrProtocolFTPS
, kSecProtocolTypeFTPS
},
80 { &kSecAttrProtocolHTTPS
, kSecProtocolTypeHTTPS
},
81 { &kSecAttrProtocolHTTPProxy
, kSecProtocolTypeHTTPProxy
},
82 { &kSecAttrProtocolHTTPSProxy
, kSecProtocolTypeHTTPSProxy
},
83 { &kSecAttrProtocolFTPProxy
, kSecProtocolTypeFTPProxy
},
84 { &kSecAttrProtocolSMB
, kSecProtocolTypeSMB
},
85 { &kSecAttrProtocolRTSP
, kSecProtocolTypeRTSP
},
86 { &kSecAttrProtocolRTSPProxy
, kSecProtocolTypeRTSPProxy
},
87 { &kSecAttrProtocolDAAP
, kSecProtocolTypeDAAP
},
88 { &kSecAttrProtocolEPPC
, kSecProtocolTypeEPPC
},
89 { &kSecAttrProtocolIPP
, kSecProtocolTypeIPP
},
90 { &kSecAttrProtocolNNTPS
, kSecProtocolTypeNNTPS
},
91 { &kSecAttrProtocolLDAPS
, kSecProtocolTypeLDAPS
},
92 { &kSecAttrProtocolTelnetS
, kSecProtocolTypeTelnetS
},
93 { &kSecAttrProtocolIMAPS
, kSecProtocolTypeIMAPS
},
94 { &kSecAttrProtocolIRCS
, kSecProtocolTypeIRCS
},
95 { &kSecAttrProtocolPOP3S
, kSecProtocolTypePOP3S
}
98 static const int kNumberOfProtocolTypes
= sizeof(gProtocolTypes
) / sizeof(ProtocolAttributeInfo
);
101 * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType.
103 static SecProtocolType
104 _SecProtocolTypeForSecAttrProtocol(
107 SecProtocolType result
= kSecProtocolTypeAny
;
109 if (protocol
!= NULL
) {
111 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) {
112 if (CFEqual(protocol
, *(gProtocolTypes
[count
].protocolValue
))) {
113 result
= gProtocolTypes
[count
].protocolType
;
123 * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol.
126 _SecAttrProtocolForSecProtocolType(
127 SecProtocolType protocolType
)
129 CFTypeRef result
= NULL
;
131 for (count
=0; count
<kNumberOfProtocolTypes
; count
++) {
132 if (gProtocolTypes
[count
].protocolType
== protocolType
) {
133 result
= *(gProtocolTypes
[count
].protocolValue
);
142 /******************************************************************************/
144 struct AuthenticationAttributeInfo
{
145 const CFTypeRef
*authValue
;
146 SecAuthenticationType authType
;
149 static AuthenticationAttributeInfo gAuthTypes
[] = {
150 { &kSecAttrAuthenticationTypeNTLM
, kSecAuthenticationTypeNTLM
},
151 { &kSecAttrAuthenticationTypeMSN
, kSecAuthenticationTypeMSN
},
152 { &kSecAttrAuthenticationTypeDPA
, kSecAuthenticationTypeDPA
},
153 { &kSecAttrAuthenticationTypeRPA
, kSecAuthenticationTypeRPA
},
154 { &kSecAttrAuthenticationTypeHTTPBasic
, kSecAuthenticationTypeHTTPBasic
},
155 { &kSecAttrAuthenticationTypeHTTPDigest
, kSecAuthenticationTypeHTTPDigest
},
156 { &kSecAttrAuthenticationTypeHTMLForm
, kSecAuthenticationTypeHTMLForm
},
157 { &kSecAttrAuthenticationTypeDefault
, kSecAuthenticationTypeDefault
}
160 static const int kNumberOfAuthenticationTypes
= sizeof(gAuthTypes
) / sizeof(AuthenticationAttributeInfo
);
163 * _SecAuthenticationTypeForSecAttrAuthenticationType converts a
164 * SecAttrAuthenticationType to a SecAuthenticationType.
166 static SecAuthenticationType
167 _SecAuthenticationTypeForSecAttrAuthenticationType(
168 CFTypeRef authenticationType
)
170 SecAuthenticationType result
= kSecAuthenticationTypeAny
;
172 if (authenticationType
!= NULL
) {
174 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) {
175 if (CFEqual(authenticationType
, *(gAuthTypes
[count
].authValue
))) {
176 result
= gAuthTypes
[count
].authType
;
186 * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType
187 * to a SecAttrAuthenticationType.
190 _SecAttrAuthenticationTypeForSecAuthenticationType(
191 SecAuthenticationType authenticationType
)
193 CFTypeRef result
= NULL
;
195 for (count
=0; count
<kNumberOfAuthenticationTypes
; count
++) {
196 if (gAuthTypes
[count
].authType
== authenticationType
) {
197 result
= *(gAuthTypes
[count
].authValue
);
206 /******************************************************************************/
208 struct KeyAlgorithmInfo
{
209 const CFTypeRef
*keyType
;
213 static KeyAlgorithmInfo gKeyTypes
[] = {
214 { &kSecAttrKeyTypeRSA
, CSSM_ALGID_RSA
},
215 { &kSecAttrKeyTypeDSA
, CSSM_ALGID_DSA
},
216 { &kSecAttrKeyTypeAES
, CSSM_ALGID_AES
},
217 { &kSecAttrKeyTypeDES
, CSSM_ALGID_DES
},
218 { &kSecAttrKeyType3DES
, CSSM_ALGID_3DES
},
219 { &kSecAttrKeyTypeRC4
, CSSM_ALGID_RC4
},
220 { &kSecAttrKeyTypeRC2
, CSSM_ALGID_RC2
},
221 { &kSecAttrKeyTypeCAST
, CSSM_ALGID_CAST
},
222 { &kSecAttrKeyTypeECDSA
, CSSM_ALGID_ECDSA
}
225 static const int kNumberOfKeyTypes
= sizeof(gKeyTypes
) / sizeof (KeyAlgorithmInfo
);
228 static UInt32
_SecAlgorithmTypeFromSecAttrKeyType(
229 CFTypeRef keyTypeRef
)
231 UInt32 keyAlgValue
= 0;
232 if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef
))
236 for (ix
=0; ix
<kNumberOfKeyTypes
; ix
++) {
237 if (CFEqual(keyTypeRef
, *(gKeyTypes
[ix
].keyType
))) {
238 keyAlgValue
= gKeyTypes
[ix
].keyValue
;
243 //%%%TODO try to convert the input string to a number here
249 enum ItemRepresentation
251 kStringRepresentation
,
253 kNumberRepresentation
,
254 kBooleanRepresentation
,
259 struct InternalAttributeListInfo
262 const CFTypeRef
*newItemType
;
263 ItemRepresentation itemRepresentation
;
267 static InternalAttributeListInfo gGenericPasswordAttributes
[] =
269 { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation
},
270 { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation
},
271 { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation
},
272 { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation
},
273 { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation
}, // UInt32, a.k.a. FourCharCode
274 { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation
}, // UInt32, a.k.a. FourCharCode
275 { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation
},
276 { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation
},
277 { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation
},
278 { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation
},
279 { kSecServiceItemAttr
, &kSecAttrService
, kStringRepresentation
},
280 { kSecGenericItemAttr
, &kSecAttrGeneric
, kDataRepresentation
}
283 static const int kNumberOfGenericPasswordAttributes
= sizeof(gGenericPasswordAttributes
) / sizeof (InternalAttributeListInfo
);
286 static InternalAttributeListInfo gInternetPasswordAttributes
[] =
288 { kSecCreationDateItemAttr
, &kSecAttrCreationDate
, kDateRepresentation
},
289 { kSecModDateItemAttr
, &kSecAttrModificationDate
, kDateRepresentation
},
290 { kSecDescriptionItemAttr
, &kSecAttrDescription
, kStringRepresentation
},
291 { kSecCommentItemAttr
, &kSecAttrComment
, kStringRepresentation
},
292 { kSecCreatorItemAttr
, &kSecAttrCreator
, kNumberRepresentation
}, // UInt32, a.k.a. FourCharCode
293 { kSecTypeItemAttr
, &kSecAttrType
, kNumberRepresentation
}, // UInt32, a.k.a. FourCharCode
294 { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation
},
295 { kSecInvisibleItemAttr
, &kSecAttrIsInvisible
, kBooleanRepresentation
},
296 { kSecNegativeItemAttr
, &kSecAttrIsNegative
, kBooleanRepresentation
},
297 { kSecAccountItemAttr
, &kSecAttrAccount
, kStringRepresentation
},
298 { kSecSecurityDomainItemAttr
, &kSecAttrSecurityDomain
, kStringRepresentation
},
299 { kSecServerItemAttr
, &kSecAttrServer
, kStringRepresentation
},
300 { kSecAuthenticationTypeItemAttr
, &kSecAttrAuthenticationType
, kStringRepresentation
}, // maps from UInt32 value to string constant
301 { kSecPortItemAttr
, &kSecAttrPort
, kNumberRepresentation
},
302 { kSecPathItemAttr
, &kSecAttrPath
, kStringRepresentation
}
305 static const int kNumberOfInternetPasswordAttributes
= sizeof(gInternetPasswordAttributes
) / sizeof (InternalAttributeListInfo
);
308 static InternalAttributeListInfo gCertificateAttributes
[] =
310 { kSecLabelItemAttr
, &kSecAttrLabel
, kStringRepresentation
},
311 { kSecSubjectItemAttr
, &kSecAttrSubject
, kDataRepresentation
},
312 { kSecIssuerItemAttr
, &kSecAttrIssuer
, kDataRepresentation
},
313 { kSecSerialNumberItemAttr
, &kSecAttrSerialNumber
, kDataRepresentation
},
314 { kSecPublicKeyHashItemAttr
, &kSecAttrPublicKeyHash
, kDataRepresentation
},
315 { kSecSubjectKeyIdentifierItemAttr
, &kSecAttrSubjectKeyID
, kDataRepresentation
},
316 { kSecCertTypeItemAttr
, &kSecAttrCertificateType
, kDataRepresentation
},
317 { kSecCertEncodingItemAttr
, &kSecAttrCertificateEncoding
, kDataRepresentation
}
320 static const int kNumberOfCertificateAttributes
= sizeof(gCertificateAttributes
) / sizeof(InternalAttributeListInfo
);
323 static InternalAttributeListInfo gKeyAttributes
[] =
325 { kSecKeyKeyClass
, &kSecAttrKeyClass
, kStringRepresentation
}, // key class maps from UInt32 value to string constant
326 { kSecKeyPrintName
, &kSecAttrLabel
, kStringRepresentation
}, // note that "print name" maps to the user-visible label
327 // { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation },
328 { kSecKeyPermanent
, &kSecAttrIsPermanent
, kBooleanRepresentation
},
329 // { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation },
330 // { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation },
331 { kSecKeyLabel
, &kSecAttrApplicationLabel
, kStringRepresentation
}, // this contains the hash of the key (or the public key hash, if asymmetric)
332 { kSecKeyApplicationTag
, &kSecAttrApplicationTag
, kDataRepresentation
},
333 // { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key
334 { kSecKeyKeyType
, &kSecAttrKeyType
, kStringRepresentation
}, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES)
335 { kSecKeyKeySizeInBits
, &kSecAttrKeySizeInBits
, kNumberRepresentation
},
336 { kSecKeyEffectiveKeySize
, &kSecAttrEffectiveKeySize
, kNumberRepresentation
},
337 // { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation },
338 // { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation },
339 // { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation },
340 // { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation },
341 // { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation },
342 // { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation },
343 { kSecKeyEncrypt
, &kSecAttrCanEncrypt
, kBooleanRepresentation
},
344 { kSecKeyDecrypt
, &kSecAttrCanDecrypt
, kBooleanRepresentation
},
345 { kSecKeyDerive
, &kSecAttrCanDerive
, kBooleanRepresentation
},
346 { kSecKeySign
, &kSecAttrCanSign
, kBooleanRepresentation
},
347 { kSecKeyVerify
, &kSecAttrCanVerify
, kBooleanRepresentation
},
348 // { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation },
349 // { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation },
350 { kSecKeyWrap
, &kSecAttrCanWrap
, kBooleanRepresentation
},
351 { kSecKeyUnwrap
, &kSecAttrCanUnwrap
, kBooleanRepresentation
}
354 static const int kNumberOfKeyAttributes
= sizeof(gKeyAttributes
) / sizeof(InternalAttributeListInfo
);
357 static void* CloneDataByType(ItemRepresentation type
, CFTypeRef value
, UInt32
& length
)
361 case kStringRepresentation
:
363 if (CFStringGetTypeID() != CFGetTypeID(value
)) {
367 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
) value
), kCFStringEncodingUTF8
) + 1;
368 char* buffer
= (char*) malloc(maxLength
);
369 Boolean converted
= CFStringGetCString((CFStringRef
) value
, buffer
, maxLength
, kCFStringEncodingUTF8
);
371 length
= strlen(buffer
);
381 case kDataRepresentation
:
383 if (CFDataGetTypeID() != CFGetTypeID(value
)) {
387 length
= CFDataGetLength((CFDataRef
) value
);
388 uint8_t* buffer
= (uint8_t*) malloc(length
);
389 CFDataGetBytes((CFDataRef
) value
, CFRangeMake(0, length
), buffer
);
393 case kNumberRepresentation
:
395 if (CFNumberGetTypeID() != CFGetTypeID(value
)) {
399 uint32_t* buffer
= (uint32_t*) malloc(sizeof(uint32_t));
400 Boolean converted
= CFNumberGetValue((CFNumberRef
) value
, kCFNumberSInt32Type
, buffer
);
402 length
= sizeof(uint32_t);
412 case kBooleanRepresentation
:
414 if (CFBooleanGetTypeID() != CFGetTypeID(value
)) {
418 uint32_t* buffer
= (uint32_t*) malloc(sizeof(uint32_t));
419 *buffer
= (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
420 length
= sizeof(uint32_t);
424 case kDateRepresentation
:
426 if (CFDateGetTypeID() != CFGetTypeID(value
)) {
430 char* buffer
= (char*) calloc(1, 32); // max length of a CSSM date string
431 CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef
) value
, buffer
);
432 length
= strlen(buffer
);
446 _ConvertNewFormatToOldFormat(
447 CFAllocatorRef allocator
,
448 const InternalAttributeListInfo
* info
,
450 CFDictionaryRef dictionaryRef
,
451 SecKeychainAttributeList
* &attrList
454 // get the keychain attributes array from the data item
455 // here's the problem. On the one hand, we have a dictionary that is purported to contain
456 // attributes for our type. On the other hand, the dictionary may contain items we don't support,
457 // and we therefore don't know how many attributes we will have unless we count them first
460 attrList
= (SecKeychainAttributeList
*) calloc(1, sizeof(SecKeychainAttributeList
));
462 // make storage to extract the dictionary items
463 int itemsInDictionary
= CFDictionaryGetCount(dictionaryRef
);
464 CFTypeRef keys
[itemsInDictionary
];
465 CFTypeRef values
[itemsInDictionary
];
467 CFTypeRef
*keysPtr
= keys
;
468 CFTypeRef
*valuesPtr
= values
;
470 CFDictionaryGetKeysAndValues(dictionaryRef
, keys
, values
);
472 // count the number of items we are interested in
476 // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that
477 // we don't pay the price for this twice
478 SecKeychainAttrType tags
[itemsInDictionary
];
479 ItemRepresentation types
[itemsInDictionary
];
481 for (i
= 0; i
< itemsInDictionary
; ++i
)
483 CFTypeRef key
= keysPtr
[i
];
486 for (j
= 0; j
< infoNumItems
; ++j
)
488 if (CFEqual(*(info
[j
].newItemType
), key
))
490 tags
[i
] = info
[j
].oldItemType
;
491 types
[i
] = info
[j
].itemRepresentation
;
497 if (j
>= infoNumItems
)
499 // if we got here, we aren't interested in this item.
504 // now we can make the result array
505 attrList
->count
= count
;
506 attrList
->attr
= (SecKeychainAttribute
*) malloc(sizeof(SecKeychainAttribute
) * count
);
508 // fill out the array
509 int resultPointer
= 0;
510 for (i
= 0; i
< itemsInDictionary
; ++i
)
512 if (values
[i
] != NULL
)
514 attrList
->attr
[resultPointer
].tag
= tags
[i
];
516 // we have to clone the data pointer. The caller will need to make sure to throw these away
517 // with _FreeAttrList when it is done...
518 attrList
->attr
[resultPointer
].data
= CloneDataByType(types
[i
], valuesPtr
[i
], attrList
->attr
[resultPointer
].length
);
529 _ConvertOldFormatToNewFormat(
530 CFAllocatorRef allocator
,
531 const InternalAttributeListInfo
* info
,
533 SecKeychainItemRef itemRef
,
534 CFMutableDictionaryRef
& dictionaryRef
)
536 SecKeychainAttributeList list
;
537 list
.count
= infoNumItems
;
538 list
.attr
= (SecKeychainAttribute
*) calloc(infoNumItems
, sizeof(SecKeychainAttribute
));
540 // fill out the array. We only need to fill in the tags, since calloc zeros what it returns
542 for (i
= 0; i
< infoNumItems
; ++i
)
544 list
.attr
[i
].tag
= info
[i
].oldItemType
;
547 OSStatus result
= SecKeychainItemCopyContent(itemRef
, NULL
, &list
, NULL
, NULL
);
550 dictionaryRef
= NULL
;
555 // create the dictionary
556 dictionaryRef
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
559 for (i
= 0; i
< infoNumItems
; ++i
)
561 if (list
.attr
[i
].data
== NULL
)
564 switch (info
[i
].itemRepresentation
)
566 case kStringRepresentation
:
568 CFStringRef stringRef
;
569 if (info
[i
].oldItemType
== kSecKeyKeyClass
) {
570 // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant
571 uint32_t keyRecordValue
= *((uint32_t*)list
.attr
[i
].data
);
572 bool retainString
= true;
573 switch (keyRecordValue
) {
574 case CSSM_DL_DB_RECORD_PUBLIC_KEY
:
575 stringRef
= (CFStringRef
) kSecAttrKeyClassPublic
;
577 case CSSM_DL_DB_RECORD_PRIVATE_KEY
:
578 stringRef
= (CFStringRef
) kSecAttrKeyClassPrivate
;
580 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
:
581 stringRef
= (CFStringRef
) kSecAttrKeyClassSymmetric
;
584 stringRef
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
);
588 if (retainString
) CFRetain(stringRef
);
589 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
);
590 CFRelease(stringRef
);
593 else if (info
[i
].oldItemType
== kSecKeyKeyType
) {
594 // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant
595 uint32_t keyAlgValue
= *((uint32_t*)list
.attr
[i
].data
);
596 bool retainString
= true;
597 switch (keyAlgValue
) {
598 case CSSM_ALGID_RSA
:
599 stringRef
= (CFStringRef
) kSecAttrKeyTypeRSA
;
601 case CSSM_ALGID_DSA
:
602 stringRef
= (CFStringRef
) kSecAttrKeyTypeDSA
;
604 case CSSM_ALGID_AES
:
605 stringRef
= (CFStringRef
) kSecAttrKeyTypeAES
;
607 case CSSM_ALGID_DES
:
608 stringRef
= (CFStringRef
) kSecAttrKeyTypeDES
;
610 case CSSM_ALGID_3DES
:
611 stringRef
= (CFStringRef
) kSecAttrKeyType3DES
;
613 case CSSM_ALGID_RC4
:
614 stringRef
= (CFStringRef
) kSecAttrKeyTypeRC4
;
616 case CSSM_ALGID_RC2
:
617 stringRef
= (CFStringRef
) kSecAttrKeyTypeRC2
;
619 case CSSM_ALGID_CAST
:
620 stringRef
= (CFStringRef
) kSecAttrKeyTypeCAST
;
622 case CSSM_ALGID_ECDSA
:
623 stringRef
= (CFStringRef
) kSecAttrKeyTypeECDSA
;
626 stringRef
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
);
627 retainString
= false;
631 if (retainString
) CFRetain(stringRef
);
632 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
);
633 CFRelease(stringRef
);
637 // normal case: attribute contains a string
638 stringRef
= CFStringCreateWithBytes(allocator
, (UInt8
*)list
.attr
[i
].data
, list
.attr
[i
].length
, kCFStringEncodingUTF8
, FALSE
);
639 if (stringRef
== NULL
)
640 stringRef
= (CFStringRef
) CFRetain(kCFNull
);
641 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), stringRef
);
642 CFRelease(stringRef
);
647 case kDataRepresentation
:
649 CFDataRef dataRef
= CFDataCreate(allocator
, (UInt8
*) list
.attr
[i
].data
, list
.attr
[i
].length
);
651 dataRef
= (CFDataRef
) CFRetain(kCFNull
);
652 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dataRef
);
657 case kNumberRepresentation
:
659 CFNumberRef numberRef
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, list
.attr
[i
].data
);
660 if (numberRef
== NULL
)
661 numberRef
= (CFNumberRef
) CFRetain(kCFNull
);
662 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), numberRef
);
663 CFRelease(numberRef
);
667 case kBooleanRepresentation
:
669 uint32_t value
= *((uint32_t*)list
.attr
[i
].data
);
670 CFBooleanRef boolRef
= (value
) ? kCFBooleanTrue
: kCFBooleanFalse
;
671 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), boolRef
);
675 case kDateRepresentation
:
677 CFDateRef dateRef
= NULL
;
678 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list
.attr
[i
].data
, list
.attr
[i
].length
, &dateRef
);
680 dateRef
= (CFDateRef
) CFRetain(kCFNull
);
681 CFDictionaryAddValue(dictionaryRef
, *(info
[i
].newItemType
), dateRef
);
689 SecKeychainItemFreeContent(&list
, NULL
);
699 * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the
700 * attributes of item.
703 _CreateAttributesDictionaryFromGenericPasswordItem(
704 CFAllocatorRef allocator
,
705 SecKeychainItemRef item
,
706 CFDictionaryRef
*dictionary
)
708 // do the basic allocations
709 CFMutableDictionaryRef dict
= NULL
;
710 OSStatus result
= _ConvertOldFormatToNewFormat(allocator
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, item
, dict
);
711 if (result
== noErr
) // did we complete OK
713 CFDictionaryAddValue(dict
, kSecClass
, kSecClassGenericPassword
);
724 * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the
725 * attributes of item.
728 _CreateAttributesDictionaryFromCertificateItem(
729 CFAllocatorRef allocator
,
730 SecKeychainItemRef item
,
731 CFDictionaryRef
*dictionary
)
733 // do the basic allocations
734 CFMutableDictionaryRef dict
= NULL
;
735 OSStatus result
= _ConvertOldFormatToNewFormat(allocator
, gCertificateAttributes
, kNumberOfCertificateAttributes
, item
, dict
);
736 if (result
== noErr
) // did we complete OK
738 CFDictionaryAddValue(dict
, kSecClass
, kSecClassCertificate
);
747 * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the
748 * attributes of item.
751 _CreateAttributesDictionaryFromKeyItem(
752 CFAllocatorRef allocator
,
753 SecKeychainItemRef item
,
754 CFDictionaryRef
*dictionary
)
757 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails.
758 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and
759 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent.
762 goto error_exit
; // unable to get the attribute info (i.e. database schema)
765 status
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
);
767 // do the basic allocations
768 CFMutableDictionaryRef dict
= NULL
;
769 OSStatus result
= _ConvertOldFormatToNewFormat(allocator
, gKeyAttributes
, kNumberOfKeyAttributes
, item
, dict
);
770 if (result
== noErr
) // did we complete OK
772 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
);
780 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
782 SecItemClass itemClass
= 0;
784 SecKeychainAttributeList
*attrList
= NULL
;
785 SecKeychainAttributeInfo
*info
= NULL
;
786 SecKeychainRef keychain
= NULL
;
788 OSStatus status
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
);
790 goto error_exit
; // item must have an itemClass
795 case kSecInternetPasswordItemClass
:
796 itemID
= CSSM_DL_DB_RECORD_INTERNET_PASSWORD
;
798 case kSecGenericPasswordItemClass
:
799 itemID
= CSSM_DL_DB_RECORD_GENERIC_PASSWORD
;
801 case kSecAppleSharePasswordItemClass
:
802 itemID
= CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
;
809 status
= SecKeychainItemCopyKeychain(item
, &keychain
);
811 goto error_exit
; // item must have a keychain, so we can get the attribute info for it
814 status
= SecKeychainAttributeInfoForItemID(keychain
, itemID
, &info
);
816 goto error_exit
; // unable to get the attribute info (i.e. database schema)
819 status
= SecKeychainItemCopyAttributesAndData(item
, info
, &itemClass
, &attrList
, NULL
, NULL
);
821 goto error_exit
; // unable to get the attribute info (i.e. database schema)
824 for (ix
= 0; ix
< info
->count
; ++ix
)
826 SecKeychainAttribute
*attribute
= &attrList
->attr
[ix
];
827 if (!attribute
->length
&& !attribute
->data
)
830 UInt32 j
, count
= kNumberOfKeyAttributes
;
831 InternalAttributeListInfo
*intInfo
= NULL
;
832 for (j
=0; j
<count
; j
++) {
833 if (gKeyAttributes
[j
].oldItemType
== info
->tag
[ix
]) {
834 intInfo
= &gKeyAttributes
[j
];
841 switch (intInfo
->itemRepresentation
)
843 case kStringRepresentation
:
845 CFStringRef stringRef
;
846 if (intInfo
->oldItemType
== kSecKeyKeyClass
) {
847 // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant
848 UInt32 keyRecordValue
= *((UInt32
*)attribute
->data
);
849 bool retainString
= true;
850 switch (keyRecordValue
) {
851 case CSSM_DL_DB_RECORD_PUBLIC_KEY
:
852 stringRef
= (CFStringRef
) kSecAttrKeyClassPublic
;
854 case CSSM_DL_DB_RECORD_PRIVATE_KEY
:
855 stringRef
= (CFStringRef
) kSecAttrKeyClassPrivate
;
857 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
:
858 stringRef
= (CFStringRef
) kSecAttrKeyClassSymmetric
;
861 stringRef
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyRecordValue
);
865 if (retainString
) CFRetain(stringRef
);
866 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
);
867 CFRelease(stringRef
);
870 else if (intInfo
->oldItemType
== kSecKeyKeyType
) {
871 // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant
872 UInt32 keyAlgValue
= *((UInt32
*)attribute
->data
);
873 bool retainString
= true;
874 switch (keyAlgValue
) {
875 case CSSM_ALGID_RSA
:
876 stringRef
= (CFStringRef
) kSecAttrKeyTypeRSA
;
878 case CSSM_ALGID_DSA
:
879 stringRef
= (CFStringRef
) kSecAttrKeyTypeDSA
;
881 case CSSM_ALGID_AES
:
882 stringRef
= (CFStringRef
) kSecAttrKeyTypeAES
;
884 case CSSM_ALGID_DES
:
885 stringRef
= (CFStringRef
) kSecAttrKeyTypeDES
;
887 case CSSM_ALGID_3DES
:
888 stringRef
= (CFStringRef
) kSecAttrKeyType3DES
;
890 case CSSM_ALGID_RC4
:
891 stringRef
= (CFStringRef
) kSecAttrKeyTypeRC4
;
893 case CSSM_ALGID_RC2
:
894 stringRef
= (CFStringRef
) kSecAttrKeyTypeRC2
;
896 case CSSM_ALGID_CAST
:
897 stringRef
= (CFStringRef
) kSecAttrKeyTypeCAST
;
899 case CSSM_ALGID_ECDSA
:
900 stringRef
= (CFStringRef
) kSecAttrKeyTypeECDSA
;
903 stringRef
= CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%d"), keyAlgValue
);
904 retainString
= false;
908 if (retainString
) CFRetain(stringRef
);
909 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
);
910 CFRelease(stringRef
);
914 // normal case: attribute contains a string
915 stringRef
= CFStringCreateWithBytes(allocator
, (UInt8
*)attribute
->data
, attribute
->length
, kCFStringEncodingUTF8
, FALSE
);
916 if (stringRef
== NULL
)
917 stringRef
= (CFStringRef
) CFRetain(kCFNull
);
918 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), stringRef
);
919 CFRelease(stringRef
);
924 case kDataRepresentation
:
926 CFDataRef dataRef
= CFDataCreate(allocator
, (UInt8
*)attribute
->data
, attribute
->length
);
928 dataRef
= (CFDataRef
) CFRetain(kCFNull
);
929 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dataRef
);
934 case kNumberRepresentation
:
936 CFNumberRef numberRef
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attribute
->data
);
937 if (numberRef
== NULL
)
938 numberRef
= (CFNumberRef
) CFRetain(kCFNull
);
939 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), numberRef
);
940 CFRelease(numberRef
);
944 case kBooleanRepresentation
:
946 UInt32 value
= *((UInt32
*)attribute
->data
);
947 CFBooleanRef boolRef
= (value
) ? kCFBooleanTrue
: kCFBooleanFalse
;
948 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), boolRef
);
952 case kDateRepresentation
:
954 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here
955 CFDateRef dateRef
= NULL
;
957 dateRef
= (CFDateRef
) CFRetain(kCFNull
);
958 CFDictionaryAddValue(dict
, *(intInfo
->newItemType
), dateRef
);
965 CFDictionaryAddValue(dict
, kSecClass
, kSecClassKey
);
970 SecKeychainItemFreeAttributesAndData(attrList
, NULL
);
973 SecKeychainFreeAttributeInfo(info
);
985 * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the
986 * attributes of item.
989 _CreateAttributesDictionaryFromInternetPasswordItem(
990 CFAllocatorRef allocator
,
991 SecKeychainItemRef item
,
992 CFDictionaryRef
*dictionary
)
995 SecKeychainAttribute attr
[] = {
996 { kSecServerItemAttr
, 0, NULL
}, /* [0] server */
997 { kSecSecurityDomainItemAttr
, 0, NULL
}, /* [1] securityDomain */
998 { kSecAccountItemAttr
, 0, NULL
}, /* [2] account */
999 { kSecPathItemAttr
, 0, NULL
}, /* [3] path */
1000 { kSecPortItemAttr
, 0, NULL
}, /* [4] port */
1001 { kSecProtocolItemAttr
, 0, NULL
}, /* [5] protocol */
1002 { kSecAuthenticationTypeItemAttr
, 0, NULL
}, /* [6] authenticationType */
1003 { kSecCommentItemAttr
, 0, NULL
}, /* [7] comment */
1004 { kSecDescriptionItemAttr
, 0, NULL
}, /* [8] description */
1005 { kSecLabelItemAttr
, 0, NULL
}, /* [9] label */
1006 { kSecCreationDateItemAttr
, 0, NULL
}, /* [10] creation date */
1007 { kSecModDateItemAttr
, 0, NULL
}, /* [11] modification date */
1008 { kSecCreatorItemAttr
, 0, NULL
}, /* [12] creator */
1009 { kSecTypeItemAttr
, 0, NULL
}, /* [13] type */
1010 { kSecInvisibleItemAttr
, 0, NULL
}, /* [14] invisible */
1011 { kSecNegativeItemAttr
, 0, NULL
}, /* [15] negative */
1013 SecKeychainAttributeList attrList
= { sizeof(attr
) / sizeof(SecKeychainAttribute
), attr
};
1016 CFTypeRef keys
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2];
1017 CFTypeRef values
[(sizeof(attr
) / sizeof(SecKeychainAttribute
)) + 2];
1021 // copy the item's attributes
1022 status
= SecKeychainItemCopyContent(item
, NULL
, &attrList
, NULL
, NULL
);
1023 require_noerr(status
, SecKeychainItemCopyContent_failed
);
1028 keys
[numValues
] = kSecClass
;
1029 values
[numValues
] = kSecClassInternetPassword
;
1032 // add kSecAttrServer
1033 if ( attrList
.attr
[0].length
> 0 ) {
1034 keys
[numValues
] = kSecAttrServer
;
1035 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[0].data
, attrList
.attr
[0].length
, kCFStringEncodingUTF8
, FALSE
);
1036 if ( values
[numValues
] != NULL
) {
1041 // add kSecAttrSecurityDomain
1042 if ( attrList
.attr
[1].length
> 0 ) {
1043 keys
[numValues
] = kSecAttrSecurityDomain
;
1044 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[1].data
, attrList
.attr
[1].length
, kCFStringEncodingUTF8
, FALSE
);
1045 if ( values
[numValues
] != NULL
) {
1050 // add kSecAttrAccount
1051 if ( attrList
.attr
[2].length
> 0 ) {
1052 keys
[numValues
] = kSecAttrAccount
;
1053 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[2].data
, attrList
.attr
[2].length
, kCFStringEncodingUTF8
, FALSE
);
1054 if ( values
[numValues
] != NULL
) {
1060 if ( attrList
.attr
[3].length
> 0 ) {
1061 keys
[numValues
] = kSecAttrPath
;
1062 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[3].data
, attrList
.attr
[3].length
, kCFStringEncodingUTF8
, FALSE
);
1063 if ( values
[numValues
] != NULL
) {
1069 if ( attrList
.attr
[4].length
> 0 ) {
1070 keys
[numValues
] = kSecAttrPort
;
1071 values
[numValues
] = CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[4].data
);
1072 if ( values
[numValues
] != NULL
) {
1077 // add kSecAttrProtocol
1078 if ( attrList
.attr
[5].length
> 0 ) {
1079 keys
[numValues
] = kSecAttrProtocol
;
1080 values
[numValues
] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType
*)attrList
.attr
[5].data
);
1081 if ( values
[numValues
] != NULL
) {
1082 CFRetain(values
[numValues
]);
1087 // add kSecAttrAuthenticationType
1088 if ( attrList
.attr
[6].length
> 0 ) {
1089 keys
[numValues
] = kSecAttrAuthenticationType
;
1090 values
[numValues
] = _SecAttrAuthenticationTypeForSecAuthenticationType(*(SecProtocolType
*)attrList
.attr
[6].data
);
1091 if ( values
[numValues
] != NULL
) {
1092 CFRetain(values
[numValues
]);
1097 // add kSecAttrComment
1098 if ( attrList
.attr
[7].length
> 0 ) {
1099 keys
[numValues
] = kSecAttrComment
;
1100 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[7].data
, attrList
.attr
[7].length
, kCFStringEncodingUTF8
, FALSE
);
1101 if ( values
[numValues
] != NULL
) {
1106 // add kSecAttrDescription
1107 if ( attrList
.attr
[8].length
> 0 ) {
1108 keys
[numValues
] = kSecAttrDescription
;
1109 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[8].data
, attrList
.attr
[8].length
, kCFStringEncodingUTF8
, FALSE
);
1110 if ( values
[numValues
] != NULL
) {
1115 // add kSecAttrLabel
1116 if ( attrList
.attr
[9].length
> 0 ) {
1117 keys
[numValues
] = kSecAttrLabel
;
1118 values
[numValues
] = CFStringCreateWithBytes(allocator
, (UInt8
*)attrList
.attr
[9].data
, attrList
.attr
[9].length
, kCFStringEncodingUTF8
, FALSE
);
1119 if ( values
[numValues
] != NULL
) {
1124 // add kSecAttrCreationDate
1125 if ( attrList
.attr
[10].length
> 0 ) {
1126 CFDateRef creationDate
= NULL
;
1127 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[10].data
, attrList
.attr
[10].length
, &creationDate
);
1128 keys
[numValues
] = kSecAttrCreationDate
;
1129 values
[numValues
] = creationDate
;
1130 if ( values
[numValues
] != NULL
) {
1135 // add kSecAttrModificationDate
1136 if ( attrList
.attr
[11].length
> 0 ) {
1137 CFDateRef modDate
= NULL
;
1138 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList
.attr
[11].data
, attrList
.attr
[11].length
, &modDate
);
1139 keys
[numValues
] = kSecAttrModificationDate
;
1140 values
[numValues
] = modDate
;
1141 if ( values
[numValues
] != NULL
) {
1146 // add kSecCreatorItemAttr
1147 if ( attrList
.attr
[12].length
> 0 ) {
1148 CFNumberRef numberRef
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[12].data
);
1149 keys
[numValues
] = kSecAttrCreator
;
1150 values
[numValues
] = numberRef
;
1151 if ( values
[numValues
] != NULL
) {
1152 CFRetain(values
[numValues
]);
1157 // add kSecTypeItemAttr
1158 if ( attrList
.attr
[13].length
> 0 ) {
1159 CFNumberRef numberRef
= CFNumberCreate(allocator
, kCFNumberSInt32Type
, attrList
.attr
[13].data
);
1160 keys
[numValues
] = kSecAttrType
;
1161 values
[numValues
] = numberRef
;
1162 if ( values
[numValues
] != NULL
) {
1163 CFRetain(values
[numValues
]);
1168 // add kSecInvisibleItemAttr
1169 if ( attrList
.attr
[14].length
> 0 ) {
1170 uint32_t value
= *((uint32_t*)attrList
.attr
[14].data
);
1171 CFBooleanRef boolRef
= (value
) ? kCFBooleanTrue
: kCFBooleanFalse
;
1172 keys
[numValues
] = kSecAttrIsInvisible
;
1173 values
[numValues
] = boolRef
;
1174 if ( values
[numValues
] != NULL
) {
1175 CFRetain(values
[numValues
]);
1180 // add kSecNegativeItemAttr
1181 if ( attrList
.attr
[15].length
> 0 ) {
1182 uint32_t value
= *((uint32_t*)attrList
.attr
[15].data
);
1183 CFBooleanRef boolRef
= (value
) ? kCFBooleanTrue
: kCFBooleanFalse
;
1184 keys
[numValues
] = kSecAttrIsNegative
;
1185 values
[numValues
] = boolRef
;
1186 if ( values
[numValues
] != NULL
) {
1187 CFRetain(values
[numValues
]);
1192 // create the dictionary
1193 *dictionary
= CFDictionaryCreate(allocator
, keys
, values
, numValues
, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1195 // release the values added to the dictionary
1196 for ( index
= 0; index
< numValues
; ++index
)
1198 CFRelease(values
[index
]);
1201 // and free the attributes
1202 (void) SecKeychainItemFreeContent(&attrList
, NULL
);
1204 SecKeychainItemCopyContent_failed
:
1211 * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the
1212 * attributes of the specified item class and item.
1215 _CreateAttributesDictionaryFromItem(
1216 CFAllocatorRef allocator
,
1217 SecItemClass itemClass
,
1218 SecKeychainItemRef item
,
1219 CFDictionaryRef
*dictionary
)
1223 case kSecInternetPasswordItemClass
:
1224 return _CreateAttributesDictionaryFromInternetPasswordItem(allocator
, item
, dictionary
);
1226 case kSecGenericPasswordItemClass
:
1227 return _CreateAttributesDictionaryFromGenericPasswordItem(allocator
, item
, dictionary
);
1229 case kSecCertificateItemClass
:
1230 return _CreateAttributesDictionaryFromCertificateItem(allocator
, item
, dictionary
);
1232 case kSecPublicKeyItemClass
:
1233 case kSecPrivateKeyItemClass
:
1234 case kSecSymmetricKeyItemClass
:
1235 return _CreateAttributesDictionaryFromKeyItem(allocator
, item
, dictionary
);
1246 * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList
1247 * by the _CreateSecKeychainAttributeListFromDictionary function.
1251 SecKeychainAttributeList
*attrListPtr
)
1255 if ( attrListPtr
!= NULL
) {
1256 if ( attrListPtr
->attr
!= NULL
) {
1257 // free any attribute data
1258 for ( index
= 0; index
< attrListPtr
->count
; ++index
) {
1259 free(attrListPtr
->attr
[index
].data
);
1261 // free the attribute array
1262 free(attrListPtr
->attr
);
1264 // free the attribute list
1270 * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by
1271 * attr using the data and tag parameters.
1273 * The memory for the SecKeychainAttribute's data field is allocated with malloc
1274 * and must be released by the caller (this is normally done by calling _FreeAttrList).
1277 _CFDataCreateAttribute(
1279 SecKeychainAttrType tag
,
1280 SecKeychainAttributePtr attr
)
1282 OSStatus status
= noErr
;
1285 // set the attribute tag
1288 // determine the attribute length
1289 attr
->length
= CFDataGetLength(data
);
1290 range
= CFRangeMake(0, (CFIndex
)attr
->length
);
1292 // allocate memory for the attribute bytes
1293 attr
->data
= malloc(attr
->length
);
1294 require_action(attr
->data
!= NULL
, malloc_failed
, status
= errSecBufferTooSmall
);
1296 // get the attribute bytes
1297 CFDataGetBytes(data
, range
, (UInt8
*)attr
->data
);
1305 * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by
1306 * attr using the string and tag parameters.
1308 * The memory for the SecKeychainAttribute's data field is allocated with malloc
1309 * and must be released by the caller (this is normally done by calling _FreeAttrList).
1312 _CFStringCreateAttribute(
1314 SecKeychainAttrType tag
,
1315 SecKeychainAttributePtr attr
)
1317 OSStatus status
= noErr
;
1320 // set the attribute tag
1323 // determine the attribute length
1324 range
= CFRangeMake(0, CFStringGetLength(string
));
1325 CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, (CFIndex
*)&attr
->length
);
1327 // allocate memory for the attribute bytes
1328 attr
->data
= malloc(attr
->length
);
1329 require_action(attr
->data
!= NULL
, malloc_failed
, status
= errSecBufferTooSmall
);
1331 // get the attribute bytes
1332 CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, FALSE
, (UInt8
*)attr
->data
, attr
->length
, NULL
);
1341 * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList
1342 * from the attribute key/values in attrDictionary.
1344 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1345 * must be freed by the caller with _FreeAttrList()
1348 _CreateSecKeychainGenericPasswordAttributeListFromDictionary(
1349 CFDictionaryRef attrDictionary
,
1350 SecKeychainAttributeList
**attrList
)
1352 return _ConvertNewFormatToOldFormat(NULL
, gGenericPasswordAttributes
, kNumberOfGenericPasswordAttributes
, attrDictionary
, *attrList
);
1357 * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList
1358 * from the attribute key/values in attrDictionary.
1360 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1361 * must be freed by the caller with _FreeAttrList()
1364 _CreateSecKeychainCertificateAttributeListFromDictionary(
1365 CFDictionaryRef attrDictionary
,
1366 SecKeychainAttributeList
**attrList
)
1368 return _ConvertNewFormatToOldFormat(NULL
, gCertificateAttributes
, kNumberOfCertificateAttributes
, attrDictionary
, *attrList
);
1373 * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList
1374 * from the attribute key/values in attrDictionary.
1376 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1377 * must be freed by the caller with _FreeAttrList()
1380 _CreateSecKeychainKeyAttributeListFromDictionary(
1381 CFDictionaryRef attrDictionary
,
1382 SecKeychainAttributeList
**attrList
)
1385 //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug
1386 return _ConvertNewFormatToOldFormat(NULL
, gKeyAttributes
, kNumberOfKeyAttributes
, attrDictionary
, *attrList
);
1388 // explicitly build attribute list for supported key attributes
1389 // NOTE: this code supports only MaxSecKeyAttributes (15) attributes
1390 const int MaxSecKeyAttributes
= 15;
1394 SecKeychainAttributeList
*attrListPtr
;
1396 attrListPtr
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
));
1397 require_action(attrListPtr
!= NULL
, calloc_attrListPtr_failed
, status
= errSecBufferTooSmall
);
1399 attrListPtr
->attr
= (SecKeychainAttribute
*)calloc(MaxSecKeyAttributes
, sizeof(SecKeychainAttribute
));
1400 require_action(attrListPtr
->attr
!= NULL
, malloc_attrPtr_failed
, status
= errSecBufferTooSmall
);
1402 // [0] get the kSecKeyKeyClass value
1403 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyClass
, (const void **)&value
) && value
) {
1404 UInt32 keyRecordValue
= 0;
1405 if (CFEqual(kSecAttrKeyClassPublic
, value
))
1406 keyRecordValue
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
1407 else if (CFEqual(kSecAttrKeyClassPrivate
, value
))
1408 keyRecordValue
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
1409 else if (CFEqual(kSecAttrKeyClassSymmetric
, value
))
1410 keyRecordValue
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
1412 // only use this attribute if we recognize the value!
1413 if (keyRecordValue
!= 0) {
1414 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1415 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1417 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyKeyClass
;
1418 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1419 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyRecordValue
;
1421 ++attrListPtr
->count
;
1425 // [1] get the kSecKeyPrintName string
1426 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) && value
) {
1427 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyPrintName
, &attrListPtr
->attr
[attrListPtr
->count
]);
1428 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1430 ++attrListPtr
->count
;
1433 // [2] get the kSecKeyPermanent boolean
1434 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsPermanent
, (const void **)&value
) && value
) {
1435 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1436 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1438 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyPermanent
;
1439 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1440 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1442 ++attrListPtr
->count
;
1445 // [3] get the kSecKeyLabel string
1446 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationLabel
, (const void **)&value
) && value
) {
1447 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyLabel
, &attrListPtr
->attr
[attrListPtr
->count
]);
1448 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1450 ++attrListPtr
->count
;
1453 // [4] get the kSecKeyApplicationTag data
1454 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrApplicationTag
, (const void **)&value
) && value
) {
1455 if (CFStringGetTypeID() == CFGetTypeID(value
))
1456 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]);
1457 else if (CFDataGetTypeID() == CFGetTypeID(value
))
1458 status
= _CFDataCreateAttribute((CFDataRef
)value
, kSecKeyApplicationTag
, &attrListPtr
->attr
[attrListPtr
->count
]);
1462 require_noerr_quiet(status
, CFDataCreateAttribute_failed
);
1463 ++attrListPtr
->count
;
1466 // [5] get the kSecKeyKeyType number
1467 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeyType
, (const void **)&value
) && value
) {
1468 UInt32 keyAlgValue
= _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType
);
1469 if (keyAlgValue
!= 0) {
1470 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1471 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1473 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyKeyType
;
1474 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1475 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = keyAlgValue
;
1477 ++attrListPtr
->count
;
1481 // [6] get the kSecKeyKeySizeInBits number
1482 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrKeySizeInBits
, (const void **)&value
) && value
) {
1483 if (CFNumberGetTypeID() == CFGetTypeID(value
)) {
1484 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1485 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1487 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyKeySizeInBits
;
1488 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1489 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
);
1491 ++attrListPtr
->count
;
1495 // [7] get the kSecKeyEffectiveKeySize number
1496 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrEffectiveKeySize
, (const void **)&value
) && value
) {
1497 if (CFNumberGetTypeID() == CFGetTypeID(value
)) {
1498 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1499 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1501 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyEffectiveKeySize
;
1502 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1503 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
);
1505 ++attrListPtr
->count
;
1509 // [8] get the kSecKeyEncrypt boolean
1510 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanEncrypt
, (const void **)&value
) && value
) {
1511 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1512 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1513 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1515 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyEncrypt
;
1516 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1517 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1519 ++attrListPtr
->count
;
1523 // [9] get the kSecKeyDecrypt boolean
1524 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDecrypt
, (const void **)&value
) && value
) {
1525 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1526 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1527 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1529 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyDecrypt
;
1530 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1531 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1533 ++attrListPtr
->count
;
1537 // [10] get the kSecKeyDerive boolean
1538 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanDerive
, (const void **)&value
) && value
) {
1539 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1540 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1541 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1543 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyDerive
;
1544 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1545 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1547 ++attrListPtr
->count
;
1551 // [11] get the kSecKeySign boolean
1552 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanSign
, (const void **)&value
) && value
) {
1553 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1554 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1555 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1557 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeySign
;
1558 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1559 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1561 ++attrListPtr
->count
;
1565 // [12] get the kSecKeyVerify boolean
1566 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanVerify
, (const void **)&value
) && value
) {
1567 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1568 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1569 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1571 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyVerify
;
1572 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1573 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1575 ++attrListPtr
->count
;
1579 // [13] get the kSecKeyWrap boolean
1580 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanWrap
, (const void **)&value
) && value
) {
1581 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1582 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1583 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1585 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyWrap
;
1586 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1587 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1589 ++attrListPtr
->count
;
1593 // [14] get the kSecKeyUnwrap boolean
1594 if (CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCanUnwrap
, (const void **)&value
) && value
) {
1595 if (CFBooleanGetTypeID() == CFGetTypeID(value
)) {
1596 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1597 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_number_failed
, status
= errSecBufferTooSmall
);
1599 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecKeyUnwrap
;
1600 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1601 *((UInt32
*)attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFEqual(kCFBooleanTrue
, value
)) ? 1 : 0;
1603 ++attrListPtr
->count
;
1607 // return the pointer to the attrList
1608 *attrList
= attrListPtr
;
1614 malloc_number_failed
:
1615 CFDataCreateAttribute_failed
:
1616 CFStringCreateAttribute_failed
:
1617 malloc_attrPtr_failed
:
1619 // free any attributes
1620 _FreeAttrList(attrListPtr
);
1622 calloc_attrListPtr_failed
:
1624 return ( errSecBufferTooSmall
);
1631 * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList
1632 * from the attribute key/values in attrDictionary.
1634 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1635 * must be freed by the caller with _FreeAttrList()
1638 _CreateSecKeychainInternetPasswordAttributeListFromDictionary(
1639 CFDictionaryRef attrDictionary
,
1640 SecKeychainAttributeList
**attrList
)
1642 // explicitly build attribute list for supported key attributes
1643 // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes
1644 const int MaxSecKeychainAttributes
= 14;
1648 SecKeychainAttributeList
*attrListPtr
;
1650 attrListPtr
= (SecKeychainAttributeList
*)calloc(1, sizeof(SecKeychainAttributeList
));
1651 require_action(attrListPtr
!= NULL
, calloc_attrListPtr_failed
, status
= errSecBufferTooSmall
);
1653 attrListPtr
->attr
= (SecKeychainAttribute
*)calloc(MaxSecKeychainAttributes
, sizeof(SecKeychainAttribute
));
1654 require_action(attrListPtr
->attr
!= NULL
, malloc_attrPtr_failed
, status
= errSecBufferTooSmall
);
1657 // [0] get the serverName string
1658 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrServer
, (const void **)&value
) ) {
1659 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecServerItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1660 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1662 ++attrListPtr
->count
;
1665 // [1] get the securityDomain string
1666 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrSecurityDomain
, (const void **)&value
) ) {
1667 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecSecurityDomainItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1668 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1670 ++attrListPtr
->count
;
1673 // [2] get the accountName string
1674 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAccount
, (const void **)&value
) ) {
1675 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecAccountItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1676 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1678 ++attrListPtr
->count
;
1681 // [3] get the path string
1682 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPath
, (const void **)&value
) ) {
1683 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecPathItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1684 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1686 ++attrListPtr
->count
;
1689 // [4] get the port number
1690 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrPort
, (const void **)&value
) ) {
1691 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt16
));
1692 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_port_failed
, status
= errSecBufferTooSmall
);
1694 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecPortItemAttr
;
1695 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt16
);
1696 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt16Type
, attrListPtr
->attr
[attrListPtr
->count
].data
);
1698 ++attrListPtr
->count
;
1701 // [5] get the protocol
1702 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrProtocol
, (const void **)&value
) ) {
1703 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(SecProtocolType
));
1704 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_protocol_failed
, status
= errSecBufferTooSmall
);
1706 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecProtocolItemAttr
;
1707 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(SecProtocolType
);
1708 *(SecProtocolType
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecProtocolTypeForSecAttrProtocol(value
);
1710 ++attrListPtr
->count
;
1713 // [6] get the authenticationType
1714 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrAuthenticationType
, (const void **)&value
) ) {
1715 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(SecAuthenticationType
));
1716 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_authenticationType_failed
, status
= errSecBufferTooSmall
);
1718 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecAuthenticationTypeItemAttr
;
1719 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(SecAuthenticationType
);
1720 *(SecAuthenticationType
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = _SecAuthenticationTypeForSecAttrAuthenticationType(value
);
1722 ++attrListPtr
->count
;
1725 // [7] get the comment string
1726 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrComment
, (const void **)&value
) ) {
1727 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecCommentItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1728 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1730 ++attrListPtr
->count
;
1733 // [8] get the description string
1734 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrDescription
, (const void **)&value
) ) {
1735 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecDescriptionItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1736 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1738 ++attrListPtr
->count
;
1741 // [9] get the label string
1742 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrLabel
, (const void **)&value
) ) {
1743 status
= _CFStringCreateAttribute((CFStringRef
)value
, kSecLabelItemAttr
, &attrListPtr
->attr
[attrListPtr
->count
]);
1744 require_noerr_quiet(status
, CFStringCreateAttribute_failed
);
1746 ++attrListPtr
->count
;
1749 // [10] get the creator code
1750 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrCreator
, (const void **)&value
) ) {
1751 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1752 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_port_failed
, status
= errSecBufferTooSmall
);
1754 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecCreatorItemAttr
;
1755 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1756 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
);
1758 ++attrListPtr
->count
;
1761 // [11] get the type code
1762 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrType
, (const void **)&value
) ) {
1763 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1764 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_port_failed
, status
= errSecBufferTooSmall
);
1766 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecTypeItemAttr
;
1767 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1768 CFNumberGetValue((CFNumberRef
)value
, kCFNumberSInt32Type
, attrListPtr
->attr
[attrListPtr
->count
].data
);
1770 ++attrListPtr
->count
;
1773 // [12] get the invisible flag
1774 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsInvisible
, (const void **)&value
) ) {
1775 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1776 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_port_failed
, status
= errSecBufferTooSmall
);
1778 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecInvisibleItemAttr
;
1779 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1780 *(UInt32
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0;
1782 ++attrListPtr
->count
;
1785 // [13] get the negative flag
1786 if ( CFDictionaryGetValueIfPresent(attrDictionary
, kSecAttrIsNegative
, (const void **)&value
) ) {
1787 attrListPtr
->attr
[attrListPtr
->count
].data
= malloc(sizeof(UInt32
));
1788 require_action(attrListPtr
->attr
[attrListPtr
->count
].data
!= NULL
, malloc_port_failed
, status
= errSecBufferTooSmall
);
1790 attrListPtr
->attr
[attrListPtr
->count
].tag
= kSecNegativeItemAttr
;
1791 attrListPtr
->attr
[attrListPtr
->count
].length
= sizeof(UInt32
);
1792 *(UInt32
*)(attrListPtr
->attr
[attrListPtr
->count
].data
) = (CFBooleanGetValue((CFBooleanRef
)value
)) ? 1 : 0;
1794 ++attrListPtr
->count
;
1797 // return the pointer to the attrList
1798 *attrList
= attrListPtr
;
1804 malloc_authenticationType_failed
:
1805 malloc_protocol_failed
:
1807 CFStringCreateAttribute_failed
:
1808 malloc_attrPtr_failed
:
1810 // free any attributes
1811 _FreeAttrList(attrListPtr
);
1813 calloc_attrListPtr_failed
:
1815 return ( errSecBufferTooSmall
);
1820 * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList
1821 * from the attribute key/values in attrDictionary for the specified item class.
1823 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1824 * must be freed by the caller with _FreeAttrList()
1827 _CreateSecKeychainAttributeListFromDictionary(
1828 CFDictionaryRef attrDictionary
,
1829 SecItemClass itemClass
,
1830 SecKeychainAttributeList
**attrList
)
1834 case kSecInternetPasswordItemClass
:
1835 return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary
, attrList
);
1837 case kSecGenericPasswordItemClass
:
1838 return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary
, attrList
);
1840 case kSecCertificateItemClass
:
1841 return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary
, attrList
);
1843 case kSecPublicKeyItemClass
:
1844 case kSecPrivateKeyItemClass
:
1845 case kSecSymmetricKeyItemClass
:
1846 return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary
, attrList
);
1856 * _AppNameFromSecTrustedApplication attempts to pull the name of the
1857 * application/tool from the SecTrustedApplicationRef.
1860 _AppNameFromSecTrustedApplication(
1861 CFAllocatorRef alloc
,
1862 SecTrustedApplicationRef appRef
)
1866 CFDataRef appDataRef
;
1870 // get the data for item's application/tool
1871 status
= SecTrustedApplicationCopyData(appRef
, &appDataRef
);
1872 if ( status
== noErr
) {
1875 // convert it to a CFString potentially containing the path
1876 path
= CFStringCreateWithCString(NULL
, (char *)CFDataGetBytePtrVoid(appDataRef
), kCFStringEncodingUTF8
);
1877 if ( path
!= NULL
) {
1878 // the path has to start with a "/" and cannot contain "://"
1879 if ( CFStringHasPrefix(path
, CFSTR("/")) && (CFStringFind(path
, CFSTR("://"), 0).location
== kCFNotFound
) ) {
1880 CFRange nameRange
, compRg
;
1882 nameRange
= CFRangeMake(0, CFStringGetLength(path
));
1884 // remove the trailing slashes (if any)
1885 while ( (nameRange
.length
> 0) && (CFStringGetCharacterAtIndex(path
, nameRange
.length
- 1) == '/') ) {
1886 nameRange
.length
--;
1889 if ( nameRange
.length
> 0 ) {
1890 // find last slash and adjust nameRange be everything after it
1891 if ( CFStringFindWithOptions(path
, CFSTR("/"), nameRange
, kCFCompareBackwards
, &compRg
) ) {
1892 nameRange
.length
= nameRange
.location
+ nameRange
.length
- (compRg
.location
+ 1);
1893 nameRange
.location
= compRg
.location
+ 1;
1896 result
= CFStringCreateWithSubstring(alloc
, path
, nameRange
);
1901 CFRelease(appDataRef
);
1907 /* (This function really belongs in SecIdentity.cpp!)
1909 * Returns the public key item corresponding to the identity, if it exists in
1910 * the same keychain as the private key. Note that the public key might not
1911 * exist in the same keychain (e.g. if the identity was imported via PKCS12),
1912 * in which case it will not be found.
1915 _SecIdentityCopyPublicKey(
1916 SecIdentityRef identityRef
,
1917 SecKeyRef
*publicKeyRef
)
1921 SecKeychainAttribute attr
= { kSecKeyLabel
, 0, NULL
};
1922 SecKeychainAttributeList attrList
= { 1, &attr
};
1923 SecKeychainAttributeList
*keyAttrList
= NULL
;
1924 SecKeychainAttributeInfo
*info
= NULL
;
1925 SecKeychainSearchRef search
= NULL
;
1926 SecKeychainRef keychain
= NULL
;
1927 SecKeychainItemRef privateKey
= NULL
;
1928 SecKeychainItemRef publicKey
= NULL
;
1930 status
= SecIdentityCopyPrivateKey(identityRef
, (SecKeyRef
*)&privateKey
);
1932 goto error_exit
; // identity must have a private key
1934 status
= SecKeychainItemCopyKeychain(privateKey
, &keychain
);
1936 goto error_exit
; // private key must have a keychain, so we can get the attribute info for it
1938 status
= SecKeychainAttributeInfoForItemID(keychain
, kSecPrivateKeyItemClass
, &info
);
1940 goto error_exit
; // unable to get the attribute info (i.e. database schema) for private keys
1942 status
= SecKeychainItemCopyAttributesAndData(privateKey
, info
, NULL
, &keyAttrList
, NULL
, NULL
);
1944 goto error_exit
; // unable to get the key label attribute for the private key
1947 // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching
1948 for (count
= 0; count
< keyAttrList
->count
; count
++) {
1949 if (keyAttrList
->attr
[count
].tag
== kSecKeyLabel
) {
1950 attr
.length
= keyAttrList
->attr
[count
].length
;
1951 attr
.data
= keyAttrList
->attr
[count
].data
;
1955 if (!attr
.length
|| !attr
.data
) {
1956 status
= errSecNoSuchAttr
;
1957 goto error_exit
; // the private key didn't have the hash of the public key in its kSecKeyLabel
1959 status
= SecKeychainSearchCreateFromAttributes(keychain
, kSecPublicKeyItemClass
, &attrList
, &search
);
1961 goto error_exit
; // unable to create the search reference
1963 status
= SecKeychainSearchCopyNext(search
, &publicKey
);
1965 goto error_exit
; // unable to find the public key
1969 *publicKeyRef
= (SecKeyRef
)publicKey
;
1971 CFRelease(publicKey
);
1974 if (status
!= noErr
) {
1976 *publicKeyRef
= NULL
;
1978 CFRelease(publicKey
);
1984 SecKeychainItemFreeAttributesAndData(keyAttrList
, NULL
);
1987 SecKeychainFreeAttributeInfo(info
);
1990 CFRelease(keychain
);
1993 CFRelease(privateKey
);
2000 * Deletes a keychain item if the current application/tool is the only application/tool
2001 * with decrypt access to that keychain item. If more than one application/tool
2002 * has decrypt access to the keychain item, the item is left on the keychain.
2004 * TBD: If more than one app/tool has access to the keychain item, we should remove
2005 * the current app/tool's decrypt access. There's no easy way to do that with
2006 * current keychain APIs without bringing up the security UI.
2009 _SafeSecKeychainItemDelete(
2010 SecKeychainItemRef itemRef
)
2013 SecAccessRef access
;
2017 CFStringRef description
;
2018 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector
;
2020 SecItemClass itemClass
;
2021 status
= SecKeychainItemCopyAttributesAndData(itemRef
, NULL
, &itemClass
, NULL
, NULL
, NULL
);
2022 if (!status
&& (itemClass
== kSecCertificateItemClass
|| itemClass
== kSecPublicKeyItemClass
)) {
2023 // the item doesn't have any access controls, so delete it normally
2024 return SecKeychainItemDelete(itemRef
);
2027 // skip access control checking for web form passwords: <rdar://10957301>
2028 // This permits Safari to manage the removal of all web form passwords,
2029 // regardless of whether they are shared by multiple applications.
2030 if (itemClass
== kSecInternetPasswordItemClass
) {
2031 UInt32 tags
[1] = { kSecAuthenticationTypeItemAttr
};
2032 SecKeychainAttributeInfo attrInfo
= { 1, tags
, NULL
};
2033 SecKeychainAttributeList
*attrs
= NULL
;
2034 status
= SecKeychainItemCopyAttributesAndData(itemRef
, &attrInfo
, NULL
, &attrs
, NULL
, NULL
);
2035 if (!status
&& attrs
) {
2036 bool webFormPassword
= (attrs
->attr
[0].length
== 4 && (!memcmp(attrs
->attr
[0].data
, "form", 4)));
2037 SecKeychainItemFreeAttributesAndData(attrs
, NULL
);
2038 if (webFormPassword
) {
2039 return SecKeychainItemDelete(itemRef
);
2044 // copy the access of the keychain item
2045 status
= SecKeychainItemCopyAccess(itemRef
, &access
);
2046 require_noerr(status
, SecKeychainItemCopyAccessFailed
);
2048 // copy the decrypt access control lists -- this is what has access to the keychain item
2049 status
= SecAccessCopySelectedACLList(access
, CSSM_ACL_AUTHORIZATION_DECRYPT
, &aclList
);
2050 require_noerr(status
, SecAccessCopySelectedACLListFailed
);
2051 require_quiet(aclList
!= NULL
, noACLList
);
2053 // get the access control list
2054 acl
= (SecACLRef
)CFArrayGetValueAtIndex(aclList
, 0);
2055 require_quiet(acl
!= NULL
, noACL
);
2057 // copy the application list, description, and CSSM prompt selector for a given access control list entry
2058 status
= SecACLCopySimpleContents(acl
, &appList
, &description
, &promptSelector
);
2059 require_noerr(status
, SecACLCopySimpleContentsFailed
);
2060 require_quiet(appList
!= NULL
, noAppList
);
2062 // does only a single application/tool have decrypt access to this item?
2063 if ( CFArrayGetCount(appList
) == 1 ) {
2064 SecTrustedApplicationRef itemAppRef
, currentAppRef
;
2065 CFStringRef itemAppName
, currentAppName
;
2067 // get SecTrustedApplicationRef for item's application/tool
2068 itemAppRef
= (SecTrustedApplicationRef
)CFArrayGetValueAtIndex(appList
, 0);
2069 require(itemAppRef
!= NULL
, noItemAppRef
);
2071 // copy the name out
2072 itemAppName
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), itemAppRef
);
2073 require(itemAppName
!= NULL
, noAppName
);
2075 // create SecTrustedApplicationRef for current application/tool
2076 status
= SecTrustedApplicationCreateFromPath(NULL
, ¤tAppRef
);
2077 require((status
== noErr
) && (currentAppRef
!= NULL
), SecTrustedApplicationCreateFromPathFailed
);
2079 // copy the name out
2080 currentAppName
= _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef
), currentAppRef
);
2081 require(currentAppName
!= NULL
, noCurrentAppName
);
2083 // compare the current application/tool's name to this item's application/tool's name to see if we own the decrypt access
2084 if ( CFStringCompare(currentAppName
, itemAppName
, 0) == kCFCompareEqualTo
) {
2085 // delete the keychain item
2086 SecKeychainItemDelete(itemRef
);
2089 CFRelease(currentAppName
);
2091 CFRelease(currentAppRef
);
2092 SecTrustedApplicationCreateFromPathFailed
:
2093 CFRelease(itemAppName
);
2099 if ( description
) {
2100 CFRelease(description
);
2104 SecACLCopySimpleContentsFailed
:
2108 SecAccessCopySelectedACLListFailed
:
2110 SecKeychainItemCopyAccessFailed
:
2116 _UpdateKeychainItem(CFTypeRef item
, CFDictionaryRef changedAttributes
)
2118 // This function updates a single keychain item, which may be specified as
2119 // a reference, persistent reference or attribute dictionary, with the
2120 // attributes provided.
2122 OSStatus status
= noErr
;
2127 SecItemClass itemClass
;
2128 SecAccessRef access
= NULL
;
2129 SecKeychainAttributeList
*changeAttrList
= NULL
;
2130 SecKeychainItemRef itemToUpdate
= NULL
;
2131 CFDataRef theData
= NULL
;
2132 CFTypeID itemType
= CFGetTypeID(item
);
2134 // validate input item (must be convertible to a SecKeychainItemRef)
2135 if (SecKeychainItemGetTypeID() == itemType
||
2136 SecCertificateGetTypeID() == itemType
||
2137 SecKeyGetTypeID() == itemType
) {
2138 // item is already a reference, retain it
2139 itemToUpdate
= (SecKeychainItemRef
) CFRetain(item
);
2141 else if (CFDataGetTypeID() == itemType
) {
2142 // item is a persistent reference, must convert it
2143 status
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToUpdate
);
2145 else if (CFDictionaryGetTypeID() == itemType
) {
2146 // item is a dictionary
2147 CFTypeRef value
= NULL
;
2148 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) {
2149 // kSecValueRef value is a SecKeychainItemRef, retain it
2150 itemToUpdate
= (SecKeychainItemRef
) CFRetain(value
);
2152 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) {
2153 // kSecValuePersistentRef value is a persistent reference, must convert it
2154 status
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToUpdate
);
2157 else if (SecIdentityGetTypeID() == itemType
) {
2158 // item is a certificate + private key; since we can't really change the
2159 // certificate's attributes, assume we want to update the private key
2160 status
= SecIdentityCopyPrivateKey((SecIdentityRef
)item
, (SecKeyRef
*)&itemToUpdate
);
2162 require_action(itemToUpdate
!= NULL
, update_failed
, status
= errSecInvalidItemRef
);
2163 require_noerr(status
, update_failed
);
2165 status
= SecKeychainItemCopyContent(itemToUpdate
, &itemClass
, NULL
, NULL
, NULL
);
2166 require_noerr(status
, update_failed
);
2168 // build changeAttrList from changedAttributes dictionary
2171 case kSecInternetPasswordItemClass
:
2173 status
= _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
);
2174 require_noerr(status
, update_failed
);
2178 case kSecGenericPasswordItemClass
:
2180 status
= _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes
, &changeAttrList
);
2181 require_noerr(status
, update_failed
);
2185 case kSecCertificateItemClass
:
2187 status
= _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes
, &changeAttrList
);
2188 require_noerr(status
, update_failed
);
2192 case kSecPublicKeyItemClass
:
2193 case kSecPrivateKeyItemClass
:
2194 case kSecSymmetricKeyItemClass
:
2196 status
= _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes
, &changeAttrList
);
2197 require_noerr(status
, update_failed
);
2202 // (if the caller is not updating the password, this value will be NULL)
2203 theData
= (CFDataRef
)CFDictionaryGetValue(changedAttributes
, kSecValueData
);
2204 if (theData
!= NULL
) {
2205 require_action(CFDataGetTypeID() == CFGetTypeID(theData
), update_failed
, status
= errSecParam
);
2208 status
= SecKeychainItemModifyContent(itemToUpdate
,
2209 (changeAttrList
->count
== 0) ? NULL
: changeAttrList
,
2210 (theData
!= NULL
) ? CFDataGetLength(theData
) : 0,
2211 (theData
!= NULL
) ? CFDataGetBytePtrVoid(theData
) : NULL
);
2213 // one more thing... update access?
2214 if (CFDictionaryGetValueIfPresent(changedAttributes
, kSecAttrAccess
, (const void **)&access
)) {
2215 status
= SecKeychainItemSetAccess(itemToUpdate
, access
);
2220 CFRelease(itemToUpdate
);
2221 _FreeAttrList(changeAttrList
);
2226 _DeleteKeychainItem(CFTypeRef item
)
2228 // This function deletes a single keychain item, which may be specified as
2229 // a reference, persistent reference or attribute dictionary. It will not
2230 // delete non-keychain items or aggregate items (such as a SecIdentityRef);
2231 // it is assumed that the caller will pass identity components separately.
2233 OSStatus status
= noErr
;
2238 SecKeychainItemRef itemToDelete
= NULL
;
2239 CFTypeID itemType
= CFGetTypeID(item
);
2240 if (SecKeychainItemGetTypeID() == itemType
||
2241 SecCertificateGetTypeID() == itemType
||
2242 SecKeyGetTypeID() == itemType
) {
2243 // item is already a reference, retain it
2244 itemToDelete
= (SecKeychainItemRef
) CFRetain(item
);
2246 else if (CFDataGetTypeID() == itemType
) {
2247 // item is a persistent reference, must convert it
2248 status
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)item
, &itemToDelete
);
2250 else if (CFDictionaryGetTypeID() == itemType
) {
2251 // item is a dictionary
2252 CFTypeRef value
= NULL
;
2253 if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValueRef
, &value
)) {
2254 // kSecValueRef value is a SecKeychainItemRef, retain it
2255 itemToDelete
= (SecKeychainItemRef
) CFRetain(value
);
2257 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef
)item
, kSecValuePersistentRef
, &value
)) {
2258 // kSecValuePersistentRef value is a persistent reference, must convert it
2259 status
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)value
, &itemToDelete
);
2265 status
= _SafeSecKeychainItemDelete(itemToDelete
);
2267 CFRelease(itemToDelete
);
2274 _DeleteIdentity(SecIdentityRef identity
)
2276 OSStatus status
, result
= noErr
;
2277 SecKeyRef privateKey
= NULL
;
2278 SecCertificateRef certificate
= NULL
;
2280 status
= SecIdentityCopyPrivateKey(identity
, &privateKey
);
2282 SecKeyRef publicKey
= NULL
;
2283 status
= _SecIdentityCopyPublicKey(identity
, &publicKey
);
2285 status
= _DeleteKeychainItem(publicKey
);
2286 CFRelease(publicKey
);
2288 status
= _DeleteKeychainItem(privateKey
);
2291 if (privateKey
) CFRelease(privateKey
);
2292 if (status
) result
= status
;
2294 status
= SecIdentityCopyCertificate(identity
, &certificate
);
2296 status
= _DeleteKeychainItem(certificate
);
2299 if (certificate
) CFRelease(certificate
);
2300 if (status
) result
= status
;
2306 _UpdateAggregateStatus(OSStatus newStatus
, OSStatus curStatus
, OSStatus baseStatus
)
2308 // This function is used when atomically processing multiple items,
2309 // where an overall error result must be returned for the entire operation.
2310 // When newStatus is something other than noErr, we want to keep the "most
2311 // interesting" status (which usually will be newStatus, unless curStatus is
2312 // already set; in that case, newStatus can trump curStatus only by being
2313 // something different than baseStatus.)
2315 OSStatus result
= curStatus
;
2317 if (newStatus
!= noErr
) {
2319 if (curStatus
!= noErr
) {
2320 result
= (newStatus
!= baseStatus
) ? newStatus
: curStatus
;
2327 _AddDictValueToOtherDict(const void *key
, const void *value
, void *context
)
2329 // CFDictionaryApplierFunction
2330 // This function just takes the given key/value pair,
2331 // and adds it to another dictionary supplied in the context argument.
2333 CFMutableDictionaryRef dict
= *((CFMutableDictionaryRef
*) context
);
2335 CFDictionaryAddValue(dict
, key
, value
);
2339 static CFStringCompareFlags
2340 _StringCompareFlagsFromQuery(CFDictionaryRef query
)
2343 CFStringCompareFlags flags
= 0;
2344 if (!query
) return flags
;
2346 if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&value
) ||
2347 CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
))
2348 flags
|= kCFCompareAnchored
;
2350 if (CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&value
))
2351 flags
|= kCFCompareBackwards
;
2353 if (CFDictionaryGetValueIfPresent(query
, kSecMatchCaseInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2354 flags
|= kCFCompareCaseInsensitive
;
2356 if (CFDictionaryGetValueIfPresent(query
, kSecMatchDiacriticInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2357 flags
|= kCFCompareDiacriticInsensitive
;
2359 if (CFDictionaryGetValueIfPresent(query
, kSecMatchWidthInsensitive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2360 flags
|= kCFCompareWidthInsensitive
;
2366 _CssmKeyUsageFromQuery(CFDictionaryRef query
)
2369 uint32 keyUsage
= 0;
2370 if (!query
) return keyUsage
;
2372 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanEncrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2373 keyUsage
|= CSSM_KEYUSE_ENCRYPT
;
2375 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDecrypt
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2376 keyUsage
|= CSSM_KEYUSE_DECRYPT
;
2378 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanSign
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2379 keyUsage
|= CSSM_KEYUSE_SIGN
;
2381 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanVerify
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2382 keyUsage
|= CSSM_KEYUSE_VERIFY
;
2384 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanWrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2385 keyUsage
|= CSSM_KEYUSE_WRAP
;
2387 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanUnwrap
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2388 keyUsage
|= CSSM_KEYUSE_UNWRAP
;
2390 if (CFDictionaryGetValueIfPresent(query
, kSecAttrCanDerive
, (const void **)&value
) && CFEqual(kCFBooleanTrue
, value
))
2391 keyUsage
|= CSSM_KEYUSE_DERIVE
;
2397 _ConvertItemClass(const void* item
, const void* keyClass
, Boolean
*isIdentity
)
2399 SecItemClass itemClass
= (SecItemClass
) 0;
2400 if (isIdentity
) *isIdentity
= false;
2402 if (CFEqual(item
, kSecClassGenericPassword
)) {
2403 itemClass
= kSecGenericPasswordItemClass
;
2405 else if (CFEqual(item
, kSecClassInternetPassword
)) {
2406 itemClass
= kSecInternetPasswordItemClass
;
2408 else if (CFEqual(item
, kSecClassCertificate
)) {
2409 itemClass
= kSecCertificateItemClass
;
2411 else if (CFEqual(item
, kSecClassIdentity
)) {
2412 // will perform a certificate lookup
2413 itemClass
= kSecCertificateItemClass
;
2414 if (isIdentity
) *isIdentity
= true;
2416 else if (CFEqual(item
, kSecClassKey
)) {
2417 // examine second parameter to determine type of key
2418 if (!keyClass
|| CFEqual(keyClass
, kSecAttrKeyClassSymmetric
)) {
2419 itemClass
= kSecSymmetricKeyItemClass
;
2421 else if (keyClass
&& CFEqual(keyClass
, kSecAttrKeyClassPublic
)) {
2422 itemClass
= kSecPublicKeyItemClass
;
2424 else if (keyClass
&& CFEqual(keyClass
, kSecAttrKeyClassPrivate
)) {
2425 itemClass
= kSecPrivateKeyItemClass
;
2432 // SecItemParams contains a validated set of input parameters, as well as a
2433 // search reference and attribute list built from those parameters. It is
2434 // designed to be allocated with _CreateSecItemParamsFromDictionary, and
2435 // freed with _FreeSecItemParams.
2437 struct SecItemParams
{
2438 CFDictionaryRef query
; // caller-supplied query
2439 int numResultTypes
; // number of result types requested
2440 int maxMatches
; // max number of matches to return
2441 uint32 keyUsage
; // key usage(s) requested
2442 Boolean returningAttributes
; // true if returning attributes dictionary
2443 Boolean returningData
; // true if returning item's data
2444 Boolean returningRef
; // true if returning item reference
2445 Boolean returningPersistentRef
; // true if returing a persistent reference
2446 Boolean returnAllMatches
; // true if we should return all matches
2447 Boolean returnIdentity
; // true if we are returning a SecIdentityRef
2448 Boolean trustedOnly
; // true if we only return trusted certs
2449 Boolean issuerAndSNToMatch
; // true if both issuer and SN were provided
2450 SecItemClass itemClass
; // item class for this query
2451 SecPolicyRef policy
; // value for kSecMatchPolicy (may be NULL)
2452 SecKeychainRef keychain
; // value for kSecUseKeychain (may be NULL)
2453 CFArrayRef useItems
; // value for kSecUseItemList (may be NULL)
2454 CFArrayRef itemList
; // value for kSecMatchItemList (may be NULL)
2455 CFTypeRef searchList
; // value for kSecMatchSearchList (may be NULL)
2456 CFTypeRef matchLimit
; // value for kSecMatchLimit (may be NULL)
2457 CFTypeRef emailAddrToMatch
; // value for kSecMatchEmailAddressIfPresent (may be NULL)
2458 CFTypeRef validOnDate
; // value for kSecMatchValidOnDate (may be NULL)
2459 CFTypeRef keyClass
; // value for kSecAttrKeyClass (may be NULL)
2460 CFTypeRef service
; // value for kSecAttrService (may be NULL)
2461 CFTypeRef issuer
; // value for kSecAttrIssuer (may be NULL)
2462 CFTypeRef serialNumber
; // value for kSecAttrSerialNumber (may be NULL)
2463 CFTypeRef search
; // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef)
2464 CFTypeRef assumedKeyClass
; // if no kSecAttrKeyClass provided, holds the current class we're searching for
2465 SecKeychainAttributeList
*attrList
; // attribute list for this query
2466 SecAccessRef access
; // access reference (for SecItemAdd only, not used to find items)
2467 CFDataRef itemData
; // item data (for SecItemAdd only, not used to find items)
2468 CFTypeRef itemRef
; // item reference (to add, update or delete, depending on context)
2469 CFDataRef itemPersistentRef
; // item persistent reference (to add, update or delete, depending on context)
2473 _ValidateDictionaryEntry(CFDictionaryRef dict
, CFTypeRef key
, const void **value
, CFTypeID expectedTypeID
, CFTypeID altTypeID
)
2475 if (!dict
|| !key
|| !value
|| !expectedTypeID
)
2478 if (!CFDictionaryGetValueIfPresent(dict
, key
, value
)) {
2479 // value was not provided for this key (not an error!)
2482 else if (!(*value
)) {
2483 // provided value is NULL (also not an error!)
2487 CFTypeID actualTypeID
= CFGetTypeID(*value
);
2488 if (!((expectedTypeID
== actualTypeID
) || (altTypeID
&& altTypeID
== actualTypeID
))) {
2489 // provided value does not have the expected (or alternate) CF type ID
2490 if ((expectedTypeID
== SecKeychainItemGetTypeID()) &&
2491 (actualTypeID
== SecKeyGetTypeID() || actualTypeID
== SecCertificateGetTypeID())) {
2492 // provided value is a "floating" reference which is not yet in a keychain
2496 return errSecItemInvalidValue
;
2499 // provided value is OK; retain it
2507 _FreeSecItemParams(SecItemParams
*itemParams
)
2512 if (itemParams
->query
) CFRelease(itemParams
->query
);
2513 if (itemParams
->policy
) CFRelease(itemParams
->policy
);
2514 if (itemParams
->keychain
) CFRelease(itemParams
->keychain
);
2515 if (itemParams
->useItems
) CFRelease(itemParams
->useItems
);
2516 if (itemParams
->itemList
) CFRelease(itemParams
->itemList
);
2517 if (itemParams
->searchList
) CFRelease(itemParams
->searchList
);
2518 if (itemParams
->matchLimit
) CFRelease(itemParams
->matchLimit
);
2519 if (itemParams
->emailAddrToMatch
) CFRelease(itemParams
->emailAddrToMatch
);
2520 if (itemParams
->validOnDate
) CFRelease(itemParams
->validOnDate
);
2521 if (itemParams
->keyClass
) CFRelease(itemParams
->keyClass
);
2522 if (itemParams
->service
) CFRelease(itemParams
->service
);
2523 if (itemParams
->issuer
) CFRelease(itemParams
->issuer
);
2524 if (itemParams
->serialNumber
) CFRelease(itemParams
->serialNumber
);
2525 if (itemParams
->search
) CFRelease(itemParams
->search
);
2526 if (itemParams
->access
) CFRelease(itemParams
->access
);
2527 if (itemParams
->itemData
) CFRelease(itemParams
->itemData
);
2528 if (itemParams
->itemRef
) CFRelease(itemParams
->itemRef
);
2529 if (itemParams
->itemPersistentRef
) CFRelease(itemParams
->itemPersistentRef
);
2531 _FreeAttrList(itemParams
->attrList
);
2536 static SecItemParams
*
2537 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict
, OSStatus
*error
)
2540 CFTypeRef value
= NULL
;
2541 SecItemParams
*itemParams
= (SecItemParams
*) malloc(sizeof(SecItemParams
));
2543 require_action(itemParams
!= NULL
, error_exit
, status
= memFullErr
);
2544 require_action(dict
&& (CFDictionaryGetTypeID() == CFGetTypeID(dict
)), error_exit
, status
= paramErr
);
2546 memset(itemParams
, 0, sizeof(SecItemParams
));
2547 itemParams
->query
= (CFDictionaryRef
) CFRetain(dict
);
2549 // validate input search parameters
2550 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecMatchPolicy
, (const void **)&itemParams
->policy
, SecPolicyGetTypeID(), NULL
), error_exit
);
2551 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecMatchSearchList
, (const void **)&itemParams
->searchList
, CFArrayGetTypeID(), NULL
), error_exit
);
2552 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecMatchItemList
, (const void **)&itemParams
->itemList
, CFArrayGetTypeID(), NULL
), error_exit
);
2553 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecMatchEmailAddressIfPresent
, (const void **)&itemParams
->emailAddrToMatch
, CFStringGetTypeID(), NULL
), error_exit
);
2554 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecMatchValidOnDate
, (const void **)&itemParams
->validOnDate
, CFDateGetTypeID(), CFNullGetTypeID()), error_exit
);
2555 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecMatchLimit
, (const void **)&itemParams
->matchLimit
, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit
);
2557 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecUseItemList
, (const void **)&itemParams
->useItems
, CFArrayGetTypeID(), NULL
), error_exit
);
2558 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecUseKeychain
, (const void **)&itemParams
->keychain
, SecKeychainGetTypeID(), NULL
), error_exit
);
2560 // validate a subset of input attributes (used to create an appropriate search reference)
2561 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecAttrIssuer
, (const void **)&itemParams
->issuer
, CFDataGetTypeID(), NULL
), error_exit
);
2562 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecAttrSerialNumber
, (const void **)&itemParams
->serialNumber
, CFDataGetTypeID(), NULL
), error_exit
);
2563 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecAttrService
, (const void **)&itemParams
->service
, CFStringGetTypeID(), NULL
), error_exit
);
2564 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecAttrKeyClass
, (const void **)&itemParams
->keyClass
, CFStringGetTypeID(), NULL
), error_exit
);
2566 // must have an item class, unless we have an item list to add
2567 if (!CFDictionaryGetValueIfPresent(dict
, kSecClass
, (const void**) &value
) && !itemParams
->useItems
)
2568 require_action(false, error_exit
, status
= errSecItemClassMissing
);
2570 itemParams
->itemClass
= _ConvertItemClass(value
, itemParams
->keyClass
, &itemParams
->returnIdentity
);
2571 if (itemParams
->itemClass
== kSecSymmetricKeyItemClass
&& !itemParams
->keyClass
) {
2572 itemParams
->assumedKeyClass
= kSecAttrKeyClassSymmetric
; // no key class specified, so start with symmetric key class; will search the others later
2574 require_action(!(itemParams
->itemClass
== 0), error_exit
, status
= errSecItemClassMissing
);
2577 itemParams
->keyUsage
= _CssmKeyUsageFromQuery(dict
);
2578 itemParams
->trustedOnly
= CFDictionaryGetValueIfPresent(dict
, kSecMatchTrustedOnly
, (const void **)&value
) && value
&& CFEqual(kCFBooleanTrue
, value
);
2579 itemParams
->issuerAndSNToMatch
= (itemParams
->issuer
!= NULL
&& itemParams
->serialNumber
!= NULL
);
2581 // other input attributes, used for SecItemAdd but not for finding items
2582 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecAttrAccess
, (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
);
2583 if (itemParams
->access
== NULL
) {
2584 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>)
2585 require_noerr(status
= _ValidateDictionaryEntry(dict
, CFSTR("kSecAttrAccess"), (const void **)&itemParams
->access
, SecAccessGetTypeID(), NULL
), error_exit
);
2588 // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items
2589 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecValueData
, (const void **)&itemParams
->itemData
, CFDataGetTypeID(), CFStringGetTypeID()), error_exit
);
2591 // validate item references
2592 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecValueRef
, (const void **)&itemParams
->itemRef
, SecKeychainItemGetTypeID(), NULL
), error_exit
);
2593 require_noerr(status
= _ValidateDictionaryEntry(dict
, kSecValuePersistentRef
, (const void **)&itemParams
->itemPersistentRef
, CFDataGetTypeID(), NULL
), error_exit
);
2594 if (itemParams
->itemRef
|| itemParams
->itemPersistentRef
) {
2595 // Caller is trying to add or find an item by reference.
2596 // The supported method for doing that is to provide a kSecUseItemList array
2597 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al,
2598 // so add the item reference to those arrays here.
2599 if (itemParams
->useItems
) {
2600 CFArrayRef tmpItems
= itemParams
->useItems
;
2601 itemParams
->useItems
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
);
2602 CFRelease(tmpItems
);
2604 itemParams
->useItems
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
2606 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemRef
);
2607 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->useItems
, itemParams
->itemPersistentRef
);
2609 if (itemParams
->itemList
) {
2610 CFArrayRef tmpItems
= itemParams
->itemList
;
2611 itemParams
->itemList
= (CFArrayRef
) CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, tmpItems
);
2612 CFRelease(tmpItems
);
2614 itemParams
->itemList
= (CFArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
2616 if (itemParams
->itemRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemRef
);
2617 if (itemParams
->itemPersistentRef
) CFArrayAppendValue((CFMutableArrayRef
)itemParams
->itemList
, itemParams
->itemPersistentRef
);
2620 // determine how to return the result
2621 itemParams
->numResultTypes
= 0;
2622 itemParams
->returningRef
= CFDictionaryGetValueIfPresent(dict
, kSecReturnRef
, (const void **)&value
) && value
&& CFEqual(kCFBooleanTrue
, value
);
2623 if (itemParams
->returningRef
) ++itemParams
->numResultTypes
;
2624 itemParams
->returningPersistentRef
= CFDictionaryGetValueIfPresent(dict
, kSecReturnPersistentRef
, (const void **)&value
) && value
&& CFEqual(kCFBooleanTrue
, value
);
2625 if (itemParams
->returningPersistentRef
) ++itemParams
->numResultTypes
;
2626 itemParams
->returningAttributes
= CFDictionaryGetValueIfPresent(dict
, kSecReturnAttributes
, (const void **)&value
) && value
&& CFEqual(kCFBooleanTrue
, value
);
2627 if (itemParams
->returningAttributes
) ++itemParams
->numResultTypes
;
2628 itemParams
->returningData
= CFDictionaryGetValueIfPresent(dict
, kSecReturnData
, (const void **)&value
) && value
&& CFEqual(kCFBooleanTrue
, value
);
2629 if (itemParams
->returningData
) ++itemParams
->numResultTypes
;
2631 // default is kSecReturnRef if no result types were specified
2632 if (!itemParams
->numResultTypes
) {
2633 itemParams
->returningRef
= TRUE
;
2634 itemParams
->numResultTypes
= 1;
2637 // determine if one, some or all matches should be returned (default is kSecMatchLimitOne)
2638 itemParams
->maxMatches
= 1;
2639 itemParams
->returnAllMatches
= FALSE
;
2640 if (itemParams
->matchLimit
) {
2641 if (CFStringGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) {
2642 itemParams
->returnAllMatches
= CFEqual(kSecMatchLimitAll
, itemParams
->matchLimit
);
2644 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams
->matchLimit
)) {
2645 CFNumberGetValue((CFNumberRef
)itemParams
->matchLimit
, kCFNumberIntType
, &itemParams
->maxMatches
);
2646 require_action(!(itemParams
->maxMatches
< 0), error_exit
, status
= errSecMatchLimitUnsupported
);
2649 if (itemParams
->returnAllMatches
) {
2650 itemParams
->maxMatches
= INT32_MAX
;
2651 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each)
2652 if ((itemParams
->itemClass
==kSecInternetPasswordItemClass
|| itemParams
->itemClass
==kSecGenericPasswordItemClass
) && itemParams
->returningData
)
2653 status
= errSecReturnDataUnsupported
;
2654 require_noerr(status
, error_exit
);
2657 // if useItems was provided, we don't need an attribute list or a search reference for adding, although we definitely need one for searching
2658 if (itemParams
->useItems
&& itemParams
->itemClass
== 0) {
2659 require_action(false, error_exit
, status
= noErr
); // all done here
2662 // build a SecKeychainAttributeList from the query dictionary for the specified item class
2663 require_noerr(status
= _CreateSecKeychainAttributeListFromDictionary(dict
, itemParams
->itemClass
, &itemParams
->attrList
), error_exit
);
2665 // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef)
2666 if ((itemParams
->itemClass
== kSecCertificateItemClass
) && itemParams
->emailAddrToMatch
) {
2667 // searching for certificates by email address
2668 char *nameBuf
= (char*)malloc(MAXPATHLEN
);
2670 status
= memFullErr
;
2672 else if (CFStringGetCString((CFStringRef
)itemParams
->emailAddrToMatch
, nameBuf
, (CFIndex
)MAXPATHLEN
-1, kCFStringEncodingUTF8
)) {
2673 status
= SecKeychainSearchCreateForCertificateByEmail(itemParams
->searchList
, (const char *)nameBuf
, (SecKeychainSearchRef
*)&itemParams
->search
);
2676 status
= errSecItemInvalidValue
;
2678 if (nameBuf
) free(nameBuf
);
2680 else if ((itemParams
->itemClass
== kSecCertificateItemClass
) && itemParams
->issuerAndSNToMatch
) {
2681 // searching for certificates by issuer and serial number
2682 status
= SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams
->searchList
,
2683 (CFDataRef
)itemParams
->issuer
,
2684 (CFDataRef
)itemParams
->serialNumber
,
2685 (SecKeychainSearchRef
*)&itemParams
->search
);
2687 else if (itemParams
->returnIdentity
&& itemParams
->policy
) {
2688 // searching for identities by policy
2689 status
= SecIdentitySearchCreateWithPolicy(itemParams
->policy
,
2690 (CFStringRef
)itemParams
->service
,
2691 itemParams
->keyUsage
,
2692 itemParams
->searchList
,
2693 itemParams
->trustedOnly
,
2694 (SecIdentitySearchRef
*)&itemParams
->search
);
2696 else if (itemParams
->returnIdentity
) {
2697 // searching for identities
2698 status
= SecIdentitySearchCreate(itemParams
->searchList
,
2699 itemParams
->keyUsage
,
2700 (SecIdentitySearchRef
*)&itemParams
->search
);
2703 // normal keychain item search
2704 status
= SecKeychainSearchCreateFromAttributes(itemParams
->searchList
,
2705 itemParams
->itemClass
,
2706 (itemParams
->attrList
->count
== 0) ? NULL
: itemParams
->attrList
,
2707 (SecKeychainSearchRef
*)&itemParams
->search
);
2712 _FreeSecItemParams(itemParams
);
2725 SecKeychainRef keychainRef
,
2726 SecAccessRef accessRef
,
2727 SecKeychainAttributeList
*attrList
,
2728 SecKeychainItemRef
*outItemRef
)
2732 // We must specify the access, since a free-floating key won't have one yet by default
2733 SecPointer
<Access
> access
;
2735 access
= Access::required(accessRef
);
2738 CFStringRef descriptor
= NULL
;
2740 for (UInt32 index
=0; index
< attrList
->count
; index
++) {
2741 SecKeychainAttribute attr
= attrList
->attr
[index
];
2742 if (attr
.tag
== kSecKeyPrintName
) {
2743 descriptor
= CFStringCreateWithBytes(NULL
, (const UInt8
*)attr
.data
, attr
.length
, kCFStringEncodingUTF8
, FALSE
);
2748 if (descriptor
== NULL
) {
2749 descriptor
= (CFStringRef
) CFRetain(CFSTR("<unknown>"));
2751 access
= new Access(cfString(descriptor
));
2752 CFRelease(descriptor
);
2755 KeyItem
*key
= KeyItem::required(keyRef
);
2756 Item item
= key
->importTo(Keychain::optional(keychainRef
), access
, attrList
);
2758 *outItemRef
= item
->handle();
2764 _CanIgnoreLeafStatusCodes(CSSM_TP_APPLE_EVIDENCE_INFO
*evidence
)
2766 /* Check for ignorable status codes in leaf certificate's evidence */
2767 Boolean result
= true;
2769 for (i
=0; i
< evidence
->NumStatusCodes
; i
++) {
2770 CSSM_RETURN scode
= evidence
->StatusCodes
[i
];
2771 if (scode
== CSSMERR_APPLETP_INVALID_CA
) {
2772 // the TP has rejected this CA cert because it's in the leaf position
2775 else if (ignorableRevocationStatusCode(scode
)) {
2787 _FilterWithPolicy(SecPolicyRef policy
, SecCertificateRef cert
)
2789 CFDictionaryRef props
= NULL
;
2790 CFArrayRef keychains
= NULL
;
2791 CFArrayRef anchors
= NULL
;
2792 CFArrayRef certs
= NULL
;
2793 CFArrayRef chain
= NULL
;
2794 SecTrustRef trust
= NULL
;
2796 SecTrustResultType trustResult
;
2797 CSSM_TP_APPLE_EVIDENCE_INFO
*evidence
= NULL
;
2798 Boolean needChain
= false;
2800 if (!policy
|| !cert
) return paramErr
;
2802 certs
= CFArrayCreate(NULL
, (const void **)&cert
, (CFIndex
)1, &kCFTypeArrayCallBacks
);
2803 status
= SecTrustCreateWithCertificates(certs
, policy
, &trust
);
2804 if(status
) goto cleanup
;
2806 /* Check whether this is the X509 Basic policy, which means chain building */
2807 props
= SecPolicyCopyProperties(policy
);
2809 CFTypeRef oid
= (CFTypeRef
) CFDictionaryGetValue(props
, kSecPolicyOid
);
2810 if (oid
&& CFEqual(oid
, kSecPolicyAppleX509Basic
)) {
2816 /* To make the evaluation as lightweight as possible, specify an empty array
2817 * of keychains which will be searched for certificates.
2819 keychains
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
2820 status
= SecTrustSetKeychains(trust
, keychains
);
2821 if(status
) goto cleanup
;
2823 /* To make the evaluation as lightweight as possible, specify an empty array
2824 * of trusted anchors.
2826 anchors
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
2827 status
= SecTrustSetAnchorCertificates(trust
, anchors
);
2828 if(status
) goto cleanup
;
2831 /* All parameters are locked and loaded, ready to evaluate! */
2832 status
= SecTrustEvaluate(trust
, &trustResult
);
2833 if(status
) goto cleanup
;
2835 /* If we didn't provide trust anchors or a way to look for them,
2836 * the evaluation will fail with kSecTrustResultRecoverableTrustFailure.
2837 * However, we can tell whether the policy evaluation succeeded by
2838 * looking at the per-cert status codes in the returned evidence.
2840 status
= SecTrustGetResult(trust
, &trustResult
, &chain
, &evidence
);
2841 if(status
) goto cleanup
;
2843 if (!(trustResult
== kSecTrustResultProceed
||
2844 trustResult
== kSecTrustResultUnspecified
||
2845 trustResult
== kSecTrustResultRecoverableTrustFailure
)) {
2846 /* The evaluation failed in a non-recoverable way */
2847 status
= errSecCertificateCannotOperate
;
2851 /* If there are no per-cert policy status codes,
2852 * and the cert has not expired, consider it valid for the policy.
2854 if((evidence
!= NULL
) && _CanIgnoreLeafStatusCodes(evidence
) &&
2855 ((evidence
[0].StatusBits
& CSSM_CERT_STATUS_EXPIRED
) == 0) &&
2856 ((evidence
[0].StatusBits
& CSSM_CERT_STATUS_NOT_VALID_YET
) == 0)) {
2860 status
= errSecCertificateCannotOperate
;
2864 if(props
) CFRelease(props
);
2865 if(chain
) CFRelease(chain
);
2866 if(anchors
) CFRelease(anchors
);
2867 if(keychains
) CFRelease(keychains
);
2868 if(certs
) CFRelease(certs
);
2869 if(trust
) CFRelease(trust
);
2875 _FilterWithDate(CFTypeRef validOnDate
, SecCertificateRef cert
)
2877 if (!validOnDate
|| !cert
) return paramErr
;
2879 CFAbsoluteTime at
, nb
, na
;
2880 if (CFGetTypeID(validOnDate
) == CFDateGetTypeID())
2881 at
= CFDateGetAbsoluteTime((CFDateRef
)validOnDate
);
2883 at
= CFAbsoluteTimeGetCurrent();
2885 OSStatus status
= noErr
;
2886 SecCertificateRefP certP
= NULL
;
2887 CFDataRef certData
= SecCertificateCopyData(cert
);
2889 certP
= SecCertificateCreateWithDataP(kCFAllocatorDefault
, certData
);
2892 nb
= SecCertificateNotValidBefore(certP
);
2893 na
= SecCertificateNotValidAfter(certP
);
2896 status
= errSecCertificateNotValidYet
;
2898 status
= errSecCertificateExpired
;
2901 status
= errSecCertificateCannotOperate
;
2904 if(certData
) CFRelease(certData
);
2905 if(certP
) CFRelease(certP
);
2910 _FilterWithTrust(Boolean trustedOnly
, SecCertificateRef cert
)
2912 if (!cert
) return paramErr
;
2913 if (!trustedOnly
) return noErr
;
2915 CFArrayRef certArray
= CFArrayCreate(NULL
, (const void**)&cert
, 1, &kCFTypeArrayCallBacks
);
2916 SecPolicyRef policy
= SecPolicyCreateWithOID(kSecPolicyAppleX509Basic
);
2917 OSStatus status
= (policy
== NULL
) ? errSecPolicyNotFound
: errSecSuccess
;
2920 SecTrustRef trust
= NULL
;
2921 status
= SecTrustCreateWithCertificates(certArray
, policy
, &trust
);
2923 SecTrustResultType trustResult
;
2924 status
= SecTrustEvaluate(trust
, &trustResult
);
2926 if (!(trustResult
== kSecTrustResultProceed
|| trustResult
== kSecTrustResultUnspecified
)) {
2927 status
= (trustResult
== kSecTrustResultDeny
) ? errSecTrustSettingDeny
: errSecNotTrusted
;
2935 CFRelease(certArray
);
2942 UpdateKeychainSearchAndCopyNext(SecItemParams
*params
, CFTypeRef
*item
)
2944 // This function refreshes the search parameters in the specific case where
2945 // the caller is searching for kSecClassKey items but did not provide the
2946 // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and
2947 // we must perform separate searches to obtain all results.
2949 OSStatus status
= errSecItemNotFound
;
2950 if (!params
|| !params
->assumedKeyClass
|| !params
->query
|| !item
)
2953 // Free the previous search reference and attribute list.
2955 CFRelease(params
->search
);
2956 params
->search
= NULL
;
2957 _FreeAttrList(params
->attrList
);
2958 params
->attrList
= NULL
;
2960 // Make a copy of the query dictionary so we can set the key class parameter.
2961 CFMutableDictionaryRef dict
= CFDictionaryCreateMutableCopy(NULL
, 0, params
->query
);
2962 CFRelease(params
->query
);
2963 params
->query
= dict
;
2964 CFDictionarySetValue(dict
, kSecAttrKeyClass
, params
->assumedKeyClass
);
2966 // Determine the current item class for this search, and the next assumed key class.
2967 if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassSymmetric
)) {
2968 params
->itemClass
= kSecSymmetricKeyItemClass
;
2969 params
->assumedKeyClass
= kSecAttrKeyClassPublic
;
2970 } else if (CFEqual(params
->assumedKeyClass
, kSecAttrKeyClassPublic
)) {
2971 params
->itemClass
= kSecPublicKeyItemClass
;
2972 params
->assumedKeyClass
= kSecAttrKeyClassPrivate
;
2974 params
->itemClass
= kSecPrivateKeyItemClass
;
2975 params
->assumedKeyClass
= NULL
;
2978 // Rebuild the attribute list for the new key class.
2979 if (_CreateSecKeychainAttributeListFromDictionary(dict
, params
->itemClass
, ¶ms
->attrList
) == noErr
) {
2980 // Create a new search reference for the new attribute list.
2981 if (SecKeychainSearchCreateFromAttributes(params
->searchList
,
2983 (params
->attrList
->count
== 0) ? NULL
: params
->attrList
,
2984 (SecKeychainSearchRef
*)¶ms
->search
) == noErr
) {
2985 // Return the first matching item from the new search.
2986 // We won't come back here again until there are no more matching items for this search.
2987 status
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)params
->search
, (SecKeychainItemRef
*)item
);
2995 SecItemSearchCopyNext(SecItemParams
*params
, CFTypeRef
*item
)
2997 // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef.
2998 // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter,
2999 // depending on the type of search reference.
3002 CFTypeRef search
= (params
) ? params
->search
: NULL
;
3003 CFTypeID typeID
= (search
) ? CFGetTypeID(search
) : 0;
3004 if (typeID
== SecIdentitySearchGetTypeID()) {
3005 status
= SecIdentitySearchCopyNext((SecIdentitySearchRef
)search
, (SecIdentityRef
*)item
);
3007 else if (typeID
== SecKeychainSearchGetTypeID()) {
3008 status
= SecKeychainSearchCopyNext((SecKeychainSearchRef
)search
, (SecKeychainItemRef
*)item
);
3009 // Check if we need to refresh the search for the next key class
3010 while (status
== errSecItemNotFound
&& params
->assumedKeyClass
!= NULL
)
3011 status
= UpdateKeychainSearchAndCopyNext(params
, item
);
3014 status
= errSecItemNotFound
;
3020 FilterCandidateItem(CFTypeRef
*item
, SecItemParams
*itemParams
, SecIdentityRef
*identity
)
3022 if (!item
|| *item
== NULL
|| !itemParams
)
3023 return errSecItemNotFound
;
3026 CFStringRef commonName
= NULL
;
3027 SecIdentityRef foundIdentity
= NULL
;
3028 if (CFGetTypeID(*item
) == SecIdentityGetTypeID()) {
3029 // we found a SecIdentityRef, rather than a SecKeychainItemRef;
3030 // replace the found "item" with its associated certificate (which is the
3031 // item we actually want for purposes of getting attributes, data, or a
3032 // persistent data reference), and return the identity separately.
3033 SecCertificateRef certificate
;
3034 status
= SecIdentityCopyCertificate((SecIdentityRef
) *item
, &certificate
);
3035 if (itemParams
->returnIdentity
) {
3036 foundIdentity
= (SecIdentityRef
) *item
;
3038 *identity
= foundIdentity
;
3044 *item
= (CFTypeRef
)certificate
;
3047 CFDictionaryRef query
= itemParams
->query
;
3049 if (itemParams
->itemClass
== kSecCertificateItemClass
) {
3050 // perform string comparisons first
3051 CFStringCompareFlags flags
= _StringCompareFlagsFromQuery(query
);
3052 CFStringRef nameContains
, nameStarts
, nameEnds
, nameExact
;
3053 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectContains
, (const void **)&nameContains
))
3054 nameContains
= NULL
;
3055 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectStartsWith
, (const void **)&nameStarts
))
3057 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectEndsWith
, (const void **)&nameEnds
))
3059 if (!CFDictionaryGetValueIfPresent(query
, kSecMatchSubjectWholeString
, (const void **)&nameExact
))
3061 if (nameContains
|| nameStarts
|| nameEnds
|| nameExact
) {
3062 status
= SecCertificateCopyCommonName((SecCertificateRef
)*item
, &commonName
);
3063 if (status
|| !commonName
) goto filterOut
;
3066 CFRange range
= CFStringFind(commonName
, nameContains
, flags
);
3067 if (range
.length
< 1)
3069 // certificate item contains string; proceed to next check
3072 CFRange range
= CFStringFind(commonName
, nameStarts
, flags
);
3073 if (range
.length
< 1 || range
.location
> 1)
3075 // certificate item starts with string; proceed to next check
3078 CFRange range
= CFStringFind(commonName
, nameEnds
, flags
);
3079 if (range
.length
< 1 || range
.location
!= (CFStringGetLength(commonName
) - CFStringGetLength(nameEnds
)))
3081 // certificate item ends with string; proceed to next check
3084 CFRange range
= CFStringFind(commonName
, nameExact
, flags
);
3085 if (range
.length
< 1 || (CFStringGetLength(commonName
) != CFStringGetLength(nameExact
)))
3087 // certificate item exactly matches string; proceed to next check
3089 if (itemParams
->returnIdentity
) {
3090 // if we already found and returned the identity, we can skip this
3091 if (!foundIdentity
) {
3092 status
= SecIdentityCreateWithCertificate(itemParams
->searchList
, (SecCertificateRef
) *item
, identity
);
3093 if (status
) goto filterOut
;
3095 // certificate item is part of an identity; proceed to next check
3097 if (itemParams
->policy
) {
3098 status
= _FilterWithPolicy(itemParams
->policy
, (SecCertificateRef
) *item
);
3099 if (status
) goto filterOut
;
3100 // certificate item is valid for specified policy
3102 if (itemParams
->validOnDate
) {
3103 status
= _FilterWithDate(itemParams
->validOnDate
, (SecCertificateRef
) *item
);
3104 if (status
) goto filterOut
;
3105 // certificate item is valid for specified date
3107 if (itemParams
->trustedOnly
) {
3108 // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search,
3109 // their trust has already been validated and we can skip this part.
3110 if (!(foundIdentity
&& itemParams
->returnIdentity
&& itemParams
->policy
)) {
3111 status
= _FilterWithTrust(itemParams
->trustedOnly
, (SecCertificateRef
) *item
);
3112 if (status
) goto filterOut
;
3114 // certificate item is trusted on this system
3117 if (itemParams
->itemList
) {
3118 Boolean foundMatch
= FALSE
;
3119 CFIndex idx
, count
= CFArrayGetCount(itemParams
->itemList
);
3120 for (idx
=0; idx
<count
; idx
++) {
3121 CFTypeRef anItem
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->itemList
, idx
);
3122 SecKeychainItemRef realItem
= NULL
;
3123 SecCertificateRef aCert
= NULL
;
3124 if (anItem
== NULL
) {
3127 if (CFDataGetTypeID() == CFGetTypeID(anItem
) &&
3128 noErr
== SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
)) {
3131 if (SecIdentityGetTypeID() == CFGetTypeID(anItem
) &&
3132 noErr
== SecIdentityCopyCertificate((SecIdentityRef
)anItem
, &aCert
)) {
3135 if (CFEqual(anItem
, (CFTypeRef
) *item
)) {
3142 CFRelease(realItem
);
3148 if (!foundMatch
) goto filterOut
;
3149 // item was found on provided list
3152 if (foundIdentity
&& !identity
) {
3153 CFRelease(foundIdentity
);
3156 CFRelease(commonName
);
3159 // if we get here, consider the item a match
3164 CFRelease(commonName
);
3168 if (foundIdentity
) {
3169 CFRelease(foundIdentity
);
3174 return errSecItemNotFound
;
3178 AddItemResults(SecKeychainItemRef item
,
3179 SecIdentityRef identity
,
3180 SecItemParams
*itemParams
,
3181 CFAllocatorRef allocator
,
3182 CFMutableArrayRef
*items
,
3185 // Given a found item (which may also be an identity), this function adds
3186 // the requested result types (specified in itemParams) to the appropriate
3187 // container as follows:
3189 // 1. If there is only one result type (numResultTypes == 1) and only one
3190 // match requested (maxMatches == 1), set *result directly.
3192 // 2. If there are multiple result types (numResultTypes > 1), and only one
3193 // match requested (maxMatches == 1), add each result type to itemDict
3194 // and set itemDict as the value of *result.
3196 // 3. If there is only one result type (numResultTypes == 1) and multiple
3197 // possible matches (maxMatches > 1), add the result type to *items
3198 // and set *items as the value of *result.
3200 // 4. If there are multiple result types (numResultTypes > 1) and multiple
3201 // possible matches (maxMatches > 1), add each result type to itemDict,
3202 // add itemDict to *items, and set *items as the value of *result.
3204 // Note that we allocate *items if needed.
3206 if (!item
|| !itemParams
|| !result
)
3209 if (itemParams
->maxMatches
> 1) {
3210 // if we can return more than one item, we must have an array
3213 else if (*items
== NULL
)
3214 *items
= CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
3217 OSStatus tmpStatus
, status
= noErr
;
3218 CFMutableArrayRef itemArray
= (items
) ? *items
: NULL
;
3219 CFMutableDictionaryRef itemDict
= NULL
;
3220 if (itemParams
->numResultTypes
> 1) {
3221 // if we're returning more than one result type, each item we return must be a dictionary
3222 itemDict
= CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3225 if (itemParams
->returningRef
) {
3226 const void* itemRef
= (identity
) ? (const void*)identity
: (const void*)item
;
3228 CFDictionaryAddValue(itemDict
, kSecValueRef
, itemRef
);
3230 else if (itemArray
) {
3231 CFArrayAppendValue(itemArray
, itemRef
);
3234 *result
= CFRetain((CFTypeRef
)itemRef
);
3238 if (itemParams
->returningPersistentRef
) {
3239 CFDataRef persistentRef
;
3240 tmpStatus
= SecKeychainItemCreatePersistentReference(item
, &persistentRef
);
3241 if (tmpStatus
== noErr
) {
3243 CFDictionaryAddValue(itemDict
, kSecValuePersistentRef
, persistentRef
);
3245 else if (itemArray
) {
3246 CFArrayAppendValue(itemArray
, persistentRef
);
3249 *result
= CFRetain(persistentRef
);
3251 CFRelease(persistentRef
);
3253 else if (status
== noErr
) {
3258 if (itemParams
->returningData
) {
3261 tmpStatus
= SecKeychainItemCopyContent(item
, NULL
, NULL
, &length
, &data
);
3262 if (tmpStatus
== noErr
) {
3263 CFDataRef dataRef
= CFDataCreate(allocator
, (UInt8
*)data
, length
);
3265 CFDictionaryAddValue(itemDict
, kSecValueData
, dataRef
);
3267 else if (itemArray
) {
3268 CFArrayAppendValue(itemArray
, dataRef
);
3271 *result
= CFRetain(dataRef
);
3274 (void) SecKeychainItemFreeContent(NULL
, data
);
3276 else if (status
== noErr
) {
3281 if (itemParams
->returningAttributes
) {
3282 CFDictionaryRef attrsDict
= NULL
;
3283 SecItemClass itemClass
;
3284 // since we have an item, allow its actual class to override the query-specified item class
3285 tmpStatus
= SecKeychainItemCopyAttributesAndData(item
, NULL
, &itemClass
, NULL
, NULL
, NULL
);
3287 itemClass
= itemParams
->itemClass
;
3289 tmpStatus
= _CreateAttributesDictionaryFromItem(allocator
, itemClass
, item
, &attrsDict
);
3292 // add all keys and values from attrsDict to the item dictionary
3293 CFDictionaryApplyFunction(attrsDict
, _AddDictValueToOtherDict
, &itemDict
);
3295 else if (itemArray
) {
3296 CFArrayAppendValue(itemArray
, attrsDict
);
3299 *result
= CFRetain(attrsDict
);
3301 CFRelease(attrsDict
);
3303 if (tmpStatus
&& (status
== noErr
)) {
3310 CFArrayAppendValue(itemArray
, itemDict
);
3311 CFRelease(itemDict
);
3312 *result
= itemArray
;
3318 else if (itemArray
) {
3319 *result
= itemArray
;
3326 /******************************************************************************/
3327 #pragma mark SecItem API functions
3328 /******************************************************************************/
3330 static Boolean
SecItemSynchronizable(CFDictionaryRef query
)
3332 static dispatch_once_t onceToken
;
3333 static Boolean synchronizable
= false;
3335 //sudo defaults write /Library/Preferences/com.apple.security SecItemSynchronizable -bool YES
3336 dispatch_once(&onceToken
, ^{
3337 CFTypeRef sync
= (CFNumberRef
)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser
, kCFPreferencesCurrentHost
);
3339 if (sync
&& CFGetTypeID(sync
) == CFBooleanGetTypeID()) {
3340 synchronizable
= CFBooleanGetValue((CFBooleanRef
)sync
);
3345 if (synchronizable
) {
3346 CFTypeRef value
= NULL
;
3347 return (_ValidateDictionaryEntry(query
, kSecAttrSynchronizable
, (const void**)&value
, CFBooleanGetTypeID(), NULL
) == noErr
&& value
&& CFEqual(kCFBooleanTrue
, value
));
3350 return synchronizable
;
3354 SecItemCopyMatching(CFDictionaryRef query
, CFTypeRef
*result
)
3356 if (!query
|| !result
)
3359 if (SecItemSynchronizable(query
)) {
3360 return SecItemCopyMatching_ios(query
, result
);
3363 return SecItemCopyMatching_osx(query
, result
);
3367 SecItemAdd(CFDictionaryRef attributes
, CFTypeRef
*result
)
3374 if (SecItemSynchronizable(attributes
)) {
3375 return SecItemAdd_ios(attributes
, result
);
3378 return SecItemAdd_osx(attributes
, result
);
3382 SecItemUpdate(CFDictionaryRef query
, CFDictionaryRef attributesToUpdate
)
3384 if (!query
|| !attributesToUpdate
)
3387 if (SecItemSynchronizable(query
)) {
3388 return SecItemUpdate_ios(query
, attributesToUpdate
);
3391 return SecItemUpdate_osx(query
, attributesToUpdate
);
3395 SecItemDelete(CFDictionaryRef query
)
3400 if (SecItemSynchronizable(query
)) {
3401 return SecItemDelete_ios(query
);
3404 return SecItemDelete_osx(query
);
3408 SecItemCopyMatching_osx(
3409 CFDictionaryRef query
,
3412 if (!query
|| !result
)
3417 CFAllocatorRef allocator
= CFGetAllocator(query
);
3418 CFIndex matchCount
= 0;
3419 CFMutableArrayRef itemArray
= NULL
;
3420 SecKeychainItemRef item
= NULL
;
3421 SecIdentityRef identity
= NULL
;
3422 OSStatus tmpStatus
, status
= noErr
;
3424 // validate input query parameters and create the search reference
3425 SecItemParams
*itemParams
= _CreateSecItemParamsFromDictionary(query
, &status
);
3426 require_action(itemParams
!= NULL
, error_exit
, itemParams
= NULL
);
3428 // find the next match until we hit maxMatches, or no more matches found
3429 while ( !(!itemParams
->returnAllMatches
&& matchCount
>= itemParams
->maxMatches
) &&
3430 SecItemSearchCopyNext(itemParams
, (CFTypeRef
*)&item
) == noErr
) {
3432 if (FilterCandidateItem((CFTypeRef
*)&item
, itemParams
, &identity
))
3433 continue; // move on to next item
3435 ++matchCount
; // we have a match
3437 tmpStatus
= AddItemResults(item
, identity
, itemParams
, allocator
, &itemArray
, result
);
3438 if (tmpStatus
&& (status
== noErr
))
3446 CFRelease(identity
);
3451 if (status
== noErr
)
3452 status
= (matchCount
> 0) ? errSecSuccess
: errSecItemNotFound
;
3455 if (status
!= noErr
&& result
!= NULL
&& *result
!= NULL
) {
3459 _FreeSecItemParams(itemParams
);
3465 SecItemCopyDisplayNames(
3467 CFArrayRef
*displayNames
)
3471 Required(displayNames
);
3479 CFDictionaryRef attributes
,
3487 CFAllocatorRef allocator
= CFGetAllocator(attributes
);
3488 CFMutableArrayRef itemArray
= NULL
;
3489 SecKeychainItemRef item
= NULL
;
3490 OSStatus tmpStatus
, status
= noErr
;
3492 // validate input attribute parameters
3493 SecItemParams
*itemParams
= _CreateSecItemParamsFromDictionary(attributes
, &status
);
3494 require_action(itemParams
!= NULL
, error_exit
, itemParams
= NULL
);
3496 // currently, we don't support adding SecIdentityRef items (an aggregate item class),
3497 // since the private key should already be in a keychain by definition. We could support
3498 // this as a copy operation for the private key if a different keychain is specified,
3499 // but in any case it should try to add the certificate. See <rdar://8317887>.
3500 require_action(!itemParams
->returnIdentity
, error_exit
, status
= errSecItemInvalidValue
);
3502 if (!itemParams
->useItems
) {
3503 // create a single keychain item specified by the input attributes
3504 status
= SecKeychainItemCreateFromContent(itemParams
->itemClass
,
3505 itemParams
->attrList
,
3506 (itemParams
->itemData
) ? CFDataGetLength(itemParams
->itemData
) : 0,
3507 (itemParams
->itemData
) ? CFDataGetBytePtrVoid(itemParams
->itemData
) : NULL
,
3508 itemParams
->keychain
,
3511 require_noerr(status
, error_exit
);
3513 // return results (if requested)
3515 itemParams
->maxMatches
= 1; // in case kSecMatchLimit was set to > 1
3516 tmpStatus
= AddItemResults(item
, NULL
, itemParams
, allocator
, &itemArray
, result
);
3517 if (tmpStatus
&& (status
== noErr
))
3523 // add multiple items which are specified in the itemParams->useItems array.
3524 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain.
3525 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain.
3526 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain.
3528 OSStatus aggregateStatus
= noErr
;
3529 CFIndex ix
, count
= CFArrayGetCount(itemParams
->useItems
);
3530 itemParams
->maxMatches
= (count
> 1) ? count
: 2; // force results to always be returned as an array
3531 for (ix
=0; ix
< count
; ix
++) {
3532 CFTypeRef anItem
= (CFTypeRef
) CFArrayGetValueAtIndex(itemParams
->useItems
, ix
);
3534 if (SecCertificateGetTypeID() == CFGetTypeID(anItem
)) {
3535 // SecCertificateRef item
3536 tmpStatus
= SecCertificateAddToKeychain((SecCertificateRef
)anItem
, itemParams
->keychain
);
3537 if (!tmpStatus
&& result
) {
3538 tmpStatus
= AddItemResults((SecKeychainItemRef
)anItem
, NULL
, itemParams
, allocator
, &itemArray
, result
);
3540 aggregateStatus
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
);
3542 else if (SecKeyGetTypeID() == CFGetTypeID(anItem
)) {
3544 SecKeychainRef itemKeychain
= NULL
;
3545 tmpStatus
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)anItem
, &itemKeychain
);
3546 if (tmpStatus
== noErr
) {
3547 // key was in a keychain, so we can attempt to copy it
3548 SecKeychainItemRef itemCopy
= NULL
;
3549 tmpStatus
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
);
3550 if (!tmpStatus
&& result
) {
3551 tmpStatus
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
);
3554 CFRelease(itemCopy
);
3558 // key was not in any keychain, so must be imported
3559 SecKeychainItemRef keyItem
= NULL
;
3560 tmpStatus
= _ImportKey((SecKeyRef
)anItem
, itemParams
->keychain
, itemParams
->access
, itemParams
->attrList
, &keyItem
);
3561 if (!tmpStatus
&& result
) {
3562 tmpStatus
= AddItemResults(keyItem
, NULL
, itemParams
, allocator
, &itemArray
, result
);
3569 CFRelease(itemKeychain
);
3571 aggregateStatus
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
);
3573 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem
)) {
3574 // SecKeychainItemRef item
3575 SecKeychainItemRef itemCopy
= NULL
;
3576 tmpStatus
= SecKeychainItemCreateCopy((SecKeychainItemRef
)anItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
);
3577 if (!tmpStatus
&& result
) {
3578 tmpStatus
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
);
3581 CFRelease(itemCopy
);
3583 aggregateStatus
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
);
3585 else if (CFDataGetTypeID() == CFGetTypeID(anItem
)) {
3586 // CFDataRef item (persistent reference)
3587 SecKeychainItemRef realItem
= NULL
;
3588 tmpStatus
= SecKeychainItemCopyFromPersistentReference((CFDataRef
)anItem
, &realItem
);
3589 if (tmpStatus
== noErr
) {
3590 // persistent reference resolved to a keychain item, so we can attempt to copy it
3591 SecKeychainItemRef itemCopy
= NULL
;
3592 tmpStatus
= SecKeychainItemCreateCopy(realItem
, itemParams
->keychain
, itemParams
->access
, &itemCopy
);
3593 if (!tmpStatus
&& result
) {
3594 tmpStatus
= AddItemResults(itemCopy
, NULL
, itemParams
, allocator
, &itemArray
, result
);
3597 CFRelease(itemCopy
);
3601 CFRelease(realItem
);
3603 aggregateStatus
= _UpdateAggregateStatus(tmpStatus
, aggregateStatus
, errSecDuplicateItem
);
3606 } // end of itemList array loop
3607 status
= aggregateStatus
;
3608 } // end processing multiple items
3611 if (status
!= noErr
&& result
!= NULL
&& *result
!= NULL
) {
3615 _FreeSecItemParams(itemParams
);
3622 CFDictionaryRef query
,
3623 CFDictionaryRef attributesToUpdate
)
3625 if (!query
|| !attributesToUpdate
)
3628 // run the provided query to get a list of items to update
3629 CFTypeRef results
= NULL
;
3630 OSStatus status
= SecItemCopyMatching(query
, &results
);
3631 if (status
!= noErr
)
3632 return status
; // nothing was matched, or the query was bad
3634 CFArrayRef items
= NULL
;
3635 if (CFArrayGetTypeID() == CFGetTypeID(results
)) {
3636 items
= (CFArrayRef
) results
;
3639 items
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
);
3643 OSStatus result
= noErr
;
3644 CFIndex ix
, count
= CFArrayGetCount(items
);
3645 for (ix
=0; ix
< count
; ix
++) {
3646 CFTypeRef anItem
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
);
3648 status
= _UpdateKeychainItem(anItem
, attributesToUpdate
);
3649 result
= _UpdateAggregateStatus(status
, result
, noErr
);
3661 CFDictionaryRef query
)
3666 // run the provided query to get a list of items to delete
3667 CFTypeRef results
= NULL
;
3668 OSStatus status
= SecItemCopyMatching(query
, &results
);
3669 if (status
!= noErr
)
3670 return status
; // nothing was matched, or the query was bad
3672 CFArrayRef items
= NULL
;
3673 if (CFArrayGetTypeID() == CFGetTypeID(results
)) {
3674 items
= (CFArrayRef
) results
;
3677 items
= CFArrayCreate(NULL
, &results
, 1, &kCFTypeArrayCallBacks
);
3681 OSStatus result
= noErr
;
3682 CFIndex ix
, count
= CFArrayGetCount(items
);
3683 for (ix
=0; ix
< count
; ix
++) {
3684 CFTypeRef anItem
= (CFTypeRef
) CFArrayGetValueAtIndex(items
, ix
);
3686 if (SecIdentityGetTypeID() == CFGetTypeID(anItem
)) {
3687 status
= _DeleteIdentity((SecIdentityRef
)anItem
);
3690 status
= _DeleteKeychainItem(anItem
);
3692 result
= _UpdateAggregateStatus(status
, result
, noErr
);