1/*
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include "SecBridge.h"
25#include "SecInternal.h"
26#include <CoreFoundation/CoreFoundation.h>
27#include <security_utilities/cfutilities.h>
28#include <Security/SecBase.h>
29#include <Security/SecKeychainItem.h>
30#include <Security/SecCertificate.h>
31#include <sys/param.h>
32#include "cssmdatetime.h"
33#include "SecItem.h"
34#include "SecItemPriv.h"
35#include "SecIdentitySearchPriv.h"
36#include "SecKeychainPriv.h"
37#include "SecCertificatePriv.h"
38#include "SecCertificatePrivP.h"
39#include "TrustAdditions.h"
40
41#include <AssertMacros.h>
42#include <syslog.h>
43
44#include <Security/SecTrustedApplication.h>
45#include <Security/SecTrustedApplicationPriv.h>
46#include <Security/SecCode.h>
47#include <Security/SecCodePriv.h>
48#include <Security/SecRequirement.h>
49
50const uint8_t kUUIDStringLength = 36;
51
52OSStatus SecItemAdd_osx(CFDictionaryRef attributes, CFTypeRef *result);
53OSStatus SecItemCopyMatching_osx(CFDictionaryRef query, CFTypeRef *result);
54OSStatus SecItemUpdate_osx(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
55OSStatus SecItemDelete_osx(CFDictionaryRef query);
56
57extern "C" {
58OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result);
59OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result);
60OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
61OSStatus SecItemDelete_ios(CFDictionaryRef query);
62
63CFTypeRef SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes);
64CFTypeRef SecItemCopyMergedResults(CFDictionaryRef query, CFTypeRef result_osx, CFTypeRef result_ios);
65OSStatus SecItemValidateAppleApplicationGroupAccess(CFStringRef group);
66CFDictionaryRef SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass,
67	bool iOSOut, bool pruneMatch, bool pruneSync, bool pruneReturn, bool pruneData, bool pruneAccess);
68}
69
70static Boolean SecItemSynchronizable(CFDictionaryRef query);
71
72static void secitemlog(int priority, const char *format, ...)
73{
74#ifndef NDEBUG
75	// log everything
76#else
77	if (priority < LOG_NOTICE) // log warnings and errors
78#endif
79	{
80		va_list list;
81		va_start(list, format);
82		vsyslog(priority, format, list);
83		va_end(list);
84	}
85}
86
87static void secitemshow(CFTypeRef obj, const char *context)
88{
89#ifndef NDEBUG
90	CFStringRef desc = CFCopyDescription(obj);
91	if (!desc) return;
92
93	CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(desc), kCFStringEncodingUTF8) + 1;
94	char* buffer = (char*) malloc(length);
95	if (buffer) {
96		Boolean converted = CFStringGetCString(desc, buffer, length, kCFStringEncodingUTF8);
97		if (converted) {
98			const char *prefix = (context) ? context : "";
99			const char *separator = (context) ? " " : "";
100			secitemlog(LOG_NOTICE, "%s%s%s", prefix, separator, buffer);
101		}
102		free(buffer);
103	}
104	CFRelease(desc);
105#endif
106}
107
108
109#define CFDataGetBytePtrVoid CFDataGetBytePtr
110
111#pragma mark SecItem private utility functions
112
113/******************************************************************************/
114
115struct ProtocolAttributeInfo {
116	const CFTypeRef *protocolValue;
117	SecProtocolType protocolType;
118};
119
120static ProtocolAttributeInfo gProtocolTypes[] = {
121	{ &kSecAttrProtocolFTP, kSecProtocolTypeFTP },
122	{ &kSecAttrProtocolFTPAccount, kSecProtocolTypeFTPAccount },
123	{ &kSecAttrProtocolHTTP, kSecProtocolTypeHTTP },
124	{ &kSecAttrProtocolIRC, kSecProtocolTypeIRC },
125	{ &kSecAttrProtocolNNTP, kSecProtocolTypeNNTP },
126	{ &kSecAttrProtocolPOP3, kSecProtocolTypePOP3 },
127	{ &kSecAttrProtocolSMTP, kSecProtocolTypeSMTP },
128	{ &kSecAttrProtocolSOCKS, kSecProtocolTypeSOCKS },
129	{ &kSecAttrProtocolIMAP, kSecProtocolTypeIMAP },
130	{ &kSecAttrProtocolLDAP, kSecProtocolTypeLDAP },
131	{ &kSecAttrProtocolAppleTalk, kSecProtocolTypeAppleTalk },
132	{ &kSecAttrProtocolAFP, kSecProtocolTypeAFP },
133	{ &kSecAttrProtocolTelnet, kSecProtocolTypeTelnet },
134	{ &kSecAttrProtocolSSH, kSecProtocolTypeSSH },
135	{ &kSecAttrProtocolFTPS, kSecProtocolTypeFTPS },
136	{ &kSecAttrProtocolHTTPS, kSecProtocolTypeHTTPS },
137	{ &kSecAttrProtocolHTTPProxy, kSecProtocolTypeHTTPProxy },
138	{ &kSecAttrProtocolHTTPSProxy, kSecProtocolTypeHTTPSProxy },
139	{ &kSecAttrProtocolFTPProxy, kSecProtocolTypeFTPProxy },
140	{ &kSecAttrProtocolSMB, kSecProtocolTypeSMB },
141	{ &kSecAttrProtocolRTSP, kSecProtocolTypeRTSP },
142	{ &kSecAttrProtocolRTSPProxy, kSecProtocolTypeRTSPProxy },
143	{ &kSecAttrProtocolDAAP, kSecProtocolTypeDAAP },
144	{ &kSecAttrProtocolEPPC, kSecProtocolTypeEPPC },
145	{ &kSecAttrProtocolIPP, kSecProtocolTypeIPP },
146	{ &kSecAttrProtocolNNTPS, kSecProtocolTypeNNTPS },
147	{ &kSecAttrProtocolLDAPS, kSecProtocolTypeLDAPS },
148	{ &kSecAttrProtocolTelnetS, kSecProtocolTypeTelnetS },
149	{ &kSecAttrProtocolIMAPS, kSecProtocolTypeIMAPS },
150	{ &kSecAttrProtocolIRCS, kSecProtocolTypeIRCS },
151	{ &kSecAttrProtocolPOP3S, kSecProtocolTypePOP3S }
152};
153
154static const int kNumberOfProtocolTypes = sizeof(gProtocolTypes) / sizeof(ProtocolAttributeInfo);
155
156/*
157 * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType.
158 */
159static SecProtocolType
160_SecProtocolTypeForSecAttrProtocol(
161	CFTypeRef protocol)
162{
163	SecProtocolType result = kSecProtocolTypeAny;
164
165	if (protocol != NULL) {
166		CFIndex count;
167		for (count=0; count<kNumberOfProtocolTypes; count++) {
168			if (CFEqual(protocol, *(gProtocolTypes[count].protocolValue))) {
169				result = gProtocolTypes[count].protocolType;
170				break;
171			}
172		}
173	}
174
175	return result;
176}
177
178/*
179 * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol.
180 */
181static CFTypeRef
182_SecAttrProtocolForSecProtocolType(
183	SecProtocolType protocolType)
184{
185	CFTypeRef result = NULL;
186	CFIndex count;
187	for (count=0; count<kNumberOfProtocolTypes; count++) {
188		if (gProtocolTypes[count].protocolType == protocolType) {
189			result = *(gProtocolTypes[count].protocolValue);
190			break;
191		}
192	}
193
194	return result;
195}
196
197
198/******************************************************************************/
199
200struct AuthenticationAttributeInfo {
201	const CFTypeRef *authValue;
202	SecAuthenticationType authType;
203};
204
205static AuthenticationAttributeInfo gAuthTypes[] = {
206	{ &kSecAttrAuthenticationTypeNTLM, kSecAuthenticationTypeNTLM },
207	{ &kSecAttrAuthenticationTypeMSN, kSecAuthenticationTypeMSN },
208	{ &kSecAttrAuthenticationTypeDPA, kSecAuthenticationTypeDPA },
209	{ &kSecAttrAuthenticationTypeRPA, kSecAuthenticationTypeRPA },
210	{ &kSecAttrAuthenticationTypeHTTPBasic, kSecAuthenticationTypeHTTPBasic },
211	{ &kSecAttrAuthenticationTypeHTTPDigest, kSecAuthenticationTypeHTTPDigest },
212	{ &kSecAttrAuthenticationTypeHTMLForm, kSecAuthenticationTypeHTMLForm },
213	{ &kSecAttrAuthenticationTypeDefault, kSecAuthenticationTypeDefault }
214};
215
216static const int kNumberOfAuthenticationTypes = sizeof(gAuthTypes) / sizeof(AuthenticationAttributeInfo);
217
218/*
219 * _SecAuthenticationTypeForSecAttrAuthenticationType converts a
220 * SecAttrAuthenticationType to a SecAuthenticationType.
221 */
222static SecAuthenticationType
223_SecAuthenticationTypeForSecAttrAuthenticationType(
224	CFTypeRef authenticationType)
225{
226	SecAuthenticationType result = kSecAuthenticationTypeAny;
227
228	if (authenticationType != NULL) {
229		CFIndex count;
230		for (count=0; count<kNumberOfAuthenticationTypes; count++) {
231			if (CFEqual(authenticationType, *(gAuthTypes[count].authValue))) {
232				result = gAuthTypes[count].authType;
233				break;
234			}
235		}
236	}
237
238	return result;
239}
240
241/*
242 * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType
243 * to a SecAttrAuthenticationType.
244 */
245static CFTypeRef
246_SecAttrAuthenticationTypeForSecAuthenticationType(
247	SecAuthenticationType authenticationType)
248{
249	CFTypeRef result = NULL;
250	CFIndex count;
251	for (count=0; count<kNumberOfAuthenticationTypes; count++) {
252		if (gAuthTypes[count].authType == authenticationType) {
253			result = *(gAuthTypes[count].authValue);
254			break;
255		}
256	}
257
258	return result;
259}
260
261
262/******************************************************************************/
263
264struct KeyAlgorithmInfo {
265	const CFTypeRef *keyType;
266	UInt32 keyValue;
267};
268
269static KeyAlgorithmInfo gKeyTypes[] = {
270	{ &kSecAttrKeyTypeRSA, CSSM_ALGID_RSA },
271	{ &kSecAttrKeyTypeDSA, CSSM_ALGID_DSA },
272	{ &kSecAttrKeyTypeAES, CSSM_ALGID_AES },
273	{ &kSecAttrKeyTypeDES, CSSM_ALGID_DES },
274	{ &kSecAttrKeyType3DES, CSSM_ALGID_3DES },
275	{ &kSecAttrKeyTypeRC4, CSSM_ALGID_RC4 },
276	{ &kSecAttrKeyTypeRC2, CSSM_ALGID_RC2 },
277	{ &kSecAttrKeyTypeCAST, CSSM_ALGID_CAST },
278	{ &kSecAttrKeyTypeECDSA, CSSM_ALGID_ECDSA },
279	{ &kSecAttrKeyTypeEC, CSSM_ALGID_ECDSA }
280};
281
282static const int kNumberOfKeyTypes = sizeof(gKeyTypes) / sizeof (KeyAlgorithmInfo);
283
284
285static UInt32 _SecAlgorithmTypeFromSecAttrKeyType(
286	CFTypeRef keyTypeRef)
287{
288	UInt32 keyAlgValue = 0;
289	if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef))
290		return keyAlgValue;
291
292	int ix;
293	for (ix=0; ix<kNumberOfKeyTypes; ix++) {
294		if (CFEqual(keyTypeRef, *(gKeyTypes[ix].keyType))) {
295			keyAlgValue = gKeyTypes[ix].keyValue;
296			return keyAlgValue;
297		}
298	}
299
300	//%%%TODO try to convert the input string to a number here
301
302	return keyAlgValue;
303}
304
305
306enum ItemRepresentation
307{
308	kStringRepresentation,
309	kDataRepresentation,
310	kNumberRepresentation,
311	kBooleanRepresentation,
312	kDateRepresentation
313};
314
315
316struct InternalAttributeListInfo
317{
318	UInt32 oldItemType;
319	const CFTypeRef *newItemType;
320	ItemRepresentation itemRepresentation;
321};
322
323
324static InternalAttributeListInfo gGenericPasswordAttributes[] =
325{
326	{ kSecCreationDateItemAttr, &kSecAttrCreationDate, kDateRepresentation },
327	{ kSecModDateItemAttr, &kSecAttrModificationDate, kDateRepresentation },
328	{ kSecDescriptionItemAttr, &kSecAttrDescription, kStringRepresentation },
329	{ kSecCommentItemAttr, &kSecAttrComment, kStringRepresentation },
330	{ kSecCreatorItemAttr, &kSecAttrCreator, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
331	{ kSecTypeItemAttr, &kSecAttrType, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
332	{ kSecLabelItemAttr, &kSecAttrLabel, kStringRepresentation },
333	{ kSecInvisibleItemAttr, &kSecAttrIsInvisible, kBooleanRepresentation },
334	{ kSecNegativeItemAttr, &kSecAttrIsNegative, kBooleanRepresentation },
335	{ kSecAccountItemAttr, &kSecAttrAccount, kStringRepresentation },
336	{ kSecServiceItemAttr, &kSecAttrService, kStringRepresentation },
337	{ kSecGenericItemAttr, &kSecAttrGeneric, kDataRepresentation }
338};
339
340static const int kNumberOfGenericPasswordAttributes = sizeof(gGenericPasswordAttributes) / sizeof (InternalAttributeListInfo);
341
342#if 0
343static InternalAttributeListInfo gInternetPasswordAttributes[] =
344{
345	{ kSecCreationDateItemAttr, &kSecAttrCreationDate, kDateRepresentation },
346	{ kSecModDateItemAttr, &kSecAttrModificationDate, kDateRepresentation },
347	{ kSecDescriptionItemAttr, &kSecAttrDescription, kStringRepresentation },
348	{ kSecCommentItemAttr, &kSecAttrComment, kStringRepresentation },
349	{ kSecCreatorItemAttr, &kSecAttrCreator, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
350	{ kSecTypeItemAttr, &kSecAttrType, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
351	{ kSecLabelItemAttr, &kSecAttrLabel, kStringRepresentation },
352	{ kSecInvisibleItemAttr, &kSecAttrIsInvisible, kBooleanRepresentation },
353	{ kSecNegativeItemAttr, &kSecAttrIsNegative, kBooleanRepresentation },
354	{ kSecAccountItemAttr, &kSecAttrAccount, kStringRepresentation },
355	{ kSecSecurityDomainItemAttr, &kSecAttrSecurityDomain, kStringRepresentation },
356	{ kSecServerItemAttr, &kSecAttrServer, kStringRepresentation },
357	{ kSecAuthenticationTypeItemAttr, &kSecAttrAuthenticationType, kStringRepresentation }, // maps from UInt32 value to string constant
358	{ kSecPortItemAttr, &kSecAttrPort, kNumberRepresentation },
359	{ kSecPathItemAttr, &kSecAttrPath, kStringRepresentation }
360};
361
362static const int kNumberOfInternetPasswordAttributes = sizeof(gInternetPasswordAttributes) / sizeof (InternalAttributeListInfo);
363#endif
364
365static InternalAttributeListInfo gCertificateAttributes[] =
366{
367	{ kSecLabelItemAttr, &kSecAttrLabel, kStringRepresentation },
368	{ kSecSubjectItemAttr, &kSecAttrSubject, kDataRepresentation },
369	{ kSecIssuerItemAttr, &kSecAttrIssuer, kDataRepresentation },
370	{ kSecSerialNumberItemAttr, &kSecAttrSerialNumber, kDataRepresentation },
371	{ kSecPublicKeyHashItemAttr, &kSecAttrPublicKeyHash, kDataRepresentation },
372	{ kSecSubjectKeyIdentifierItemAttr, &kSecAttrSubjectKeyID, kDataRepresentation },
373	{ kSecCertTypeItemAttr, &kSecAttrCertificateType, kDataRepresentation },
374	{ kSecCertEncodingItemAttr, &kSecAttrCertificateEncoding, kDataRepresentation }
375};
376
377static const int kNumberOfCertificateAttributes = sizeof(gCertificateAttributes) / sizeof(InternalAttributeListInfo);
378
379
380static InternalAttributeListInfo gKeyAttributes[] =
381{
382    { kSecKeyKeyClass, &kSecAttrKeyClass, kStringRepresentation }, // key class maps from UInt32 value to string constant
383    { kSecKeyPrintName, &kSecAttrLabel, kStringRepresentation }, // note that "print name" maps to the user-visible label
384//  { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation },
385    { kSecKeyPermanent, &kSecAttrIsPermanent, kBooleanRepresentation },
386//  { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation },
387//  { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation },
388    { kSecKeyLabel, &kSecAttrApplicationLabel, kDataRepresentation }, // this contains the hash of the key (or the public key hash, if asymmetric) as a CFData. Legacy keys may contain a UUID as a CFString
389    { kSecKeyApplicationTag, &kSecAttrApplicationTag, kDataRepresentation },
390//  { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key
391    { kSecKeyKeyType, &kSecAttrKeyType, kStringRepresentation }, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES)
392    { kSecKeyKeySizeInBits, &kSecAttrKeySizeInBits, kNumberRepresentation },
393    { kSecKeyEffectiveKeySize, &kSecAttrEffectiveKeySize, kNumberRepresentation },
394//  { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation },
395//  { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation },
396//  { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation },
397//  { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation },
398//  { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation },
399//  { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation },
400    { kSecKeyEncrypt, &kSecAttrCanEncrypt, kBooleanRepresentation },
401    { kSecKeyDecrypt, &kSecAttrCanDecrypt, kBooleanRepresentation },
402    { kSecKeyDerive, &kSecAttrCanDerive, kBooleanRepresentation },
403    { kSecKeySign, &kSecAttrCanSign, kBooleanRepresentation },
404    { kSecKeyVerify, &kSecAttrCanVerify, kBooleanRepresentation },
405//  { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation },
406//  { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation },
407    { kSecKeyWrap, &kSecAttrCanWrap, kBooleanRepresentation },
408    { kSecKeyUnwrap, &kSecAttrCanUnwrap, kBooleanRepresentation }
409};
410
411static const int kNumberOfKeyAttributes = sizeof(gKeyAttributes) / sizeof(InternalAttributeListInfo);
412
413
414static void* CloneDataByType(ItemRepresentation type, CFTypeRef value, UInt32& length)
415{
416	switch (type)
417	{
418		case kStringRepresentation:
419		{
420			if (CFStringGetTypeID() != CFGetTypeID(value)) {
421				length = 0;
422				return NULL;
423			}
424			CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef) value), kCFStringEncodingUTF8) + 1;
425			char* buffer = (char*) malloc(maxLength);
426			Boolean converted = CFStringGetCString((CFStringRef) value, buffer, maxLength, kCFStringEncodingUTF8);
427			if (converted) {
428				length = (UInt32)strlen(buffer);
429			}
430			else {
431				length = 0;
432				free(buffer);
433				buffer = NULL;
434			}
435			return buffer;
436		}
437
438		case kDataRepresentation:
439		{
440			if (CFStringGetTypeID() == CFGetTypeID(value)) {
441                // We may have a string here, since the key label may be a GUID for the symmetric keys
442                CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef) value), kCFStringEncodingUTF8) + 1;
443                char* buffer = (char*) malloc(maxLength);
444                Boolean converted = CFStringGetCString((CFStringRef) value, buffer, maxLength, kCFStringEncodingUTF8);
445                if (converted) {
446                    length = (UInt32)strlen(buffer);
447                }
448                else {
449                    length = 0;
450                    free(buffer);
451                    buffer = NULL;
452                }
453                return buffer;
454			}
455
456			if (CFDataGetTypeID() != CFGetTypeID(value)) {
457				length = 0;
458				return NULL;
459			}
460			length = (UInt32)CFDataGetLength((CFDataRef) value);
461			uint8_t* buffer = (uint8_t*) malloc(length);
462			CFDataGetBytes((CFDataRef) value, CFRangeMake(0, length), buffer);
463			return buffer;
464		}
465
466		case kNumberRepresentation:
467		{
468			if (CFNumberGetTypeID() != CFGetTypeID(value)) {
469				length = 0;
470				return NULL;
471			}
472			uint32_t* buffer = (uint32_t*) malloc(sizeof(uint32_t));
473			Boolean converted = CFNumberGetValue((CFNumberRef) value, kCFNumberSInt32Type, buffer);
474			if (converted) {
475				length = sizeof(uint32_t);
476			}
477			else {
478				length = 0;
479				free(buffer);
480				buffer = NULL;
481			}
482			return buffer;
483		}
484
485		case kBooleanRepresentation:
486		{
487			if (CFBooleanGetTypeID() != CFGetTypeID(value)) {
488				length = 0;
489				return NULL;
490			}
491			uint32_t* buffer = (uint32_t*) malloc(sizeof(uint32_t));
492			*buffer = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
493			length = sizeof(uint32_t);
494			return buffer;
495		}
496
497		case kDateRepresentation:
498		{
499			if (CFDateGetTypeID() != CFGetTypeID(value)) {
500				length = 0;
501				return NULL;
502			}
503			char* buffer = (char*) calloc(1, 32); // max length of a CSSM date string
504			CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef) value, buffer);
505			length = (UInt32)strlen(buffer);
506			return buffer;
507		}
508
509		default:
510		{
511			length = 0;
512			return NULL;
513		}
514	}
515}
516
517
518static OSStatus
519_ConvertNewFormatToOldFormat(
520	CFAllocatorRef allocator,
521	const InternalAttributeListInfo* info,
522	int infoNumItems,
523	CFDictionaryRef dictionaryRef,
524	SecKeychainAttributeList* &attrList
525	)
526{
527	// get the keychain attributes array from the data item
528	// here's the problem.  On the one hand, we have a dictionary that is purported to contain
529	// attributes for our type.  On the other hand, the dictionary may contain items we don't support,
530	// and we therefore don't know how many attributes we will have unless we count them first
531
532	// setup the return
533	attrList = (SecKeychainAttributeList*) calloc(1, sizeof(SecKeychainAttributeList));
534
535	// make storage to extract the dictionary items
536	CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef);
537	CFTypeRef keys[itemsInDictionary];
538	CFTypeRef values[itemsInDictionary];
539
540	CFTypeRef *keysPtr = keys;
541	CFTypeRef *valuesPtr = values;
542
543	CFDictionaryGetKeysAndValues(dictionaryRef, keys, values);
544
545	// count the number of items we are interested in
546	CFIndex count = 0;
547	CFIndex i;
548
549	// since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that
550	// we don't pay the price for this twice
551	SecKeychainAttrType tags[itemsInDictionary];
552	ItemRepresentation types[itemsInDictionary];
553
554	for (i = 0; i < itemsInDictionary; ++i)
555	{
556		CFTypeRef key = keysPtr[i];
557
558		int j;
559		for (j = 0; j < infoNumItems; ++j)
560		{
561			if (CFEqual(*(info[j].newItemType), key))
562			{
563				tags[i] = info[j].oldItemType;
564				types[i] = info[j].itemRepresentation;
565				count += 1;
566				break;
567			}
568		}
569
570		if (j >= infoNumItems)
571		{
572			// if we got here, we aren't interested in this item.
573			valuesPtr[i] = NULL;
574		}
575	}
576
577	// now we can make the result array
578	attrList->count = (UInt32)count;
579	attrList->attr = (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count);
580
581	// fill out the array
582	int resultPointer = 0;
583	for (i = 0; i < itemsInDictionary; ++i)
584	{
585		if (values[i] != NULL)
586		{
587			attrList->attr[resultPointer].tag = tags[i];
588
589			// we have to clone the data pointer.  The caller will need to make sure to throw these away
590			// with _FreeAttrList when it is done...
591			attrList->attr[resultPointer].data = CloneDataByType(types[i], valuesPtr[i], attrList->attr[resultPointer].length);
592			resultPointer += 1;
593		}
594	}
595
596	return errSecSuccess;
597}
598
599
600
601static OSStatus
602_ConvertOldFormatToNewFormat(
603	CFAllocatorRef allocator,
604	const InternalAttributeListInfo* info,
605	int infoNumItems,
606	SecKeychainItemRef itemRef,
607	CFMutableDictionaryRef& dictionaryRef)
608{
609	SecKeychainAttributeList list;
610	list.count = infoNumItems;
611	list.attr = (SecKeychainAttribute*) calloc(infoNumItems, sizeof(SecKeychainAttribute));
612
613	// fill out the array.  We only need to fill in the tags, since calloc zeros what it returns
614	int i;
615	for (i = 0; i < infoNumItems; ++i)
616	{
617		list.attr[i].tag = info[i].oldItemType;
618	}
619
620	OSStatus result = SecKeychainItemCopyContent(itemRef, NULL, &list, NULL, NULL);
621	if (result != errSecSuccess)
622	{
623		dictionaryRef = NULL;
624		free(list.attr);
625		return result;
626	}
627
628	// create the dictionary
629	dictionaryRef = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
630
631	// add the pairs
632	for (i = 0; i < infoNumItems; ++i)
633	{
634		if (list.attr[i].data == NULL)
635			continue;
636
637		switch (info[i].itemRepresentation)
638		{
639			case kStringRepresentation:
640			{
641				CFStringRef stringRef;
642				if (info[i].oldItemType == kSecKeyKeyClass) {
643					// special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant
644					uint32_t keyRecordValue = *((uint32_t*)list.attr[i].data);
645					bool retainString = true;
646					switch (keyRecordValue) {
647						case CSSM_DL_DB_RECORD_PUBLIC_KEY :
648							stringRef = (CFStringRef) kSecAttrKeyClassPublic;
649							break;
650						case CSSM_DL_DB_RECORD_PRIVATE_KEY:
651							stringRef = (CFStringRef) kSecAttrKeyClassPrivate;
652							break;
653						case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
654							stringRef = (CFStringRef) kSecAttrKeyClassSymmetric;
655							break;
656						default:
657							stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyRecordValue);
658							break;
659					}
660					if (stringRef) {
661						if (retainString) CFRetain(stringRef);
662						CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
663						CFRelease(stringRef);
664					}
665				}
666				else if (info[i].oldItemType == kSecKeyKeyType) {
667					// special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant
668					uint32_t keyAlgValue = *((uint32_t*)list.attr[i].data);
669					bool retainString = true;
670					switch (keyAlgValue) {
671						case CSSM_ALGID_RSA :
672							stringRef = (CFStringRef) kSecAttrKeyTypeRSA;
673							break;
674						case CSSM_ALGID_DSA :
675							stringRef = (CFStringRef) kSecAttrKeyTypeDSA;
676							break;
677						case CSSM_ALGID_AES :
678							stringRef = (CFStringRef) kSecAttrKeyTypeAES;
679							break;
680						case CSSM_ALGID_DES :
681							stringRef = (CFStringRef) kSecAttrKeyTypeDES;
682							break;
683						case CSSM_ALGID_3DES :
684							stringRef = (CFStringRef) kSecAttrKeyType3DES;
685							break;
686						case CSSM_ALGID_RC4 :
687							stringRef = (CFStringRef) kSecAttrKeyTypeRC4;
688							break;
689						case CSSM_ALGID_RC2 :
690							stringRef = (CFStringRef) kSecAttrKeyTypeRC2;
691							break;
692						case CSSM_ALGID_CAST :
693							stringRef = (CFStringRef) kSecAttrKeyTypeCAST;
694							break;
695						case CSSM_ALGID_ECDSA :
696							stringRef = (CFStringRef) kSecAttrKeyTypeEC;
697							break;
698						default :
699							stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyAlgValue);
700							retainString = false;
701							break;
702					}
703					if (stringRef) {
704						if (retainString) CFRetain(stringRef);
705						CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
706						CFRelease(stringRef);
707					}
708				}
709				else {
710					// normal case: attribute contains a string
711					stringRef = CFStringCreateWithBytes(allocator, (UInt8*)list.attr[i].data, list.attr[i].length, kCFStringEncodingUTF8, FALSE);
712					if (stringRef == NULL)
713						stringRef = (CFStringRef) CFRetain(kCFNull);
714					CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
715					CFRelease(stringRef);
716				}
717			}
718			break;
719
720			case kDataRepresentation:
721			{
722                if ((info[i].oldItemType == kSecKeyLabel) && (list.attr[i].length == kUUIDStringLength)) {
723					// It's possible that there could be a string here because the key label may have a UUID
724					CFStringRef stringRef = CFStringCreateWithBytes(allocator, (UInt8*)list.attr[i].data, list.attr[i].length, kCFStringEncodingUTF8, FALSE);
725					if (stringRef == NULL)
726						stringRef = (CFStringRef) CFRetain(kCFNull);
727					CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
728					CFRelease(stringRef);
729                    break;
730                }
731                CFDataRef dataRef = CFDataCreate(allocator, (UInt8*) list.attr[i].data, list.attr[i].length);
732                if (dataRef == NULL)
733                    dataRef = (CFDataRef) CFRetain(kCFNull);
734                CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), dataRef);
735                CFRelease(dataRef);
736			}
737			break;
738
739			case kNumberRepresentation:
740			{
741				CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, list.attr[i].data);
742				if (numberRef == NULL)
743					numberRef = (CFNumberRef) CFRetain(kCFNull);
744				CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), numberRef);
745				CFRelease(numberRef);
746			}
747			break;
748
749			case kBooleanRepresentation:
750			{
751				uint32_t value = *((uint32_t*)list.attr[i].data);
752				CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
753				CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), boolRef);
754			}
755			break;
756
757			case kDateRepresentation:
758			{
759				CFDateRef dateRef = NULL;
760				CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list.attr[i].data, list.attr[i].length, &dateRef);
761				if (dateRef == NULL)
762					dateRef = (CFDateRef) CFRetain(kCFNull);
763				CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), dateRef);
764				CFRelease(dateRef);
765			}
766			break;
767		}
768	}
769
770	// cleanup
771	SecKeychainItemFreeContent(&list, NULL);
772	free(list.attr);
773
774	return result;
775}
776
777
778
779//
780/*
781 * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the
782 * attributes of item.
783 */
784static OSStatus
785_CreateAttributesDictionaryFromGenericPasswordItem(
786	CFAllocatorRef allocator,
787	SecKeychainItemRef item,
788	CFDictionaryRef *dictionary)
789{
790	// do the basic allocations
791	CFMutableDictionaryRef dict = NULL;
792	OSStatus result = _ConvertOldFormatToNewFormat(allocator, gGenericPasswordAttributes, kNumberOfGenericPasswordAttributes, item, dict);
793	if (result == errSecSuccess) // did we complete OK
794	{
795		CFDictionaryAddValue(dict, kSecClass, kSecClassGenericPassword);
796	}
797
798	*dictionary = dict;
799
800	return result;
801}
802
803
804
805/*
806 * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the
807 * attributes of item.
808 */
809static OSStatus
810_CreateAttributesDictionaryFromCertificateItem(
811	CFAllocatorRef allocator,
812	SecKeychainItemRef item,
813	CFDictionaryRef *dictionary)
814{
815	// do the basic allocations
816	CFMutableDictionaryRef dict = NULL;
817	OSStatus result = _ConvertOldFormatToNewFormat(allocator, gCertificateAttributes, kNumberOfCertificateAttributes, item, dict);
818	if (result == errSecSuccess) // did we complete OK
819	{
820		CFDictionaryAddValue(dict, kSecClass, kSecClassCertificate);
821	}
822
823	*dictionary = dict;
824
825	return errSecSuccess;
826}
827
828/*
829 * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the
830 * attributes of item.
831 */
832static OSStatus
833_CreateAttributesDictionaryFromKeyItem(
834	CFAllocatorRef allocator,
835	SecKeychainItemRef item,
836	CFDictionaryRef *dictionary)
837{
838#if 0
839//%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails.
840// Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and
841// SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent.
842
843	if (status) {
844		goto error_exit; // unable to get the attribute info (i.e. database schema)
845	}
846
847	status = SecKeychainItemCopyAttributesAndData(item, info, &itemClass, &attrList, NULL, NULL);
848
849	// do the basic allocations
850	CFMutableDictionaryRef dict = NULL;
851	OSStatus result = _ConvertOldFormatToNewFormat(allocator, gKeyAttributes, kNumberOfKeyAttributes, item, dict);
852	if (result == errSecSuccess) // did we complete OK
853	{
854		CFDictionaryAddValue(dict, kSecClass, kSecClassKey);
855	}
856
857	*dictionary = dict;
858
859	return errSecSuccess;
860#endif
861
862	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
863	unsigned int ix;
864	SecItemClass itemClass = 0;
865	UInt32 itemID;
866	SecKeychainAttributeList *attrList = NULL;
867	SecKeychainAttributeInfo *info = NULL;
868	SecKeychainRef keychain = NULL;
869
870	OSStatus status = SecKeychainItemCopyAttributesAndData(item, NULL, &itemClass, NULL, NULL, NULL);
871	if (status) {
872		goto error_exit; // item must have an itemClass
873	}
874
875	switch (itemClass)
876	{
877    case kSecInternetPasswordItemClass:
878		itemID = CSSM_DL_DB_RECORD_INTERNET_PASSWORD;
879		break;
880    case kSecGenericPasswordItemClass:
881		itemID = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
882		break;
883    case 'ashp': /* kSecAppleSharePasswordItemClass */
884		itemID = CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD;
885		break;
886	default:
887		itemID = itemClass;
888		break;
889	}
890
891	status = SecKeychainItemCopyKeychain(item, &keychain);
892	if (status) {
893		goto error_exit; // item must have a keychain, so we can get the attribute info for it
894	}
895
896	status = SecKeychainAttributeInfoForItemID(keychain, itemID, &info);
897	if (status) {
898		goto error_exit; // unable to get the attribute info (i.e. database schema)
899	}
900
901	status = SecKeychainItemCopyAttributesAndData(item, info, &itemClass, &attrList, NULL, NULL);
902	if (status) {
903		goto error_exit; // unable to get the attribute info (i.e. database schema)
904	}
905
906	for (ix = 0; ix < info->count; ++ix)
907	{
908		SecKeychainAttribute *attribute = &attrList->attr[ix];
909		if (!attribute->length && !attribute->data)
910			continue;
911
912		UInt32 j, count = kNumberOfKeyAttributes;
913		InternalAttributeListInfo *intInfo = NULL;
914		for (j=0; j<count; j++) {
915			if (gKeyAttributes[j].oldItemType == info->tag[ix]) {
916				intInfo = &gKeyAttributes[j];
917				break;
918			}
919		}
920		if (!intInfo)
921			continue;
922
923		switch (intInfo->itemRepresentation)
924		{
925			case kStringRepresentation:
926			{
927				CFStringRef stringRef;
928				if (intInfo->oldItemType == kSecKeyKeyClass) {
929					// special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant
930					UInt32 keyRecordValue = *((UInt32*)attribute->data);
931					bool retainString = true;
932					switch (keyRecordValue) {
933						case CSSM_DL_DB_RECORD_PUBLIC_KEY :
934							stringRef = (CFStringRef) kSecAttrKeyClassPublic;
935							break;
936						case CSSM_DL_DB_RECORD_PRIVATE_KEY:
937							stringRef = (CFStringRef) kSecAttrKeyClassPrivate;
938							break;
939						case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
940							stringRef = (CFStringRef) kSecAttrKeyClassSymmetric;
941							break;
942						default:
943							stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%u"), (unsigned int)keyRecordValue);
944							break;
945					}
946					if (stringRef) {
947						if (retainString) CFRetain(stringRef);
948						CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
949						CFRelease(stringRef);
950					}
951				}
952				else if (intInfo->oldItemType == kSecKeyKeyType) {
953					// special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant
954					UInt32 keyAlgValue = *((UInt32*)attribute->data);
955					bool retainString = true;
956					switch (keyAlgValue) {
957						case CSSM_ALGID_RSA :
958							stringRef = (CFStringRef) kSecAttrKeyTypeRSA;
959							break;
960						case CSSM_ALGID_DSA :
961							stringRef = (CFStringRef) kSecAttrKeyTypeDSA;
962							break;
963						case CSSM_ALGID_AES :
964							stringRef = (CFStringRef) kSecAttrKeyTypeAES;
965							break;
966						case CSSM_ALGID_DES :
967							stringRef = (CFStringRef) kSecAttrKeyTypeDES;
968							break;
969						case CSSM_ALGID_3DES :
970							stringRef = (CFStringRef) kSecAttrKeyType3DES;
971							break;
972						case CSSM_ALGID_RC4 :
973							stringRef = (CFStringRef) kSecAttrKeyTypeRC4;
974							break;
975						case CSSM_ALGID_RC2 :
976							stringRef = (CFStringRef) kSecAttrKeyTypeRC2;
977							break;
978						case CSSM_ALGID_CAST :
979							stringRef = (CFStringRef) kSecAttrKeyTypeCAST;
980							break;
981						case CSSM_ALGID_ECDSA :
982							stringRef = (CFStringRef) kSecAttrKeyTypeEC;
983							break;
984						default :
985							stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%u"), (unsigned int)keyAlgValue);
986							retainString = false;
987							break;
988					}
989					if (stringRef) {
990						if (retainString) CFRetain(stringRef);
991						CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
992						CFRelease(stringRef);
993					}
994                }
995				else {
996					// normal case: attribute contains a string
997					stringRef = CFStringCreateWithBytes(allocator, (UInt8*)attribute->data, attribute->length, kCFStringEncodingUTF8, FALSE);
998					if (stringRef == NULL)
999						stringRef = (CFStringRef) CFRetain(kCFNull);
1000					CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
1001					CFRelease(stringRef);
1002				}
1003			}
1004			break;
1005
1006			case kDataRepresentation:
1007			{
1008                if ((intInfo->oldItemType == kSecKeyLabel) && (attribute->length == kUUIDStringLength)) {
1009					// It's possible that there could be a string here because the key label may have a UUID
1010                    CFStringRef stringRef = CFStringCreateWithBytes(allocator, (UInt8*)attribute->data, attribute->length, kCFStringEncodingUTF8, FALSE);
1011					if (stringRef == NULL)
1012						stringRef = (CFStringRef) CFRetain(kCFNull);
1013					CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
1014					CFRelease(stringRef);
1015                    break;
1016                }
1017
1018				CFDataRef dataRef = CFDataCreate(allocator, (UInt8*)attribute->data, attribute->length);
1019				if (dataRef == NULL)
1020					dataRef = (CFDataRef) CFRetain(kCFNull);
1021				CFDictionaryAddValue(dict, *(intInfo->newItemType), dataRef);
1022				CFRelease(dataRef);
1023			}
1024			break;
1025
1026			case kNumberRepresentation:
1027			{
1028				CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, attribute->data);
1029				if (numberRef == NULL)
1030					numberRef = (CFNumberRef) CFRetain(kCFNull);
1031				CFDictionaryAddValue(dict, *(intInfo->newItemType), numberRef);
1032				CFRelease(numberRef);
1033			}
1034			break;
1035
1036			case kBooleanRepresentation:
1037			{
1038				UInt32 value = *((UInt32*)attribute->data);
1039				CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
1040				CFDictionaryAddValue(dict, *(intInfo->newItemType), boolRef);
1041			}
1042			break;
1043
1044			case kDateRepresentation:
1045			{
1046				//%%% FIXME need to convert from a CSSM date string to a CFDateRef here
1047				CFDateRef dateRef = NULL;
1048				if (dateRef == NULL)
1049					dateRef = (CFDateRef) CFRetain(kCFNull);
1050				CFDictionaryAddValue(dict, *(intInfo->newItemType), dateRef);
1051				CFRelease(dateRef);
1052			}
1053			break;
1054		}
1055	}
1056
1057	CFDictionaryAddValue(dict, kSecClass, kSecClassKey);
1058
1059error_exit:
1060
1061	if (attrList)
1062		SecKeychainItemFreeAttributesAndData(attrList, NULL);
1063
1064	if (info)
1065		SecKeychainFreeAttributeInfo(info);
1066
1067	if (keychain)
1068		CFRelease(keychain);
1069
1070	*dictionary = dict;
1071
1072	return status;
1073}
1074
1075
1076/*
1077 * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the
1078 * attributes of item.
1079 */
1080static OSStatus
1081_CreateAttributesDictionaryFromInternetPasswordItem(
1082	CFAllocatorRef allocator,
1083	SecKeychainItemRef item,
1084	CFDictionaryRef *dictionary)
1085{
1086	OSStatus status;
1087	SecKeychainAttribute attr[] = {
1088		{ kSecServerItemAttr, 0, NULL },		/* [0] server */
1089		{ kSecSecurityDomainItemAttr, 0, NULL },	/* [1] securityDomain */
1090		{ kSecAccountItemAttr, 0, NULL },		/* [2] account */
1091		{ kSecPathItemAttr, 0, NULL },			/* [3] path */
1092		{ kSecPortItemAttr, 0, NULL },			/* [4] port */
1093		{ kSecProtocolItemAttr, 0, NULL },		/* [5] protocol */
1094		{ kSecAuthenticationTypeItemAttr, 0, NULL },	/* [6] authenticationType */
1095		{ kSecCommentItemAttr, 0, NULL },		/* [7] comment */
1096		{ kSecDescriptionItemAttr, 0, NULL },		/* [8] description */
1097		{ kSecLabelItemAttr, 0, NULL },			/* [9] label */
1098		{ kSecCreationDateItemAttr, 0, NULL },	/* [10] creation date */
1099		{ kSecModDateItemAttr, 0, NULL },		/* [11] modification date */
1100		{ kSecCreatorItemAttr, 0, NULL },		/* [12] creator */
1101		{ kSecTypeItemAttr, 0, NULL },			/* [13] type */
1102		{ kSecInvisibleItemAttr, 0, NULL },		/* [14] invisible */
1103		{ kSecNegativeItemAttr, 0, NULL },		/* [15] negative */
1104	};
1105	SecKeychainAttributeList attrList = { sizeof(attr) / sizeof(SecKeychainAttribute), attr };
1106	CFIndex numValues;
1107	CFIndex index;
1108	CFTypeRef keys[(sizeof(attr) / sizeof(SecKeychainAttribute)) + 2];
1109	CFTypeRef values[(sizeof(attr) / sizeof(SecKeychainAttribute)) + 2];
1110
1111	*dictionary = NULL;
1112
1113	// copy the item's attributes
1114	status = SecKeychainItemCopyContent(item, NULL, &attrList, NULL, NULL);
1115	require_noerr(status, SecKeychainItemCopyContent_failed);
1116
1117	numValues = 0;
1118
1119	// add kSecClass
1120	keys[numValues] = kSecClass;
1121	values[numValues] = kSecClassInternetPassword;
1122	++numValues;
1123
1124	// add kSecAttrServer
1125	if ( attrList.attr[0].length > 0 ) {
1126		keys[numValues] = kSecAttrServer;
1127		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[0].data, attrList.attr[0].length, kCFStringEncodingUTF8, FALSE);
1128		if ( values[numValues] != NULL ) {
1129			++numValues;
1130		}
1131	}
1132
1133	// add kSecAttrSecurityDomain
1134	if ( attrList.attr[1].length > 0 ) {
1135		keys[numValues] = kSecAttrSecurityDomain;
1136		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[1].data, attrList.attr[1].length, kCFStringEncodingUTF8, FALSE);
1137		if ( values[numValues] != NULL ) {
1138			++numValues;
1139		}
1140	}
1141
1142	// add kSecAttrAccount
1143	if ( attrList.attr[2].length > 0 ) {
1144		keys[numValues] = kSecAttrAccount;
1145		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[2].data, attrList.attr[2].length, kCFStringEncodingUTF8, FALSE);
1146		if ( values[numValues] != NULL ) {
1147			++numValues;
1148		}
1149	}
1150
1151	// add kSecAttrPath
1152	if ( attrList.attr[3].length > 0 ) {
1153		keys[numValues] = kSecAttrPath;
1154		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[3].data, attrList.attr[3].length, kCFStringEncodingUTF8, FALSE);
1155		if ( values[numValues] != NULL ) {
1156			++numValues;
1157		}
1158	}
1159
1160	// add kSecAttrPort
1161	if ( attrList.attr[4].length > 0 ) {
1162		keys[numValues] = kSecAttrPort;
1163		values[numValues] = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[4].data);
1164		if ( values[numValues] != NULL ) {
1165			++numValues;
1166		}
1167	}
1168
1169	// add kSecAttrProtocol
1170	if ( attrList.attr[5].length > 0 ) {
1171		keys[numValues] = kSecAttrProtocol;
1172		values[numValues] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType*)attrList.attr[5].data);
1173		if ( values[numValues] != NULL ) {
1174			CFRetain(values[numValues]);
1175			++numValues;
1176		}
1177	}
1178
1179	// add kSecAttrAuthenticationType
1180	if ( attrList.attr[6].length > 0 ) {
1181		keys[numValues] = kSecAttrAuthenticationType;
1182		values[numValues] = _SecAttrAuthenticationTypeForSecAuthenticationType(*(SecProtocolType*)attrList.attr[6].data);
1183		if ( values[numValues] != NULL ) {
1184			CFRetain(values[numValues]);
1185			++numValues;
1186		}
1187	}
1188
1189	// add kSecAttrComment
1190	if ( attrList.attr[7].length > 0 ) {
1191		keys[numValues] = kSecAttrComment;
1192		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[7].data, attrList.attr[7].length, kCFStringEncodingUTF8, FALSE);
1193		if ( values[numValues] != NULL ) {
1194			++numValues;
1195		}
1196	}
1197
1198	// add kSecAttrDescription
1199	if ( attrList.attr[8].length > 0 ) {
1200		keys[numValues] = kSecAttrDescription;
1201		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[8].data, attrList.attr[8].length, kCFStringEncodingUTF8, FALSE);
1202		if ( values[numValues] != NULL ) {
1203			++numValues;
1204		}
1205	}
1206
1207	// add kSecAttrLabel
1208	if ( attrList.attr[9].length > 0 ) {
1209		keys[numValues] = kSecAttrLabel;
1210		values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[9].data, attrList.attr[9].length, kCFStringEncodingUTF8, FALSE);
1211		if ( values[numValues] != NULL ) {
1212			++numValues;
1213		}
1214	}
1215
1216	// add kSecAttrCreationDate
1217	if ( attrList.attr[10].length > 0 ) {
1218		CFDateRef creationDate = NULL;
1219		CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList.attr[10].data, attrList.attr[10].length, &creationDate);
1220		keys[numValues] = kSecAttrCreationDate;
1221		values[numValues] = creationDate;
1222		if ( values[numValues] != NULL ) {
1223			++numValues;
1224		}
1225	}
1226
1227	// add kSecAttrModificationDate
1228	if ( attrList.attr[11].length > 0 ) {
1229		CFDateRef modDate = NULL;
1230		CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList.attr[11].data, attrList.attr[11].length, &modDate);
1231		keys[numValues] = kSecAttrModificationDate;
1232		values[numValues] = modDate;
1233		if ( values[numValues] != NULL ) {
1234			++numValues;
1235		}
1236	}
1237
1238	// add kSecCreatorItemAttr
1239	if ( attrList.attr[12].length > 0 ) {
1240		CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[12].data);
1241		keys[numValues] = kSecAttrCreator;
1242		values[numValues] = numberRef;
1243		if ( values[numValues] != NULL ) {
1244			CFRetain(values[numValues]);
1245			++numValues;
1246		}
1247	}
1248
1249	// add kSecTypeItemAttr
1250	if ( attrList.attr[13].length > 0 ) {
1251		CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[13].data);
1252		keys[numValues] = kSecAttrType;
1253		values[numValues] = numberRef;
1254		if ( values[numValues] != NULL ) {
1255			CFRetain(values[numValues]);
1256			++numValues;
1257		}
1258	}
1259
1260	// add kSecInvisibleItemAttr
1261	if ( attrList.attr[14].length > 0 ) {
1262		uint32_t value = *((uint32_t*)attrList.attr[14].data);
1263		CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
1264		keys[numValues] = kSecAttrIsInvisible;
1265		values[numValues] = boolRef;
1266		if ( values[numValues] != NULL ) {
1267			CFRetain(values[numValues]);
1268			++numValues;
1269		}
1270	}
1271
1272	// add kSecNegativeItemAttr
1273	if ( attrList.attr[15].length > 0 ) {
1274		uint32_t value = *((uint32_t*)attrList.attr[15].data);
1275		CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
1276		keys[numValues] = kSecAttrIsNegative;
1277		values[numValues] = boolRef;
1278		if ( values[numValues] != NULL ) {
1279			CFRetain(values[numValues]);
1280			++numValues;
1281		}
1282	}
1283
1284	// create the dictionary
1285	*dictionary = CFDictionaryCreate(allocator, keys, values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1286
1287	// release the values added to the dictionary
1288	for ( index = 0; index < numValues; ++index )
1289	{
1290		CFRelease(values[index]);
1291	}
1292
1293	// and free the attributes
1294	(void) SecKeychainItemFreeContent(&attrList, NULL);
1295
1296SecKeychainItemCopyContent_failed:
1297
1298	return ( status );
1299}
1300
1301
1302/*
1303 * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the
1304 * attributes of the specified item class and item.
1305 */
1306static OSStatus
1307_CreateAttributesDictionaryFromItem(
1308	CFAllocatorRef allocator,
1309	SecItemClass itemClass,
1310	SecKeychainItemRef item,
1311	CFDictionaryRef *dictionary)
1312{
1313	switch (itemClass)
1314	{
1315		case kSecInternetPasswordItemClass:
1316			return _CreateAttributesDictionaryFromInternetPasswordItem(allocator, item, dictionary);
1317
1318		case kSecGenericPasswordItemClass:
1319			return _CreateAttributesDictionaryFromGenericPasswordItem(allocator, item, dictionary);
1320
1321		case kSecCertificateItemClass:
1322			return _CreateAttributesDictionaryFromCertificateItem(allocator, item, dictionary);
1323
1324		case kSecPublicKeyItemClass:
1325		case kSecPrivateKeyItemClass:
1326		case kSecSymmetricKeyItemClass:
1327			return _CreateAttributesDictionaryFromKeyItem(allocator, item, dictionary);
1328
1329		default:
1330			*dictionary = NULL;
1331			break;
1332	}
1333	return errSecParam;
1334}
1335
1336
1337/*
1338 * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList
1339 * by the _CreateSecKeychainAttributeListFromDictionary function.
1340 */
1341static void
1342_FreeAttrList(
1343	SecKeychainAttributeList *attrListPtr)
1344{
1345	UInt32 index;
1346
1347	if ( attrListPtr != NULL ) {
1348		if ( attrListPtr->attr != NULL ) {
1349			// free any attribute data
1350			for ( index = 0; index < attrListPtr->count; ++index ) {
1351				free(attrListPtr->attr[index].data);
1352			}
1353			// free the attribute array
1354			free(attrListPtr->attr);
1355		}
1356		// free the attribute list
1357		free(attrListPtr);
1358	}
1359}
1360
1361/*
1362 * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by
1363 * attr using the data and tag parameters.
1364 *
1365 * The memory for the SecKeychainAttribute's data field is allocated with malloc
1366 * and must be released by the caller (this is normally done by calling _FreeAttrList).
1367 */
1368static OSStatus
1369_CFDataCreateAttribute(
1370	CFDataRef data,
1371	SecKeychainAttrType tag,
1372	SecKeychainAttributePtr attr)
1373{
1374	OSStatus status = errSecSuccess;
1375	CFRange range;
1376
1377	// set the attribute tag
1378	attr->tag = tag;
1379
1380	// determine the attribute length
1381	attr->length = (UInt32) CFDataGetLength(data);
1382	range = CFRangeMake(0, (CFIndex)attr->length);
1383
1384	// allocate memory for the attribute bytes
1385	attr->data = malloc(attr->length);
1386	require_action(attr->data != NULL, malloc_failed, status = errSecBufferTooSmall);
1387
1388	// get the attribute bytes
1389	CFDataGetBytes(data, range, (UInt8 *)attr->data);
1390
1391malloc_failed:
1392
1393	return ( status );
1394}
1395
1396/*
1397 * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by
1398 * attr using the string and tag parameters.
1399 *
1400 * The memory for the SecKeychainAttribute's data field is allocated with malloc
1401 * and must be released by the caller (this is normally done by calling _FreeAttrList).
1402 */
1403static OSStatus
1404_CFStringCreateAttribute(
1405	CFStringRef string,
1406	SecKeychainAttrType tag,
1407	SecKeychainAttributePtr attr)
1408{
1409	OSStatus status = errSecSuccess;
1410	CFRange range;
1411
1412	// set the attribute tag
1413	attr->tag = tag;
1414
1415	// determine the attribute length
1416	range = CFRangeMake(0, CFStringGetLength(string));
1417	CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, FALSE, NULL, 0, (CFIndex *)&attr->length);
1418
1419	// allocate memory for the attribute bytes
1420	attr->data = malloc(attr->length);
1421	require_action(attr->data != NULL, malloc_failed, status = errSecBufferTooSmall);
1422
1423	// get the attribute bytes
1424	CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, FALSE, (UInt8 *)attr->data, attr->length, NULL);
1425
1426malloc_failed:
1427
1428	return ( status );
1429}
1430
1431
1432/*
1433 * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList
1434 * from the attribute key/values in attrDictionary.
1435 *
1436 * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList
1437 * must be freed by the caller with _FreeAttrList()
1438 */
1439static OSStatus
1440_CreateSecKeychainGenericPasswordAttributeListFromDictionary(
1441	CFDictionaryRef attrDictionary,
1442	SecKeychainAttributeList **attrList)
1443{
1444	return _ConvertNewFormatToOldFormat(NULL, gGenericPasswordAttributes, kNumberOfGenericPasswordAttributes, attrDictionary, *attrList);
1445}
1446
1447
1448/*
1449 * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList
1450 * from the attribute key/values in attrDictionary.
1451 *
1452 * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList
1453 * must be freed by the caller with _FreeAttrList()
1454 */
1455static OSStatus
1456_CreateSecKeychainCertificateAttributeListFromDictionary(
1457	CFDictionaryRef attrDictionary,
1458	SecKeychainAttributeList **attrList)
1459{
1460	return _ConvertNewFormatToOldFormat(NULL, gCertificateAttributes, kNumberOfCertificateAttributes, attrDictionary, *attrList);
1461}
1462
1463
1464/*
1465 * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList
1466 * from the attribute key/values in attrDictionary.
1467 *
1468 * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList
1469 * must be freed by the caller with _FreeAttrList()
1470 */
1471static OSStatus
1472_CreateSecKeychainKeyAttributeListFromDictionary(
1473	CFDictionaryRef attrDictionary,
1474	SecKeychainAttributeList **attrList)
1475{
1476#if 0
1477	//%%%FIXME this function should work for key attributes, but currently doesn't; need to debug
1478	return _ConvertNewFormatToOldFormat(NULL, gKeyAttributes, kNumberOfKeyAttributes, attrDictionary, *attrList);
1479#else
1480	// explicitly build attribute list for supported key attributes
1481	// NOTE: this code supports only MaxSecKeyAttributes (15) attributes
1482	const int MaxSecKeyAttributes = 15;
1483
1484	OSStatus status;
1485	CFTypeRef value;
1486	SecKeychainAttributeList *attrListPtr;
1487
1488	attrListPtr = (SecKeychainAttributeList*)calloc(1, sizeof(SecKeychainAttributeList));
1489	require_action(attrListPtr != NULL, calloc_attrListPtr_failed, status = errSecBufferTooSmall);
1490
1491	attrListPtr->attr = (SecKeychainAttribute*)calloc(MaxSecKeyAttributes, sizeof(SecKeychainAttribute));
1492	require_action(attrListPtr->attr != NULL, malloc_attrPtr_failed, status = errSecBufferTooSmall);
1493
1494	// [0] get the kSecKeyKeyClass value
1495	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeyClass, (const void **)&value) && value) {
1496		UInt32 keyRecordValue = 0;
1497		if (CFEqual(kSecAttrKeyClassPublic, value))
1498			keyRecordValue = CSSM_DL_DB_RECORD_PUBLIC_KEY;
1499		else if (CFEqual(kSecAttrKeyClassPrivate, value))
1500			keyRecordValue = CSSM_DL_DB_RECORD_PRIVATE_KEY;
1501		else if (CFEqual(kSecAttrKeyClassSymmetric, value))
1502			keyRecordValue = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
1503
1504		// only use this attribute if we recognize the value!
1505		if (keyRecordValue != 0) {
1506			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1507			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1508
1509			attrListPtr->attr[attrListPtr->count].tag = kSecKeyKeyClass;
1510			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1511			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = keyRecordValue;
1512
1513			++attrListPtr->count;
1514		}
1515	}
1516
1517	// [1] get the kSecKeyPrintName string
1518	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrLabel, (const void **)&value) && value) {
1519		status = _CFStringCreateAttribute((CFStringRef)value, kSecKeyPrintName, &attrListPtr->attr[attrListPtr->count]);
1520		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1521
1522		++attrListPtr->count;
1523	}
1524
1525	// [2] get the kSecKeyPermanent boolean
1526	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrIsPermanent, (const void **)&value) && value) {
1527		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1528		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1529
1530		attrListPtr->attr[attrListPtr->count].tag = kSecKeyPermanent;
1531		attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1532		*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1533
1534		++attrListPtr->count;
1535	}
1536
1537	// [3] get the kSecKeyLabel string
1538	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrApplicationLabel, (const void **)&value) && value) {
1539        if (CFStringGetTypeID() == CFGetTypeID(value))
1540            status = _CFStringCreateAttribute((CFStringRef)value, kSecKeyLabel, &attrListPtr->attr[attrListPtr->count]);
1541        else if (CFDataGetTypeID() == CFGetTypeID(value))
1542            status = _CFDataCreateAttribute((CFDataRef)value, kSecKeyLabel, &attrListPtr->attr[attrListPtr->count]);
1543        else
1544            status = errSecParam;
1545
1546		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1547
1548		++attrListPtr->count;
1549	}
1550
1551	// [4] get the kSecKeyApplicationTag data
1552	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrApplicationTag, (const void **)&value) && value) {
1553		if (CFStringGetTypeID() == CFGetTypeID(value))
1554			status = _CFStringCreateAttribute((CFStringRef)value, kSecKeyApplicationTag, &attrListPtr->attr[attrListPtr->count]);
1555		else if (CFDataGetTypeID() == CFGetTypeID(value))
1556			status = _CFDataCreateAttribute((CFDataRef)value, kSecKeyApplicationTag, &attrListPtr->attr[attrListPtr->count]);
1557		else
1558			status = errSecParam;
1559
1560		require_noerr_quiet(status, CFDataCreateAttribute_failed);
1561		++attrListPtr->count;
1562	}
1563
1564	// [5] get the kSecKeyKeyType number
1565	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeyType, (const void **)&value) && value) {
1566		UInt32 keyAlgValue = _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType);
1567		if (keyAlgValue != 0) {
1568			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1569			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1570
1571			attrListPtr->attr[attrListPtr->count].tag = kSecKeyKeyType;
1572			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1573			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = keyAlgValue;
1574
1575			++attrListPtr->count;
1576		}
1577	}
1578
1579	// [6] get the kSecKeyKeySizeInBits number
1580	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeySizeInBits, (const void **)&value) && value) {
1581		if (CFNumberGetTypeID() == CFGetTypeID(value)) {
1582			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1583			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1584
1585			attrListPtr->attr[attrListPtr->count].tag = kSecKeyKeySizeInBits;
1586			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1587			CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1588
1589			++attrListPtr->count;
1590		}
1591	}
1592
1593	// [7] get the kSecKeyEffectiveKeySize number
1594	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrEffectiveKeySize, (const void **)&value) && value) {
1595		if (CFNumberGetTypeID() == CFGetTypeID(value)) {
1596			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1597			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1598
1599			attrListPtr->attr[attrListPtr->count].tag = kSecKeyEffectiveKeySize;
1600			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1601			CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1602
1603			++attrListPtr->count;
1604		}
1605	}
1606
1607	// [8] get the kSecKeyEncrypt boolean
1608	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanEncrypt, (const void **)&value) && value) {
1609		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1610			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1611			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1612
1613			attrListPtr->attr[attrListPtr->count].tag = kSecKeyEncrypt;
1614			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1615			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1616
1617			++attrListPtr->count;
1618		}
1619	}
1620
1621	// [9] get the kSecKeyDecrypt boolean
1622	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanDecrypt, (const void **)&value) && value) {
1623		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1624			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1625			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1626
1627			attrListPtr->attr[attrListPtr->count].tag = kSecKeyDecrypt;
1628			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1629			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1630
1631			++attrListPtr->count;
1632		}
1633	}
1634
1635	// [10] get the kSecKeyDerive boolean
1636	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanDerive, (const void **)&value) && value) {
1637		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1638			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1639			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1640
1641			attrListPtr->attr[attrListPtr->count].tag = kSecKeyDerive;
1642			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1643			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1644
1645			++attrListPtr->count;
1646		}
1647	}
1648
1649	// [11] get the kSecKeySign boolean
1650	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanSign, (const void **)&value) && value) {
1651		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1652			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1653			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1654
1655			attrListPtr->attr[attrListPtr->count].tag = kSecKeySign;
1656			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1657			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1658
1659			++attrListPtr->count;
1660		}
1661	}
1662
1663	// [12] get the kSecKeyVerify boolean
1664	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanVerify, (const void **)&value) && value) {
1665		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1666			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1667			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1668
1669			attrListPtr->attr[attrListPtr->count].tag = kSecKeyVerify;
1670			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1671			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1672
1673			++attrListPtr->count;
1674		}
1675	}
1676
1677	// [13] get the kSecKeyWrap boolean
1678	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanWrap, (const void **)&value) && value) {
1679		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1680			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1681			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1682
1683			attrListPtr->attr[attrListPtr->count].tag = kSecKeyWrap;
1684			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1685			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1686
1687			++attrListPtr->count;
1688		}
1689	}
1690
1691	// [14] get the kSecKeyUnwrap boolean
1692	if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanUnwrap, (const void **)&value) && value) {
1693		if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1694			attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1695			require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1696
1697			attrListPtr->attr[attrListPtr->count].tag = kSecKeyUnwrap;
1698			attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1699			*((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1700
1701			++attrListPtr->count;
1702		}
1703	}
1704
1705	// return the pointer to the attrList
1706	*attrList = attrListPtr;
1707
1708	return ( errSecSuccess );
1709
1710	/***************/
1711
1712malloc_number_failed:
1713CFDataCreateAttribute_failed:
1714CFStringCreateAttribute_failed:
1715malloc_attrPtr_failed:
1716
1717	// free any attributes
1718	_FreeAttrList(attrListPtr);
1719
1720calloc_attrListPtr_failed:
1721
1722	return ( errSecBufferTooSmall );
1723
1724#endif
1725}
1726
1727static CFTypeRef copyNumber(CFTypeRef obj)
1728{
1729    if (!obj)
1730        return NULL;
1731
1732    CFTypeID tid = CFGetTypeID(obj);
1733    if (tid == CFNumberGetTypeID())
1734    {
1735        CFRetain(obj);
1736        return obj;
1737    }
1738
1739    if (tid == CFBooleanGetTypeID())
1740    {
1741        SInt32 value = CFBooleanGetValue((CFBooleanRef)obj);
1742        return CFNumberCreate(0, kCFNumberSInt32Type, &value);
1743    }
1744
1745    if (tid == CFStringGetTypeID())
1746    {
1747        SInt32 value = CFStringGetIntValue((CFStringRef)obj);
1748        CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long) value);
1749        /* If a string converted to an int isn't equal to the int printed as
1750         a string, return a NULL instead. */
1751        if (!CFEqual(t, obj))
1752        {
1753            CFRelease(t);
1754            return NULL;
1755        }
1756        CFRelease(t);
1757        return CFNumberCreate(0, kCFNumberSInt32Type, &value);
1758    }
1759    return NULL;
1760}
1761
1762/*
1763 * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList
1764 * from the attribute key/values in attrDictionary.
1765 *
1766 * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList
1767 * must be freed by the caller with _FreeAttrList()
1768 */
1769static OSStatus
1770_CreateSecKeychainInternetPasswordAttributeListFromDictionary(
1771	CFDictionaryRef attrDictionary,
1772	SecKeychainAttributeList **attrList)
1773{
1774	// explicitly build attribute list for supported key attributes
1775	// NOTE: this code supports only MaxSecKeychainAttributes (14) attributes
1776	const int MaxSecKeychainAttributes = 14;
1777
1778	OSStatus status;
1779	CFTypeRef value;
1780	SecKeychainAttributeList *attrListPtr;
1781
1782	attrListPtr = (SecKeychainAttributeList*)calloc(1, sizeof(SecKeychainAttributeList));
1783	require_action(attrListPtr != NULL, calloc_attrListPtr_failed, status = errSecBufferTooSmall);
1784
1785	attrListPtr->attr = (SecKeychainAttribute*)calloc(MaxSecKeychainAttributes, sizeof(SecKeychainAttribute));
1786	require_action(attrListPtr->attr != NULL, malloc_attrPtr_failed, status = errSecBufferTooSmall);
1787
1788
1789	// [0] get the serverName string
1790	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrServer, (const void **)&value) ) {
1791		status = _CFStringCreateAttribute((CFStringRef)value, kSecServerItemAttr, &attrListPtr->attr[attrListPtr->count]);
1792		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1793
1794		++attrListPtr->count;
1795	}
1796
1797	// [1] get the securityDomain string
1798	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrSecurityDomain, (const void **)&value) ) {
1799		status = _CFStringCreateAttribute((CFStringRef)value, kSecSecurityDomainItemAttr, &attrListPtr->attr[attrListPtr->count]);
1800		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1801
1802		++attrListPtr->count;
1803	}
1804
1805	// [2] get the accountName string
1806	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrAccount, (const void **)&value) ) {
1807		status = _CFStringCreateAttribute((CFStringRef)value, kSecAccountItemAttr, &attrListPtr->attr[attrListPtr->count]);
1808		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1809
1810		++attrListPtr->count;
1811	}
1812
1813	// [3] get the path string
1814	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrPath, (const void **)&value) ) {
1815		status = _CFStringCreateAttribute((CFStringRef)value, kSecPathItemAttr, &attrListPtr->attr[attrListPtr->count]);
1816		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1817
1818		++attrListPtr->count;
1819	}
1820
1821	// [4] get the port number
1822	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrPort, (const void **)&value) ) {
1823		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt16));
1824		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1825
1826        CFTypeRef num = copyNumber(value);
1827		require_action(num != NULL, CFStringCreateAttribute_failed, status = errSecParam);
1828		attrListPtr->attr[attrListPtr->count].tag = kSecPortItemAttr;
1829		attrListPtr->attr[attrListPtr->count].length = sizeof(UInt16);
1830		CFNumberGetValue((CFNumberRef)num, kCFNumberSInt16Type, attrListPtr->attr[attrListPtr->count].data);
1831        CFRelease(num);
1832
1833		++attrListPtr->count;
1834	}
1835
1836	// [5] get the protocol
1837	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrProtocol, (const void **)&value) ) {
1838		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(SecProtocolType));
1839		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_protocol_failed, status = errSecBufferTooSmall);
1840
1841		attrListPtr->attr[attrListPtr->count].tag = kSecProtocolItemAttr;
1842		attrListPtr->attr[attrListPtr->count].length = sizeof(SecProtocolType);
1843		*(SecProtocolType *)(attrListPtr->attr[attrListPtr->count].data) = _SecProtocolTypeForSecAttrProtocol(value);
1844
1845		++attrListPtr->count;
1846	}
1847
1848	// [6] get the authenticationType
1849	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrAuthenticationType, (const void **)&value) ) {
1850		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(SecAuthenticationType));
1851		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_authenticationType_failed, status = errSecBufferTooSmall);
1852
1853		attrListPtr->attr[attrListPtr->count].tag = kSecAuthenticationTypeItemAttr;
1854		attrListPtr->attr[attrListPtr->count].length = sizeof(SecAuthenticationType);
1855		*(SecAuthenticationType *)(attrListPtr->attr[attrListPtr->count].data) = _SecAuthenticationTypeForSecAttrAuthenticationType(value);
1856
1857		++attrListPtr->count;
1858	}
1859
1860	// [7] get the comment string
1861	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrComment, (const void **)&value) ) {
1862		status = _CFStringCreateAttribute((CFStringRef)value, kSecCommentItemAttr, &attrListPtr->attr[attrListPtr->count]);
1863		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1864
1865		++attrListPtr->count;
1866	}
1867
1868	// [8] get the description string
1869	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrDescription, (const void **)&value) ) {
1870		status = _CFStringCreateAttribute((CFStringRef)value, kSecDescriptionItemAttr, &attrListPtr->attr[attrListPtr->count]);
1871		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1872
1873		++attrListPtr->count;
1874	}
1875
1876	// [9] get the label string
1877	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrLabel, (const void **)&value) ) {
1878		status = _CFStringCreateAttribute((CFStringRef)value, kSecLabelItemAttr, &attrListPtr->attr[attrListPtr->count]);
1879		require_noerr_quiet(status, CFStringCreateAttribute_failed);
1880
1881		++attrListPtr->count;
1882	}
1883
1884	// [10] get the creator code
1885	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCreator, (const void **)&value) ) {
1886		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1887		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1888
1889        CFTypeRef num = copyNumber(value);
1890		require_action(num != NULL, CFStringCreateAttribute_failed, status = errSecParam);
1891		attrListPtr->attr[attrListPtr->count].tag = kSecCreatorItemAttr;
1892		attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1893		CFNumberGetValue((CFNumberRef)num, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1894        CFRelease(num);
1895
1896		++attrListPtr->count;
1897	}
1898
1899	// [11] get the type code
1900	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrType, (const void **)&value) ) {
1901		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1902		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1903
1904        CFTypeRef num = copyNumber(value);
1905		require_action(num != NULL, CFStringCreateAttribute_failed, status = errSecParam);
1906		attrListPtr->attr[attrListPtr->count].tag = kSecTypeItemAttr;
1907		attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1908		CFNumberGetValue((CFNumberRef)num, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1909        CFRelease(num);
1910
1911		++attrListPtr->count;
1912	}
1913
1914	// [12] get the invisible flag
1915	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrIsInvisible, (const void **)&value) ) {
1916		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1917		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1918
1919		attrListPtr->attr[attrListPtr->count].tag = kSecInvisibleItemAttr;
1920		attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1921		*(UInt32 *)(attrListPtr->attr[attrListPtr->count].data) = (CFBooleanGetValue((CFBooleanRef)value)) ? 1 : 0;
1922
1923		++attrListPtr->count;
1924	}
1925
1926	// [13] get the negative flag
1927	if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrIsNegative, (const void **)&value) ) {
1928		attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1929		require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1930
1931		attrListPtr->attr[attrListPtr->count].tag = kSecNegativeItemAttr;
1932		attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1933		*(UInt32 *)(attrListPtr->attr[attrListPtr->count].data) = (CFBooleanGetValue((CFBooleanRef)value)) ? 1 : 0;
1934
1935		++attrListPtr->count;
1936	}
1937
1938	// return the pointer to the attrList
1939	*attrList = attrListPtr;
1940
1941	return ( errSecSuccess );
1942
1943	/***************/
1944
1945malloc_authenticationType_failed:
1946malloc_protocol_failed:
1947malloc_port_failed:
1948CFStringCreateAttribute_failed:
1949malloc_attrPtr_failed:
1950
1951	// free any attributes
1952	_FreeAttrList(attrListPtr);
1953
1954calloc_attrListPtr_failed:
1955
1956	return ( errSecBufferTooSmall );
1957}
1958
1959
1960/*
1961 * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList
1962 * from the attribute key/values in attrDictionary for the specified item class.
1963 *
1964 * If this function returns errSecSuccess, the pointer to the SecKeychainAttributeList
1965 * must be freed by the caller with _FreeAttrList()
1966 */
1967static OSStatus
1968_CreateSecKeychainAttributeListFromDictionary(
1969	CFDictionaryRef attrDictionary,
1970	SecItemClass itemClass,
1971	SecKeychainAttributeList **attrList)
1972{
1973	switch (itemClass)
1974	{
1975		case kSecInternetPasswordItemClass:
1976			return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary, attrList);
1977
1978		case kSecGenericPasswordItemClass:
1979			return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary, attrList);
1980
1981		case kSecCertificateItemClass:
1982			return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary, attrList);
1983
1984		case kSecPublicKeyItemClass:
1985		case kSecPrivateKeyItemClass:
1986		case kSecSymmetricKeyItemClass:
1987			return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary, attrList);
1988
1989		default:
1990			break;
1991	}
1992	return errSecParam;
1993}
1994
1995
1996/*
1997 * _AppNameFromSecTrustedApplication attempts to pull the name of the
1998 * application/tool from the SecTrustedApplicationRef.
1999 */
2000static CFStringRef
2001_AppNameFromSecTrustedApplication(
2002	CFAllocatorRef alloc,
2003	SecTrustedApplicationRef appRef)
2004{
2005	CFStringRef result;
2006	OSStatus status;
2007	CFDataRef appDataRef;
2008
2009	result = NULL;
2010
2011	// get the data for item's application/tool
2012	status = SecTrustedApplicationCopyData(appRef, &appDataRef);
2013	if ( status == errSecSuccess ) {
2014		CFStringRef path;
2015
2016		// convert it to a CFString potentially containing the path
2017		path = CFStringCreateWithCString(NULL, (char *)CFDataGetBytePtrVoid(appDataRef), kCFStringEncodingUTF8);
2018		if ( path != NULL ) {
2019			// the path has to start with a "/" and cannot contain "://"
2020			if ( CFStringHasPrefix(path, CFSTR("/")) && (CFStringFind(path, CFSTR("://"), 0).location == kCFNotFound) ) {
2021				CFRange nameRange, compRg;
2022
2023				nameRange = CFRangeMake(0, CFStringGetLength(path));
2024
2025				// remove the trailing slashes (if any)
2026				while ( (nameRange.length > 0) && (CFStringGetCharacterAtIndex(path, nameRange.length - 1) == '/') ) {
2027					nameRange.length --;
2028				}
2029
2030				if ( nameRange.length > 0 ) {
2031					// find last slash and adjust nameRange to be everything after it
2032					if ( CFStringFindWithOptions(path, CFSTR("/"), nameRange, kCFCompareBackwards, &compRg) ) {
2033						nameRange.length = nameRange.location + nameRange.length - (compRg.location + 1);
2034						nameRange.location = compRg.location + 1;
2035					}
2036
2037					result = CFStringCreateWithSubstring(alloc, path, nameRange);
2038				}
2039			}
2040			CFRelease(path);
2041		}
2042		CFRelease(appDataRef);
2043	}
2044
2045	return ( result );
2046}
2047
2048/* (This function really belongs in SecIdentity.cpp!)
2049 *
2050 * Returns the public key item corresponding to the identity, if it exists in
2051 * the same keychain as the private key. Note that the public key might not
2052 * exist in the same keychain (e.g. if the identity was imported via PKCS12),
2053 * in which case it will not be found.
2054 */
2055static OSStatus
2056_SecIdentityCopyPublicKey(
2057	SecIdentityRef identityRef,
2058	SecKeyRef *publicKeyRef)
2059{
2060	OSStatus status;
2061	UInt32 count;
2062	SecKeychainAttribute attr = { kSecKeyLabel, 0, NULL };
2063	SecKeychainAttributeList attrList = { 1, &attr };
2064	SecKeychainAttributeList *keyAttrList = NULL;
2065	SecKeychainAttributeInfo *info = NULL;
2066	SecKeychainSearchRef search = NULL;
2067	SecKeychainRef keychain = NULL;
2068	SecKeychainItemRef privateKey = NULL;
2069	SecKeychainItemRef publicKey = NULL;
2070
2071	status = SecIdentityCopyPrivateKey(identityRef, (SecKeyRef *)&privateKey);
2072	if (status) {
2073		goto error_exit; // identity must have a private key
2074	}
2075	status = SecKeychainItemCopyKeychain(privateKey, &keychain);
2076	if (status) {
2077		goto error_exit; // private key must have a keychain, so we can get the attribute info for it
2078	}
2079	status = SecKeychainAttributeInfoForItemID(keychain, kSecPrivateKeyItemClass, &info);
2080	if (status) {
2081		goto error_exit; // unable to get the attribute info (i.e. database schema) for private keys
2082	}
2083	status = SecKeychainItemCopyAttributesAndData(privateKey, info, NULL, &keyAttrList, NULL, NULL);
2084	if (status) {
2085		goto error_exit; // unable to get the key label attribute for the private key
2086	}
2087
2088	// use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching
2089	for (count = 0; count < keyAttrList->count; count++) {
2090		if (keyAttrList->attr[count].tag == kSecKeyLabel) {
2091			attr.length = keyAttrList->attr[count].length;
2092			attr.data = keyAttrList->attr[count].data;
2093			break;
2094		}
2095	}
2096	if (!attr.length || !attr.data) {
2097		status = errSecNoSuchAttr;
2098		goto error_exit; // the private key didn't have the hash of the public key in its kSecKeyLabel
2099	}
2100	status = SecKeychainSearchCreateFromAttributes(keychain, kSecPublicKeyItemClass, &attrList, &search);
2101	if (status) {
2102		goto error_exit; // unable to create the search reference
2103	}
2104	status = SecKeychainSearchCopyNext(search, &publicKey);
2105	if (status) {
2106		goto error_exit; // unable to find the public key
2107	}
2108
2109	if (publicKeyRef)
2110		*publicKeyRef = (SecKeyRef)publicKey;
2111	else
2112		CFRelease(publicKey);
2113
2114error_exit:
2115	if (status != errSecSuccess) {
2116		if (publicKeyRef)
2117			*publicKeyRef = NULL;
2118		if (publicKey)
2119			CFRelease(publicKey);
2120	}
2121	if (search)
2122		CFRelease(search);
2123
2124	if (keyAttrList)
2125		SecKeychainItemFreeAttributesAndData(keyAttrList, NULL);
2126
2127	if (info)
2128		SecKeychainFreeAttributeInfo(info);
2129
2130	if (keychain)
2131		CFRelease(keychain);
2132
2133	if (privateKey)
2134		CFRelease(privateKey);
2135
2136	return status;
2137}
2138
2139
2140/*
2141 * Deletes a keychain item if the current application/tool is the only application/tool
2142 * with decrypt access to that keychain item. If more than one application/tool
2143 * has decrypt access to the keychain item, the item is left on the keychain.
2144 *
2145 * TBD: If more than one app/tool has access to the keychain item, we should remove
2146 * the current app/tool's decrypt access. There's no easy way to do that with
2147 * current keychain APIs without bringing up the security UI.
2148 */
2149static OSStatus
2150_SafeSecKeychainItemDelete(
2151	SecKeychainItemRef itemRef)
2152{
2153	OSStatus status;
2154	SecAccessRef access = NULL;
2155	CFArrayRef aclList = NULL;
2156	SecACLRef acl = NULL;
2157	CFArrayRef appList = NULL;
2158	CFStringRef description = NULL;
2159	CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
2160	CFIndex count = 0;
2161	SecTrustedApplicationRef currentAppRef = NULL;
2162	CFStringRef itemAppName = NULL, currentAppName = NULL;
2163
2164	SecItemClass itemClass = (SecItemClass)0;
2165	status = SecKeychainItemCopyAttributesAndData(itemRef, NULL, &itemClass, NULL, NULL, NULL);
2166	if (!(itemClass == kSecInternetPasswordItemClass || itemClass == kSecGenericPasswordItemClass)) {
2167		// only perform the access control safety check on deletion of password credentials;
2168		// if the item is of some other type, delete it normally.
2169		return SecKeychainItemDelete(itemRef);
2170	}
2171
2172	// skip access control checking for web form passwords: <rdar://10957301>
2173	// This permits Safari to manage the removal of all web form passwords,
2174	// regardless of whether they are shared by multiple applications.
2175	if (itemClass == kSecInternetPasswordItemClass) {
2176		UInt32 tags[1] = { kSecAuthenticationTypeItemAttr };
2177		SecKeychainAttributeInfo attrInfo = { 1, tags, NULL };
2178		SecKeychainAttributeList *attrs = NULL;
2179		status = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrs, NULL, NULL);
2180		if (!status && attrs) {
2181			bool webFormPassword = (attrs->attr[0].length == 4 && (!memcmp(attrs->attr[0].data, "form", 4)));
2182			SecKeychainItemFreeAttributesAndData(attrs, NULL);
2183			if (webFormPassword) {
2184				return SecKeychainItemDelete(itemRef);
2185			}
2186		}
2187	}
2188
2189	// copy the access of the keychain item
2190	status = SecKeychainItemCopyAccess(itemRef, &access);
2191	require_noerr(status, finish);
2192	require_quiet(access != NULL, finish);
2193
2194	// copy the decrypt access control lists -- this is what has access to the keychain item
2195	status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
2196	require_noerr(status, finish);
2197	require_quiet(aclList != NULL, finish);
2198
2199	// get the access control list
2200	acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
2201	require_quiet(acl != NULL, finish);
2202
2203	// copy the application list, description, and CSSM prompt selector for a given access control list entry
2204	status = SecACLCopySimpleContents(acl, &appList, &description, &promptSelector);
2205	require_noerr(status, finish);
2206	require_quiet(appList != NULL, finish);
2207
2208	// does only a single application/tool have decrypt access to this item?
2209	count = CFArrayGetCount(appList);
2210	if ( count == 1 ) {
2211		// get SecTrustedApplicationRef for item's application/tool
2212		SecTrustedApplicationRef itemAppRef = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(appList, 0);
2213		require_quiet(itemAppRef != NULL, finish);
2214
2215		// copy the name out
2216		itemAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), itemAppRef);
2217		if (itemAppName == NULL) {
2218			/*
2219			 * If there is no app name, it's probably because it's not an appname
2220			 * in the ACE but an entitlement/info.plist based rule instead;
2221			 * just let the caller have it. */
2222			count--;
2223			goto finish;
2224		}
2225
2226		// create SecTrustedApplicationRef for current application/tool
2227		status = SecTrustedApplicationCreateFromPath(NULL, &currentAppRef);
2228		require_noerr(status, finish);
2229		require_quiet(currentAppRef != NULL, finish);
2230
2231		// copy the name out
2232		currentAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), currentAppRef);
2233		require_quiet(currentAppName != NULL, finish);
2234
2235		// compare the names to see if we own the decrypt access
2236		if ( CFStringCompare(currentAppName, itemAppName, 0) == kCFCompareEqualTo ) {
2237			// decrement the count to zero, which will remove the item below
2238			--count;
2239		}
2240	}
2241
2242finish:
2243
2244	CFReleaseSafe(currentAppName);
2245	CFReleaseSafe(itemAppName);
2246	CFReleaseSafe(currentAppRef);
2247	CFReleaseSafe(description);
2248	CFReleaseSafe(appList);
2249	CFReleaseSafe(aclList);
2250	CFReleaseSafe(access);
2251
2252	if ((count == 0) || (status == errSecVerifyFailed)) {
2253		// no "owners" remain in the ACL list (or unable to get ACL)
2254		status = SecKeychainItemDelete(itemRef);
2255	} else {
2256		// caller is not the "owner" of the item
2257		status = errSecInvalidOwnerEdit;
2258	}
2259
2260	return status;
2261}
2262
2263static OSStatus
2264_UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes)
2265{
2266	// This function updates a single keychain item, which may be specified as
2267	// a reference, persistent reference or attribute dictionary, with the
2268	// attributes provided.
2269
2270	OSStatus status = errSecSuccess;
2271	if (!item) {
2272		return errSecParam;
2273	}
2274
2275	SecItemClass itemClass;
2276	SecAccessRef access = NULL;
2277	SecKeychainAttributeList *changeAttrList = NULL;
2278	SecKeychainItemRef itemToUpdate = NULL;
2279	CFDataRef theData = NULL;
2280	CFTypeID itemType = CFGetTypeID(item);
2281
2282	// validate input item (must be convertible to a SecKeychainItemRef)
2283	if (SecKeychainItemGetTypeID() == itemType ||
2284		SecCertificateGetTypeID() == itemType ||
2285		SecKeyGetTypeID() == itemType) {
2286		// item is already a reference, retain it
2287		itemToUpdate = (SecKeychainItemRef) CFRetain(item);
2288	}
2289	else if (CFDataGetTypeID() == itemType) {
2290		// item is a persistent reference, must convert it
2291		status = SecKeychainItemCopyFromPersistentReference((CFDataRef)item, &itemToUpdate);
2292	}
2293	else if (CFDictionaryGetTypeID() == itemType) {
2294		// item is a dictionary
2295		CFTypeRef value = NULL;
2296		if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValueRef, &value)) {
2297			// kSecValueRef value is a SecKeychainItemRef, retain it
2298			itemToUpdate = (SecKeychainItemRef) CFRetain(value);
2299		}
2300		else if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValuePersistentRef, &value)) {
2301			// kSecValuePersistentRef value is a persistent reference, must convert it
2302			status = SecKeychainItemCopyFromPersistentReference((CFDataRef)value, &itemToUpdate);
2303		}
2304	}
2305	else if (SecIdentityGetTypeID() == itemType) {
2306		// item is a certificate + private key; since we can't really change the
2307		// certificate's attributes, assume we want to update the private key
2308		status = SecIdentityCopyPrivateKey((SecIdentityRef)item, (SecKeyRef*)&itemToUpdate);
2309	}
2310	require_action(itemToUpdate != NULL, update_failed, status = errSecInvalidItemRef);
2311	require_noerr(status, update_failed);
2312
2313	status = SecKeychainItemCopyContent(itemToUpdate, &itemClass, NULL, NULL, NULL);
2314	require_noerr(status, update_failed);
2315
2316	// build changeAttrList from changedAttributes dictionary
2317	switch (itemClass)
2318	{
2319		case kSecInternetPasswordItemClass:
2320		{
2321			status = _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes, &changeAttrList);
2322			require_noerr(status, update_failed);
2323		}
2324		break;
2325
2326		case kSecGenericPasswordItemClass:
2327		{
2328			status = _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes, &changeAttrList);
2329			require_noerr(status, update_failed);
2330		}
2331		break;
2332
2333		case kSecCertificateItemClass:
2334		{
2335			status = _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes, &changeAttrList);
2336			require_noerr(status, update_failed);
2337		}
2338		break;
2339
2340		case kSecPublicKeyItemClass:
2341		case kSecPrivateKeyItemClass:
2342		case kSecSymmetricKeyItemClass:
2343		{
2344			status = _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes, &changeAttrList);
2345			require_noerr(status, update_failed);
2346		}
2347	}
2348
2349	// get the password
2350	// (if the caller is not updating the password, this value will be NULL)
2351	theData = (CFDataRef)CFDictionaryGetValue(changedAttributes, kSecValueData);
2352	if (theData != NULL) {
2353		require_action(CFDataGetTypeID() == CFGetTypeID(theData), update_failed, status = errSecParam);
2354	}
2355	// update item
2356	status = SecKeychainItemModifyContent(itemToUpdate,
2357				(changeAttrList->count == 0) ? NULL : changeAttrList,
2358				(theData != NULL) ? (UInt32)CFDataGetLength(theData) : 0,
2359				(theData != NULL) ? CFDataGetBytePtrVoid(theData) : NULL);
2360
2361	// one more thing... update access?
2362	if (CFDictionaryGetValueIfPresent(changedAttributes, kSecAttrAccess, (const void **)&access)) {
2363		status = SecKeychainItemSetAccess(itemToUpdate, access);
2364	}
2365
2366update_failed:
2367	if (itemToUpdate)
2368		CFRelease(itemToUpdate);
2369	_FreeAttrList(changeAttrList);
2370	return status;
2371}
2372
2373static OSStatus
2374_DeleteKeychainItem(CFTypeRef item)
2375{
2376	// This function deletes a single keychain item, which may be specified as
2377	// a reference, persistent reference or attribute dictionary. It will not
2378	// delete non-keychain items or aggregate items (such as a SecIdentityRef);
2379	// it is assumed that the caller will pass identity components separately.
2380
2381	OSStatus status = errSecSuccess;
2382	if (!item) {
2383		return errSecParam;
2384	}
2385
2386	SecKeychainItemRef itemToDelete = NULL;
2387	CFTypeID itemType = CFGetTypeID(item);
2388	if (SecKeychainItemGetTypeID() == itemType ||
2389		SecCertificateGetTypeID() == itemType ||
2390		SecKeyGetTypeID() == itemType) {
2391		// item is already a reference, retain it
2392		itemToDelete = (SecKeychainItemRef) CFRetain(item);
2393	}
2394	else if (CFDataGetTypeID() == itemType) {
2395		// item is a persistent reference, must convert it
2396		status = SecKeychainItemCopyFromPersistentReference((CFDataRef)item, &itemToDelete);
2397	}
2398	else if (CFDictionaryGetTypeID() == itemType) {
2399		// item is a dictionary
2400		CFTypeRef value = NULL;
2401		if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValueRef, &value)) {
2402			// kSecValueRef value is a SecKeychainItemRef, retain it
2403			itemToDelete = (SecKeychainItemRef) CFRetain(value);
2404		}
2405		else if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValuePersistentRef, &value)) {
2406			// kSecValuePersistentRef value is a persistent reference, must convert it
2407			status = SecKeychainItemCopyFromPersistentReference((CFDataRef)value, &itemToDelete);
2408		}
2409	}
2410
2411	if (itemToDelete) {
2412		if (!status) {
2413			status = _SafeSecKeychainItemDelete(itemToDelete);
2414		}
2415		CFRelease(itemToDelete);
2416	}
2417
2418	return status;
2419}
2420
2421static OSStatus
2422_DeleteIdentity(SecIdentityRef identity)
2423{
2424	OSStatus status, result = errSecSuccess;
2425	SecKeyRef privateKey = NULL;
2426	SecCertificateRef certificate = NULL;
2427
2428	status = SecIdentityCopyPrivateKey(identity, &privateKey);
2429	if (!status) {
2430		SecKeyRef publicKey = NULL;
2431		status = _SecIdentityCopyPublicKey(identity, &publicKey);
2432		if (!status) {
2433			status = _DeleteKeychainItem(publicKey);
2434			CFRelease(publicKey);
2435		}
2436		status = _DeleteKeychainItem(privateKey);
2437	}
2438
2439	if (privateKey) CFRelease(privateKey);
2440	if (status) result = status;
2441
2442	status = SecIdentityCopyCertificate(identity, &certificate);
2443	if (!status) {
2444		status = _DeleteKeychainItem(certificate);
2445	}
2446
2447	if (certificate) CFRelease(certificate);
2448	if (status) result = status;
2449
2450	return result;
2451}
2452
2453static OSStatus
2454_UpdateAggregateStatus(OSStatus newStatus, OSStatus curStatus, OSStatus baseStatus)
2455{
2456	// This function is used when atomically processing multiple items,
2457	// where an overall error result must be returned for the entire operation.
2458	// When newStatus is something other than errSecSuccess, we want to keep the "most
2459	// interesting" status (which usually will be newStatus, unless curStatus is
2460	// already set; in that case, newStatus can trump curStatus only by being
2461	// something different than baseStatus.)
2462
2463	OSStatus result = curStatus;
2464
2465	if (newStatus != errSecSuccess) {
2466		result = newStatus;
2467		if (curStatus != errSecSuccess) {
2468			result = (newStatus != baseStatus) ? newStatus : curStatus;
2469		}
2470	}
2471	return result;
2472}
2473
2474static void
2475_AddDictValueToOtherDict(const void *key, const void *value, void *context)
2476{
2477	// CFDictionaryApplierFunction
2478	// This function just takes the given key/value pair,
2479	// and adds it to another dictionary supplied in the context argument.
2480
2481	CFMutableDictionaryRef dict = *((CFMutableDictionaryRef*) context);
2482	if (key && value) {
2483		CFDictionaryAddValue(dict, key, value);
2484	}
2485}
2486
2487static CFStringCompareFlags
2488_StringCompareFlagsFromQuery(CFDictionaryRef query)
2489{
2490	CFTypeRef value;
2491	CFStringCompareFlags flags = 0;
2492	if (!query) return flags;
2493
2494	if (CFDictionaryGetValueIfPresent(query, kSecMatchSubjectStartsWith, (const void **)&value) ||
2495		CFDictionaryGetValueIfPresent(query, kSecMatchSubjectEndsWith, (const void **)&value))
2496		flags |= kCFCompareAnchored;
2497
2498	if (CFDictionaryGetValueIfPresent(query, kSecMatchSubjectEndsWith, (const void **)&value))
2499		flags |= kCFCompareBackwards;
2500
2501	if (CFDictionaryGetValueIfPresent(query, kSecMatchCaseInsensitive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2502		flags |= kCFCompareCaseInsensitive;
2503
2504	if (CFDictionaryGetValueIfPresent(query, kSecMatchDiacriticInsensitive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2505		flags |= kCFCompareDiacriticInsensitive;
2506
2507	if (CFDictionaryGetValueIfPresent(query, kSecMatchWidthInsensitive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2508		flags |= kCFCompareWidthInsensitive;
2509
2510	return flags;
2511}
2512
2513static uint32
2514_CssmKeyUsageFromQuery(CFDictionaryRef query)
2515{
2516	CFTypeRef value;
2517	uint32 keyUsage = 0;
2518	if (!query) return keyUsage;
2519
2520	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanEncrypt, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2521		keyUsage |= CSSM_KEYUSE_ENCRYPT;
2522
2523	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanDecrypt, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2524		keyUsage |= CSSM_KEYUSE_DECRYPT;
2525
2526	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanSign, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2527		keyUsage |= CSSM_KEYUSE_SIGN;
2528
2529	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanVerify, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2530		keyUsage |= CSSM_KEYUSE_VERIFY;
2531
2532	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanWrap, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2533		keyUsage |= CSSM_KEYUSE_WRAP;
2534
2535	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanUnwrap, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2536		keyUsage |= CSSM_KEYUSE_UNWRAP;
2537
2538	if (CFDictionaryGetValueIfPresent(query, kSecAttrCanDerive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2539		keyUsage |= CSSM_KEYUSE_DERIVE;
2540
2541	return keyUsage;
2542}
2543
2544static SecItemClass
2545_ConvertItemClass(const void* item, const void* keyClass, Boolean *isIdentity)
2546{
2547	SecItemClass itemClass = (SecItemClass) 0;
2548	if (isIdentity) *isIdentity = false;
2549
2550	if (CFEqual(item, kSecClassGenericPassword)) {
2551		itemClass = kSecGenericPasswordItemClass;
2552	}
2553	else if (CFEqual(item, kSecClassInternetPassword)) {
2554		itemClass = kSecInternetPasswordItemClass;
2555	}
2556	else if (CFEqual(item, kSecClassCertificate)) {
2557		itemClass = kSecCertificateItemClass;
2558	}
2559	else if (CFEqual(item, kSecClassIdentity)) {
2560		// will perform a certificate lookup
2561		itemClass = kSecCertificateItemClass;
2562		if (isIdentity) *isIdentity = true;
2563	}
2564	else if (CFEqual(item, kSecClassKey)) {
2565		// examine second parameter to determine type of key
2566		if (!keyClass || CFEqual(keyClass, kSecAttrKeyClassSymmetric)) {
2567			itemClass = kSecSymmetricKeyItemClass;
2568		}
2569		else if (keyClass && CFEqual(keyClass, kSecAttrKeyClassPublic)) {
2570			itemClass = kSecPublicKeyItemClass;
2571		}
2572		else if (keyClass && CFEqual(keyClass, kSecAttrKeyClassPrivate)) {
2573			itemClass = kSecPrivateKeyItemClass;
2574		}
2575	}
2576
2577	return itemClass;
2578}
2579
2580static SecItemClass
2581_ItemClassFromItemList(CFArrayRef itemList)
2582{
2583	// Given a list of items (standard or persistent references),
2584	// determine whether they all have the same item class. Returns
2585	// the item class, or 0 if multiple classes in list.
2586	SecItemClass result = 0;
2587	CFIndex index, count = (itemList) ? CFArrayGetCount(itemList) : 0;
2588	for (index=0; index < count; index++) {
2589		CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(itemList, index);
2590		if (item) {
2591			SecKeychainItemRef itemRef = NULL;
2592			OSStatus status;
2593			if (CFGetTypeID(item) == CFDataGetTypeID()) {
2594				// persistent reference, resolve first
2595				status = SecKeychainItemCopyFromPersistentReference((CFDataRef)item, &itemRef);
2596			}
2597			else {
2598				itemRef = (SecKeychainItemRef) CFRetain(item);
2599			}
2600			if (itemRef) {
2601				SecItemClass itemClass = 0;
2602				CFTypeID itemTypeID = CFGetTypeID(itemRef);
2603				if (itemTypeID == SecIdentityGetTypeID() || itemTypeID == SecCertificateGetTypeID()) {
2604					// Identities and certificates have the same underlying item class
2605					itemClass = kSecCertificateItemClass;
2606				}
2607				else if (itemTypeID == SecKeychainItemGetTypeID()) {
2608					// Reference to item in a keychain
2609					status = SecKeychainItemCopyAttributesAndData(itemRef, NULL, &itemClass, NULL, NULL, NULL);
2610				}
2611				else if (itemTypeID == SecKeyGetTypeID()) {
2612					// SecKey that isn't stored in a keychain
2613					// %%% will need to change this code when SecKey is no longer CSSM-based %%%
2614					const CSSM_KEY *cssmKey;
2615					status = SecKeyGetCSSMKey((SecKeyRef)itemRef, &cssmKey);
2616					if (status == errSecSuccess) {
2617						if (cssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY)
2618							itemClass = kSecPublicKeyItemClass;
2619						else if (cssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)
2620							itemClass = kSecPrivateKeyItemClass;
2621						else
2622							itemClass = kSecSymmetricKeyItemClass;
2623					}
2624				}
2625				CFRelease(itemRef);
2626				if (itemClass != 0) {
2627					if (result != 0 && result != itemClass) {
2628						return 0; // different item classes in list; bail out
2629					}
2630					result = itemClass;
2631				}
2632			}
2633		}
2634	}
2635	return result;
2636}
2637
2638// SecItemParams contains a validated set of input parameters, as well as a
2639// search reference and attribute list built from those parameters. It is
2640// designed to be allocated with _CreateSecItemParamsFromDictionary, and
2641// freed with _FreeSecItemParams.
2642
2643struct SecItemParams {
2644	CFDictionaryRef query;				// caller-supplied query
2645	int numResultTypes;					// number of result types requested
2646	int maxMatches;						// max number of matches to return
2647	uint32 keyUsage;					// key usage(s) requested
2648	Boolean returningAttributes;		// true if returning attributes dictionary
2649	Boolean returningData;				// true if returning item's data
2650	Boolean returningRef;				// true if returning item reference
2651	Boolean returningPersistentRef;		// true if returing a persistent reference
2652	Boolean returnAllMatches;			// true if we should return all matches
2653	Boolean returnIdentity;				// true if we are returning a SecIdentityRef
2654	Boolean trustedOnly;				// true if we only return trusted certs
2655	Boolean	issuerAndSNToMatch;			// true if both issuer and SN were provided
2656	SecItemClass itemClass;				// item class for this query
2657	SecPolicyRef policy;				// value for kSecMatchPolicy (may be NULL)
2658	SecKeychainRef keychain;			// value for kSecUseKeychain (may be NULL)
2659	CFArrayRef useItems;				// value for kSecUseItemList (may be NULL)
2660	CFArrayRef itemList;				// value for kSecMatchItemList (may be NULL)
2661	CFTypeRef searchList;				// value for kSecMatchSearchList (may be NULL)
2662	CFTypeRef matchLimit;				// value for kSecMatchLimit (may be NULL)
2663	CFTypeRef emailAddrToMatch;			// value for kSecMatchEmailAddressIfPresent (may be NULL)
2664	CFTypeRef validOnDate;				// value for kSecMatchValidOnDate (may be NULL)
2665	CFTypeRef keyClass;					// value for kSecAttrKeyClass (may be NULL)
2666	CFTypeRef service;					// value for kSecAttrService (may be NULL)
2667	CFTypeRef issuer;					// value for kSecAttrIssuer (may be NULL)
2668	CFTypeRef serialNumber;				// value for kSecAttrSerialNumber (may be NULL)
2669	CFTypeRef search;					// search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef)
2670	CFTypeRef assumedKeyClass;			// if no kSecAttrKeyClass provided, holds the current class we're searching for
2671	CFIndex itemListIndex;				// if no search reference but we have itemList, holds index of next item to return
2672	SecKeychainAttributeList *attrList;	// attribute list for this query
2673	SecAccessRef access;				// access reference (for SecItemAdd only, not used to find items)
2674	CFDataRef itemData;					// item data (for SecItemAdd only, not used to find items)
2675	CFTypeRef itemRef;					// item reference (to find, add, update or delete, depending on context)
2676	SecIdentityRef identityRef;			// identity reference (input as kSecValueRef)
2677	CFDataRef itemPersistentRef;		// item persistent reference (to find, add, update or delete, depending on context)
2678	Boolean isPCSItem;					// true if this query is for a Protected Cloud Storage item
2679};
2680
2681static OSStatus
2682_ValidateDictionaryEntry(CFDictionaryRef dict, CFTypeRef key, const void **value, CFTypeID expectedTypeID, CFTypeID altTypeID)
2683{
2684	if (!dict || !key || !value || !expectedTypeID)
2685		return errSecParam;
2686
2687	if (!CFDictionaryGetValueIfPresent(dict, key, value)) {
2688		// value was not provided for this key (not an error!)
2689		*value = NULL;
2690	}
2691	else if (!(*value)) {
2692		// provided value is NULL (also not an error!)
2693		return errSecSuccess;
2694	}
2695	else {
2696		CFTypeID actualTypeID = CFGetTypeID(*value);
2697		if (!((expectedTypeID == actualTypeID) || (altTypeID && altTypeID == actualTypeID))) {
2698			// provided value does not have the expected (or alternate) CF type ID
2699			if ((expectedTypeID == SecKeychainItemGetTypeID()) &&
2700				(actualTypeID == SecKeyGetTypeID() || actualTypeID == SecCertificateGetTypeID())) {
2701				// provided value is a "floating" reference which is not yet in a keychain
2702				CFRetain(*value);
2703				return errSecSuccess;
2704			}
2705			return errSecItemInvalidValue;
2706		}
2707		else {
2708			// provided value is OK; retain it
2709			CFRetain(*value);
2710		}
2711	}
2712	return errSecSuccess;
2713}
2714
2715static void
2716_EnsureUserDefaultKeychainIsSearched(SecItemParams *itemParams)
2717{
2718	OSStatus status;
2719	CFArrayRef tmpList = (CFArrayRef) itemParams->searchList;
2720	if (tmpList) {
2721		// search list exists; make it mutable
2722		itemParams->searchList = (CFArrayRef) CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, tmpList);
2723		CFRelease(tmpList);
2724	} else {
2725		// no search list; start with default list
2726		status = SecKeychainCopySearchList(&tmpList);
2727		if (!status && tmpList) {
2728			itemParams->searchList = (CFArrayRef) CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, tmpList);
2729			CFRelease(tmpList);
2730		}
2731		else {
2732			itemParams->searchList = (CFArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2733		}
2734	}
2735
2736	SecKeychainRef userKeychain = NULL;
2737	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser, &userKeychain);
2738	if (!status && userKeychain) {
2739		if (!CFArrayContainsValue((CFArrayRef)itemParams->searchList,
2740			CFRangeMake(0, CFArrayGetCount((CFArrayRef)itemParams->searchList)), userKeychain)) {
2741			// user's default keychain isn't currently in the search list, so append it
2742			CFArrayAppendValue((CFMutableArrayRef)itemParams->searchList, userKeychain);
2743		}
2744		CFRelease(userKeychain);
2745	}
2746}
2747
2748static void
2749_EnsureUserDefaultKeychainIsTargeted(SecItemParams *itemParams)
2750{
2751	if (itemParams->keychain) {
2752		return; // keychain is already explicitly specified, assume it's correct
2753	}
2754	SecKeychainRef userKeychain = NULL;
2755	OSStatus status = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser, &userKeychain);
2756	if (!status && userKeychain) {
2757		itemParams->keychain = userKeychain;
2758	}
2759}
2760
2761static void
2762_FreeSecItemParams(SecItemParams *itemParams)
2763{
2764	if (!itemParams)
2765		return;
2766
2767	if (itemParams->query) CFRelease(itemParams->query);
2768	if (itemParams->policy) CFRelease(itemParams->policy);
2769	if (itemParams->keychain) CFRelease(itemParams->keychain);
2770	if (itemParams->useItems) CFRelease(itemParams->useItems);
2771	if (itemParams->itemList) CFRelease(itemParams->itemList);
2772	if (itemParams->searchList) CFRelease(itemParams->searchList);
2773	if (itemParams->matchLimit) CFRelease(itemParams->matchLimit);
2774	if (itemParams->emailAddrToMatch) CFRelease(itemParams->emailAddrToMatch);
2775	if (itemParams->validOnDate) CFRelease(itemParams->validOnDate);
2776	if (itemParams->keyClass) CFRelease(itemParams->keyClass);
2777	if (itemParams->service) CFRelease(itemParams->service);
2778	if (itemParams->issuer) CFRelease(itemParams->issuer);
2779	if (itemParams->serialNumber) CFRelease(itemParams->serialNumber);
2780	if (itemParams->search) CFRelease(itemParams->search);
2781	if (itemParams->access) CFRelease(itemParams->access);
2782	if (itemParams->itemData) CFRelease(itemParams->itemData);
2783	if (itemParams->itemRef) CFRelease(itemParams->itemRef);
2784	if (itemParams->identityRef) CFRelease(itemParams->identityRef);
2785	if (itemParams->itemPersistentRef) CFRelease(itemParams->itemPersistentRef);
2786
2787	_FreeAttrList(itemParams->attrList);
2788
2789	free(itemParams);
2790}
2791
2792static SecItemParams*
2793_CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error)
2794{
2795	OSStatus status;
2796	CFTypeRef value = NULL;
2797	SecItemParams *itemParams = (SecItemParams *) malloc(sizeof(SecItemParams));
2798
2799	require_action(itemParams != NULL, error_exit, status = errSecAllocate);
2800	require_action(dict && (CFDictionaryGetTypeID() == CFGetTypeID(dict)), error_exit, status = errSecParam);
2801
2802	memset(itemParams, 0, sizeof(SecItemParams));
2803	itemParams->query = (CFDictionaryRef) CFRetain(dict);
2804
2805	// validate input search parameters
2806	require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchPolicy, (const void **)&itemParams->policy, SecPolicyGetTypeID(), NULL), error_exit);
2807	require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchSearchList, (const void **)&itemParams->searchList, CFArrayGetTypeID(), NULL), error_exit);
2808	require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchItemList, (const void **)&itemParams->itemList, CFArrayGetTypeID(), NULL), error_exit);
2809	require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchEmailAddressIfPresent, (const void **)&itemParams->emailAddrToMatch, CFStringGetTypeID(), NULL), error_exit);
2810	require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchValidOnDate, (const void **)&itemParams->validOnDate, CFDateGetTypeID(), CFNullGetTypeID()), error_exit);
2811	require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchLimit, (const void **)&itemParams->matchLimit, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit);
2812
2813	require_noerr(status = _ValidateDictionaryEntry(dict, kSecUseItemList, (const void **)&itemParams->useItems, CFArrayGetTypeID(), NULL), error_exit);
2814	require_noerr(status = _ValidateDictionaryEntry(dict, kSecUseKeychain, (const void **)&itemParams->keychain, SecKeychainGetTypeID(), NULL), error_exit);
2815
2816	// validate a subset of input attributes (used to create an appropriate search reference)
2817	require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrIssuer, (const void **)&itemParams->issuer, CFDataGetTypeID(), NULL), error_exit);
2818	require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrSerialNumber, (const void **)&itemParams->serialNumber, CFDataGetTypeID(), NULL), error_exit);
2819	require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrService, (const void **)&itemParams->service, CFStringGetTypeID(), NULL), error_exit);
2820	require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrKeyClass, (const void **)&itemParams->keyClass, CFStringGetTypeID(), NULL), error_exit);
2821
2822	if (itemParams->service && CFStringHasPrefix((CFStringRef)itemParams->service, CFSTR("ProtectedCloudStorage"))) {
2823		itemParams->isPCSItem = true;
2824		if (!SecItemSynchronizable(dict)) {
2825			_EnsureUserDefaultKeychainIsSearched(itemParams); // for SecItemCopyMatching, SecItemUpdate, SecItemDelete
2826			_EnsureUserDefaultKeychainIsTargeted(itemParams); // for SecItemAdd
2827		}
2828	}
2829
2830	// validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items
2831	require_noerr(status = _ValidateDictionaryEntry(dict, kSecValueData, (const void **)&itemParams->itemData, CFDataGetTypeID(), CFStringGetTypeID()), error_exit);
2832
2833	// validate item references
2834	require_noerr(status = _ValidateDictionaryEntry(dict, kSecValueRef, (const void **)&itemParams->itemRef, SecKeychainItemGetTypeID(), SecIdentityGetTypeID()), error_exit);
2835	if (itemParams->itemRef && (CFGetTypeID(itemParams->itemRef) == SecIdentityGetTypeID())) {
2836		itemParams->identityRef = (SecIdentityRef)itemParams->itemRef;
2837		itemParams->itemRef = NULL;
2838		SecIdentityCopyCertificate(itemParams->identityRef, (SecCertificateRef *)&itemParams->itemRef);
2839	}
2840	require_noerr(status = _ValidateDictionaryEntry(dict, kSecValuePersistentRef, (const void **)&itemParams->itemPersistentRef, CFDataGetTypeID(), NULL), error_exit);
2841	if (itemParams->itemRef || itemParams->itemPersistentRef) {
2842		// Caller is trying to add or find an item by reference.
2843		// The supported method for doing that is to provide a kSecUseItemList array
2844		// for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al,
2845		// so add the item reference to those arrays here.
2846		if (itemParams->useItems) {
2847			CFArrayRef tmpItems = itemParams->useItems;
2848			itemParams->useItems = (CFArrayRef) CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, tmpItems);
2849			CFRelease(tmpItems);
2850		} else {
2851			itemParams->useItems = (CFArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2852		}
2853		if (itemParams->itemRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->useItems, itemParams->itemRef);
2854		if (itemParams->itemPersistentRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->useItems, itemParams->itemPersistentRef);
2855
2856		if (itemParams->itemList) {
2857			CFArrayRef tmpItems = itemParams->itemList;
2858			itemParams->itemList = (CFArrayRef) CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, tmpItems);
2859			CFRelease(tmpItems);
2860		} else {
2861			itemParams->itemList = (CFArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2862		}
2863		if (itemParams->itemRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->itemList, itemParams->itemRef);
2864		if (itemParams->itemPersistentRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->itemList, itemParams->itemPersistentRef);
2865	}
2866
2867	// must have an explicit item class, unless one of the following is true:
2868	//   - we have an item list to add or search (kSecUseItemList)
2869	//   - we have an item reference or persistent reference for the thing we want to look up
2870	// Note that both of these cases will set itemParams->useItems.
2871	// If we have an item list to match (kSecMatchItemList), that still requires an item class,
2872	// so we can perform a search and see if the results match items in the list.
2873	//
2874	if (!CFDictionaryGetValueIfPresent(dict, kSecClass, (const void**) &value) && !itemParams->useItems) {
2875		require_action(false, error_exit, status = errSecItemClassMissing);
2876	}
2877	else if (value) {
2878		itemParams->itemClass = _ConvertItemClass(value, itemParams->keyClass, &itemParams->returnIdentity);
2879		if (itemParams->itemClass == kSecSymmetricKeyItemClass && !itemParams->keyClass) {
2880			itemParams->assumedKeyClass = kSecAttrKeyClassSymmetric; // no key class specified, so start with symmetric key class; will search the others later
2881		}
2882		require_action(!(itemParams->itemClass == 0 && !itemParams->useItems), error_exit, status = errSecItemClassMissing);
2883	}
2884
2885	itemParams->keyUsage = _CssmKeyUsageFromQuery(dict);
2886	itemParams->trustedOnly = CFDictionaryGetValueIfPresent(dict, kSecMatchTrustedOnly, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2887	itemParams->issuerAndSNToMatch = (itemParams->issuer != NULL && itemParams->serialNumber != NULL);
2888
2889	// other input attributes, used for SecItemAdd but not for finding items
2890	require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrAccess, (const void **)&itemParams->access, SecAccessGetTypeID(), NULL), error_exit);
2891	if (itemParams->access == NULL) {
2892		// check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>)
2893		require_noerr(status = _ValidateDictionaryEntry(dict, CFSTR("kSecAttrAccess"), (const void **)&itemParams->access, SecAccessGetTypeID(), NULL), error_exit);
2894	}
2895
2896	// determine how to return the result
2897	itemParams->numResultTypes = 0;
2898	itemParams->returningRef = CFDictionaryGetValueIfPresent(dict, kSecReturnRef, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2899	if (itemParams->returningRef) ++itemParams->numResultTypes;
2900	itemParams->returningPersistentRef = CFDictionaryGetValueIfPresent(dict, kSecReturnPersistentRef, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2901	if (itemParams->returningPersistentRef) ++itemParams->numResultTypes;
2902	itemParams->returningAttributes = CFDictionaryGetValueIfPresent(dict, kSecReturnAttributes, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2903	if (itemParams->returningAttributes) ++itemParams->numResultTypes;
2904	itemParams->returningData = CFDictionaryGetValueIfPresent(dict, kSecReturnData, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2905	if (itemParams->returningData) ++itemParams->numResultTypes;
2906
2907	// default is kSecReturnRef if no result types were specified
2908	if (!itemParams->numResultTypes) {
2909		itemParams->returningRef = TRUE;
2910		itemParams->numResultTypes = 1;
2911	}
2912
2913	// determine if one, some or all matches should be returned (default is kSecMatchLimitOne)
2914	itemParams->maxMatches = 1;
2915	itemParams->returnAllMatches = FALSE;
2916	if (itemParams->matchLimit) {
2917		if (CFStringGetTypeID() == CFGetTypeID(itemParams->matchLimit)) {
2918			itemParams->returnAllMatches = CFEqual(kSecMatchLimitAll, itemParams->matchLimit);
2919		}
2920		else if (CFNumberGetTypeID() == CFGetTypeID(itemParams->matchLimit)) {
2921			CFNumberGetValue((CFNumberRef)itemParams->matchLimit, kCFNumberIntType, &itemParams->maxMatches);
2922			require_action(!(itemParams->maxMatches < 0), error_exit, status = errSecMatchLimitUnsupported);
2923		}
2924	}
2925	if (itemParams->returnAllMatches) {
2926		itemParams->maxMatches = INT32_MAX;
2927		// if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each)
2928		if ((itemParams->itemClass==kSecInternetPasswordItemClass || itemParams->itemClass==kSecGenericPasswordItemClass) && itemParams->returningData)
2929			status = errSecReturnDataUnsupported;
2930		require_noerr(status, error_exit);
2931	}
2932
2933	// if we already have an item list (to add or find items in), we don't need an item class, attribute list or a search reference
2934	if (itemParams->useItems) {
2935		if (itemParams->itemClass == 0) {
2936			itemParams->itemClass = _ItemClassFromItemList(itemParams->useItems);
2937		}
2938		status = errSecSuccess;
2939		goto error_exit; // all done here
2940	}
2941
2942	// build a SecKeychainAttributeList from the query dictionary for the specified item class
2943	require_noerr(status = _CreateSecKeychainAttributeListFromDictionary(dict, itemParams->itemClass, &itemParams->attrList), error_exit);
2944
2945	// create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef)
2946	if ((itemParams->itemClass == kSecCertificateItemClass) && itemParams->emailAddrToMatch) {
2947		// searching for certificates by email address
2948		char *nameBuf = (char*)malloc(MAXPATHLEN);
2949		if (!nameBuf) {
2950			status = errSecAllocate;
2951		}
2952		else if (CFStringGetCString((CFStringRef)itemParams->emailAddrToMatch, nameBuf, (CFIndex)MAXPATHLEN-1, kCFStringEncodingUTF8)) {
2953			status = SecKeychainSearchCreateForCertificateByEmail(itemParams->searchList, (const char *)nameBuf, (SecKeychainSearchRef*)&itemParams->search);
2954		}
2955		else {
2956			status = errSecItemInvalidValue;
2957		}
2958		if (nameBuf) free(nameBuf);
2959	}
2960	else if ((itemParams->itemClass == kSecCertificateItemClass) && itemParams->issuerAndSNToMatch) {
2961		// searching for certificates by issuer and serial number
2962		status = SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams->searchList,
2963				(CFDataRef)itemParams->issuer,
2964				(CFDataRef)itemParams->serialNumber,
2965				(SecKeychainSearchRef*)&itemParams->search);
2966	}
2967	else if (itemParams->returnIdentity && itemParams->policy) {
2968		// searching for identities by policy
2969		status = SecIdentitySearchCreateWithPolicy(itemParams->policy,
2970				(CFStringRef)itemParams->service,
2971				itemParams->keyUsage,
2972				itemParams->searchList,
2973				itemParams->trustedOnly,
2974				(SecIdentitySearchRef*)&itemParams->search);
2975	}
2976	else if (itemParams->returnIdentity) {
2977		// searching for identities
2978		status = SecIdentitySearchCreate(itemParams->searchList,
2979				itemParams->keyUsage,
2980				(SecIdentitySearchRef*)&itemParams->search);
2981	}
2982	else {
2983		// normal keychain item search
2984		status = SecKeychainSearchCreateFromAttributes(itemParams->searchList,
2985				itemParams->itemClass,
2986				(itemParams->attrList->count == 0) ? NULL : itemParams->attrList,
2987				(SecKeychainSearchRef*)&itemParams->search);
2988	}
2989
2990error_exit:
2991	if (status) {
2992		_FreeSecItemParams(itemParams);
2993		itemParams = NULL;
2994	}
2995	if (error) {
2996		*error = status;
2997	}
2998	return itemParams;
2999}
3000
3001
3002static OSStatus
3003_ImportKey(
3004	SecKeyRef keyRef,
3005	SecKeychainRef keychainRef,
3006	SecAccessRef accessRef,
3007	SecKeychainAttributeList *attrList,
3008	SecKeychainItemRef *outItemRef)
3009{
3010    BEGIN_SECAPI
3011
3012		// We must specify the access, since a free-floating key won't have one yet by default
3013		SecPointer<Access> access;
3014		if (accessRef) {
3015			access = Access::required(accessRef);
3016		}
3017		else {
3018			CFStringRef descriptor = NULL;
3019			if (attrList) {
3020				for (UInt32 index=0; index < attrList->count; index++) {
3021					SecKeychainAttribute attr = attrList->attr[index];
3022					if (attr.tag == kSecKeyPrintName) {
3023						descriptor = CFStringCreateWithBytes(NULL, (const UInt8 *)attr.data, attr.length, kCFStringEncodingUTF8, FALSE);
3024						break;
3025					}
3026				}
3027			}
3028			if (descriptor == NULL) {
3029				descriptor = (CFStringRef) CFRetain(CFSTR("<unknown>"));
3030			}
3031			access = new Access(cfString(descriptor));
3032			CFRelease(descriptor);
3033		}
3034
3035		KeyItem *key = KeyItem::required(keyRef);
3036		Item item = key->importTo(Keychain::optional(keychainRef), access, attrList);
3037		if (outItemRef)
3038			*outItemRef = item->handle();
3039
3040	END_SECAPI
3041}
3042
3043static Boolean
3044_CanIgnoreLeafStatusCodes(CSSM_TP_APPLE_EVIDENCE_INFO *evidence)
3045{
3046	/* Check for ignorable status codes in leaf certificate's evidence */
3047	Boolean result = true;
3048	unsigned int i;
3049	for (i=0; i < evidence->NumStatusCodes; i++) {
3050		CSSM_RETURN scode = evidence->StatusCodes[i];
3051		if (scode == CSSMERR_APPLETP_INVALID_CA) {
3052			// the TP has rejected this CA cert because it's in the leaf position
3053			result = true;
3054		}
3055		else if (ignorableRevocationStatusCode(scode)) {
3056			result = true;
3057		}
3058		else {
3059			result = false;
3060			break;
3061		}
3062	}
3063	return result;
3064}
3065
3066static OSStatus
3067_FilterWithPolicy(SecPolicyRef policy, CFDateRef date, SecCertificateRef cert)
3068{
3069	CFDictionaryRef props = NULL;
3070	CFArrayRef keychains = NULL;
3071	CFArrayRef anchors = NULL;
3072	CFArrayRef certs = NULL;
3073	CFArrayRef chain = NULL;
3074	SecTrustRef trust = NULL;
3075
3076	SecTrustResultType	trustResult;
3077	CSSM_TP_APPLE_EVIDENCE_INFO *evidence = NULL;
3078	Boolean needChain = false;
3079	OSStatus status;
3080	if (!policy || !cert) return errSecParam;
3081
3082	certs = CFArrayCreate(NULL, (const void **)&cert, (CFIndex)1, &kCFTypeArrayCallBacks);
3083	status = SecTrustCreateWithCertificates(certs, policy, &trust);
3084	if(status) goto cleanup;
3085
3086	/* Set evaluation date, if specified (otherwise current date is implied) */
3087	if (date && (CFGetTypeID(date) == CFDateGetTypeID())) {
3088		status = SecTrustSetVerifyDate(trust, date);
3089		if(status) goto cleanup;
3090	}
3091
3092	/* Check whether this is the X509 Basic policy, which means chain building */
3093	props = SecPolicyCopyProperties(policy);
3094	if (props) {
3095		CFTypeRef oid = (CFTypeRef) CFDictionaryGetValue(props, kSecPolicyOid);
3096		if (oid && CFEqual(oid, kSecPolicyAppleX509Basic)) {
3097			needChain = true;
3098		}
3099	}
3100
3101	if (!needChain) {
3102		/* To make the evaluation as lightweight as possible, specify an empty array
3103		 * of keychains which will be searched for certificates.
3104		 */
3105		keychains = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
3106		status = SecTrustSetKeychains(trust, keychains);
3107		if(status) goto cleanup;
3108
3109		/* To make the evaluation as lightweight as possible, specify an empty array
3110		 * of trusted anchors.
3111		 */
3112		anchors = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
3113		status = SecTrustSetAnchorCertificates(trust, anchors);
3114		if(status) goto cleanup;
3115	}
3116
3117	/* All parameters are locked and loaded, ready to evaluate! */
3118	status = SecTrustEvaluate(trust, &trustResult);
3119	if(status) goto cleanup;
3120
3121	/* If we didn't provide trust anchors or a way to look for them,
3122	 * the evaluation will fail with kSecTrustResultRecoverableTrustFailure.
3123	 * However, we can tell whether the policy evaluation succeeded by
3124	 * looking at the per-cert status codes in the returned evidence.
3125	 */
3126	status = SecTrustGetResult(trust, &trustResult, &chain, &evidence);
3127	if(status) goto cleanup;
3128
3129	if (!(trustResult == kSecTrustResultProceed ||
3130		  trustResult == kSecTrustResultUnspecified ||
3131		  trustResult == kSecTrustResultRecoverableTrustFailure)) {
3132		/* The evaluation failed in a non-recoverable way */
3133		status = errSecCertificateCannotOperate;
3134		goto cleanup;
3135	}
3136
3137	/* If there are no per-cert policy status codes,
3138	 * and the cert has not expired, consider it valid for the policy.
3139	 */
3140	if((evidence != NULL) && _CanIgnoreLeafStatusCodes(evidence) &&
3141	   ((evidence[0].StatusBits & CSSM_CERT_STATUS_EXPIRED) == 0) &&
3142	   ((evidence[0].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET) == 0)) {
3143		status = errSecSuccess;
3144	}
3145	else {
3146		status = errSecCertificateCannotOperate;
3147	}
3148
3149cleanup:
3150	if(props) CFRelease(props);
3151	if(chain) CFRelease(chain);
3152	if(anchors) CFRelease(anchors);
3153	if(keychains) CFRelease(keychains);
3154	if(certs) CFRelease(certs);
3155	if(trust) CFRelease(trust);
3156
3157	return status;
3158}
3159
3160static OSStatus
3161_FilterWithDate(CFTypeRef validOnDate, SecCertificateRef cert)
3162{
3163	if (!validOnDate || !cert) return errSecParam;
3164
3165	CFAbsoluteTime at, nb, na;
3166	if (CFGetTypeID(validOnDate) == CFDateGetTypeID())
3167		at = CFDateGetAbsoluteTime((CFDateRef)validOnDate);
3168	else
3169		at = CFAbsoluteTimeGetCurrent();
3170
3171	OSStatus status = errSecSuccess;
3172	nb = SecCertificateNotValidBefore(cert);
3173	na = SecCertificateNotValidAfter(cert);
3174
3175	if (nb == 0 || na == 0 || nb == na)
3176		status = errSecCertificateCannotOperate;
3177	else if (at < nb)
3178		status = errSecCertificateNotValidYet;
3179	else if (at > na)
3180		status = errSecCertificateExpired;
3181
3182	return status;
3183}
3184
3185static OSStatus
3186_FilterWithTrust(Boolean trustedOnly, SecCertificateRef cert)
3187{
3188	if (!cert) return errSecParam;
3189	if (!trustedOnly) return errSecSuccess;
3190
3191	CFArrayRef certArray = CFArrayCreate(NULL, (const void**)&cert, 1, &kCFTypeArrayCallBacks);
3192	SecPolicyRef policy = SecPolicyCreateWithOID(kSecPolicyAppleX509Basic);
3193	OSStatus status = (policy == NULL) ? errSecPolicyNotFound : errSecSuccess;
3194
3195	if (!status) {
3196		SecTrustRef trust = NULL;
3197		status = SecTrustCreateWithCertificates(certArray, policy, &trust);
3198		if (!status) {
3199			SecTrustResultType trustResult;
3200			status = SecTrustEvaluate(trust, &trustResult);
3201			if (!status) {
3202				if (!(trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified)) {
3203					status = (trustResult == kSecTrustResultDeny) ? errSecTrustSettingDeny : errSecNotTrusted;
3204				}
3205			}
3206			CFRelease(trust);
3207		}
3208		CFRelease(policy);
3209	}
3210	if (certArray) {
3211		CFRelease(certArray);
3212	}
3213
3214	return status;
3215}
3216
3217static SecKeychainItemRef
3218CopyResolvedKeychainItem(CFTypeRef item)
3219{
3220	SecKeychainItemRef kcItem = NULL;
3221	OSStatus status;
3222	if (item) {
3223		if (CFGetTypeID(item) == CFDataGetTypeID()) {
3224			// persistent reference, resolve first
3225			status = SecKeychainItemCopyFromPersistentReference((CFDataRef)item, &kcItem);
3226		}
3227		else {
3228			// normal reference
3229			kcItem = (SecKeychainItemRef) CFRetain(item);
3230		}
3231		if (kcItem) {
3232			// ask for the item's class:
3233			// will return an error if the item has been deleted
3234			SecItemClass itemClass;
3235			SecKeychainItemRef certRef = NULL;
3236			if (CFGetTypeID(kcItem) == SecIdentityGetTypeID()) {
3237				status = SecIdentityCopyCertificate((SecIdentityRef)kcItem, (SecCertificateRef *)&certRef);
3238			}
3239			status = SecKeychainItemCopyAttributesAndData((certRef) ? certRef : kcItem, NULL, &itemClass, NULL, NULL, NULL);
3240			if (certRef) {
3241				CFRelease(certRef);
3242			}
3243			if (status) {
3244				CFRelease(kcItem);
3245				kcItem = NULL;
3246			}
3247		}
3248	}
3249	return kcItem;
3250}
3251
3252static OSStatus
3253UpdateKeychainSearchAndCopyNext(SecItemParams *params, CFTypeRef *item)
3254{
3255	// This function refreshes the search parameters in the specific case where
3256	// the caller is searching for kSecClassKey items but did not provide the
3257	// kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and
3258	// we must perform separate searches to obtain all results.
3259
3260	OSStatus status = errSecItemNotFound;
3261	if (!params || !params->assumedKeyClass || !params->query || !item)
3262		return status;
3263
3264	// Free the previous search reference and attribute list.
3265	if (params->search)
3266		CFRelease(params->search);
3267	params->search = NULL;
3268	_FreeAttrList(params->attrList);
3269	params->attrList = NULL;
3270
3271	// Make a copy of the query dictionary so we can set the key class parameter.
3272	CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(NULL, 0, params->query);
3273	CFRelease(params->query);
3274	params->query = dict;
3275	CFDictionarySetValue(dict, kSecAttrKeyClass, params->assumedKeyClass);
3276
3277	// Determine the current item class for this search, and the next assumed key class.
3278	if (CFEqual(params->assumedKeyClass, kSecAttrKeyClassSymmetric)) {
3279		params->itemClass = kSecSymmetricKeyItemClass;
3280		params->assumedKeyClass = kSecAttrKeyClassPublic;
3281	} else if (CFEqual(params->assumedKeyClass, kSecAttrKeyClassPublic)) {
3282		params->itemClass = kSecPublicKeyItemClass;
3283		params->assumedKeyClass = kSecAttrKeyClassPrivate;
3284	} else {
3285		params->itemClass = kSecPrivateKeyItemClass;
3286		params->assumedKeyClass = NULL;
3287	}
3288
3289	// Rebuild the attribute list for the new key class.
3290	if (_CreateSecKeychainAttributeListFromDictionary(dict, params->itemClass, &params->attrList) == errSecSuccess) {
3291		// Create a new search reference for the new attribute list.
3292		if (SecKeychainSearchCreateFromAttributes(params->searchList,
3293			params->itemClass,
3294			(params->attrList->count == 0) ? NULL : params->attrList,
3295			(SecKeychainSearchRef*)&params->search) == errSecSuccess) {
3296			// Return the first matching item from the new search.
3297			// We won't come back here again until there are no more matching items for this search.
3298			status = SecKeychainSearchCopyNext((SecKeychainSearchRef)params->search, (SecKeychainItemRef*)item);
3299		}
3300	}
3301	return status;
3302}
3303
3304
3305static OSStatus
3306SecItemSearchCopyNext(SecItemParams *params, CFTypeRef *item)
3307{
3308	// Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef.
3309	// Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter,
3310	// depending on the type of search reference.
3311
3312	OSStatus status;
3313	CFTypeRef search = (params) ? params->search : NULL;
3314	CFTypeID typeID = (search) ? CFGetTypeID(search) : 0;
3315	if (typeID == SecIdentitySearchGetTypeID()) {
3316		status = SecIdentitySearchCopyNext((SecIdentitySearchRef)search, (SecIdentityRef*)item);
3317	}
3318	else if (typeID == SecKeychainSearchGetTypeID()) {
3319		status = SecKeychainSearchCopyNext((SecKeychainSearchRef)search, (SecKeychainItemRef*)item);
3320		// Check if we need to refresh the search for the next key class
3321		while (status == errSecItemNotFound && params->assumedKeyClass != NULL)
3322			status = UpdateKeychainSearchAndCopyNext(params, item);
3323	}
3324	else if (typeID == 0 && (params->useItems || params->itemList)) {
3325		// No search available, but there is an item list available.
3326		// Return the next candidate item from the caller's item list
3327		CFArrayRef itemList = (params->useItems) ? params->useItems : params->itemList;
3328		CFIndex count = CFArrayGetCount(itemList);
3329		*item = (CFTypeRef) NULL;
3330		if (params->itemListIndex < count) {
3331			*item = (CFTypeRef)CFArrayGetValueAtIndex(itemList, params->itemListIndex++);
3332			if (*item) {
3333				// Potentially resolve persistent item references here, and
3334				// verify the item reference we're about to hand back is still
3335				// valid (it could have been deleted from the keychain while
3336				// our query was holding onto the itemList).
3337				*item = CopyResolvedKeychainItem(*item);
3338				if (*item && (CFGetTypeID(*item) == SecIdentityGetTypeID())) {
3339					// Persistent reference resolved to an identity, so return that type.
3340					params->returnIdentity = true;
3341				}
3342			}
3343		}
3344		status = (*item) ? errSecSuccess : errSecItemNotFound;
3345	}
3346	else {
3347		status = errSecItemNotFound;
3348	}
3349	return status;
3350}
3351
3352static OSStatus
3353FilterCandidateItem(CFTypeRef *item, SecItemParams *itemParams, SecIdentityRef *identity)
3354{
3355	if (!item || *item == NULL || !itemParams)
3356		return errSecItemNotFound;
3357
3358	OSStatus status;
3359	CFStringRef commonName = NULL;
3360	SecIdentityRef foundIdentity = NULL;
3361	if (CFGetTypeID(*item) == SecIdentityGetTypeID()) {
3362		// we found a SecIdentityRef, rather than a SecKeychainItemRef;
3363		// replace the found "item" with its associated certificate (which is the
3364		// item we actually want for purposes of getting attributes, data, or a
3365		// persistent data reference), and return the identity separately.
3366		SecCertificateRef certificate;
3367		status = SecIdentityCopyCertificate((SecIdentityRef) *item, &certificate);
3368		if (itemParams->returnIdentity) {
3369			foundIdentity = (SecIdentityRef) *item;
3370			if (identity) {
3371				*identity = foundIdentity;
3372			}
3373		}
3374		else {
3375			CFRelease(*item);
3376		}
3377		*item = (CFTypeRef)certificate;
3378	}
3379
3380	CFDictionaryRef query = itemParams->query;
3381
3382	if (itemParams->itemClass == kSecCertificateItemClass) {
3383		// perform string comparisons first
3384		CFStringCompareFlags flags = _StringCompareFlagsFromQuery(query);
3385		CFStringRef nameContains, nameStarts, nameEnds, nameExact;
3386		if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectContains, (const void **)&nameContains))
3387			nameContains = NULL;
3388		if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectStartsWith, (const void **)&nameStarts))
3389			nameStarts = NULL;
3390		if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectEndsWith, (const void **)&nameEnds))
3391			nameEnds = NULL;
3392		if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectWholeString, (const void **)&nameExact))
3393			nameExact = NULL;
3394		if (nameContains || nameStarts || nameEnds || nameExact) {
3395			status = SecCertificateCopyCommonName((SecCertificateRef)*item, &commonName);
3396			if (status || !commonName) goto filterOut;
3397		}
3398		if (nameContains) {
3399			CFRange range = CFStringFind(commonName, nameContains, flags);
3400			if (range.length < 1)
3401				goto filterOut;
3402			// certificate item contains string; proceed to next check
3403		}
3404		if (nameStarts) {
3405			CFRange range = CFStringFind(commonName, nameStarts, flags);
3406			if (range.length < 1 || range.location > 1)
3407				goto filterOut;
3408			// certificate item starts with string; proceed to next check
3409		}
3410		if (nameEnds) {
3411			CFRange range = CFStringFind(commonName, nameEnds, flags);
3412			if (range.length < 1 || range.location != (CFStringGetLength(commonName) - CFStringGetLength(nameEnds)))
3413				goto filterOut;
3414			// certificate item ends with string; proceed to next check
3415		}
3416		if (nameExact) {
3417			CFRange range = CFStringFind(commonName, nameExact, flags);
3418			if (range.length < 1 || (CFStringGetLength(commonName) != CFStringGetLength(nameExact)))
3419				goto filterOut;
3420			// certificate item exactly matches string; proceed to next check
3421		}
3422		if (itemParams->returnIdentity) {
3423			// if we already found and returned the identity, we can skip this
3424			if (!foundIdentity) {
3425				status = SecIdentityCreateWithCertificate(itemParams->searchList, (SecCertificateRef) *item, identity);
3426				if (status) goto filterOut;
3427			}
3428			// certificate item is part of an identity; proceed to next check
3429		}
3430		if (itemParams->policy) {
3431			status = _FilterWithPolicy(itemParams->policy, (CFDateRef)itemParams->validOnDate, (SecCertificateRef) *item);
3432			if (status) goto filterOut;
3433			// certificate item is valid for specified policy (and optionally specified date)
3434		}
3435		if (itemParams->validOnDate) {
3436			status = _FilterWithDate(itemParams->validOnDate, (SecCertificateRef) *item);
3437			if (status) goto filterOut;
3438			// certificate item is valid for specified date
3439		}
3440		if (itemParams->trustedOnly) {
3441			// if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search,
3442			// their trust has already been validated and we can skip this part.
3443			if (!(foundIdentity && itemParams->returnIdentity && itemParams->policy)) {
3444				status = _FilterWithTrust(itemParams->trustedOnly, (SecCertificateRef) *item);
3445				if (status) goto filterOut;
3446			}
3447			// certificate item is trusted on this system
3448		}
3449	}
3450	if (itemParams->itemList) {
3451		Boolean foundMatch = FALSE;
3452		CFIndex idx, count = CFArrayGetCount(itemParams->itemList);
3453		for (idx=0; idx<count; idx++) {
3454			CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(itemParams->itemList, idx);
3455			SecKeychainItemRef realItem = NULL;
3456			SecCertificateRef aCert = NULL;
3457			if (anItem == NULL) {
3458				continue;
3459			}
3460			if (CFDataGetTypeID() == CFGetTypeID(anItem) &&
3461				errSecSuccess == SecKeychainItemCopyFromPersistentReference((CFDataRef)anItem, &realItem)) {
3462				anItem = realItem;
3463			}
3464			if (SecIdentityGetTypeID() == CFGetTypeID(anItem) &&
3465				errSecSuccess == SecIdentityCopyCertificate((SecIdentityRef)anItem, &aCert)) {
3466				anItem = aCert;
3467			}
3468			if (CFEqual(anItem, (CFTypeRef) *item)) {
3469				foundMatch = TRUE;
3470			}
3471			if (aCert) {
3472				CFRelease(aCert);
3473			}
3474			if (realItem) {
3475				CFRelease(realItem);
3476			}
3477			if (foundMatch) {
3478				break;
3479			}
3480		}
3481		if (!foundMatch) goto filterOut;
3482		// item was found on provided list
3483	}
3484
3485	if (foundIdentity && !identity) {
3486		CFRelease(foundIdentity);
3487	}
3488	if (commonName) {
3489		CFRelease(commonName);
3490	}
3491
3492	// if we get here, consider the item a match
3493	return errSecSuccess;
3494
3495filterOut:
3496	if (commonName) {
3497		CFRelease(commonName);
3498	}
3499	CFRelease(*item);
3500	*item = NULL;
3501	if (foundIdentity) {
3502		CFRelease(foundIdentity);
3503		if (identity) {
3504			*identity = NULL;
3505		}
3506	}
3507	return errSecItemNotFound;
3508}
3509
3510static OSStatus
3511AddItemResults(SecKeychainItemRef item,
3512	SecIdentityRef identity,
3513	SecItemParams *itemParams,
3514	CFAllocatorRef allocator,
3515	CFMutableArrayRef *items,
3516	CFTypeRef *result)
3517{
3518	// Given a found item (which may also be an identity), this function adds
3519	// the requested result types (specified in itemParams) to the appropriate
3520	// container as follows:
3521	//
3522	// 1. If there is only one result type (numResultTypes == 1) and only one
3523	//    match requested (maxMatches == 1), set *result directly.
3524	//
3525	// 2. If there are multiple result types (numResultTypes > 1), and only one
3526	//    match requested (maxMatches == 1), add each result type to itemDict
3527	//    and set itemDict as the value of *result.
3528	//
3529	// 3. If there is only one result type (numResultTypes == 1) and multiple
3530	//    possible matches (maxMatches > 1), add the result type to *items
3531	//    and set *items as the value of *result.
3532	//
3533	// 4. If there are multiple result types (numResultTypes > 1) and multiple
3534	//    possible matches (maxMatches > 1), add each result type to itemDict,
3535	//    add itemDict to *items, and set *items as the value of *result.
3536	//
3537	// Note that we allocate *items if needed.
3538
3539	if (!item || !itemParams || !result)
3540		return errSecParam;
3541
3542	if (itemParams->maxMatches > 1) {
3543		// if we can return more than one item, we must have an array
3544		if (!items)
3545			return errSecParam;
3546		else if (*items == NULL)
3547			*items = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
3548	}
3549
3550	OSStatus tmpStatus, status = errSecSuccess;
3551	CFMutableArrayRef itemArray = (items) ? *items : NULL;
3552	CFMutableDictionaryRef itemDict = NULL;
3553	if (itemParams->numResultTypes > 1) {
3554		// if we're returning more than one result type, each item we return must be a dictionary
3555		itemDict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3556	}
3557
3558	if (itemParams->returningRef) {
3559		const void* itemRef = (identity) ? (const void*)identity : (const void*)item;
3560		if (itemDict) {
3561			CFDictionaryAddValue(itemDict, kSecValueRef, itemRef);
3562		}
3563		else if (itemArray) {
3564			CFArrayAppendValue(itemArray, itemRef);
3565		}
3566		else {
3567			*result = CFRetain((CFTypeRef)itemRef);
3568		}
3569	}
3570
3571	if (itemParams->returningPersistentRef) {
3572		CFDataRef persistentRef;
3573		SecKeychainItemRef tmpItem = item;
3574		if (itemParams->identityRef) {
3575			tmpItem = (SecKeychainItemRef)itemParams->identityRef;
3576		}
3577		tmpStatus = SecKeychainItemCreatePersistentReference(tmpItem, &persistentRef);
3578		if (tmpStatus == errSecSuccess) {
3579			if (itemDict) {
3580				CFDictionaryAddValue(itemDict, kSecValuePersistentRef, persistentRef);
3581			}
3582			else if (itemArray) {
3583				CFArrayAppendValue(itemArray, persistentRef);
3584			}
3585			else {
3586				*result = CFRetain(persistentRef);
3587			}
3588			CFRelease(persistentRef);
3589		}
3590		else if (status == errSecSuccess) {
3591			status = tmpStatus;
3592		}
3593	}
3594
3595	if (itemParams->returningData) {
3596		UInt32 length;
3597		void *data;
3598		tmpStatus = SecKeychainItemCopyContent(item, NULL, NULL, &length, &data);
3599		if (tmpStatus == errSecSuccess) {
3600			CFDataRef dataRef = CFDataCreate(allocator, (UInt8 *)data, length);
3601			if (itemDict) {
3602				CFDictionaryAddValue(itemDict, kSecValueData, dataRef);
3603			}
3604			else if (itemArray) {
3605				CFArrayAppendValue(itemArray, dataRef);
3606			}
3607			else {
3608				*result = CFRetain(dataRef);
3609			}
3610			CFRelease(dataRef);
3611			(void) SecKeychainItemFreeContent(NULL, data);
3612		}
3613		else if (status == errSecSuccess) {
3614			status = tmpStatus;
3615		}
3616	}
3617
3618	if (itemParams->returningAttributes) {
3619		CFDictionaryRef attrsDict = NULL;
3620		SecItemClass itemClass;
3621		// since we have an item, allow its actual class to override the query-specified item class
3622		tmpStatus = SecKeychainItemCopyAttributesAndData(item, NULL, &itemClass, NULL, NULL, NULL);
3623		if (tmpStatus) {
3624			itemClass = itemParams->itemClass;
3625		}
3626		tmpStatus = _CreateAttributesDictionaryFromItem(allocator, itemClass, item, &attrsDict);
3627		if (attrsDict) {
3628			if (itemDict) {
3629				// add all keys and values from attrsDict to the item dictionary
3630				CFDictionaryApplyFunction(attrsDict, _AddDictValueToOtherDict, &itemDict);
3631			}
3632			else if (itemArray) {
3633				CFArrayAppendValue(itemArray, attrsDict);
3634			}
3635			else {
3636				*result = CFRetain(attrsDict);
3637			}
3638			CFRelease(attrsDict);
3639		}
3640		if (tmpStatus && (status == errSecSuccess)) {
3641			status = tmpStatus;
3642		}
3643	}
3644
3645	if (itemDict) {
3646		if (itemArray) {
3647			CFArrayAppendValue(itemArray, itemDict);
3648			CFRelease(itemDict);
3649			*result = itemArray;
3650		}
3651		else {
3652			*result = itemDict;
3653		}
3654	}
3655	else if (itemArray) {
3656		*result = itemArray;
3657	}
3658
3659	return status;
3660}
3661
3662CFDataRef _SecItemGetPersistentReference(CFTypeRef raw_item)
3663{
3664	try {
3665		Item item = ItemImpl::required((SecKeychainItemRef)raw_item);
3666		return item->getPersistentRef();
3667	} catch(...) {
3668		return NULL;
3669	}
3670}
3671
3672/******************************************************************************/
3673#pragma mark SecItem API functions
3674/******************************************************************************/
3675
3676//
3677// Approximate result of using iOS sec's copyNumber, 0 return could be zero, or error.
3678//
3679static SInt32 readNumber(CFTypeRef obj) {
3680    CFTypeID tid = CFGetTypeID(obj);
3681    SInt32 v = 0;
3682    if (tid == CFNumberGetTypeID()) {
3683        CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt32Type, &v);
3684        return v;
3685    } else if (tid == CFBooleanGetTypeID()) {
3686        v = CFBooleanGetValue((CFBooleanRef)obj);
3687        return v;
3688    } else if (tid == CFStringGetTypeID()) {
3689        v = CFStringGetIntValue((CFStringRef)obj);
3690        CFStringRef t = CFStringCreateWithFormat(0, 0, CFSTR("%ld"), (long)v);
3691        /* If a string converted to an int isn't equal to the int printed as
3692         a string, return a CFStringRef instead. */
3693        if (!CFEqual(t, obj)) {
3694            CFRelease(t);
3695            return 0;
3696        }
3697        CFRelease(t);
3698        return v;
3699    } else
3700        return NULL;
3701}
3702
3703//
3704// Function to ensure the syncable keychain is unlocked.
3705// Currently, this means unlocking the login keychain,
3706// which will also unlock the keybag as a side effect.
3707//
3708static OSStatus SecItemUnlockSynchronizableKeychain()
3709{
3710	SecKeychainRef keychain = NULL;
3711	OSStatus status = SecKeychainCopyLogin(&keychain);
3712	if (!status) {
3713		status = SecKeychainUnlock(keychain, 0, NULL, false);
3714	}
3715	CFReleaseSafe(keychain);
3716	return status;
3717}
3718
3719//
3720// Function to check whether the kSecAttrSynchronizable flag is set in the query.
3721//
3722static Boolean SecItemSynchronizable(CFDictionaryRef query)
3723{
3724	CFTypeRef value = CFDictionaryGetValue(query, kSecAttrSynchronizable);
3725	Boolean result = (value && readNumber(value));
3726
3727	return result;
3728}
3729
3730//
3731// Function to check whether the kSecAttrSynchronizable flag is set in the query,
3732// and has the special value of kSecAttrSynchronizableAny.
3733//
3734static Boolean SecItemSynchronizableAny(CFDictionaryRef query)
3735{
3736	CFTypeRef value = CFDictionaryGetValue(query, kSecAttrSynchronizable);
3737	if (value) {
3738		return (CFGetTypeID(value) == CFStringGetTypeID() &&
3739				CFEqual(value, kSecAttrSynchronizableAny));
3740	}
3741	return false;
3742}
3743
3744//
3745// Function to check whether the kSecAttrSynchronizable attribute is being updated.
3746//
3747static Boolean SecItemHasSynchronizableUpdate(Boolean synchronizable, CFDictionaryRef changes)
3748{
3749	CFTypeRef newValue = CFDictionaryGetValue(changes, kSecAttrSynchronizable);
3750	if (!newValue)
3751		return false;
3752
3753	Boolean new_sync = readNumber(newValue);
3754	Boolean old_sync = synchronizable;
3755
3756	return (old_sync != new_sync);
3757}
3758
3759//
3760// Returns true if keychain syncing is globally enabled.
3761//
3762static Boolean SecItemSyncEnabled()
3763{
3764	static dispatch_once_t onceToken;
3765	static Boolean syncEnabled = true;
3766
3767	//sudo defaults write /Library/Preferences/com.apple.security SecItemSynchronizable -bool YES
3768	dispatch_once(&onceToken, ^{
3769			CFTypeRef sync = (CFNumberRef)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
3770
3771			if (sync && CFGetTypeID(sync) == CFBooleanGetTypeID()) {
3772			syncEnabled = CFBooleanGetValue((CFBooleanRef)sync);
3773			CFRelease(sync);
3774			}
3775			});
3776
3777	return syncEnabled;
3778}
3779
3780//
3781// Function to check whether a synchronizable persistent reference was provided.
3782//
3783static Boolean SecItemHasSynchronizablePersistentReference(CFDictionaryRef query)
3784{
3785	CFTypeRef value = CFDictionaryGetValue(query, kSecValuePersistentRef);
3786	if (value) {
3787		/* Synchronizable persistent ref consists of the sqlite rowid and 4-byte class value */
3788		const CFIndex kSynchronizablePersistentRefLength = sizeof(int64_t) + 4;
3789		return (CFGetTypeID(value) == CFDataGetTypeID() &&
3790				CFDataGetLength((CFDataRef)value) == kSynchronizablePersistentRefLength);
3791	}
3792	return false;
3793}
3794
3795//
3796// Function to apply changes to a mutable dictionary.
3797// (CFDictionaryApplierFunction, called by CFDictionaryApplyFunction)
3798//
3799static void SecItemApplyChanges(const void *key, const void *value, void *context)
3800{
3801	CFMutableDictionaryRef dict = (CFMutableDictionaryRef) context;
3802	if (!dict) return;
3803
3804	CFDictionarySetValue(dict, key, value);
3805}
3806
3807//
3808// Function to change matching items from non-syncable to syncable
3809// (if toSyncable is true), otherwise from syncable to non-syncable.
3810// This currently moves items between keychain containers.
3811//
3812static OSStatus SecItemChangeSynchronizability(CFDictionaryRef query, CFDictionaryRef changes, Boolean toSyncable)
3813{
3814	// Note: the input query dictionary is a mutable copy of the query originally
3815	// provided by the caller as the first parameter to SecItemUpdate. It may not
3816	// specify returning attributes or data, but we will need both to make a copy.
3817	//
3818	CFDictionaryRemoveValue((CFMutableDictionaryRef)query, kSecReturnRef);
3819	CFDictionaryRemoveValue((CFMutableDictionaryRef)query, kSecReturnPersistentRef);
3820	CFDictionaryRemoveValue((CFMutableDictionaryRef)query, kSecReturnData);
3821	CFDictionarySetValue((CFMutableDictionaryRef)query, kSecReturnAttributes, kCFBooleanTrue);
3822	if (NULL == CFDictionaryGetValue(changes, kSecValueData))
3823		CFDictionarySetValue((CFMutableDictionaryRef)query, kSecReturnData, kCFBooleanTrue);
3824
3825	CFTypeRef result;
3826	OSStatus status;
3827	if (toSyncable)
3828		status = SecItemCopyMatching_osx(query, &result);
3829	else
3830		status = SecItemCopyMatching_ios(query, &result);
3831
3832	if (status)
3833		return status;
3834	if (!result)
3835		return errSecItemNotFound;
3836
3837	CFMutableArrayRef items;
3838	if (CFGetTypeID(result) != CFArrayGetTypeID()) {
3839		items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
3840		CFArrayAppendValue(items, result);
3841		CFRelease(result);
3842	}
3843	else {
3844		items = (CFMutableArrayRef)result;
3845	}
3846
3847	CFIndex idx, count = (items) ? CFArrayGetCount(items) : 0;
3848	int priority = LOG_DEBUG;
3849	OSStatus err = 0;
3850	for (idx = 0; idx < count; idx++) {
3851		CFDictionaryRef dict = (CFDictionaryRef) CFArrayGetValueAtIndex(items, idx);
3852		CFMutableDictionaryRef item = (CFMutableDictionaryRef)
3853			SecItemCopyTranslatedAttributes(dict,
3854				CFDictionaryGetValue(query, kSecClass),
3855				(toSyncable) ? true : false /*iOSOut*/,
3856				true /*pruneMatch*/,
3857				true /*pruneSync*/,
3858				true /*pruneReturn*/,
3859				false /*pruneData*/,
3860				(toSyncable) ? true : false /*pruneAccess*/);
3861		// hold onto the query before applying changes, in case the item already exists.
3862		// note that we cannot include the creation or modification dates from our
3863		// found item in this query, as they may not match the item in the other keychain.
3864		CFMutableDictionaryRef itemQuery = CFDictionaryCreateMutableCopy(NULL, 0, item);
3865		CFDictionaryRemoveValue(itemQuery, kSecAttrCreationDate);
3866		CFDictionaryRemoveValue(itemQuery, kSecAttrModificationDate);
3867		// apply changes to the item dictionary that we will pass to SecItemAdd
3868		CFDictionaryApplyFunction(changes, SecItemApplyChanges, item);
3869		if (toSyncable) {
3870			CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanTrue);
3871			status = SecItemAdd_ios(item, NULL);
3872			secitemlog(priority, "ChangeSync: SecItemAdd_ios=%d", status);
3873			if (errSecDuplicateItem == status) {
3874				// find and apply changes to the existing syncable item.
3875				CFDictionarySetValue(itemQuery, kSecAttrSynchronizable, kCFBooleanTrue);
3876				status = SecItemUpdate_ios(itemQuery, changes);
3877				secitemlog(priority, "ChangeSync: SecItemUpdate_ios=%d", status);
3878			}
3879			if (errSecSuccess == status) {
3880				CFDictionarySetValue(itemQuery, kSecAttrSynchronizable, kCFBooleanFalse);
3881				status = SecItemDelete_osx(itemQuery);
3882				secitemlog(priority, "ChangeSync: SecItemDelete_osx=%d", status);
3883			}
3884		}
3885		else {
3886			CFDictionarySetValue(item, kSecAttrSynchronizable, kCFBooleanFalse);
3887			status = SecItemAdd_osx(item, NULL);
3888			secitemlog(priority, "ChangeSync: SecItemAdd_osx=%d", status);
3889			if (errSecDuplicateItem == status) {
3890				// find and apply changes to the existing non-syncable item.
3891				CFDictionarySetValue(itemQuery, kSecAttrSynchronizable, kCFBooleanFalse);
3892				status = SecItemUpdate_osx(itemQuery, changes);
3893				secitemlog(priority, "ChangeSync: SecItemUpdate_osx=%d", status);
3894			}
3895			if (errSecSuccess == status) {
3896				CFDictionarySetValue(itemQuery, kSecAttrSynchronizable, kCFBooleanTrue);
3897				status = SecItemDelete_ios(itemQuery);
3898				secitemlog(priority, "ChangeSync: SecItemDelete_ios=%d", status);
3899			}
3900		}
3901		CFReleaseSafe(item);
3902		CFReleaseSafe(itemQuery);
3903		if (status)
3904			err = status;
3905	}
3906	CFReleaseSafe(items);
3907
3908	return err;
3909}
3910
3911
3912extern "C" {
3913
3914CFTypeRef
3915SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
3916	CFTypeRef ref = NULL;
3917	CFStringRef key_class_string = (CFStringRef)CFDictionaryGetValue(refAttributes, kSecClass);
3918	SecItemClass key_class;
3919	bool key_class_found = false;
3920
3921	if (CFEqual(key_class_string, kSecClassGenericPassword)) {
3922		key_class = kSecGenericPasswordItemClass;
3923		key_class_found = true;
3924	}
3925	if (CFEqual(key_class_string, kSecClassInternetPassword)) {
3926		key_class = kSecInternetPasswordItemClass;
3927		key_class_found = true;
3928	}
3929
3930	if (key_class_found) {
3931		// we carry v_Data around here so the *_ios calls can find it and locate
3932		// their own data.   Putting things in the attribute list doesn't help as
3933		// the osx keychainitem and item calls bail when they don't see a keychain
3934		// object.   If we need to make them work we either have to bridge them, or
3935		// find a way to craft a workable keychain object.   #if'ed code left below
3936		// in case we need to go down that path.
3937
3938		struct SecKeychainAttributeList *attrs = (struct SecKeychainAttributeList *)malloc(sizeof(struct SecKeychainAttributeList) + sizeof(struct SecKeychainAttribute) * 0);
3939		attrs->attr = (struct SecKeychainAttribute *)(attrs + 1);
3940		attrs->count = 0;
3941		CFTypeRef v;
3942#if 0
3943		// The C++ string objects need to last at least as long as the attr struct.
3944		string account;
3945
3946		v = CFDictionaryGetValue(refAttributes, CFSTR("mdat"));
3947		if (v) {
3948			attrs->attr[attrs->count].tag = kSecModDateItemAttr;
3949			// XXX need to convert to YYYYMMDDhhmmSSZ
3950			attrs->attr[attrs->count].data = (void*)"19690223140232Z";
3951			attrs->attr[attrs->count].length = strlen((char*)(attrs->attr[attrs->count].data));
3952			attrs->count++;
3953		}
3954		v = CFDictionaryGetValue(refAttributes, CFSTR("cdat"));
3955		if (v) {
3956			attrs->attr[attrs->count].tag = kSecCreationDateItemAttr;
3957			// XXX need to convert to YYYYMMDDhhmmSSZ
3958			attrs->attr[attrs->count].data = (void*)"19690223140232Z";
3959			attrs->attr[attrs->count].length = strlen((char*)(attrs->attr[attrs->count].data));
3960			attrs->count++;
3961		}
3962
3963		v = CFDictionaryGetValue(refAttributes, CFSTR("acct"));
3964		if (v) {
3965			attrs->attr[attrs->count].tag = kSecAccountItemAttr;
3966			account = cfString((CFStringRef)v);
3967			attrs->attr[attrs->count].data = (void*)(account.c_str());
3968			attrs->attr[attrs->count].length = account.length();
3969			attrs->count++;
3970		}
3971
3972		// class isn't treated as an attribute by the creation API
3973
3974		v = CFDictionaryGetValue(refAttributes, CFSTR("svce"));
3975		if (v) {
3976			attrs->attr[attrs->count].tag = kSecServiceItemAttr;
3977			account = cfString((CFStringRef)v);
3978			attrs->attr[attrs->count].data = (void*)(account.c_str());
3979			attrs->attr[attrs->count].length = account.length();
3980			attrs->count++;
3981		}
3982
3983		v = CFDictionaryGetValue(refAttributes, CFSTR("acct"));
3984		if (v) {
3985			attrs->attr[attrs->count].tag = kSecLabelItemAttr;
3986			account = cfString((CFStringRef)v);
3987			attrs->attr[attrs->count].data = (void*)(account.c_str());
3988			attrs->attr[attrs->count].length = account.length();
3989			attrs->count++;
3990		}
3991#endif
3992		Item item = Item(key_class, attrs, 0, "");
3993		ItemImpl *real_item = item.get();
3994		v = CFDictionaryGetValue(refAttributes, kSecValuePersistentRef);
3995		if (v) {
3996			real_item->setPersistentRef((CFDataRef)v);
3997		}
3998		ref = real_item->handle();
3999	} else {
4000		// keys, certs, identities are not currently sync'able.
4001		ref = NULL;
4002	}
4003	return ref;
4004}
4005
4006/*
4007 * SecItemValidateAppleApplicationGroupAccess determines if the caller
4008 * is a member of the specified application group, and is signed by Apple.
4009 */
4010OSStatus
4011SecItemValidateAppleApplicationGroupAccess(CFStringRef group)
4012{
4013	SecTrustedApplicationRef app = NULL;
4014	SecRequirementRef requirement = NULL;
4015	SecCodeRef code = NULL;
4016	OSStatus status = errSecParam;
4017
4018	if (group) {
4019		CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(group), kCFStringEncodingUTF8) + 1;
4020		char* buffer = (char*) malloc(length);
4021		if (buffer) {
4022			if (CFStringGetCString(group, buffer, length, kCFStringEncodingUTF8)) {
4023				status = SecTrustedApplicationCreateApplicationGroup(buffer, NULL, &app);
4024			}
4025			free(buffer);
4026		} else {
4027			status = errSecMemoryError;
4028		}
4029	}
4030	if (!status) {
4031		status = SecTrustedApplicationCopyRequirement(app, &requirement);
4032	}
4033	if (!status) {
4034		status = SecCodeCopySelf(kSecCSDefaultFlags, &code);
4035	}
4036	if (!status) {
4037		status = SecCodeCheckValidity(code, kSecCSDefaultFlags, requirement);
4038	}
4039
4040	CFReleaseSafe(code);
4041	CFReleaseSafe(requirement);
4042	CFReleaseSafe(app);
4043	return status;
4044}
4045
4046/*
4047 * SecItemCopyTranslatedAttributes accepts a user-provided attribute dictionary
4048 * and attempts to return a sanitized copy for passing to the underlying
4049 * platform-specific implementation code.
4050 *
4051 * If iOSOut is true, one or more translations may apply:
4052 *   - SecKeychain refs are removed, since there aren't multiple keychains
4053 *   - SecPolicy refs are removed, since they can't be externalized
4054 *   - SecAccess refs are removed, and potentially translated to entitlements
4055 *
4056 * If pruneMatch is true, kSecMatch* attributes are removed; this avoids
4057 * parameter errors due to strict input checks in secd, which only permits
4058 * these constants for calls to SecItemCopyMatching.
4059 *
4060 * If pruneSync is true, the kSecAttrSynchronizable attribute is removed.
4061 * This permits a query to be reused for non-synchronizable items, or to
4062 * resolve a search based on a persistent item reference for iOS.
4063 *
4064 * If pruneReturn is true, kSecReturn* attributes are removed; this avoids
4065 * parameter errors due to strict input checks in secd, which do not permit
4066 * these constants for calls to SecItemUpdate.
4067 */
4068CFDictionaryRef
4069SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass,
4070	bool iOSOut, bool pruneMatch, bool pruneSync, bool pruneReturn, bool pruneData, bool pruneAccess)
4071{
4072	CFMutableDictionaryRef result = CFDictionaryCreateMutableCopy(NULL, 0, inOSXDict);
4073	if (result == NULL) {
4074		return result;
4075	}
4076
4077	if (pruneSync) {
4078		CFDictionaryRemoveValue(result, kSecAttrSynchronizable);
4079	}
4080
4081	if (pruneMatch) {
4082		/* Match constants are only supported on iOS for SecItemCopyMatching,
4083		 * and will generate an error if passed to other SecItem API functions;
4084		 * on OS X, they're just ignored if not applicable for the context.
4085		 */
4086		CFDictionaryRemoveValue(result, kSecMatchPolicy);
4087		CFDictionaryRemoveValue(result, kSecMatchItemList);
4088		CFDictionaryRemoveValue(result, kSecMatchSearchList);
4089		CFDictionaryRemoveValue(result, kSecMatchIssuers);
4090		CFDictionaryRemoveValue(result, kSecMatchEmailAddressIfPresent);
4091		CFDictionaryRemoveValue(result, kSecMatchSubjectContains);
4092		CFDictionaryRemoveValue(result, kSecMatchCaseInsensitive);
4093		CFDictionaryRemoveValue(result, kSecMatchTrustedOnly);
4094		CFDictionaryRemoveValue(result, kSecMatchValidOnDate);
4095		CFDictionaryRemoveValue(result, kSecMatchLimit);
4096		CFDictionaryRemoveValue(result, kSecMatchLimitOne);
4097		CFDictionaryRemoveValue(result, kSecMatchLimitAll);
4098	}
4099
4100	if (pruneReturn) {
4101		/* Return constants are not supported on iOS for SecItemUpdate,
4102		 * where they will generate an error; on OS X, they're just ignored
4103		 * if not applicable for the context.
4104		 */
4105		CFDictionaryRemoveValue(result, kSecReturnData);
4106		CFDictionaryRemoveValue(result, kSecReturnAttributes);
4107		CFDictionaryRemoveValue(result, kSecReturnRef);
4108		CFDictionaryRemoveValue(result, kSecReturnPersistentRef);
4109	}
4110
4111	if (pruneData) {
4112		/* Searching on data is not supported. */
4113		CFDictionaryRemoveValue(result, kSecValueData);
4114	}
4115
4116    if (pruneAccess) {
4117        /* Searching on access lists is not supported */
4118        CFDictionaryRemoveValue(result, kSecAttrAccess);
4119    }
4120
4121	if (iOSOut) {
4122		/* Remove kSecMatchSearchList (value is array of SecKeychainRef);
4123		 * cannot specify a keychain search list on iOS
4124		 */
4125		CFDictionaryRemoveValue(result, kSecMatchSearchList);
4126
4127		/* Remove kSecUseKeychain (value is a SecKeychainRef);
4128		 * cannot specify a keychain on iOS
4129		 */
4130		CFDictionaryRemoveValue(result, kSecUseKeychain);
4131
4132		/* Remove kSecMatchPolicy (value is a SecPolicyRef);
4133		 * TODO: need a way to externalize and restore a policy instance
4134		 */
4135		CFDictionaryRemoveValue(result, kSecMatchPolicy);
4136
4137		/* Potentially translate kSecAttrAccess (value is a SecAccessRef),
4138		 * unless kSecAttrAccessGroup has already been specified.
4139		 */
4140		SecAccessRef access = (SecAccessRef) CFDictionaryGetValue(result, kSecAttrAccess);
4141		CFStringRef accessGroup = (CFStringRef) CFDictionaryGetValue(result, kSecAttrAccessGroup);
4142		if (access != NULL && accessGroup == NULL) {
4143			/* Translate "InternetAccounts" application group to an access group */
4144			if (errSecSuccess == SecItemValidateAppleApplicationGroupAccess(CFSTR("InternetAccounts"))) {
4145				/* The caller is a valid member of the application group. */
4146				CFStringRef groupName = CFSTR("appleaccount");
4147				CFTypeRef value = CFDictionaryGetValue(result, kSecAttrAuthenticationType);
4148				if (value && CFEqual(value, kSecAttrAuthenticationTypeHTMLForm)) {
4149					groupName = CFSTR("com.apple.cfnetwork");
4150				}
4151				CFDictionarySetValue(result, kSecAttrAccessGroup, groupName);
4152			}
4153		}
4154		CFDictionaryRemoveValue(result, kSecAttrAccess);
4155
4156		/* If item is specified by direct reference, and this is an iOS search,
4157		 * replace it with a persistent reference.
4158		 */
4159        CFTypeRef directRef = CFDictionaryGetValue(result, kSecValueRef);
4160		if (directRef) {
4161			CFDataRef persistentRef = _SecItemGetPersistentReference(directRef);
4162			if (persistentRef) {
4163                CFDictionarySetValue(result, kSecValuePersistentRef, persistentRef);
4164			}
4165			CFDictionaryRemoveValue(result, kSecValueRef);
4166		}
4167
4168		/* If item is specified by persistent reference, and this is an iOS search,
4169		 * remove the synchronizable attribute as it will be rejected by secd.
4170		 */
4171		CFTypeRef persistentRef = CFDictionaryGetValue(result, kSecValuePersistentRef);
4172		if (persistentRef) {
4173			CFDictionaryRemoveValue(result, kSecAttrSynchronizable);
4174		}
4175
4176		/* Remove kSecAttrModificationDate; this should never be used as criteria
4177		 * for a search, or to add/modify an item. (If we are cloning an item
4178		 * and want to keep its modification date, we don't call this function.)
4179		 * It turns out that some clients are using the full attributes dictionary
4180		 * returned by SecItemCopyMatching as a query to find the same item later,
4181		 * which won't work once the item is updated.
4182		 */
4183		CFDictionaryRemoveValue(result, kSecAttrModificationDate);
4184    }
4185	else {
4186		/* iOS doesn't add the class attribute, so we must do it here. */
4187		if (itemClass)
4188			CFDictionarySetValue(result, kSecClass, itemClass);
4189
4190		/* Remove attributes which are not part of the OS X database schema. */
4191		CFDictionaryRemoveValue(result, kSecAttrAccessible);
4192		CFDictionaryRemoveValue(result, kSecAttrAccessGroup);
4193		CFDictionaryRemoveValue(result, kSecAttrSynchronizable);
4194		CFDictionaryRemoveValue(result, kSecAttrTombstone);
4195	}
4196
4197	return result;
4198}
4199
4200/*
4201 * SecItemCopyMergedResults takes two input objects, which may be containers,
4202 * and returns a retained object which merges the results. Merging depends on the
4203 * result type. If each result is valid and is not an array, then only one match was
4204 * requested; in that case, the syncable (ios) match is preferred.
4205 *
4206 * FIXME: There are some edge cases still to deal with; e.g. if the OSX search specified a
4207 * particular keychain to search, we do not want to merge in any IOS results. Also, may need
4208 * to filter out duplicates if two items differ only in the sync attribute.
4209 */
4210CFTypeRef
4211SecItemCopyMergedResults(CFDictionaryRef query, CFTypeRef result_osx, CFTypeRef result_ios)
4212{
4213	CFTypeID id_osx = (result_osx) ? CFGetTypeID(result_osx) : 0;
4214	CFTypeID id_ios = (result_ios) ? CFGetTypeID(result_ios) : 0;
4215	CFTypeID id_array = CFArrayGetTypeID();
4216	if ((id_osx == id_array) && (id_ios == id_array)) {
4217		// Fold the arrays into one.
4218		CFMutableArrayRef results = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
4219		CFArrayAppendArray(results, (CFArrayRef)result_ios, CFRangeMake(0, CFArrayGetCount((CFArrayRef)result_ios)));
4220		CFArrayAppendArray(results, (CFArrayRef)result_osx, CFRangeMake(0, CFArrayGetCount((CFArrayRef)result_osx)));
4221		return results;
4222	}
4223	// Result type is not an array, so only one match can be returned.
4224	return (id_ios) ? CFRetain(result_ios) : CFRetain(result_osx);
4225}
4226
4227} /* extern "C" */
4228
4229
4230OSStatus
4231SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result)
4232{
4233	secitemlog(LOG_NOTICE, "SecItemCopyMatching");
4234	if (!query) {
4235		return errSecParam;
4236	}
4237	secitemshow(query, "SecItemCopyMatching query:");
4238
4239	OSStatus status_osx = errSecItemNotFound, status_ios = errSecItemNotFound;
4240	CFTypeRef result_osx = NULL, result_ios = NULL;
4241	Boolean sync_enabled = SecItemSyncEnabled();
4242	Boolean search_ios = SecItemSynchronizable(query);
4243	Boolean merge_search = SecItemSynchronizableAny(query);
4244	Boolean persistref_ios = SecItemHasSynchronizablePersistentReference(query);
4245
4246	if (sync_enabled && (merge_search || persistref_ios || search_ios)) {
4247		CFDictionaryRef attrs_ios = SecItemCopyTranslatedAttributes(query,
4248			CFDictionaryGetValue(query, kSecClass), true, false, false, false, true, true);
4249		if (!attrs_ios) {
4250			status_ios = errSecParam;
4251		}
4252		else {
4253            SecItemUnlockSynchronizableKeychain();
4254            status_ios = SecItemCopyMatching_ios(attrs_ios, &result_ios);
4255			CFRelease(attrs_ios);
4256		}
4257		secitemlog(LOG_NOTICE, "SecItemCopyMatching_ios result: %d", status_ios);
4258		if (!merge_search || persistref_ios) {
4259			AssignOrReleaseResult(result_ios, result);
4260			return status_ios; // no need to search non-syncable keychains
4261		}
4262	}
4263
4264	CFDictionaryRef attrs_osx = SecItemCopyTranslatedAttributes(query,
4265		CFDictionaryGetValue(query, kSecClass), false, false, true, false, true, true);
4266	if (!attrs_osx) {
4267		status_osx = errSecParam;
4268	}
4269	else {
4270		status_osx = SecItemCopyMatching_osx(attrs_osx, &result_osx);
4271		CFRelease(attrs_osx);
4272	}
4273	secitemlog(LOG_NOTICE, "SecItemCopyMatching_osx result: %d", status_osx);
4274
4275	// If one of the searches failed to occur or produce results, we can eliminate it
4276	if (result_ios == NULL) {
4277		AssignOrReleaseResult(result_osx, result);
4278		return status_osx; // we can only have non-syncable results
4279	}
4280	if (result_osx == NULL) {
4281		AssignOrReleaseResult(result_ios, result);
4282		return status_ios; // we can only have syncable results
4283	}
4284
4285	// If we get here, need to merge results
4286	CFTypeRef result_merged = SecItemCopyMergedResults(query, result_osx, result_ios);
4287	CFReleaseSafe(result_osx);
4288	CFReleaseSafe(result_ios);
4289	AssignOrReleaseResult(result_merged, result);
4290
4291	if (status_osx == status_ios) {
4292		return status_osx; // both searches produced the same result
4293	}
4294	else if (!status_osx || !status_ios) {
4295		return errSecSuccess; // one of the searches succeeded
4296	}
4297	else if (status_osx == errSecItemNotFound) {
4298		return status_ios; // this failure was more interesting
4299	}
4300	return status_osx;
4301}
4302
4303OSStatus
4304SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)
4305{
4306	secitemlog(LOG_NOTICE, "SecItemAdd");
4307	if (!attributes) {
4308		return errSecParam;
4309	}
4310	else if (result) {
4311		*result = NULL;
4312	}
4313	secitemshow(attributes, "SecItemAdd attrs:");
4314
4315	OSStatus status_osx, status_ios;
4316	CFTypeRef result_osx = NULL, result_ios = NULL;
4317	Boolean sync_enabled = SecItemSyncEnabled();
4318	Boolean add_ios = SecItemSynchronizable(attributes);
4319
4320	if (sync_enabled && add_ios) {
4321		CFDictionaryRef attrs_ios = SecItemCopyTranslatedAttributes(attributes,
4322			NULL, true, true, false, false, false, false);
4323		if (!attrs_ios) {
4324			status_ios = errSecParam;
4325		}
4326		else {
4327            SecItemUnlockSynchronizableKeychain();
4328            status_ios = SecItemAdd_ios(attrs_ios, &result_ios);
4329			CFRelease(attrs_ios);
4330		}
4331		secitemlog(LOG_NOTICE, "SecItemAdd_ios result: %d", status_ios);
4332		if (result)
4333			*result = result_ios;
4334		else
4335			CFReleaseSafe(result_ios);
4336		return status_ios;
4337	}
4338
4339	CFDictionaryRef attrs_osx = SecItemCopyTranslatedAttributes(attributes,
4340		NULL, false, false, true, false, false, false);
4341	if (!attrs_osx) {
4342		status_osx = errSecParam;
4343	}
4344	else {
4345		status_osx = SecItemAdd_osx(attrs_osx, &result_osx);
4346		CFRelease(attrs_osx);
4347	}
4348	secitemlog(LOG_NOTICE, "SecItemAdd_osx result: %d", status_osx);
4349	if (result)
4350		*result = result_osx;
4351	else
4352		CFReleaseSafe(result_osx);
4353	return status_osx;
4354}
4355
4356OSStatus
4357SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
4358{
4359	secitemlog(LOG_NOTICE, "SecItemUpdate");
4360	if (!query || !attributesToUpdate) {
4361		return errSecParam;
4362	}
4363	secitemshow(query, "SecItemUpdate query:");
4364	secitemshow(attributesToUpdate, "SecItemUpdate attrs:");
4365
4366	OSStatus status_osx = errSecItemNotFound, status_ios = errSecItemNotFound;
4367	Boolean sync_enabled = SecItemSyncEnabled();
4368	Boolean search_ios = SecItemSynchronizable(query);
4369	Boolean merge_search = SecItemSynchronizableAny(query);
4370	Boolean persistref_ios = SecItemHasSynchronizablePersistentReference(query);
4371
4372	if (sync_enabled && (merge_search || persistref_ios || search_ios)) {
4373		CFDictionaryRef attrs_ios = SecItemCopyTranslatedAttributes(query,
4374			CFDictionaryGetValue(query, kSecClass), true, true, false, true, true, true);
4375		if (!attrs_ios) {
4376			status_ios = errSecParam;
4377		}
4378		else {
4379			SecItemUnlockSynchronizableKeychain();
4380            if (SecItemHasSynchronizableUpdate(true, attributesToUpdate))
4381                status_ios = SecItemChangeSynchronizability(attrs_ios, attributesToUpdate, false);
4382            else
4383                status_ios = SecItemUpdate_ios(attrs_ios, attributesToUpdate);
4384			CFRelease(attrs_ios);
4385		}
4386		secitemlog(LOG_NOTICE, "SecItemUpdate_ios result: %d", status_ios);
4387		if (!merge_search || persistref_ios)
4388			return status_ios;
4389	}
4390
4391	CFDictionaryRef attrs_osx = SecItemCopyTranslatedAttributes(query,
4392		CFDictionaryGetValue(query, kSecClass), false, false, true, true, true, true);
4393	if (!attrs_osx) {
4394		status_osx = errSecParam;
4395	}
4396	else {
4397		if (SecItemHasSynchronizableUpdate(false, attributesToUpdate))
4398			status_osx = SecItemChangeSynchronizability(attrs_osx, attributesToUpdate, true);
4399		else
4400			status_osx = SecItemUpdate_osx(attrs_osx, attributesToUpdate);
4401
4402		CFRelease(attrs_osx);
4403	}
4404	secitemlog(LOG_NOTICE, "SecItemUpdate_osx result: %d", status_osx);
4405	if (merge_search) {
4406		// Harmonize the result of the update attempts.
4407		if (status_osx == status_ios) {
4408			// both updates produced the same result
4409			return status_ios;
4410		}
4411		else if (!status_osx || !status_ios) {
4412			// one of the updates succeeded, but the other failed
4413			if (status_osx == errSecItemNotFound || status_ios == errSecItemNotFound)
4414				return errSecSuccess; // item only found in one keychain
4415			else
4416				return (status_osx) ? status_osx : status_ios; // return the error
4417		}
4418		else if (status_osx == errSecItemNotFound) {
4419			// both updates failed, status_ios failure is more interesting
4420			// since the item was actually found
4421			return status_ios;
4422		}
4423	}
4424	return status_osx;
4425}
4426
4427OSStatus
4428SecItemDelete(CFDictionaryRef query)
4429{
4430	secitemlog(LOG_NOTICE, "SecItemDelete");
4431	if (!query) {
4432		return errSecParam;
4433	}
4434	secitemshow(query, "SecItemDelete query:");
4435
4436	OSStatus status_osx = errSecItemNotFound, status_ios = errSecItemNotFound;
4437	Boolean sync_enabled = SecItemSyncEnabled();
4438	Boolean search_ios = SecItemSynchronizable(query);
4439	Boolean merge_search = SecItemSynchronizableAny(query);
4440	Boolean persistref_ios = SecItemHasSynchronizablePersistentReference(query);
4441
4442	if (sync_enabled && (merge_search || persistref_ios || search_ios)) {
4443		CFDictionaryRef attrs_ios = SecItemCopyTranslatedAttributes(query,
4444			NULL, true, true, false, true, true, true);
4445		if (!attrs_ios) {
4446			status_ios = errSecParam;
4447		}
4448		else {
4449            SecItemUnlockSynchronizableKeychain();
4450            status_ios = SecItemDelete_ios(attrs_ios);
4451			CFRelease(attrs_ios);
4452		}
4453		secitemlog(LOG_NOTICE, "SecItemDelete_ios result: %d", status_ios);
4454		if (!merge_search || persistref_ios)
4455			return status_ios;
4456	}
4457
4458	CFDictionaryRef attrs_osx = SecItemCopyTranslatedAttributes(query,
4459		NULL, false, false, true, true, true, true);
4460	if (!attrs_osx) {
4461		status_osx = errSecParam;
4462	}
4463	else {
4464		status_osx = SecItemDelete_osx(attrs_osx);
4465		CFRelease(attrs_osx);
4466	}
4467	secitemlog(LOG_NOTICE, "SecItemDelete_osx result: %d", status_osx);
4468
4469	if (merge_search) {
4470		// Harmonize the result of the delete attempts.
4471		if (status_osx == status_ios) {
4472			// both deletes produced the same result
4473			return status_ios;
4474		}
4475		else if (!status_osx || !status_ios) {
4476			// one of the deletes succeeded, but the other failed
4477			if (status_osx == errSecItemNotFound || status_ios == errSecItemNotFound)
4478				return errSecSuccess; // item only found in one keychain
4479			else
4480				return (status_osx) ? status_osx : status_ios; // return the error
4481		}
4482		else if (status_osx == errSecItemNotFound) {
4483			// both deletes failed, status_ios failure is more interesting
4484			// since the item was actually found
4485			return status_ios;
4486		}
4487	}
4488	return status_osx;
4489}
4490
4491OSStatus
4492SecItemCopyMatching_osx(
4493	CFDictionaryRef query,
4494	CFTypeRef *result)
4495{
4496	if (!query || !result)
4497		return errSecParam;
4498	else
4499		*result = NULL;
4500
4501	CFAllocatorRef allocator = CFGetAllocator(query);
4502	CFIndex matchCount = 0;
4503	CFMutableArrayRef itemArray = NULL;
4504	SecKeychainItemRef item = NULL;
4505	SecIdentityRef identity = NULL;
4506	OSStatus tmpStatus, status = errSecSuccess;
4507
4508	// validate input query parameters and create the search reference
4509	SecItemParams *itemParams = _CreateSecItemParamsFromDictionary(query, &status);
4510	require_action(itemParams != NULL, error_exit, itemParams = NULL);
4511
4512	// find the next match until we hit maxMatches, or no more matches found
4513	while ( !(!itemParams->returnAllMatches && matchCount >= itemParams->maxMatches) &&
4514			SecItemSearchCopyNext(itemParams, (CFTypeRef*)&item) == errSecSuccess) {
4515
4516		if (FilterCandidateItem((CFTypeRef*)&item, itemParams, &identity))
4517			continue; // move on to next item
4518
4519		++matchCount; // we have a match
4520
4521		tmpStatus = AddItemResults(item, identity, itemParams, allocator, &itemArray, result);
4522		if (tmpStatus && (status == errSecSuccess))
4523			status = tmpStatus;
4524
4525		if (item) {
4526			CFRelease(item);
4527			item = NULL;
4528		}
4529		if (identity) {
4530			CFRelease(identity);
4531			identity = NULL;
4532		}
4533	}
4534
4535	if (status == errSecSuccess)
4536		status = (matchCount > 0) ? errSecSuccess : errSecItemNotFound;
4537
4538error_exit:
4539	if (status != errSecSuccess && result != NULL && *result != NULL) {
4540		CFRelease(*result);
4541		*result = NULL;
4542	}
4543	_FreeSecItemParams(itemParams);
4544
4545	return status;
4546}
4547
4548OSStatus
4549SecItemCopyDisplayNames(
4550	CFArrayRef items,
4551	CFArrayRef *displayNames)
4552{
4553    BEGIN_SECAPI
4554	Required(items);
4555	Required(displayNames);
4556    //%%%TBI
4557    return errSecUnimplemented;
4558    END_SECAPI
4559}
4560
4561OSStatus
4562SecItemAdd_osx(
4563	CFDictionaryRef attributes,
4564	CFTypeRef *result)
4565{
4566	if (!attributes)
4567		return errSecParam;
4568	else if (result)
4569		*result = NULL;
4570
4571	CFAllocatorRef allocator = CFGetAllocator(attributes);
4572	CFMutableArrayRef itemArray = NULL;
4573	SecKeychainItemRef item = NULL;
4574	OSStatus tmpStatus, status = errSecSuccess;
4575
4576	// validate input attribute parameters
4577	SecItemParams *itemParams = _CreateSecItemParamsFromDictionary(attributes, &status);
4578	require_action(itemParams != NULL, error_exit, itemParams = NULL);
4579
4580	// currently, we don't support adding SecIdentityRef items (an aggregate item class),
4581	// since the private key should already be in a keychain by definition. We could support
4582	// this as a copy operation for the private key if a different keychain is specified,
4583	// but in any case it should try to add the certificate. See <rdar://8317887>.
4584	require_action(!itemParams->returnIdentity, error_exit, status = errSecItemInvalidValue);
4585
4586	if (!itemParams->useItems) {
4587		// create a single keychain item specified by the input attributes
4588		status = SecKeychainItemCreateFromContent(itemParams->itemClass,
4589			itemParams->attrList,
4590			(itemParams->itemData) ? (UInt32)CFDataGetLength(itemParams->itemData) : 0,
4591			(itemParams->itemData) ? CFDataGetBytePtrVoid(itemParams->itemData) : NULL,
4592			itemParams->keychain,
4593			itemParams->access,
4594			&item);
4595		require_noerr(status, error_exit);
4596
4597		// return results (if requested)
4598		if (result) {
4599			itemParams->maxMatches = 1; // in case kSecMatchLimit was set to > 1
4600			tmpStatus = AddItemResults(item, NULL, itemParams, allocator, &itemArray, result);
4601			if (tmpStatus && (status == errSecSuccess))
4602				status = tmpStatus;
4603		}
4604		CFRelease(item);
4605	}
4606	else {
4607		// add multiple items which are specified in the itemParams->useItems array.
4608		// -- SecCertificateRef or SecKeyRef items may or may not be in a keychain.
4609		// -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain.
4610		// -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain.
4611		//
4612		OSStatus aggregateStatus = errSecSuccess;
4613		CFIndex ix, count = CFArrayGetCount(itemParams->useItems);
4614		itemParams->maxMatches = (count > 1) ? (int)count : 2; // force results to always be returned as an array
4615		for (ix=0; ix < count; ix++) {
4616			CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(itemParams->useItems, ix);
4617			if (anItem) {
4618				if (SecCertificateGetTypeID() == CFGetTypeID(anItem)) {
4619					// SecCertificateRef item
4620					tmpStatus = SecCertificateAddToKeychain((SecCertificateRef)anItem, itemParams->keychain);
4621					if (!tmpStatus && result) {
4622						tmpStatus = AddItemResults((SecKeychainItemRef)anItem, NULL, itemParams, allocator, &itemArray, result);
4623					}
4624					aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
4625				}
4626				else if (SecKeyGetTypeID() == CFGetTypeID(anItem)) {
4627					// SecKeyRef item
4628					SecKeychainRef itemKeychain = NULL;
4629					tmpStatus = SecKeychainItemCopyKeychain((SecKeychainItemRef)anItem, &itemKeychain);
4630					if (tmpStatus == errSecSuccess) {
4631						// key was in a keychain, so we can attempt to copy it
4632						SecKeychainItemRef itemCopy = NULL;
4633						tmpStatus = SecKeychainItemCreateCopy((SecKeychainItemRef)anItem, itemParams->keychain, itemParams->access, &itemCopy);
4634						if (!tmpStatus && result) {
4635							tmpStatus = AddItemResults(itemCopy, NULL, itemParams, allocator, &itemArray, result);
4636						}
4637						if (itemCopy) {
4638							CFRelease(itemCopy);
4639						}
4640					}
4641					else {
4642						// key was not in any keychain, so must be imported
4643						SecKeychainItemRef keyItem = NULL;
4644						tmpStatus = _ImportKey((SecKeyRef)anItem, itemParams->keychain, itemParams->access, itemParams->attrList, &keyItem);
4645						if (!tmpStatus && result) {
4646							tmpStatus = AddItemResults(keyItem, NULL, itemParams, allocator, &itemArray, result);
4647						}
4648						if (keyItem) {
4649							CFRelease(keyItem);
4650						}
4651					}
4652					if (itemKeychain) {
4653						CFRelease(itemKeychain);
4654					}
4655					aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
4656				}
4657				else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem)) {
4658					// SecKeychainItemRef item
4659					SecKeychainItemRef itemCopy = NULL;
4660					tmpStatus = SecKeychainItemCreateCopy((SecKeychainItemRef)anItem, itemParams->keychain, itemParams->access, &itemCopy);
4661					if (!tmpStatus && result) {
4662						tmpStatus = AddItemResults(itemCopy, NULL, itemParams, allocator, &itemArray, result);
4663					}
4664					if (itemCopy) {
4665						CFRelease(itemCopy);
4666					}
4667					aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
4668				}
4669				else if (CFDataGetTypeID() == CFGetTypeID(anItem)) {
4670					// CFDataRef item (persistent reference)
4671					SecKeychainItemRef realItem = NULL;
4672					tmpStatus = SecKeychainItemCopyFromPersistentReference((CFDataRef)anItem, &realItem);
4673					if (tmpStatus == errSecSuccess) {
4674						// persistent reference resolved to a keychain item, so we can attempt to copy it
4675						SecKeychainItemRef itemCopy = NULL;
4676						tmpStatus = SecKeychainItemCreateCopy(realItem, itemParams->keychain, itemParams->access, &itemCopy);
4677						if (!tmpStatus && result) {
4678							tmpStatus = AddItemResults(itemCopy, NULL, itemParams, allocator, &itemArray, result);
4679						}
4680						if (itemCopy) {
4681							CFRelease(itemCopy);
4682						}
4683					}
4684					if (realItem) {
4685						CFRelease(realItem);
4686					}
4687					aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
4688				}
4689			}
4690		} // end of itemList array loop
4691		status = aggregateStatus;
4692	} // end processing multiple items
4693
4694error_exit:
4695	if (status != errSecSuccess && result != NULL && *result != NULL) {
4696		CFRelease(*result);
4697		*result = NULL;
4698	}
4699	_FreeSecItemParams(itemParams);
4700
4701	return status;
4702}
4703
4704OSStatus
4705SecItemUpdate_osx(
4706	CFDictionaryRef query,
4707	CFDictionaryRef attributesToUpdate)
4708{
4709	if (!query || !attributesToUpdate)
4710		return errSecParam;
4711
4712	// run the provided query to get a list of items to update
4713	CFTypeRef results = NULL;
4714	OSStatus status = SecItemCopyMatching(query, &results);
4715	if (status != errSecSuccess)
4716		return status; // nothing was matched, or the query was bad
4717
4718	CFArrayRef items = NULL;
4719	if (CFArrayGetTypeID() == CFGetTypeID(results)) {
4720		items = (CFArrayRef) results;
4721	}
4722	else {
4723		items = CFArrayCreate(NULL, &results, 1, &kCFTypeArrayCallBacks);
4724		CFRelease(results);
4725	}
4726
4727	OSStatus result = errSecSuccess;
4728	CFIndex ix, count = CFArrayGetCount(items);
4729	for (ix=0; ix < count; ix++) {
4730		CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(items, ix);
4731		if (anItem) {
4732			status = _UpdateKeychainItem(anItem, attributesToUpdate);
4733			result = _UpdateAggregateStatus(status, result, errSecSuccess);
4734		}
4735	}
4736
4737	if (items) {
4738		CFRelease(items);
4739	}
4740	return result;
4741}
4742
4743OSStatus
4744SecItemDelete_osx(
4745	CFDictionaryRef query)
4746{
4747	if (!query)
4748		return errSecParam;
4749
4750	// run the provided query to get a list of items to delete
4751	CFTypeRef results = NULL;
4752	OSStatus status = SecItemCopyMatching_osx(query, &results);
4753	if (status != errSecSuccess)
4754		return status; // nothing was matched, or the query was bad
4755
4756	CFArrayRef items = NULL;
4757	if (CFArrayGetTypeID() == CFGetTypeID(results)) {
4758		items = (CFArrayRef) results;
4759	}
4760	else {
4761		items = CFArrayCreate(NULL, &results, 1, &kCFTypeArrayCallBacks);
4762		CFRelease(results);
4763	}
4764
4765	OSStatus result = errSecSuccess;
4766	CFIndex ix, count = CFArrayGetCount(items);
4767	for (ix=0; ix < count; ix++) {
4768		CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(items, ix);
4769		if (anItem) {
4770			if (SecIdentityGetTypeID() == CFGetTypeID(anItem)) {
4771				status = _DeleteIdentity((SecIdentityRef)anItem);
4772			}
4773			else {
4774				status = _DeleteKeychainItem(anItem);
4775			}
4776			result = _UpdateAggregateStatus(status, result, errSecSuccess);
4777		}
4778	}
4779
4780	if (items)
4781		CFRelease(items);
4782
4783	return result;
4784}
4785