]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/SecItem.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_keychain / lib / SecItem.cpp
1 /*
2 * Copyright (c) 2006-2010,2012 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 <security_utilities/cfutilities.h>
26 #include <CoreFoundation/CoreFoundation.h>
27 #include <Security/SecKeychainItem.h>
28 #include <Security/SecCertificate.h>
29 #include <sys/param.h>
30 #include "cssmdatetime.h"
31 #include "SecItem.h"
32 #include "SecItemPriv.h"
33 #include "SecIdentitySearchPriv.h"
34 #include "SecCertificatePriv.h"
35 #include "SecCertificatePrivP.h"
36 #include "TrustAdditions.h"
37
38 #include <AssertMacros.h>
39
40 OSStatus SecItemAdd_osx(CFDictionaryRef attributes, CFTypeRef *result);
41 OSStatus SecItemCopyMatching_osx(CFDictionaryRef query, CFTypeRef *result);
42 OSStatus SecItemUpdate_osx(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
43 OSStatus SecItemDelete_osx(CFDictionaryRef query);
44
45 extern "C" {
46 OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result);
47 OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result);
48 OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
49 OSStatus SecItemDelete_ios(CFDictionaryRef query);
50 }
51
52
53 #define CFDataGetBytePtrVoid CFDataGetBytePtr
54
55 #pragma mark SecItem private utility functions
56
57 /******************************************************************************/
58
59 struct ProtocolAttributeInfo {
60 const CFTypeRef *protocolValue;
61 SecProtocolType protocolType;
62 };
63
64 static ProtocolAttributeInfo gProtocolTypes[] = {
65 { &kSecAttrProtocolFTP, kSecProtocolTypeFTP },
66 { &kSecAttrProtocolFTPAccount, kSecProtocolTypeFTPAccount },
67 { &kSecAttrProtocolHTTP, kSecProtocolTypeHTTP },
68 { &kSecAttrProtocolIRC, kSecProtocolTypeIRC },
69 { &kSecAttrProtocolNNTP, kSecProtocolTypeNNTP },
70 { &kSecAttrProtocolPOP3, kSecProtocolTypePOP3 },
71 { &kSecAttrProtocolSMTP, kSecProtocolTypeSMTP },
72 { &kSecAttrProtocolSOCKS, kSecProtocolTypeSOCKS },
73 { &kSecAttrProtocolIMAP, kSecProtocolTypeIMAP },
74 { &kSecAttrProtocolLDAP, kSecProtocolTypeLDAP },
75 { &kSecAttrProtocolAppleTalk, kSecProtocolTypeAppleTalk },
76 { &kSecAttrProtocolAFP, kSecProtocolTypeAFP },
77 { &kSecAttrProtocolTelnet, kSecProtocolTypeTelnet },
78 { &kSecAttrProtocolSSH, kSecProtocolTypeSSH },
79 { &kSecAttrProtocolFTPS, kSecProtocolTypeFTPS },
80 { &kSecAttrProtocolHTTPS, kSecProtocolTypeHTTPS },
81 { &kSecAttrProtocolHTTPProxy, kSecProtocolTypeHTTPProxy },
82 { &kSecAttrProtocolHTTPSProxy, kSecProtocolTypeHTTPSProxy },
83 { &kSecAttrProtocolFTPProxy, kSecProtocolTypeFTPProxy },
84 { &kSecAttrProtocolSMB, kSecProtocolTypeSMB },
85 { &kSecAttrProtocolRTSP, kSecProtocolTypeRTSP },
86 { &kSecAttrProtocolRTSPProxy, kSecProtocolTypeRTSPProxy },
87 { &kSecAttrProtocolDAAP, kSecProtocolTypeDAAP },
88 { &kSecAttrProtocolEPPC, kSecProtocolTypeEPPC },
89 { &kSecAttrProtocolIPP, kSecProtocolTypeIPP },
90 { &kSecAttrProtocolNNTPS, kSecProtocolTypeNNTPS },
91 { &kSecAttrProtocolLDAPS, kSecProtocolTypeLDAPS },
92 { &kSecAttrProtocolTelnetS, kSecProtocolTypeTelnetS },
93 { &kSecAttrProtocolIMAPS, kSecProtocolTypeIMAPS },
94 { &kSecAttrProtocolIRCS, kSecProtocolTypeIRCS },
95 { &kSecAttrProtocolPOP3S, kSecProtocolTypePOP3S }
96 };
97
98 static const int kNumberOfProtocolTypes = sizeof(gProtocolTypes) / sizeof(ProtocolAttributeInfo);
99
100 /*
101 * _SecProtocolTypeForSecAttrProtocol converts a SecAttrProtocol to a SecProtocolType.
102 */
103 static SecProtocolType
104 _SecProtocolTypeForSecAttrProtocol(
105 CFTypeRef protocol)
106 {
107 SecProtocolType result = kSecProtocolTypeAny;
108
109 if (protocol != NULL) {
110 CFIndex count;
111 for (count=0; count<kNumberOfProtocolTypes; count++) {
112 if (CFEqual(protocol, *(gProtocolTypes[count].protocolValue))) {
113 result = gProtocolTypes[count].protocolType;
114 break;
115 }
116 }
117 }
118
119 return result;
120 }
121
122 /*
123 * _SecAttrProtocolForSecProtocolType converts a SecProtocolType to a SecAttrProtocol.
124 */
125 static CFTypeRef
126 _SecAttrProtocolForSecProtocolType(
127 SecProtocolType protocolType)
128 {
129 CFTypeRef result = NULL;
130 CFIndex count;
131 for (count=0; count<kNumberOfProtocolTypes; count++) {
132 if (gProtocolTypes[count].protocolType == protocolType) {
133 result = *(gProtocolTypes[count].protocolValue);
134 break;
135 }
136 }
137
138 return result;
139 }
140
141
142 /******************************************************************************/
143
144 struct AuthenticationAttributeInfo {
145 const CFTypeRef *authValue;
146 SecAuthenticationType authType;
147 };
148
149 static AuthenticationAttributeInfo gAuthTypes[] = {
150 { &kSecAttrAuthenticationTypeNTLM, kSecAuthenticationTypeNTLM },
151 { &kSecAttrAuthenticationTypeMSN, kSecAuthenticationTypeMSN },
152 { &kSecAttrAuthenticationTypeDPA, kSecAuthenticationTypeDPA },
153 { &kSecAttrAuthenticationTypeRPA, kSecAuthenticationTypeRPA },
154 { &kSecAttrAuthenticationTypeHTTPBasic, kSecAuthenticationTypeHTTPBasic },
155 { &kSecAttrAuthenticationTypeHTTPDigest, kSecAuthenticationTypeHTTPDigest },
156 { &kSecAttrAuthenticationTypeHTMLForm, kSecAuthenticationTypeHTMLForm },
157 { &kSecAttrAuthenticationTypeDefault, kSecAuthenticationTypeDefault }
158 };
159
160 static const int kNumberOfAuthenticationTypes = sizeof(gAuthTypes) / sizeof(AuthenticationAttributeInfo);
161
162 /*
163 * _SecAuthenticationTypeForSecAttrAuthenticationType converts a
164 * SecAttrAuthenticationType to a SecAuthenticationType.
165 */
166 static SecAuthenticationType
167 _SecAuthenticationTypeForSecAttrAuthenticationType(
168 CFTypeRef authenticationType)
169 {
170 SecAuthenticationType result = kSecAuthenticationTypeAny;
171
172 if (authenticationType != NULL) {
173 CFIndex count;
174 for (count=0; count<kNumberOfAuthenticationTypes; count++) {
175 if (CFEqual(authenticationType, *(gAuthTypes[count].authValue))) {
176 result = gAuthTypes[count].authType;
177 break;
178 }
179 }
180 }
181
182 return result;
183 }
184
185 /*
186 * _SecAttrAuthenticationTypeForSecAuthenticationType converts a SecAuthenticationType
187 * to a SecAttrAuthenticationType.
188 */
189 static CFTypeRef
190 _SecAttrAuthenticationTypeForSecAuthenticationType(
191 SecAuthenticationType authenticationType)
192 {
193 CFTypeRef result = NULL;
194 CFIndex count;
195 for (count=0; count<kNumberOfAuthenticationTypes; count++) {
196 if (gAuthTypes[count].authType == authenticationType) {
197 result = *(gAuthTypes[count].authValue);
198 break;
199 }
200 }
201
202 return result;
203 }
204
205
206 /******************************************************************************/
207
208 struct KeyAlgorithmInfo {
209 const CFTypeRef *keyType;
210 UInt32 keyValue;
211 };
212
213 static KeyAlgorithmInfo gKeyTypes[] = {
214 { &kSecAttrKeyTypeRSA, CSSM_ALGID_RSA },
215 { &kSecAttrKeyTypeDSA, CSSM_ALGID_DSA },
216 { &kSecAttrKeyTypeAES, CSSM_ALGID_AES },
217 { &kSecAttrKeyTypeDES, CSSM_ALGID_DES },
218 { &kSecAttrKeyType3DES, CSSM_ALGID_3DES },
219 { &kSecAttrKeyTypeRC4, CSSM_ALGID_RC4 },
220 { &kSecAttrKeyTypeRC2, CSSM_ALGID_RC2 },
221 { &kSecAttrKeyTypeCAST, CSSM_ALGID_CAST },
222 { &kSecAttrKeyTypeECDSA, CSSM_ALGID_ECDSA }
223 };
224
225 static const int kNumberOfKeyTypes = sizeof(gKeyTypes) / sizeof (KeyAlgorithmInfo);
226
227
228 static UInt32 _SecAlgorithmTypeFromSecAttrKeyType(
229 CFTypeRef keyTypeRef)
230 {
231 UInt32 keyAlgValue = 0;
232 if (CFStringGetTypeID() != CFGetTypeID(keyTypeRef))
233 return keyAlgValue;
234
235 int ix;
236 for (ix=0; ix<kNumberOfKeyTypes; ix++) {
237 if (CFEqual(keyTypeRef, *(gKeyTypes[ix].keyType))) {
238 keyAlgValue = gKeyTypes[ix].keyValue;
239 return keyAlgValue;
240 }
241 }
242
243 //%%%TODO try to convert the input string to a number here
244
245 return keyAlgValue;
246 }
247
248
249 enum ItemRepresentation
250 {
251 kStringRepresentation,
252 kDataRepresentation,
253 kNumberRepresentation,
254 kBooleanRepresentation,
255 kDateRepresentation
256 };
257
258
259 struct InternalAttributeListInfo
260 {
261 UInt32 oldItemType;
262 const CFTypeRef *newItemType;
263 ItemRepresentation itemRepresentation;
264 };
265
266
267 static InternalAttributeListInfo gGenericPasswordAttributes[] =
268 {
269 { kSecCreationDateItemAttr, &kSecAttrCreationDate, kDateRepresentation },
270 { kSecModDateItemAttr, &kSecAttrModificationDate, kDateRepresentation },
271 { kSecDescriptionItemAttr, &kSecAttrDescription, kStringRepresentation },
272 { kSecCommentItemAttr, &kSecAttrComment, kStringRepresentation },
273 { kSecCreatorItemAttr, &kSecAttrCreator, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
274 { kSecTypeItemAttr, &kSecAttrType, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
275 { kSecLabelItemAttr, &kSecAttrLabel, kStringRepresentation },
276 { kSecInvisibleItemAttr, &kSecAttrIsInvisible, kBooleanRepresentation },
277 { kSecNegativeItemAttr, &kSecAttrIsNegative, kBooleanRepresentation },
278 { kSecAccountItemAttr, &kSecAttrAccount, kStringRepresentation },
279 { kSecServiceItemAttr, &kSecAttrService, kStringRepresentation },
280 { kSecGenericItemAttr, &kSecAttrGeneric, kDataRepresentation }
281 };
282
283 static const int kNumberOfGenericPasswordAttributes = sizeof(gGenericPasswordAttributes) / sizeof (InternalAttributeListInfo);
284
285
286 static InternalAttributeListInfo gInternetPasswordAttributes[] =
287 {
288 { kSecCreationDateItemAttr, &kSecAttrCreationDate, kDateRepresentation },
289 { kSecModDateItemAttr, &kSecAttrModificationDate, kDateRepresentation },
290 { kSecDescriptionItemAttr, &kSecAttrDescription, kStringRepresentation },
291 { kSecCommentItemAttr, &kSecAttrComment, kStringRepresentation },
292 { kSecCreatorItemAttr, &kSecAttrCreator, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
293 { kSecTypeItemAttr, &kSecAttrType, kNumberRepresentation }, // UInt32, a.k.a. FourCharCode
294 { kSecLabelItemAttr, &kSecAttrLabel, kStringRepresentation },
295 { kSecInvisibleItemAttr, &kSecAttrIsInvisible, kBooleanRepresentation },
296 { kSecNegativeItemAttr, &kSecAttrIsNegative, kBooleanRepresentation },
297 { kSecAccountItemAttr, &kSecAttrAccount, kStringRepresentation },
298 { kSecSecurityDomainItemAttr, &kSecAttrSecurityDomain, kStringRepresentation },
299 { kSecServerItemAttr, &kSecAttrServer, kStringRepresentation },
300 { kSecAuthenticationTypeItemAttr, &kSecAttrAuthenticationType, kStringRepresentation }, // maps from UInt32 value to string constant
301 { kSecPortItemAttr, &kSecAttrPort, kNumberRepresentation },
302 { kSecPathItemAttr, &kSecAttrPath, kStringRepresentation }
303 };
304
305 static const int kNumberOfInternetPasswordAttributes = sizeof(gInternetPasswordAttributes) / sizeof (InternalAttributeListInfo);
306
307
308 static InternalAttributeListInfo gCertificateAttributes[] =
309 {
310 { kSecLabelItemAttr, &kSecAttrLabel, kStringRepresentation },
311 { kSecSubjectItemAttr, &kSecAttrSubject, kDataRepresentation },
312 { kSecIssuerItemAttr, &kSecAttrIssuer, kDataRepresentation },
313 { kSecSerialNumberItemAttr, &kSecAttrSerialNumber, kDataRepresentation },
314 { kSecPublicKeyHashItemAttr, &kSecAttrPublicKeyHash, kDataRepresentation },
315 { kSecSubjectKeyIdentifierItemAttr, &kSecAttrSubjectKeyID, kDataRepresentation },
316 { kSecCertTypeItemAttr, &kSecAttrCertificateType, kDataRepresentation },
317 { kSecCertEncodingItemAttr, &kSecAttrCertificateEncoding, kDataRepresentation }
318 };
319
320 static const int kNumberOfCertificateAttributes = sizeof(gCertificateAttributes) / sizeof(InternalAttributeListInfo);
321
322
323 static InternalAttributeListInfo gKeyAttributes[] =
324 {
325 { kSecKeyKeyClass, &kSecAttrKeyClass, kStringRepresentation }, // key class maps from UInt32 value to string constant
326 { kSecKeyPrintName, &kSecAttrLabel, kStringRepresentation }, // note that "print name" maps to the user-visible label
327 // { kSecKeyAlias, /* not yet exposed by SecItem */, kDataRepresentation },
328 { kSecKeyPermanent, &kSecAttrIsPermanent, kBooleanRepresentation },
329 // { kSecKeyPrivate, /* not yet exposed by SecItem */, kBooleanRepresentation },
330 // { kSecKeyModifiable, /* not yet exposed by SecItem */, kBooleanRepresentation },
331 { kSecKeyLabel, &kSecAttrApplicationLabel, kStringRepresentation }, // this contains the hash of the key (or the public key hash, if asymmetric)
332 { kSecKeyApplicationTag, &kSecAttrApplicationTag, kDataRepresentation },
333 // { kSecKeyKeyCreator, /* not yet exposed by SecItem */, kStringRepresentation }, // this is the GUID of the CSP that owns this key
334 { kSecKeyKeyType, &kSecAttrKeyType, kStringRepresentation }, // algorithm type is given as a string constant (e.g. kSecAttrKeyTypeAES)
335 { kSecKeyKeySizeInBits, &kSecAttrKeySizeInBits, kNumberRepresentation },
336 { kSecKeyEffectiveKeySize, &kSecAttrEffectiveKeySize, kNumberRepresentation },
337 // { kSecKeyStartDate, /* not yet exposed by SecItem */, kDateRepresentation },
338 // { kSecKeyEndDate, /* not yet exposed by SecItem */, kDateRepresentation },
339 // { kSecKeySensitive, /* not yet exposed by SecItem */, kBooleanRepresentation },
340 // { kSecKeyAlwaysSensitive, /* not yet exposed by SecItem */, kBooleanRepresentation },
341 // { kSecKeyExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation },
342 // { kSecKeyNeverExtractable, /* not yet exposed by SecItem */, kBooleanRepresentation },
343 { kSecKeyEncrypt, &kSecAttrCanEncrypt, kBooleanRepresentation },
344 { kSecKeyDecrypt, &kSecAttrCanDecrypt, kBooleanRepresentation },
345 { kSecKeyDerive, &kSecAttrCanDerive, kBooleanRepresentation },
346 { kSecKeySign, &kSecAttrCanSign, kBooleanRepresentation },
347 { kSecKeyVerify, &kSecAttrCanVerify, kBooleanRepresentation },
348 // { kSecKeySignRecover, /* not yet exposed by SecItem */, kBooleanRepresentation },
349 // { kSecKeyVerifyRecover, /* not yet exposed by SecItem */, kBooleanRepresentation },
350 { kSecKeyWrap, &kSecAttrCanWrap, kBooleanRepresentation },
351 { kSecKeyUnwrap, &kSecAttrCanUnwrap, kBooleanRepresentation }
352 };
353
354 static const int kNumberOfKeyAttributes = sizeof(gKeyAttributes) / sizeof(InternalAttributeListInfo);
355
356
357 static void* CloneDataByType(ItemRepresentation type, CFTypeRef value, UInt32& length)
358 {
359 switch (type)
360 {
361 case kStringRepresentation:
362 {
363 if (CFStringGetTypeID() != CFGetTypeID(value)) {
364 length = 0;
365 return NULL;
366 }
367 CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef) value), kCFStringEncodingUTF8) + 1;
368 char* buffer = (char*) malloc(maxLength);
369 Boolean converted = CFStringGetCString((CFStringRef) value, buffer, maxLength, kCFStringEncodingUTF8);
370 if (converted) {
371 length = strlen(buffer);
372 }
373 else {
374 length = 0;
375 free(buffer);
376 buffer = NULL;
377 }
378 return buffer;
379 }
380
381 case kDataRepresentation:
382 {
383 if (CFDataGetTypeID() != CFGetTypeID(value)) {
384 length = 0;
385 return NULL;
386 }
387 length = CFDataGetLength((CFDataRef) value);
388 uint8_t* buffer = (uint8_t*) malloc(length);
389 CFDataGetBytes((CFDataRef) value, CFRangeMake(0, length), buffer);
390 return buffer;
391 }
392
393 case kNumberRepresentation:
394 {
395 if (CFNumberGetTypeID() != CFGetTypeID(value)) {
396 length = 0;
397 return NULL;
398 }
399 uint32_t* buffer = (uint32_t*) malloc(sizeof(uint32_t));
400 Boolean converted = CFNumberGetValue((CFNumberRef) value, kCFNumberSInt32Type, buffer);
401 if (converted) {
402 length = sizeof(uint32_t);
403 }
404 else {
405 length = 0;
406 free(buffer);
407 buffer = NULL;
408 }
409 return buffer;
410 }
411
412 case kBooleanRepresentation:
413 {
414 if (CFBooleanGetTypeID() != CFGetTypeID(value)) {
415 length = 0;
416 return NULL;
417 }
418 uint32_t* buffer = (uint32_t*) malloc(sizeof(uint32_t));
419 *buffer = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
420 length = sizeof(uint32_t);
421 return buffer;
422 }
423
424 case kDateRepresentation:
425 {
426 if (CFDateGetTypeID() != CFGetTypeID(value)) {
427 length = 0;
428 return NULL;
429 }
430 char* buffer = (char*) calloc(1, 32); // max length of a CSSM date string
431 CSSMDateTimeUtils::CFDateToCssmDate((CFDateRef) value, buffer);
432 length = strlen(buffer);
433 return buffer;
434 }
435
436 default:
437 {
438 length = 0;
439 return NULL;
440 }
441 }
442 }
443
444
445 static OSStatus
446 _ConvertNewFormatToOldFormat(
447 CFAllocatorRef allocator,
448 const InternalAttributeListInfo* info,
449 int infoNumItems,
450 CFDictionaryRef dictionaryRef,
451 SecKeychainAttributeList* &attrList
452 )
453 {
454 // get the keychain attributes array from the data item
455 // here's the problem. On the one hand, we have a dictionary that is purported to contain
456 // attributes for our type. On the other hand, the dictionary may contain items we don't support,
457 // and we therefore don't know how many attributes we will have unless we count them first
458
459 // setup the return
460 attrList = (SecKeychainAttributeList*) calloc(1, sizeof(SecKeychainAttributeList));
461
462 // make storage to extract the dictionary items
463 int itemsInDictionary = CFDictionaryGetCount(dictionaryRef);
464 CFTypeRef keys[itemsInDictionary];
465 CFTypeRef values[itemsInDictionary];
466
467 CFTypeRef *keysPtr = keys;
468 CFTypeRef *valuesPtr = values;
469
470 CFDictionaryGetKeysAndValues(dictionaryRef, keys, values);
471
472 // count the number of items we are interested in
473 int count = 0;
474 int i;
475
476 // since this is one of those nasty order n^2 loops, we cache as much stuff as possible so that
477 // we don't pay the price for this twice
478 SecKeychainAttrType tags[itemsInDictionary];
479 ItemRepresentation types[itemsInDictionary];
480
481 for (i = 0; i < itemsInDictionary; ++i)
482 {
483 CFTypeRef key = keysPtr[i];
484
485 int j;
486 for (j = 0; j < infoNumItems; ++j)
487 {
488 if (CFEqual(*(info[j].newItemType), key))
489 {
490 tags[i] = info[j].oldItemType;
491 types[i] = info[j].itemRepresentation;
492 count += 1;
493 break;
494 }
495 }
496
497 if (j >= infoNumItems)
498 {
499 // if we got here, we aren't interested in this item.
500 valuesPtr[i] = NULL;
501 }
502 }
503
504 // now we can make the result array
505 attrList->count = count;
506 attrList->attr = (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count);
507
508 // fill out the array
509 int resultPointer = 0;
510 for (i = 0; i < itemsInDictionary; ++i)
511 {
512 if (values[i] != NULL)
513 {
514 attrList->attr[resultPointer].tag = tags[i];
515
516 // we have to clone the data pointer. The caller will need to make sure to throw these away
517 // with _FreeAttrList when it is done...
518 attrList->attr[resultPointer].data = CloneDataByType(types[i], valuesPtr[i], attrList->attr[resultPointer].length);
519 resultPointer += 1;
520 }
521 }
522
523 return noErr;
524 }
525
526
527
528 static OSStatus
529 _ConvertOldFormatToNewFormat(
530 CFAllocatorRef allocator,
531 const InternalAttributeListInfo* info,
532 int infoNumItems,
533 SecKeychainItemRef itemRef,
534 CFMutableDictionaryRef& dictionaryRef)
535 {
536 SecKeychainAttributeList list;
537 list.count = infoNumItems;
538 list.attr = (SecKeychainAttribute*) calloc(infoNumItems, sizeof(SecKeychainAttribute));
539
540 // fill out the array. We only need to fill in the tags, since calloc zeros what it returns
541 int i;
542 for (i = 0; i < infoNumItems; ++i)
543 {
544 list.attr[i].tag = info[i].oldItemType;
545 }
546
547 OSStatus result = SecKeychainItemCopyContent(itemRef, NULL, &list, NULL, NULL);
548 if (result != noErr)
549 {
550 dictionaryRef = NULL;
551 free(list.attr);
552 return result;
553 }
554
555 // create the dictionary
556 dictionaryRef = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
557
558 // add the pairs
559 for (i = 0; i < infoNumItems; ++i)
560 {
561 if (list.attr[i].data == NULL)
562 continue;
563
564 switch (info[i].itemRepresentation)
565 {
566 case kStringRepresentation:
567 {
568 CFStringRef stringRef;
569 if (info[i].oldItemType == kSecKeyKeyClass) {
570 // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant
571 uint32_t keyRecordValue = *((uint32_t*)list.attr[i].data);
572 bool retainString = true;
573 switch (keyRecordValue) {
574 case CSSM_DL_DB_RECORD_PUBLIC_KEY :
575 stringRef = (CFStringRef) kSecAttrKeyClassPublic;
576 break;
577 case CSSM_DL_DB_RECORD_PRIVATE_KEY:
578 stringRef = (CFStringRef) kSecAttrKeyClassPrivate;
579 break;
580 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
581 stringRef = (CFStringRef) kSecAttrKeyClassSymmetric;
582 break;
583 default:
584 stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyRecordValue);
585 break;
586 }
587 if (stringRef) {
588 if (retainString) CFRetain(stringRef);
589 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
590 CFRelease(stringRef);
591 }
592 }
593 else if (info[i].oldItemType == kSecKeyKeyType) {
594 // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant
595 uint32_t keyAlgValue = *((uint32_t*)list.attr[i].data);
596 bool retainString = true;
597 switch (keyAlgValue) {
598 case CSSM_ALGID_RSA :
599 stringRef = (CFStringRef) kSecAttrKeyTypeRSA;
600 break;
601 case CSSM_ALGID_DSA :
602 stringRef = (CFStringRef) kSecAttrKeyTypeDSA;
603 break;
604 case CSSM_ALGID_AES :
605 stringRef = (CFStringRef) kSecAttrKeyTypeAES;
606 break;
607 case CSSM_ALGID_DES :
608 stringRef = (CFStringRef) kSecAttrKeyTypeDES;
609 break;
610 case CSSM_ALGID_3DES :
611 stringRef = (CFStringRef) kSecAttrKeyType3DES;
612 break;
613 case CSSM_ALGID_RC4 :
614 stringRef = (CFStringRef) kSecAttrKeyTypeRC4;
615 break;
616 case CSSM_ALGID_RC2 :
617 stringRef = (CFStringRef) kSecAttrKeyTypeRC2;
618 break;
619 case CSSM_ALGID_CAST :
620 stringRef = (CFStringRef) kSecAttrKeyTypeCAST;
621 break;
622 case CSSM_ALGID_ECDSA :
623 stringRef = (CFStringRef) kSecAttrKeyTypeECDSA;
624 break;
625 default :
626 stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyAlgValue);
627 retainString = false;
628 break;
629 }
630 if (stringRef) {
631 if (retainString) CFRetain(stringRef);
632 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
633 CFRelease(stringRef);
634 }
635 }
636 else {
637 // normal case: attribute contains a string
638 stringRef = CFStringCreateWithBytes(allocator, (UInt8*)list.attr[i].data, list.attr[i].length, kCFStringEncodingUTF8, FALSE);
639 if (stringRef == NULL)
640 stringRef = (CFStringRef) CFRetain(kCFNull);
641 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), stringRef);
642 CFRelease(stringRef);
643 }
644 }
645 break;
646
647 case kDataRepresentation:
648 {
649 CFDataRef dataRef = CFDataCreate(allocator, (UInt8*) list.attr[i].data, list.attr[i].length);
650 if (dataRef == NULL)
651 dataRef = (CFDataRef) CFRetain(kCFNull);
652 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), dataRef);
653 CFRelease(dataRef);
654 }
655 break;
656
657 case kNumberRepresentation:
658 {
659 CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, list.attr[i].data);
660 if (numberRef == NULL)
661 numberRef = (CFNumberRef) CFRetain(kCFNull);
662 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), numberRef);
663 CFRelease(numberRef);
664 }
665 break;
666
667 case kBooleanRepresentation:
668 {
669 uint32_t value = *((uint32_t*)list.attr[i].data);
670 CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
671 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), boolRef);
672 }
673 break;
674
675 case kDateRepresentation:
676 {
677 CFDateRef dateRef = NULL;
678 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)list.attr[i].data, list.attr[i].length, &dateRef);
679 if (dateRef == NULL)
680 dateRef = (CFDateRef) CFRetain(kCFNull);
681 CFDictionaryAddValue(dictionaryRef, *(info[i].newItemType), dateRef);
682 CFRelease(dateRef);
683 }
684 break;
685 }
686 }
687
688 // cleanup
689 SecKeychainItemFreeContent(&list, NULL);
690 free(list.attr);
691
692 return result;
693 }
694
695
696
697 //
698 /*
699 * _CreateAttributesDictionaryFromGenericPasswordItem creates a CFDictionaryRef using the
700 * attributes of item.
701 */
702 static OSStatus
703 _CreateAttributesDictionaryFromGenericPasswordItem(
704 CFAllocatorRef allocator,
705 SecKeychainItemRef item,
706 CFDictionaryRef *dictionary)
707 {
708 // do the basic allocations
709 CFMutableDictionaryRef dict = NULL;
710 OSStatus result = _ConvertOldFormatToNewFormat(allocator, gGenericPasswordAttributes, kNumberOfGenericPasswordAttributes, item, dict);
711 if (result == noErr) // did we complete OK
712 {
713 CFDictionaryAddValue(dict, kSecClass, kSecClassGenericPassword);
714 }
715
716 *dictionary = dict;
717
718 return result;
719 }
720
721
722
723 /*
724 * _CreateAttributesDictionaryFromCertificateItem creates a CFDictionaryRef using the
725 * attributes of item.
726 */
727 static OSStatus
728 _CreateAttributesDictionaryFromCertificateItem(
729 CFAllocatorRef allocator,
730 SecKeychainItemRef item,
731 CFDictionaryRef *dictionary)
732 {
733 // do the basic allocations
734 CFMutableDictionaryRef dict = NULL;
735 OSStatus result = _ConvertOldFormatToNewFormat(allocator, gCertificateAttributes, kNumberOfCertificateAttributes, item, dict);
736 if (result == noErr) // did we complete OK
737 {
738 CFDictionaryAddValue(dict, kSecClass, kSecClassCertificate);
739 }
740
741 *dictionary = dict;
742
743 return noErr;
744 }
745
746 /*
747 * _CreateAttributesDictionaryFromKeyItem creates a CFDictionaryRef using the
748 * attributes of item.
749 */
750 static OSStatus
751 _CreateAttributesDictionaryFromKeyItem(
752 CFAllocatorRef allocator,
753 SecKeychainItemRef item,
754 CFDictionaryRef *dictionary)
755 {
756 #if 0
757 //%%%FIXME this ought to work, but the call to SecKeychainCopyContent in _ConvertOldFormatToNewFormat fails.
758 // Need to rewrite _ConvertOldFormatToNewFormat so that it uses SecKeychainAttributeInfoForItemID and
759 // SecKeychainItemCopyAttributesAndData to get the attributes, rather than SecKeychainCopyContent.
760
761 if (status) {
762 goto error_exit; // unable to get the attribute info (i.e. database schema)
763 }
764
765 status = SecKeychainItemCopyAttributesAndData(item, info, &itemClass, &attrList, NULL, NULL);
766
767 // do the basic allocations
768 CFMutableDictionaryRef dict = NULL;
769 OSStatus result = _ConvertOldFormatToNewFormat(allocator, gKeyAttributes, kNumberOfKeyAttributes, item, dict);
770 if (result == noErr) // did we complete OK
771 {
772 CFDictionaryAddValue(dict, kSecClass, kSecClassKey);
773 }
774
775 *dictionary = dict;
776
777 return noErr;
778 #endif
779
780 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
781 unsigned int ix;
782 SecItemClass itemClass = 0;
783 UInt32 itemID;
784 SecKeychainAttributeList *attrList = NULL;
785 SecKeychainAttributeInfo *info = NULL;
786 SecKeychainRef keychain = NULL;
787
788 OSStatus status = SecKeychainItemCopyAttributesAndData(item, NULL, &itemClass, NULL, NULL, NULL);
789 if (status) {
790 goto error_exit; // item must have an itemClass
791 }
792
793 switch (itemClass)
794 {
795 case kSecInternetPasswordItemClass:
796 itemID = CSSM_DL_DB_RECORD_INTERNET_PASSWORD;
797 break;
798 case kSecGenericPasswordItemClass:
799 itemID = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
800 break;
801 case kSecAppleSharePasswordItemClass:
802 itemID = CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD;
803 break;
804 default:
805 itemID = itemClass;
806 break;
807 }
808
809 status = SecKeychainItemCopyKeychain(item, &keychain);
810 if (status) {
811 goto error_exit; // item must have a keychain, so we can get the attribute info for it
812 }
813
814 status = SecKeychainAttributeInfoForItemID(keychain, itemID, &info);
815 if (status) {
816 goto error_exit; // unable to get the attribute info (i.e. database schema)
817 }
818
819 status = SecKeychainItemCopyAttributesAndData(item, info, &itemClass, &attrList, NULL, NULL);
820 if (status) {
821 goto error_exit; // unable to get the attribute info (i.e. database schema)
822 }
823
824 for (ix = 0; ix < info->count; ++ix)
825 {
826 SecKeychainAttribute *attribute = &attrList->attr[ix];
827 if (!attribute->length && !attribute->data)
828 continue;
829
830 UInt32 j, count = kNumberOfKeyAttributes;
831 InternalAttributeListInfo *intInfo = NULL;
832 for (j=0; j<count; j++) {
833 if (gKeyAttributes[j].oldItemType == info->tag[ix]) {
834 intInfo = &gKeyAttributes[j];
835 break;
836 }
837 }
838 if (!intInfo)
839 continue;
840
841 switch (intInfo->itemRepresentation)
842 {
843 case kStringRepresentation:
844 {
845 CFStringRef stringRef;
846 if (intInfo->oldItemType == kSecKeyKeyClass) {
847 // special case: kSecKeyKeyClass is a UInt32 value that maps to a CFStringRef constant
848 UInt32 keyRecordValue = *((UInt32*)attribute->data);
849 bool retainString = true;
850 switch (keyRecordValue) {
851 case CSSM_DL_DB_RECORD_PUBLIC_KEY :
852 stringRef = (CFStringRef) kSecAttrKeyClassPublic;
853 break;
854 case CSSM_DL_DB_RECORD_PRIVATE_KEY:
855 stringRef = (CFStringRef) kSecAttrKeyClassPrivate;
856 break;
857 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
858 stringRef = (CFStringRef) kSecAttrKeyClassSymmetric;
859 break;
860 default:
861 stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyRecordValue);
862 break;
863 }
864 if (stringRef) {
865 if (retainString) CFRetain(stringRef);
866 CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
867 CFRelease(stringRef);
868 }
869 }
870 else if (intInfo->oldItemType == kSecKeyKeyType) {
871 // special case: kSecKeyKeyType is a UInt32 value that maps to a CFStringRef constant
872 UInt32 keyAlgValue = *((UInt32*)attribute->data);
873 bool retainString = true;
874 switch (keyAlgValue) {
875 case CSSM_ALGID_RSA :
876 stringRef = (CFStringRef) kSecAttrKeyTypeRSA;
877 break;
878 case CSSM_ALGID_DSA :
879 stringRef = (CFStringRef) kSecAttrKeyTypeDSA;
880 break;
881 case CSSM_ALGID_AES :
882 stringRef = (CFStringRef) kSecAttrKeyTypeAES;
883 break;
884 case CSSM_ALGID_DES :
885 stringRef = (CFStringRef) kSecAttrKeyTypeDES;
886 break;
887 case CSSM_ALGID_3DES :
888 stringRef = (CFStringRef) kSecAttrKeyType3DES;
889 break;
890 case CSSM_ALGID_RC4 :
891 stringRef = (CFStringRef) kSecAttrKeyTypeRC4;
892 break;
893 case CSSM_ALGID_RC2 :
894 stringRef = (CFStringRef) kSecAttrKeyTypeRC2;
895 break;
896 case CSSM_ALGID_CAST :
897 stringRef = (CFStringRef) kSecAttrKeyTypeCAST;
898 break;
899 case CSSM_ALGID_ECDSA :
900 stringRef = (CFStringRef) kSecAttrKeyTypeECDSA;
901 break;
902 default :
903 stringRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%d"), keyAlgValue);
904 retainString = false;
905 break;
906 }
907 if (stringRef) {
908 if (retainString) CFRetain(stringRef);
909 CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
910 CFRelease(stringRef);
911 }
912 }
913 else {
914 // normal case: attribute contains a string
915 stringRef = CFStringCreateWithBytes(allocator, (UInt8*)attribute->data, attribute->length, kCFStringEncodingUTF8, FALSE);
916 if (stringRef == NULL)
917 stringRef = (CFStringRef) CFRetain(kCFNull);
918 CFDictionaryAddValue(dict, *(intInfo->newItemType), stringRef);
919 CFRelease(stringRef);
920 }
921 }
922 break;
923
924 case kDataRepresentation:
925 {
926 CFDataRef dataRef = CFDataCreate(allocator, (UInt8*)attribute->data, attribute->length);
927 if (dataRef == NULL)
928 dataRef = (CFDataRef) CFRetain(kCFNull);
929 CFDictionaryAddValue(dict, *(intInfo->newItemType), dataRef);
930 CFRelease(dataRef);
931 }
932 break;
933
934 case kNumberRepresentation:
935 {
936 CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, attribute->data);
937 if (numberRef == NULL)
938 numberRef = (CFNumberRef) CFRetain(kCFNull);
939 CFDictionaryAddValue(dict, *(intInfo->newItemType), numberRef);
940 CFRelease(numberRef);
941 }
942 break;
943
944 case kBooleanRepresentation:
945 {
946 UInt32 value = *((UInt32*)attribute->data);
947 CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
948 CFDictionaryAddValue(dict, *(intInfo->newItemType), boolRef);
949 }
950 break;
951
952 case kDateRepresentation:
953 {
954 //%%% FIXME need to convert from a CSSM date string to a CFDateRef here
955 CFDateRef dateRef = NULL;
956 if (dateRef == NULL)
957 dateRef = (CFDateRef) CFRetain(kCFNull);
958 CFDictionaryAddValue(dict, *(intInfo->newItemType), dateRef);
959 CFRelease(dateRef);
960 }
961 break;
962 }
963 }
964
965 CFDictionaryAddValue(dict, kSecClass, kSecClassKey);
966
967 error_exit:
968
969 if (attrList)
970 SecKeychainItemFreeAttributesAndData(attrList, NULL);
971
972 if (info)
973 SecKeychainFreeAttributeInfo(info);
974
975 if (keychain)
976 CFRelease(keychain);
977
978 *dictionary = dict;
979
980 return status;
981 }
982
983
984 /*
985 * _CreateAttributesDictionaryFromInternetPasswordItem creates a CFDictionaryRef using the
986 * attributes of item.
987 */
988 static OSStatus
989 _CreateAttributesDictionaryFromInternetPasswordItem(
990 CFAllocatorRef allocator,
991 SecKeychainItemRef item,
992 CFDictionaryRef *dictionary)
993 {
994 OSStatus status;
995 SecKeychainAttribute attr[] = {
996 { kSecServerItemAttr, 0, NULL }, /* [0] server */
997 { kSecSecurityDomainItemAttr, 0, NULL }, /* [1] securityDomain */
998 { kSecAccountItemAttr, 0, NULL }, /* [2] account */
999 { kSecPathItemAttr, 0, NULL }, /* [3] path */
1000 { kSecPortItemAttr, 0, NULL }, /* [4] port */
1001 { kSecProtocolItemAttr, 0, NULL }, /* [5] protocol */
1002 { kSecAuthenticationTypeItemAttr, 0, NULL }, /* [6] authenticationType */
1003 { kSecCommentItemAttr, 0, NULL }, /* [7] comment */
1004 { kSecDescriptionItemAttr, 0, NULL }, /* [8] description */
1005 { kSecLabelItemAttr, 0, NULL }, /* [9] label */
1006 { kSecCreationDateItemAttr, 0, NULL }, /* [10] creation date */
1007 { kSecModDateItemAttr, 0, NULL }, /* [11] modification date */
1008 { kSecCreatorItemAttr, 0, NULL }, /* [12] creator */
1009 { kSecTypeItemAttr, 0, NULL }, /* [13] type */
1010 { kSecInvisibleItemAttr, 0, NULL }, /* [14] invisible */
1011 { kSecNegativeItemAttr, 0, NULL }, /* [15] negative */
1012 };
1013 SecKeychainAttributeList attrList = { sizeof(attr) / sizeof(SecKeychainAttribute), attr };
1014 CFIndex numValues;
1015 CFIndex index;
1016 CFTypeRef keys[(sizeof(attr) / sizeof(SecKeychainAttribute)) + 2];
1017 CFTypeRef values[(sizeof(attr) / sizeof(SecKeychainAttribute)) + 2];
1018
1019 *dictionary = NULL;
1020
1021 // copy the item's attributes
1022 status = SecKeychainItemCopyContent(item, NULL, &attrList, NULL, NULL);
1023 require_noerr(status, SecKeychainItemCopyContent_failed);
1024
1025 numValues = 0;
1026
1027 // add kSecClass
1028 keys[numValues] = kSecClass;
1029 values[numValues] = kSecClassInternetPassword;
1030 ++numValues;
1031
1032 // add kSecAttrServer
1033 if ( attrList.attr[0].length > 0 ) {
1034 keys[numValues] = kSecAttrServer;
1035 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[0].data, attrList.attr[0].length, kCFStringEncodingUTF8, FALSE);
1036 if ( values[numValues] != NULL ) {
1037 ++numValues;
1038 }
1039 }
1040
1041 // add kSecAttrSecurityDomain
1042 if ( attrList.attr[1].length > 0 ) {
1043 keys[numValues] = kSecAttrSecurityDomain;
1044 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[1].data, attrList.attr[1].length, kCFStringEncodingUTF8, FALSE);
1045 if ( values[numValues] != NULL ) {
1046 ++numValues;
1047 }
1048 }
1049
1050 // add kSecAttrAccount
1051 if ( attrList.attr[2].length > 0 ) {
1052 keys[numValues] = kSecAttrAccount;
1053 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[2].data, attrList.attr[2].length, kCFStringEncodingUTF8, FALSE);
1054 if ( values[numValues] != NULL ) {
1055 ++numValues;
1056 }
1057 }
1058
1059 // add kSecAttrPath
1060 if ( attrList.attr[3].length > 0 ) {
1061 keys[numValues] = kSecAttrPath;
1062 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[3].data, attrList.attr[3].length, kCFStringEncodingUTF8, FALSE);
1063 if ( values[numValues] != NULL ) {
1064 ++numValues;
1065 }
1066 }
1067
1068 // add kSecAttrPort
1069 if ( attrList.attr[4].length > 0 ) {
1070 keys[numValues] = kSecAttrPort;
1071 values[numValues] = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[4].data);
1072 if ( values[numValues] != NULL ) {
1073 ++numValues;
1074 }
1075 }
1076
1077 // add kSecAttrProtocol
1078 if ( attrList.attr[5].length > 0 ) {
1079 keys[numValues] = kSecAttrProtocol;
1080 values[numValues] = _SecAttrProtocolForSecProtocolType(*(SecProtocolType*)attrList.attr[5].data);
1081 if ( values[numValues] != NULL ) {
1082 CFRetain(values[numValues]);
1083 ++numValues;
1084 }
1085 }
1086
1087 // add kSecAttrAuthenticationType
1088 if ( attrList.attr[6].length > 0 ) {
1089 keys[numValues] = kSecAttrAuthenticationType;
1090 values[numValues] = _SecAttrAuthenticationTypeForSecAuthenticationType(*(SecProtocolType*)attrList.attr[6].data);
1091 if ( values[numValues] != NULL ) {
1092 CFRetain(values[numValues]);
1093 ++numValues;
1094 }
1095 }
1096
1097 // add kSecAttrComment
1098 if ( attrList.attr[7].length > 0 ) {
1099 keys[numValues] = kSecAttrComment;
1100 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[7].data, attrList.attr[7].length, kCFStringEncodingUTF8, FALSE);
1101 if ( values[numValues] != NULL ) {
1102 ++numValues;
1103 }
1104 }
1105
1106 // add kSecAttrDescription
1107 if ( attrList.attr[8].length > 0 ) {
1108 keys[numValues] = kSecAttrDescription;
1109 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[8].data, attrList.attr[8].length, kCFStringEncodingUTF8, FALSE);
1110 if ( values[numValues] != NULL ) {
1111 ++numValues;
1112 }
1113 }
1114
1115 // add kSecAttrLabel
1116 if ( attrList.attr[9].length > 0 ) {
1117 keys[numValues] = kSecAttrLabel;
1118 values[numValues] = CFStringCreateWithBytes(allocator, (UInt8 *)attrList.attr[9].data, attrList.attr[9].length, kCFStringEncodingUTF8, FALSE);
1119 if ( values[numValues] != NULL ) {
1120 ++numValues;
1121 }
1122 }
1123
1124 // add kSecAttrCreationDate
1125 if ( attrList.attr[10].length > 0 ) {
1126 CFDateRef creationDate = NULL;
1127 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList.attr[10].data, attrList.attr[10].length, &creationDate);
1128 keys[numValues] = kSecAttrCreationDate;
1129 values[numValues] = creationDate;
1130 if ( values[numValues] != NULL ) {
1131 ++numValues;
1132 }
1133 }
1134
1135 // add kSecAttrModificationDate
1136 if ( attrList.attr[11].length > 0 ) {
1137 CFDateRef modDate = NULL;
1138 CSSMDateTimeUtils::CssmDateStringToCFDate((const char *)attrList.attr[11].data, attrList.attr[11].length, &modDate);
1139 keys[numValues] = kSecAttrModificationDate;
1140 values[numValues] = modDate;
1141 if ( values[numValues] != NULL ) {
1142 ++numValues;
1143 }
1144 }
1145
1146 // add kSecCreatorItemAttr
1147 if ( attrList.attr[12].length > 0 ) {
1148 CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[12].data);
1149 keys[numValues] = kSecAttrCreator;
1150 values[numValues] = numberRef;
1151 if ( values[numValues] != NULL ) {
1152 CFRetain(values[numValues]);
1153 ++numValues;
1154 }
1155 }
1156
1157 // add kSecTypeItemAttr
1158 if ( attrList.attr[13].length > 0 ) {
1159 CFNumberRef numberRef = CFNumberCreate(allocator, kCFNumberSInt32Type, attrList.attr[13].data);
1160 keys[numValues] = kSecAttrType;
1161 values[numValues] = numberRef;
1162 if ( values[numValues] != NULL ) {
1163 CFRetain(values[numValues]);
1164 ++numValues;
1165 }
1166 }
1167
1168 // add kSecInvisibleItemAttr
1169 if ( attrList.attr[14].length > 0 ) {
1170 uint32_t value = *((uint32_t*)attrList.attr[14].data);
1171 CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
1172 keys[numValues] = kSecAttrIsInvisible;
1173 values[numValues] = boolRef;
1174 if ( values[numValues] != NULL ) {
1175 CFRetain(values[numValues]);
1176 ++numValues;
1177 }
1178 }
1179
1180 // add kSecNegativeItemAttr
1181 if ( attrList.attr[15].length > 0 ) {
1182 uint32_t value = *((uint32_t*)attrList.attr[15].data);
1183 CFBooleanRef boolRef = (value) ? kCFBooleanTrue : kCFBooleanFalse;
1184 keys[numValues] = kSecAttrIsNegative;
1185 values[numValues] = boolRef;
1186 if ( values[numValues] != NULL ) {
1187 CFRetain(values[numValues]);
1188 ++numValues;
1189 }
1190 }
1191
1192 // create the dictionary
1193 *dictionary = CFDictionaryCreate(allocator, keys, values, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1194
1195 // release the values added to the dictionary
1196 for ( index = 0; index < numValues; ++index )
1197 {
1198 CFRelease(values[index]);
1199 }
1200
1201 // and free the attributes
1202 (void) SecKeychainItemFreeContent(&attrList, NULL);
1203
1204 SecKeychainItemCopyContent_failed:
1205
1206 return ( status );
1207 }
1208
1209
1210 /*
1211 * _CreateAttributesDictionaryFromItem creates a CFDictionaryRef using the
1212 * attributes of the specified item class and item.
1213 */
1214 static OSStatus
1215 _CreateAttributesDictionaryFromItem(
1216 CFAllocatorRef allocator,
1217 SecItemClass itemClass,
1218 SecKeychainItemRef item,
1219 CFDictionaryRef *dictionary)
1220 {
1221 switch (itemClass)
1222 {
1223 case kSecInternetPasswordItemClass:
1224 return _CreateAttributesDictionaryFromInternetPasswordItem(allocator, item, dictionary);
1225
1226 case kSecGenericPasswordItemClass:
1227 return _CreateAttributesDictionaryFromGenericPasswordItem(allocator, item, dictionary);
1228
1229 case kSecCertificateItemClass:
1230 return _CreateAttributesDictionaryFromCertificateItem(allocator, item, dictionary);
1231
1232 case kSecPublicKeyItemClass:
1233 case kSecPrivateKeyItemClass:
1234 case kSecSymmetricKeyItemClass:
1235 return _CreateAttributesDictionaryFromKeyItem(allocator, item, dictionary);
1236
1237 default:
1238 *dictionary = NULL;
1239 break;
1240 }
1241 return paramErr;
1242 }
1243
1244
1245 /*
1246 * _FreeAttrList frees the memory allocated for the SecKeychainAttributeList
1247 * by the _CreateSecKeychainAttributeListFromDictionary function.
1248 */
1249 static void
1250 _FreeAttrList(
1251 SecKeychainAttributeList *attrListPtr)
1252 {
1253 UInt32 index;
1254
1255 if ( attrListPtr != NULL ) {
1256 if ( attrListPtr->attr != NULL ) {
1257 // free any attribute data
1258 for ( index = 0; index < attrListPtr->count; ++index ) {
1259 free(attrListPtr->attr[index].data);
1260 }
1261 // free the attribute array
1262 free(attrListPtr->attr);
1263 }
1264 // free the attribute list
1265 free(attrListPtr);
1266 }
1267 }
1268
1269 /*
1270 * _CFDataCreateAttribute initializes the SecKeychainAttribute pointed to by
1271 * attr using the data and tag parameters.
1272 *
1273 * The memory for the SecKeychainAttribute's data field is allocated with malloc
1274 * and must be released by the caller (this is normally done by calling _FreeAttrList).
1275 */
1276 static OSStatus
1277 _CFDataCreateAttribute(
1278 CFDataRef data,
1279 SecKeychainAttrType tag,
1280 SecKeychainAttributePtr attr)
1281 {
1282 OSStatus status = noErr;
1283 CFRange range;
1284
1285 // set the attribute tag
1286 attr->tag = tag;
1287
1288 // determine the attribute length
1289 attr->length = CFDataGetLength(data);
1290 range = CFRangeMake(0, (CFIndex)attr->length);
1291
1292 // allocate memory for the attribute bytes
1293 attr->data = malloc(attr->length);
1294 require_action(attr->data != NULL, malloc_failed, status = errSecBufferTooSmall);
1295
1296 // get the attribute bytes
1297 CFDataGetBytes(data, range, (UInt8 *)attr->data);
1298
1299 malloc_failed:
1300
1301 return ( status );
1302 }
1303
1304 /*
1305 * _CFStringCreateAttribute initializes the SecKeychainAttribute pointed to by
1306 * attr using the string and tag parameters.
1307 *
1308 * The memory for the SecKeychainAttribute's data field is allocated with malloc
1309 * and must be released by the caller (this is normally done by calling _FreeAttrList).
1310 */
1311 static OSStatus
1312 _CFStringCreateAttribute(
1313 CFStringRef string,
1314 SecKeychainAttrType tag,
1315 SecKeychainAttributePtr attr)
1316 {
1317 OSStatus status = noErr;
1318 CFRange range;
1319
1320 // set the attribute tag
1321 attr->tag = tag;
1322
1323 // determine the attribute length
1324 range = CFRangeMake(0, CFStringGetLength(string));
1325 CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, FALSE, NULL, 0, (CFIndex *)&attr->length);
1326
1327 // allocate memory for the attribute bytes
1328 attr->data = malloc(attr->length);
1329 require_action(attr->data != NULL, malloc_failed, status = errSecBufferTooSmall);
1330
1331 // get the attribute bytes
1332 CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, FALSE, (UInt8 *)attr->data, attr->length, NULL);
1333
1334 malloc_failed:
1335
1336 return ( status );
1337 }
1338
1339
1340 /*
1341 * _CreateSecKeychainGenericPasswordAttributeListFromDictionary creates a SecKeychainAttributeList
1342 * from the attribute key/values in attrDictionary.
1343 *
1344 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1345 * must be freed by the caller with _FreeAttrList()
1346 */
1347 static OSStatus
1348 _CreateSecKeychainGenericPasswordAttributeListFromDictionary(
1349 CFDictionaryRef attrDictionary,
1350 SecKeychainAttributeList **attrList)
1351 {
1352 return _ConvertNewFormatToOldFormat(NULL, gGenericPasswordAttributes, kNumberOfGenericPasswordAttributes, attrDictionary, *attrList);
1353 }
1354
1355
1356 /*
1357 * _CreateSecKeychainCertificateAttributeListFromDictionary creates a SecKeychainAttributeList
1358 * from the attribute key/values in attrDictionary.
1359 *
1360 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1361 * must be freed by the caller with _FreeAttrList()
1362 */
1363 static OSStatus
1364 _CreateSecKeychainCertificateAttributeListFromDictionary(
1365 CFDictionaryRef attrDictionary,
1366 SecKeychainAttributeList **attrList)
1367 {
1368 return _ConvertNewFormatToOldFormat(NULL, gCertificateAttributes, kNumberOfCertificateAttributes, attrDictionary, *attrList);
1369 }
1370
1371
1372 /*
1373 * _CreateSecKeychainKeyAttributeListFromDictionary creates a SecKeychainAttributeList
1374 * from the attribute key/values in attrDictionary.
1375 *
1376 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1377 * must be freed by the caller with _FreeAttrList()
1378 */
1379 static OSStatus
1380 _CreateSecKeychainKeyAttributeListFromDictionary(
1381 CFDictionaryRef attrDictionary,
1382 SecKeychainAttributeList **attrList)
1383 {
1384 #if 0
1385 //%%%FIXME this function should work for key attributes, but currently doesn't; need to debug
1386 return _ConvertNewFormatToOldFormat(NULL, gKeyAttributes, kNumberOfKeyAttributes, attrDictionary, *attrList);
1387 #else
1388 // explicitly build attribute list for supported key attributes
1389 // NOTE: this code supports only MaxSecKeyAttributes (15) attributes
1390 const int MaxSecKeyAttributes = 15;
1391
1392 OSStatus status;
1393 CFTypeRef value;
1394 SecKeychainAttributeList *attrListPtr;
1395
1396 attrListPtr = (SecKeychainAttributeList*)calloc(1, sizeof(SecKeychainAttributeList));
1397 require_action(attrListPtr != NULL, calloc_attrListPtr_failed, status = errSecBufferTooSmall);
1398
1399 attrListPtr->attr = (SecKeychainAttribute*)calloc(MaxSecKeyAttributes, sizeof(SecKeychainAttribute));
1400 require_action(attrListPtr->attr != NULL, malloc_attrPtr_failed, status = errSecBufferTooSmall);
1401
1402 // [0] get the kSecKeyKeyClass value
1403 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeyClass, (const void **)&value) && value) {
1404 UInt32 keyRecordValue = 0;
1405 if (CFEqual(kSecAttrKeyClassPublic, value))
1406 keyRecordValue = CSSM_DL_DB_RECORD_PUBLIC_KEY;
1407 else if (CFEqual(kSecAttrKeyClassPrivate, value))
1408 keyRecordValue = CSSM_DL_DB_RECORD_PRIVATE_KEY;
1409 else if (CFEqual(kSecAttrKeyClassSymmetric, value))
1410 keyRecordValue = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
1411
1412 // only use this attribute if we recognize the value!
1413 if (keyRecordValue != 0) {
1414 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1415 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1416
1417 attrListPtr->attr[attrListPtr->count].tag = kSecKeyKeyClass;
1418 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1419 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = keyRecordValue;
1420
1421 ++attrListPtr->count;
1422 }
1423 }
1424
1425 // [1] get the kSecKeyPrintName string
1426 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrLabel, (const void **)&value) && value) {
1427 status = _CFStringCreateAttribute((CFStringRef)value, kSecKeyPrintName, &attrListPtr->attr[attrListPtr->count]);
1428 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1429
1430 ++attrListPtr->count;
1431 }
1432
1433 // [2] get the kSecKeyPermanent boolean
1434 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrIsPermanent, (const void **)&value) && value) {
1435 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1436 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1437
1438 attrListPtr->attr[attrListPtr->count].tag = kSecKeyPermanent;
1439 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1440 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1441
1442 ++attrListPtr->count;
1443 }
1444
1445 // [3] get the kSecKeyLabel string
1446 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrApplicationLabel, (const void **)&value) && value) {
1447 status = _CFStringCreateAttribute((CFStringRef)value, kSecKeyLabel, &attrListPtr->attr[attrListPtr->count]);
1448 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1449
1450 ++attrListPtr->count;
1451 }
1452
1453 // [4] get the kSecKeyApplicationTag data
1454 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrApplicationTag, (const void **)&value) && value) {
1455 if (CFStringGetTypeID() == CFGetTypeID(value))
1456 status = _CFStringCreateAttribute((CFStringRef)value, kSecKeyApplicationTag, &attrListPtr->attr[attrListPtr->count]);
1457 else if (CFDataGetTypeID() == CFGetTypeID(value))
1458 status = _CFDataCreateAttribute((CFDataRef)value, kSecKeyApplicationTag, &attrListPtr->attr[attrListPtr->count]);
1459 else
1460 status = paramErr;
1461
1462 require_noerr_quiet(status, CFDataCreateAttribute_failed);
1463 ++attrListPtr->count;
1464 }
1465
1466 // [5] get the kSecKeyKeyType number
1467 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeyType, (const void **)&value) && value) {
1468 UInt32 keyAlgValue = _SecAlgorithmTypeFromSecAttrKeyType(kSecAttrKeyType);
1469 if (keyAlgValue != 0) {
1470 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1471 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1472
1473 attrListPtr->attr[attrListPtr->count].tag = kSecKeyKeyType;
1474 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1475 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = keyAlgValue;
1476
1477 ++attrListPtr->count;
1478 }
1479 }
1480
1481 // [6] get the kSecKeyKeySizeInBits number
1482 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrKeySizeInBits, (const void **)&value) && value) {
1483 if (CFNumberGetTypeID() == CFGetTypeID(value)) {
1484 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1485 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1486
1487 attrListPtr->attr[attrListPtr->count].tag = kSecKeyKeySizeInBits;
1488 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1489 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1490
1491 ++attrListPtr->count;
1492 }
1493 }
1494
1495 // [7] get the kSecKeyEffectiveKeySize number
1496 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrEffectiveKeySize, (const void **)&value) && value) {
1497 if (CFNumberGetTypeID() == CFGetTypeID(value)) {
1498 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1499 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1500
1501 attrListPtr->attr[attrListPtr->count].tag = kSecKeyEffectiveKeySize;
1502 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1503 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1504
1505 ++attrListPtr->count;
1506 }
1507 }
1508
1509 // [8] get the kSecKeyEncrypt boolean
1510 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanEncrypt, (const void **)&value) && value) {
1511 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1512 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1513 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1514
1515 attrListPtr->attr[attrListPtr->count].tag = kSecKeyEncrypt;
1516 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1517 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1518
1519 ++attrListPtr->count;
1520 }
1521 }
1522
1523 // [9] get the kSecKeyDecrypt boolean
1524 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanDecrypt, (const void **)&value) && value) {
1525 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1526 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1527 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1528
1529 attrListPtr->attr[attrListPtr->count].tag = kSecKeyDecrypt;
1530 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1531 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1532
1533 ++attrListPtr->count;
1534 }
1535 }
1536
1537 // [10] get the kSecKeyDerive boolean
1538 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanDerive, (const void **)&value) && value) {
1539 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1540 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1541 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1542
1543 attrListPtr->attr[attrListPtr->count].tag = kSecKeyDerive;
1544 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1545 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1546
1547 ++attrListPtr->count;
1548 }
1549 }
1550
1551 // [11] get the kSecKeySign boolean
1552 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanSign, (const void **)&value) && value) {
1553 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1554 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1555 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1556
1557 attrListPtr->attr[attrListPtr->count].tag = kSecKeySign;
1558 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1559 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1560
1561 ++attrListPtr->count;
1562 }
1563 }
1564
1565 // [12] get the kSecKeyVerify boolean
1566 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanVerify, (const void **)&value) && value) {
1567 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1568 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1569 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1570
1571 attrListPtr->attr[attrListPtr->count].tag = kSecKeyVerify;
1572 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1573 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1574
1575 ++attrListPtr->count;
1576 }
1577 }
1578
1579 // [13] get the kSecKeyWrap boolean
1580 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanWrap, (const void **)&value) && value) {
1581 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1582 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1583 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1584
1585 attrListPtr->attr[attrListPtr->count].tag = kSecKeyWrap;
1586 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1587 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1588
1589 ++attrListPtr->count;
1590 }
1591 }
1592
1593 // [14] get the kSecKeyUnwrap boolean
1594 if (CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCanUnwrap, (const void **)&value) && value) {
1595 if (CFBooleanGetTypeID() == CFGetTypeID(value)) {
1596 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1597 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_number_failed, status = errSecBufferTooSmall);
1598
1599 attrListPtr->attr[attrListPtr->count].tag = kSecKeyUnwrap;
1600 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1601 *((UInt32*)attrListPtr->attr[attrListPtr->count].data) = (CFEqual(kCFBooleanTrue, value)) ? 1 : 0;
1602
1603 ++attrListPtr->count;
1604 }
1605 }
1606
1607 // return the pointer to the attrList
1608 *attrList = attrListPtr;
1609
1610 return ( noErr );
1611
1612 /***************/
1613
1614 malloc_number_failed:
1615 CFDataCreateAttribute_failed:
1616 CFStringCreateAttribute_failed:
1617 malloc_attrPtr_failed:
1618
1619 // free any attributes
1620 _FreeAttrList(attrListPtr);
1621
1622 calloc_attrListPtr_failed:
1623
1624 return ( errSecBufferTooSmall );
1625
1626 #endif
1627 }
1628
1629
1630 /*
1631 * _CreateSecKeychainInternetPasswordAttributeListFromDictionary creates a SecKeychainAttributeList
1632 * from the attribute key/values in attrDictionary.
1633 *
1634 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1635 * must be freed by the caller with _FreeAttrList()
1636 */
1637 static OSStatus
1638 _CreateSecKeychainInternetPasswordAttributeListFromDictionary(
1639 CFDictionaryRef attrDictionary,
1640 SecKeychainAttributeList **attrList)
1641 {
1642 // explicitly build attribute list for supported key attributes
1643 // NOTE: this code supports only MaxSecKeychainAttributes (14) attributes
1644 const int MaxSecKeychainAttributes = 14;
1645
1646 OSStatus status;
1647 CFTypeRef value;
1648 SecKeychainAttributeList *attrListPtr;
1649
1650 attrListPtr = (SecKeychainAttributeList*)calloc(1, sizeof(SecKeychainAttributeList));
1651 require_action(attrListPtr != NULL, calloc_attrListPtr_failed, status = errSecBufferTooSmall);
1652
1653 attrListPtr->attr = (SecKeychainAttribute*)calloc(MaxSecKeychainAttributes, sizeof(SecKeychainAttribute));
1654 require_action(attrListPtr->attr != NULL, malloc_attrPtr_failed, status = errSecBufferTooSmall);
1655
1656
1657 // [0] get the serverName string
1658 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrServer, (const void **)&value) ) {
1659 status = _CFStringCreateAttribute((CFStringRef)value, kSecServerItemAttr, &attrListPtr->attr[attrListPtr->count]);
1660 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1661
1662 ++attrListPtr->count;
1663 }
1664
1665 // [1] get the securityDomain string
1666 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrSecurityDomain, (const void **)&value) ) {
1667 status = _CFStringCreateAttribute((CFStringRef)value, kSecSecurityDomainItemAttr, &attrListPtr->attr[attrListPtr->count]);
1668 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1669
1670 ++attrListPtr->count;
1671 }
1672
1673 // [2] get the accountName string
1674 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrAccount, (const void **)&value) ) {
1675 status = _CFStringCreateAttribute((CFStringRef)value, kSecAccountItemAttr, &attrListPtr->attr[attrListPtr->count]);
1676 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1677
1678 ++attrListPtr->count;
1679 }
1680
1681 // [3] get the path string
1682 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrPath, (const void **)&value) ) {
1683 status = _CFStringCreateAttribute((CFStringRef)value, kSecPathItemAttr, &attrListPtr->attr[attrListPtr->count]);
1684 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1685
1686 ++attrListPtr->count;
1687 }
1688
1689 // [4] get the port number
1690 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrPort, (const void **)&value) ) {
1691 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt16));
1692 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1693
1694 attrListPtr->attr[attrListPtr->count].tag = kSecPortItemAttr;
1695 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt16);
1696 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt16Type, attrListPtr->attr[attrListPtr->count].data);
1697
1698 ++attrListPtr->count;
1699 }
1700
1701 // [5] get the protocol
1702 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrProtocol, (const void **)&value) ) {
1703 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(SecProtocolType));
1704 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_protocol_failed, status = errSecBufferTooSmall);
1705
1706 attrListPtr->attr[attrListPtr->count].tag = kSecProtocolItemAttr;
1707 attrListPtr->attr[attrListPtr->count].length = sizeof(SecProtocolType);
1708 *(SecProtocolType *)(attrListPtr->attr[attrListPtr->count].data) = _SecProtocolTypeForSecAttrProtocol(value);
1709
1710 ++attrListPtr->count;
1711 }
1712
1713 // [6] get the authenticationType
1714 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrAuthenticationType, (const void **)&value) ) {
1715 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(SecAuthenticationType));
1716 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_authenticationType_failed, status = errSecBufferTooSmall);
1717
1718 attrListPtr->attr[attrListPtr->count].tag = kSecAuthenticationTypeItemAttr;
1719 attrListPtr->attr[attrListPtr->count].length = sizeof(SecAuthenticationType);
1720 *(SecAuthenticationType *)(attrListPtr->attr[attrListPtr->count].data) = _SecAuthenticationTypeForSecAttrAuthenticationType(value);
1721
1722 ++attrListPtr->count;
1723 }
1724
1725 // [7] get the comment string
1726 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrComment, (const void **)&value) ) {
1727 status = _CFStringCreateAttribute((CFStringRef)value, kSecCommentItemAttr, &attrListPtr->attr[attrListPtr->count]);
1728 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1729
1730 ++attrListPtr->count;
1731 }
1732
1733 // [8] get the description string
1734 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrDescription, (const void **)&value) ) {
1735 status = _CFStringCreateAttribute((CFStringRef)value, kSecDescriptionItemAttr, &attrListPtr->attr[attrListPtr->count]);
1736 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1737
1738 ++attrListPtr->count;
1739 }
1740
1741 // [9] get the label string
1742 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrLabel, (const void **)&value) ) {
1743 status = _CFStringCreateAttribute((CFStringRef)value, kSecLabelItemAttr, &attrListPtr->attr[attrListPtr->count]);
1744 require_noerr_quiet(status, CFStringCreateAttribute_failed);
1745
1746 ++attrListPtr->count;
1747 }
1748
1749 // [10] get the creator code
1750 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrCreator, (const void **)&value) ) {
1751 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1752 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1753
1754 attrListPtr->attr[attrListPtr->count].tag = kSecCreatorItemAttr;
1755 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1756 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1757
1758 ++attrListPtr->count;
1759 }
1760
1761 // [11] get the type code
1762 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrType, (const void **)&value) ) {
1763 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1764 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1765
1766 attrListPtr->attr[attrListPtr->count].tag = kSecTypeItemAttr;
1767 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1768 CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, attrListPtr->attr[attrListPtr->count].data);
1769
1770 ++attrListPtr->count;
1771 }
1772
1773 // [12] get the invisible flag
1774 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrIsInvisible, (const void **)&value) ) {
1775 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1776 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1777
1778 attrListPtr->attr[attrListPtr->count].tag = kSecInvisibleItemAttr;
1779 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1780 *(UInt32 *)(attrListPtr->attr[attrListPtr->count].data) = (CFBooleanGetValue((CFBooleanRef)value)) ? 1 : 0;
1781
1782 ++attrListPtr->count;
1783 }
1784
1785 // [13] get the negative flag
1786 if ( CFDictionaryGetValueIfPresent(attrDictionary, kSecAttrIsNegative, (const void **)&value) ) {
1787 attrListPtr->attr[attrListPtr->count].data = malloc(sizeof(UInt32));
1788 require_action(attrListPtr->attr[attrListPtr->count].data != NULL, malloc_port_failed, status = errSecBufferTooSmall);
1789
1790 attrListPtr->attr[attrListPtr->count].tag = kSecNegativeItemAttr;
1791 attrListPtr->attr[attrListPtr->count].length = sizeof(UInt32);
1792 *(UInt32 *)(attrListPtr->attr[attrListPtr->count].data) = (CFBooleanGetValue((CFBooleanRef)value)) ? 1 : 0;
1793
1794 ++attrListPtr->count;
1795 }
1796
1797 // return the pointer to the attrList
1798 *attrList = attrListPtr;
1799
1800 return ( noErr );
1801
1802 /***************/
1803
1804 malloc_authenticationType_failed:
1805 malloc_protocol_failed:
1806 malloc_port_failed:
1807 CFStringCreateAttribute_failed:
1808 malloc_attrPtr_failed:
1809
1810 // free any attributes
1811 _FreeAttrList(attrListPtr);
1812
1813 calloc_attrListPtr_failed:
1814
1815 return ( errSecBufferTooSmall );
1816 }
1817
1818
1819 /*
1820 * _CreateSecKeychainAttributeListFromDictionary creates a SecKeychainAttributeList
1821 * from the attribute key/values in attrDictionary for the specified item class.
1822 *
1823 * If this function returns noErr, the pointer to the SecKeychainAttributeList
1824 * must be freed by the caller with _FreeAttrList()
1825 */
1826 static OSStatus
1827 _CreateSecKeychainAttributeListFromDictionary(
1828 CFDictionaryRef attrDictionary,
1829 SecItemClass itemClass,
1830 SecKeychainAttributeList **attrList)
1831 {
1832 switch (itemClass)
1833 {
1834 case kSecInternetPasswordItemClass:
1835 return _CreateSecKeychainInternetPasswordAttributeListFromDictionary(attrDictionary, attrList);
1836
1837 case kSecGenericPasswordItemClass:
1838 return _CreateSecKeychainGenericPasswordAttributeListFromDictionary(attrDictionary, attrList);
1839
1840 case kSecCertificateItemClass:
1841 return _CreateSecKeychainCertificateAttributeListFromDictionary(attrDictionary, attrList);
1842
1843 case kSecPublicKeyItemClass:
1844 case kSecPrivateKeyItemClass:
1845 case kSecSymmetricKeyItemClass:
1846 return _CreateSecKeychainKeyAttributeListFromDictionary(attrDictionary, attrList);
1847
1848 default:
1849 break;
1850 }
1851 return paramErr;
1852 }
1853
1854
1855 /*
1856 * _AppNameFromSecTrustedApplication attempts to pull the name of the
1857 * application/tool from the SecTrustedApplicationRef.
1858 */
1859 static CFStringRef
1860 _AppNameFromSecTrustedApplication(
1861 CFAllocatorRef alloc,
1862 SecTrustedApplicationRef appRef)
1863 {
1864 CFStringRef result;
1865 OSStatus status;
1866 CFDataRef appDataRef;
1867
1868 result = NULL;
1869
1870 // get the data for item's application/tool
1871 status = SecTrustedApplicationCopyData(appRef, &appDataRef);
1872 if ( status == noErr ) {
1873 CFStringRef path;
1874
1875 // convert it to a CFString potentially containing the path
1876 path = CFStringCreateWithCString(NULL, (char *)CFDataGetBytePtrVoid(appDataRef), kCFStringEncodingUTF8);
1877 if ( path != NULL ) {
1878 // the path has to start with a "/" and cannot contain "://"
1879 if ( CFStringHasPrefix(path, CFSTR("/")) && (CFStringFind(path, CFSTR("://"), 0).location == kCFNotFound) ) {
1880 CFRange nameRange, compRg;
1881
1882 nameRange = CFRangeMake(0, CFStringGetLength(path));
1883
1884 // remove the trailing slashes (if any)
1885 while ( (nameRange.length > 0) && (CFStringGetCharacterAtIndex(path, nameRange.length - 1) == '/') ) {
1886 nameRange.length --;
1887 }
1888
1889 if ( nameRange.length > 0 ) {
1890 // find last slash and adjust nameRange be everything after it
1891 if ( CFStringFindWithOptions(path, CFSTR("/"), nameRange, kCFCompareBackwards, &compRg) ) {
1892 nameRange.length = nameRange.location + nameRange.length - (compRg.location + 1);
1893 nameRange.location = compRg.location + 1;
1894 }
1895
1896 result = CFStringCreateWithSubstring(alloc, path, nameRange);
1897 }
1898 }
1899 CFRelease(path);
1900 }
1901 CFRelease(appDataRef);
1902 }
1903
1904 return ( result );
1905 }
1906
1907 /* (This function really belongs in SecIdentity.cpp!)
1908 *
1909 * Returns the public key item corresponding to the identity, if it exists in
1910 * the same keychain as the private key. Note that the public key might not
1911 * exist in the same keychain (e.g. if the identity was imported via PKCS12),
1912 * in which case it will not be found.
1913 */
1914 static OSStatus
1915 _SecIdentityCopyPublicKey(
1916 SecIdentityRef identityRef,
1917 SecKeyRef *publicKeyRef)
1918 {
1919 OSStatus status;
1920 UInt32 count;
1921 SecKeychainAttribute attr = { kSecKeyLabel, 0, NULL };
1922 SecKeychainAttributeList attrList = { 1, &attr };
1923 SecKeychainAttributeList *keyAttrList = NULL;
1924 SecKeychainAttributeInfo *info = NULL;
1925 SecKeychainSearchRef search = NULL;
1926 SecKeychainRef keychain = NULL;
1927 SecKeychainItemRef privateKey = NULL;
1928 SecKeychainItemRef publicKey = NULL;
1929
1930 status = SecIdentityCopyPrivateKey(identityRef, (SecKeyRef *)&privateKey);
1931 if (status) {
1932 goto error_exit; // identity must have a private key
1933 }
1934 status = SecKeychainItemCopyKeychain(privateKey, &keychain);
1935 if (status) {
1936 goto error_exit; // private key must have a keychain, so we can get the attribute info for it
1937 }
1938 status = SecKeychainAttributeInfoForItemID(keychain, kSecPrivateKeyItemClass, &info);
1939 if (status) {
1940 goto error_exit; // unable to get the attribute info (i.e. database schema) for private keys
1941 }
1942 status = SecKeychainItemCopyAttributesAndData(privateKey, info, NULL, &keyAttrList, NULL, NULL);
1943 if (status) {
1944 goto error_exit; // unable to get the key label attribute for the private key
1945 }
1946
1947 // use the found kSecKeyLabel attribute from the private key in a separate attribute list for searching
1948 for (count = 0; count < keyAttrList->count; count++) {
1949 if (keyAttrList->attr[count].tag == kSecKeyLabel) {
1950 attr.length = keyAttrList->attr[count].length;
1951 attr.data = keyAttrList->attr[count].data;
1952 break;
1953 }
1954 }
1955 if (!attr.length || !attr.data) {
1956 status = errSecNoSuchAttr;
1957 goto error_exit; // the private key didn't have the hash of the public key in its kSecKeyLabel
1958 }
1959 status = SecKeychainSearchCreateFromAttributes(keychain, kSecPublicKeyItemClass, &attrList, &search);
1960 if (status) {
1961 goto error_exit; // unable to create the search reference
1962 }
1963 status = SecKeychainSearchCopyNext(search, &publicKey);
1964 if (status) {
1965 goto error_exit; // unable to find the public key
1966 }
1967
1968 if (publicKeyRef)
1969 *publicKeyRef = (SecKeyRef)publicKey;
1970 else
1971 CFRelease(publicKey);
1972
1973 error_exit:
1974 if (status != noErr) {
1975 if (publicKeyRef)
1976 *publicKeyRef = NULL;
1977 if (publicKey)
1978 CFRelease(publicKey);
1979 }
1980 if (search)
1981 CFRelease(search);
1982
1983 if (keyAttrList)
1984 SecKeychainItemFreeAttributesAndData(keyAttrList, NULL);
1985
1986 if (info)
1987 SecKeychainFreeAttributeInfo(info);
1988
1989 if (keychain)
1990 CFRelease(keychain);
1991
1992 if (privateKey)
1993 CFRelease(privateKey);
1994
1995 return status;
1996 }
1997
1998
1999 /*
2000 * Deletes a keychain item if the current application/tool is the only application/tool
2001 * with decrypt access to that keychain item. If more than one application/tool
2002 * has decrypt access to the keychain item, the item is left on the keychain.
2003 *
2004 * TBD: If more than one app/tool has access to the keychain item, we should remove
2005 * the current app/tool's decrypt access. There's no easy way to do that with
2006 * current keychain APIs without bringing up the security UI.
2007 */
2008 static OSStatus
2009 _SafeSecKeychainItemDelete(
2010 SecKeychainItemRef itemRef)
2011 {
2012 OSStatus status;
2013 SecAccessRef access;
2014 CFArrayRef aclList;
2015 SecACLRef acl;
2016 CFArrayRef appList;
2017 CFStringRef description;
2018 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
2019
2020 SecItemClass itemClass;
2021 status = SecKeychainItemCopyAttributesAndData(itemRef, NULL, &itemClass, NULL, NULL, NULL);
2022 if (!status && (itemClass == kSecCertificateItemClass || itemClass == kSecPublicKeyItemClass)) {
2023 // the item doesn't have any access controls, so delete it normally
2024 return SecKeychainItemDelete(itemRef);
2025 }
2026
2027 // skip access control checking for web form passwords: <rdar://10957301>
2028 // This permits Safari to manage the removal of all web form passwords,
2029 // regardless of whether they are shared by multiple applications.
2030 if (itemClass == kSecInternetPasswordItemClass) {
2031 UInt32 tags[1] = { kSecAuthenticationTypeItemAttr };
2032 SecKeychainAttributeInfo attrInfo = { 1, tags, NULL };
2033 SecKeychainAttributeList *attrs = NULL;
2034 status = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrs, NULL, NULL);
2035 if (!status && attrs) {
2036 bool webFormPassword = (attrs->attr[0].length == 4 && (!memcmp(attrs->attr[0].data, "form", 4)));
2037 SecKeychainItemFreeAttributesAndData(attrs, NULL);
2038 if (webFormPassword) {
2039 return SecKeychainItemDelete(itemRef);
2040 }
2041 }
2042 }
2043
2044 // copy the access of the keychain item
2045 status = SecKeychainItemCopyAccess(itemRef, &access);
2046 require_noerr(status, SecKeychainItemCopyAccessFailed);
2047
2048 // copy the decrypt access control lists -- this is what has access to the keychain item
2049 status = SecAccessCopySelectedACLList(access, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList);
2050 require_noerr(status, SecAccessCopySelectedACLListFailed);
2051 require_quiet(aclList != NULL, noACLList);
2052
2053 // get the access control list
2054 acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
2055 require_quiet(acl != NULL, noACL);
2056
2057 // copy the application list, description, and CSSM prompt selector for a given access control list entry
2058 status = SecACLCopySimpleContents(acl, &appList, &description, &promptSelector);
2059 require_noerr(status, SecACLCopySimpleContentsFailed);
2060 require_quiet(appList != NULL, noAppList);
2061
2062 // does only a single application/tool have decrypt access to this item?
2063 if ( CFArrayGetCount(appList) == 1 ) {
2064 SecTrustedApplicationRef itemAppRef, currentAppRef;
2065 CFStringRef itemAppName, currentAppName;
2066
2067 // get SecTrustedApplicationRef for item's application/tool
2068 itemAppRef = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(appList, 0);
2069 require(itemAppRef != NULL, noItemAppRef);
2070
2071 // copy the name out
2072 itemAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), itemAppRef);
2073 require(itemAppName != NULL, noAppName);
2074
2075 // create SecTrustedApplicationRef for current application/tool
2076 status = SecTrustedApplicationCreateFromPath(NULL, &currentAppRef);
2077 require((status == noErr) && (currentAppRef != NULL), SecTrustedApplicationCreateFromPathFailed);
2078
2079 // copy the name out
2080 currentAppName = _AppNameFromSecTrustedApplication(CFGetAllocator(itemRef), currentAppRef);
2081 require(currentAppName != NULL, noCurrentAppName);
2082
2083 // compare the current application/tool's name to this item's application/tool's name to see if we own the decrypt access
2084 if ( CFStringCompare(currentAppName, itemAppName, 0) == kCFCompareEqualTo ) {
2085 // delete the keychain item
2086 SecKeychainItemDelete(itemRef);
2087 }
2088
2089 CFRelease(currentAppName);
2090 noCurrentAppName:
2091 CFRelease(currentAppRef);
2092 SecTrustedApplicationCreateFromPathFailed:
2093 CFRelease(itemAppName);
2094 noAppName:
2095 noItemAppRef:
2096 ;
2097 }
2098
2099 if ( description ) {
2100 CFRelease(description);
2101 }
2102 CFRelease(appList);
2103 noAppList:
2104 SecACLCopySimpleContentsFailed:
2105 noACL:
2106 CFRelease(aclList);
2107 noACLList:
2108 SecAccessCopySelectedACLListFailed:
2109 CFRelease(access);
2110 SecKeychainItemCopyAccessFailed:
2111
2112 return status;
2113 }
2114
2115 OSStatus
2116 _UpdateKeychainItem(CFTypeRef item, CFDictionaryRef changedAttributes)
2117 {
2118 // This function updates a single keychain item, which may be specified as
2119 // a reference, persistent reference or attribute dictionary, with the
2120 // attributes provided.
2121
2122 OSStatus status = noErr;
2123 if (!item) {
2124 return paramErr;
2125 }
2126
2127 SecItemClass itemClass;
2128 SecAccessRef access = NULL;
2129 SecKeychainAttributeList *changeAttrList = NULL;
2130 SecKeychainItemRef itemToUpdate = NULL;
2131 CFDataRef theData = NULL;
2132 CFTypeID itemType = CFGetTypeID(item);
2133
2134 // validate input item (must be convertible to a SecKeychainItemRef)
2135 if (SecKeychainItemGetTypeID() == itemType ||
2136 SecCertificateGetTypeID() == itemType ||
2137 SecKeyGetTypeID() == itemType) {
2138 // item is already a reference, retain it
2139 itemToUpdate = (SecKeychainItemRef) CFRetain(item);
2140 }
2141 else if (CFDataGetTypeID() == itemType) {
2142 // item is a persistent reference, must convert it
2143 status = SecKeychainItemCopyFromPersistentReference((CFDataRef)item, &itemToUpdate);
2144 }
2145 else if (CFDictionaryGetTypeID() == itemType) {
2146 // item is a dictionary
2147 CFTypeRef value = NULL;
2148 if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValueRef, &value)) {
2149 // kSecValueRef value is a SecKeychainItemRef, retain it
2150 itemToUpdate = (SecKeychainItemRef) CFRetain(value);
2151 }
2152 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValuePersistentRef, &value)) {
2153 // kSecValuePersistentRef value is a persistent reference, must convert it
2154 status = SecKeychainItemCopyFromPersistentReference((CFDataRef)value, &itemToUpdate);
2155 }
2156 }
2157 else if (SecIdentityGetTypeID() == itemType) {
2158 // item is a certificate + private key; since we can't really change the
2159 // certificate's attributes, assume we want to update the private key
2160 status = SecIdentityCopyPrivateKey((SecIdentityRef)item, (SecKeyRef*)&itemToUpdate);
2161 }
2162 require_action(itemToUpdate != NULL, update_failed, status = errSecInvalidItemRef);
2163 require_noerr(status, update_failed);
2164
2165 status = SecKeychainItemCopyContent(itemToUpdate, &itemClass, NULL, NULL, NULL);
2166 require_noerr(status, update_failed);
2167
2168 // build changeAttrList from changedAttributes dictionary
2169 switch (itemClass)
2170 {
2171 case kSecInternetPasswordItemClass:
2172 {
2173 status = _CreateSecKeychainInternetPasswordAttributeListFromDictionary(changedAttributes, &changeAttrList);
2174 require_noerr(status, update_failed);
2175 }
2176 break;
2177
2178 case kSecGenericPasswordItemClass:
2179 {
2180 status = _CreateSecKeychainGenericPasswordAttributeListFromDictionary(changedAttributes, &changeAttrList);
2181 require_noerr(status, update_failed);
2182 }
2183 break;
2184
2185 case kSecCertificateItemClass:
2186 {
2187 status = _CreateSecKeychainCertificateAttributeListFromDictionary(changedAttributes, &changeAttrList);
2188 require_noerr(status, update_failed);
2189 }
2190 break;
2191
2192 case kSecPublicKeyItemClass:
2193 case kSecPrivateKeyItemClass:
2194 case kSecSymmetricKeyItemClass:
2195 {
2196 status = _CreateSecKeychainKeyAttributeListFromDictionary(changedAttributes, &changeAttrList);
2197 require_noerr(status, update_failed);
2198 }
2199 }
2200
2201 // get the password
2202 // (if the caller is not updating the password, this value will be NULL)
2203 theData = (CFDataRef)CFDictionaryGetValue(changedAttributes, kSecValueData);
2204 if (theData != NULL) {
2205 require_action(CFDataGetTypeID() == CFGetTypeID(theData), update_failed, status = errSecParam);
2206 }
2207 // update item
2208 status = SecKeychainItemModifyContent(itemToUpdate,
2209 (changeAttrList->count == 0) ? NULL : changeAttrList,
2210 (theData != NULL) ? CFDataGetLength(theData) : 0,
2211 (theData != NULL) ? CFDataGetBytePtrVoid(theData) : NULL);
2212
2213 // one more thing... update access?
2214 if (CFDictionaryGetValueIfPresent(changedAttributes, kSecAttrAccess, (const void **)&access)) {
2215 status = SecKeychainItemSetAccess(itemToUpdate, access);
2216 }
2217
2218 update_failed:
2219 if (itemToUpdate)
2220 CFRelease(itemToUpdate);
2221 _FreeAttrList(changeAttrList);
2222 return status;
2223 }
2224
2225 OSStatus
2226 _DeleteKeychainItem(CFTypeRef item)
2227 {
2228 // This function deletes a single keychain item, which may be specified as
2229 // a reference, persistent reference or attribute dictionary. It will not
2230 // delete non-keychain items or aggregate items (such as a SecIdentityRef);
2231 // it is assumed that the caller will pass identity components separately.
2232
2233 OSStatus status = noErr;
2234 if (!item) {
2235 return paramErr;
2236 }
2237
2238 SecKeychainItemRef itemToDelete = NULL;
2239 CFTypeID itemType = CFGetTypeID(item);
2240 if (SecKeychainItemGetTypeID() == itemType ||
2241 SecCertificateGetTypeID() == itemType ||
2242 SecKeyGetTypeID() == itemType) {
2243 // item is already a reference, retain it
2244 itemToDelete = (SecKeychainItemRef) CFRetain(item);
2245 }
2246 else if (CFDataGetTypeID() == itemType) {
2247 // item is a persistent reference, must convert it
2248 status = SecKeychainItemCopyFromPersistentReference((CFDataRef)item, &itemToDelete);
2249 }
2250 else if (CFDictionaryGetTypeID() == itemType) {
2251 // item is a dictionary
2252 CFTypeRef value = NULL;
2253 if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValueRef, &value)) {
2254 // kSecValueRef value is a SecKeychainItemRef, retain it
2255 itemToDelete = (SecKeychainItemRef) CFRetain(value);
2256 }
2257 else if (CFDictionaryGetValueIfPresent((CFDictionaryRef)item, kSecValuePersistentRef, &value)) {
2258 // kSecValuePersistentRef value is a persistent reference, must convert it
2259 status = SecKeychainItemCopyFromPersistentReference((CFDataRef)value, &itemToDelete);
2260 }
2261 }
2262
2263 if (itemToDelete) {
2264 if (!status) {
2265 status = _SafeSecKeychainItemDelete(itemToDelete);
2266 }
2267 CFRelease(itemToDelete);
2268 }
2269
2270 return status;
2271 }
2272
2273 OSStatus
2274 _DeleteIdentity(SecIdentityRef identity)
2275 {
2276 OSStatus status, result = noErr;
2277 SecKeyRef privateKey = NULL;
2278 SecCertificateRef certificate = NULL;
2279
2280 status = SecIdentityCopyPrivateKey(identity, &privateKey);
2281 if (!status) {
2282 SecKeyRef publicKey = NULL;
2283 status = _SecIdentityCopyPublicKey(identity, &publicKey);
2284 if (!status) {
2285 status = _DeleteKeychainItem(publicKey);
2286 CFRelease(publicKey);
2287 }
2288 status = _DeleteKeychainItem(privateKey);
2289 }
2290
2291 if (privateKey) CFRelease(privateKey);
2292 if (status) result = status;
2293
2294 status = SecIdentityCopyCertificate(identity, &certificate);
2295 if (!status) {
2296 status = _DeleteKeychainItem(certificate);
2297 }
2298
2299 if (certificate) CFRelease(certificate);
2300 if (status) result = status;
2301
2302 return result;
2303 }
2304
2305 OSStatus
2306 _UpdateAggregateStatus(OSStatus newStatus, OSStatus curStatus, OSStatus baseStatus)
2307 {
2308 // This function is used when atomically processing multiple items,
2309 // where an overall error result must be returned for the entire operation.
2310 // When newStatus is something other than noErr, we want to keep the "most
2311 // interesting" status (which usually will be newStatus, unless curStatus is
2312 // already set; in that case, newStatus can trump curStatus only by being
2313 // something different than baseStatus.)
2314
2315 OSStatus result = curStatus;
2316
2317 if (newStatus != noErr) {
2318 result = newStatus;
2319 if (curStatus != noErr) {
2320 result = (newStatus != baseStatus) ? newStatus : curStatus;
2321 }
2322 }
2323 return result;
2324 }
2325
2326 void
2327 _AddDictValueToOtherDict(const void *key, const void *value, void *context)
2328 {
2329 // CFDictionaryApplierFunction
2330 // This function just takes the given key/value pair,
2331 // and adds it to another dictionary supplied in the context argument.
2332
2333 CFMutableDictionaryRef dict = *((CFMutableDictionaryRef*) context);
2334 if (key && value) {
2335 CFDictionaryAddValue(dict, key, value);
2336 }
2337 }
2338
2339 static CFStringCompareFlags
2340 _StringCompareFlagsFromQuery(CFDictionaryRef query)
2341 {
2342 CFTypeRef value;
2343 CFStringCompareFlags flags = 0;
2344 if (!query) return flags;
2345
2346 if (CFDictionaryGetValueIfPresent(query, kSecMatchSubjectStartsWith, (const void **)&value) ||
2347 CFDictionaryGetValueIfPresent(query, kSecMatchSubjectEndsWith, (const void **)&value))
2348 flags |= kCFCompareAnchored;
2349
2350 if (CFDictionaryGetValueIfPresent(query, kSecMatchSubjectEndsWith, (const void **)&value))
2351 flags |= kCFCompareBackwards;
2352
2353 if (CFDictionaryGetValueIfPresent(query, kSecMatchCaseInsensitive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2354 flags |= kCFCompareCaseInsensitive;
2355
2356 if (CFDictionaryGetValueIfPresent(query, kSecMatchDiacriticInsensitive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2357 flags |= kCFCompareDiacriticInsensitive;
2358
2359 if (CFDictionaryGetValueIfPresent(query, kSecMatchWidthInsensitive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2360 flags |= kCFCompareWidthInsensitive;
2361
2362 return flags;
2363 }
2364
2365 static uint32
2366 _CssmKeyUsageFromQuery(CFDictionaryRef query)
2367 {
2368 CFTypeRef value;
2369 uint32 keyUsage = 0;
2370 if (!query) return keyUsage;
2371
2372 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanEncrypt, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2373 keyUsage |= CSSM_KEYUSE_ENCRYPT;
2374
2375 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanDecrypt, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2376 keyUsage |= CSSM_KEYUSE_DECRYPT;
2377
2378 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanSign, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2379 keyUsage |= CSSM_KEYUSE_SIGN;
2380
2381 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanVerify, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2382 keyUsage |= CSSM_KEYUSE_VERIFY;
2383
2384 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanWrap, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2385 keyUsage |= CSSM_KEYUSE_WRAP;
2386
2387 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanUnwrap, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2388 keyUsage |= CSSM_KEYUSE_UNWRAP;
2389
2390 if (CFDictionaryGetValueIfPresent(query, kSecAttrCanDerive, (const void **)&value) && CFEqual(kCFBooleanTrue, value))
2391 keyUsage |= CSSM_KEYUSE_DERIVE;
2392
2393 return keyUsage;
2394 }
2395
2396 static SecItemClass
2397 _ConvertItemClass(const void* item, const void* keyClass, Boolean *isIdentity)
2398 {
2399 SecItemClass itemClass = (SecItemClass) 0;
2400 if (isIdentity) *isIdentity = false;
2401
2402 if (CFEqual(item, kSecClassGenericPassword)) {
2403 itemClass = kSecGenericPasswordItemClass;
2404 }
2405 else if (CFEqual(item, kSecClassInternetPassword)) {
2406 itemClass = kSecInternetPasswordItemClass;
2407 }
2408 else if (CFEqual(item, kSecClassCertificate)) {
2409 itemClass = kSecCertificateItemClass;
2410 }
2411 else if (CFEqual(item, kSecClassIdentity)) {
2412 // will perform a certificate lookup
2413 itemClass = kSecCertificateItemClass;
2414 if (isIdentity) *isIdentity = true;
2415 }
2416 else if (CFEqual(item, kSecClassKey)) {
2417 // examine second parameter to determine type of key
2418 if (!keyClass || CFEqual(keyClass, kSecAttrKeyClassSymmetric)) {
2419 itemClass = kSecSymmetricKeyItemClass;
2420 }
2421 else if (keyClass && CFEqual(keyClass, kSecAttrKeyClassPublic)) {
2422 itemClass = kSecPublicKeyItemClass;
2423 }
2424 else if (keyClass && CFEqual(keyClass, kSecAttrKeyClassPrivate)) {
2425 itemClass = kSecPrivateKeyItemClass;
2426 }
2427 }
2428
2429 return itemClass;
2430 }
2431
2432 // SecItemParams contains a validated set of input parameters, as well as a
2433 // search reference and attribute list built from those parameters. It is
2434 // designed to be allocated with _CreateSecItemParamsFromDictionary, and
2435 // freed with _FreeSecItemParams.
2436
2437 struct SecItemParams {
2438 CFDictionaryRef query; // caller-supplied query
2439 int numResultTypes; // number of result types requested
2440 int maxMatches; // max number of matches to return
2441 uint32 keyUsage; // key usage(s) requested
2442 Boolean returningAttributes; // true if returning attributes dictionary
2443 Boolean returningData; // true if returning item's data
2444 Boolean returningRef; // true if returning item reference
2445 Boolean returningPersistentRef; // true if returing a persistent reference
2446 Boolean returnAllMatches; // true if we should return all matches
2447 Boolean returnIdentity; // true if we are returning a SecIdentityRef
2448 Boolean trustedOnly; // true if we only return trusted certs
2449 Boolean issuerAndSNToMatch; // true if both issuer and SN were provided
2450 SecItemClass itemClass; // item class for this query
2451 SecPolicyRef policy; // value for kSecMatchPolicy (may be NULL)
2452 SecKeychainRef keychain; // value for kSecUseKeychain (may be NULL)
2453 CFArrayRef useItems; // value for kSecUseItemList (may be NULL)
2454 CFArrayRef itemList; // value for kSecMatchItemList (may be NULL)
2455 CFTypeRef searchList; // value for kSecMatchSearchList (may be NULL)
2456 CFTypeRef matchLimit; // value for kSecMatchLimit (may be NULL)
2457 CFTypeRef emailAddrToMatch; // value for kSecMatchEmailAddressIfPresent (may be NULL)
2458 CFTypeRef validOnDate; // value for kSecMatchValidOnDate (may be NULL)
2459 CFTypeRef keyClass; // value for kSecAttrKeyClass (may be NULL)
2460 CFTypeRef service; // value for kSecAttrService (may be NULL)
2461 CFTypeRef issuer; // value for kSecAttrIssuer (may be NULL)
2462 CFTypeRef serialNumber; // value for kSecAttrSerialNumber (may be NULL)
2463 CFTypeRef search; // search reference for this query (SecKeychainSearchRef or SecIdentitySearchRef)
2464 CFTypeRef assumedKeyClass; // if no kSecAttrKeyClass provided, holds the current class we're searching for
2465 SecKeychainAttributeList *attrList; // attribute list for this query
2466 SecAccessRef access; // access reference (for SecItemAdd only, not used to find items)
2467 CFDataRef itemData; // item data (for SecItemAdd only, not used to find items)
2468 CFTypeRef itemRef; // item reference (to add, update or delete, depending on context)
2469 CFDataRef itemPersistentRef; // item persistent reference (to add, update or delete, depending on context)
2470 };
2471
2472 static OSStatus
2473 _ValidateDictionaryEntry(CFDictionaryRef dict, CFTypeRef key, const void **value, CFTypeID expectedTypeID, CFTypeID altTypeID)
2474 {
2475 if (!dict || !key || !value || !expectedTypeID)
2476 return paramErr;
2477
2478 if (!CFDictionaryGetValueIfPresent(dict, key, value)) {
2479 // value was not provided for this key (not an error!)
2480 *value = NULL;
2481 }
2482 else if (!(*value)) {
2483 // provided value is NULL (also not an error!)
2484 return noErr;
2485 }
2486 else {
2487 CFTypeID actualTypeID = CFGetTypeID(*value);
2488 if (!((expectedTypeID == actualTypeID) || (altTypeID && altTypeID == actualTypeID))) {
2489 // provided value does not have the expected (or alternate) CF type ID
2490 if ((expectedTypeID == SecKeychainItemGetTypeID()) &&
2491 (actualTypeID == SecKeyGetTypeID() || actualTypeID == SecCertificateGetTypeID())) {
2492 // provided value is a "floating" reference which is not yet in a keychain
2493 CFRetain(*value);
2494 return noErr;
2495 }
2496 return errSecItemInvalidValue;
2497 }
2498 else {
2499 // provided value is OK; retain it
2500 CFRetain(*value);
2501 }
2502 }
2503 return noErr;
2504 }
2505
2506 static void
2507 _FreeSecItemParams(SecItemParams *itemParams)
2508 {
2509 if (!itemParams)
2510 return;
2511
2512 if (itemParams->query) CFRelease(itemParams->query);
2513 if (itemParams->policy) CFRelease(itemParams->policy);
2514 if (itemParams->keychain) CFRelease(itemParams->keychain);
2515 if (itemParams->useItems) CFRelease(itemParams->useItems);
2516 if (itemParams->itemList) CFRelease(itemParams->itemList);
2517 if (itemParams->searchList) CFRelease(itemParams->searchList);
2518 if (itemParams->matchLimit) CFRelease(itemParams->matchLimit);
2519 if (itemParams->emailAddrToMatch) CFRelease(itemParams->emailAddrToMatch);
2520 if (itemParams->validOnDate) CFRelease(itemParams->validOnDate);
2521 if (itemParams->keyClass) CFRelease(itemParams->keyClass);
2522 if (itemParams->service) CFRelease(itemParams->service);
2523 if (itemParams->issuer) CFRelease(itemParams->issuer);
2524 if (itemParams->serialNumber) CFRelease(itemParams->serialNumber);
2525 if (itemParams->search) CFRelease(itemParams->search);
2526 if (itemParams->access) CFRelease(itemParams->access);
2527 if (itemParams->itemData) CFRelease(itemParams->itemData);
2528 if (itemParams->itemRef) CFRelease(itemParams->itemRef);
2529 if (itemParams->itemPersistentRef) CFRelease(itemParams->itemPersistentRef);
2530
2531 _FreeAttrList(itemParams->attrList);
2532
2533 free(itemParams);
2534 }
2535
2536 static SecItemParams*
2537 _CreateSecItemParamsFromDictionary(CFDictionaryRef dict, OSStatus *error)
2538 {
2539 OSStatus status;
2540 CFTypeRef value = NULL;
2541 SecItemParams *itemParams = (SecItemParams *) malloc(sizeof(SecItemParams));
2542
2543 require_action(itemParams != NULL, error_exit, status = memFullErr);
2544 require_action(dict && (CFDictionaryGetTypeID() == CFGetTypeID(dict)), error_exit, status = paramErr);
2545
2546 memset(itemParams, 0, sizeof(SecItemParams));
2547 itemParams->query = (CFDictionaryRef) CFRetain(dict);
2548
2549 // validate input search parameters
2550 require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchPolicy, (const void **)&itemParams->policy, SecPolicyGetTypeID(), NULL), error_exit);
2551 require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchSearchList, (const void **)&itemParams->searchList, CFArrayGetTypeID(), NULL), error_exit);
2552 require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchItemList, (const void **)&itemParams->itemList, CFArrayGetTypeID(), NULL), error_exit);
2553 require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchEmailAddressIfPresent, (const void **)&itemParams->emailAddrToMatch, CFStringGetTypeID(), NULL), error_exit);
2554 require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchValidOnDate, (const void **)&itemParams->validOnDate, CFDateGetTypeID(), CFNullGetTypeID()), error_exit);
2555 require_noerr(status = _ValidateDictionaryEntry(dict, kSecMatchLimit, (const void **)&itemParams->matchLimit, CFStringGetTypeID(), CFNumberGetTypeID()), error_exit);
2556
2557 require_noerr(status = _ValidateDictionaryEntry(dict, kSecUseItemList, (const void **)&itemParams->useItems, CFArrayGetTypeID(), NULL), error_exit);
2558 require_noerr(status = _ValidateDictionaryEntry(dict, kSecUseKeychain, (const void **)&itemParams->keychain, SecKeychainGetTypeID(), NULL), error_exit);
2559
2560 // validate a subset of input attributes (used to create an appropriate search reference)
2561 require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrIssuer, (const void **)&itemParams->issuer, CFDataGetTypeID(), NULL), error_exit);
2562 require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrSerialNumber, (const void **)&itemParams->serialNumber, CFDataGetTypeID(), NULL), error_exit);
2563 require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrService, (const void **)&itemParams->service, CFStringGetTypeID(), NULL), error_exit);
2564 require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrKeyClass, (const void **)&itemParams->keyClass, CFStringGetTypeID(), NULL), error_exit);
2565
2566 // must have an item class, unless we have an item list to add
2567 if (!CFDictionaryGetValueIfPresent(dict, kSecClass, (const void**) &value) && !itemParams->useItems)
2568 require_action(false, error_exit, status = errSecItemClassMissing);
2569 else if (value) {
2570 itemParams->itemClass = _ConvertItemClass(value, itemParams->keyClass, &itemParams->returnIdentity);
2571 if (itemParams->itemClass == kSecSymmetricKeyItemClass && !itemParams->keyClass) {
2572 itemParams->assumedKeyClass = kSecAttrKeyClassSymmetric; // no key class specified, so start with symmetric key class; will search the others later
2573 }
2574 require_action(!(itemParams->itemClass == 0), error_exit, status = errSecItemClassMissing);
2575 }
2576
2577 itemParams->keyUsage = _CssmKeyUsageFromQuery(dict);
2578 itemParams->trustedOnly = CFDictionaryGetValueIfPresent(dict, kSecMatchTrustedOnly, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2579 itemParams->issuerAndSNToMatch = (itemParams->issuer != NULL && itemParams->serialNumber != NULL);
2580
2581 // other input attributes, used for SecItemAdd but not for finding items
2582 require_noerr(status = _ValidateDictionaryEntry(dict, kSecAttrAccess, (const void **)&itemParams->access, SecAccessGetTypeID(), NULL), error_exit);
2583 if (itemParams->access == NULL) {
2584 // check for the old definition of kSecAttrAccess from SecItem-shim (see <rdar://7987447>)
2585 require_noerr(status = _ValidateDictionaryEntry(dict, CFSTR("kSecAttrAccess"), (const void **)&itemParams->access, SecAccessGetTypeID(), NULL), error_exit);
2586 }
2587
2588 // validate the payload (password, key or certificate data), used for SecItemAdd but not for finding items
2589 require_noerr(status = _ValidateDictionaryEntry(dict, kSecValueData, (const void **)&itemParams->itemData, CFDataGetTypeID(), CFStringGetTypeID()), error_exit);
2590
2591 // validate item references
2592 require_noerr(status = _ValidateDictionaryEntry(dict, kSecValueRef, (const void **)&itemParams->itemRef, SecKeychainItemGetTypeID(), NULL), error_exit);
2593 require_noerr(status = _ValidateDictionaryEntry(dict, kSecValuePersistentRef, (const void **)&itemParams->itemPersistentRef, CFDataGetTypeID(), NULL), error_exit);
2594 if (itemParams->itemRef || itemParams->itemPersistentRef) {
2595 // Caller is trying to add or find an item by reference.
2596 // The supported method for doing that is to provide a kSecUseItemList array
2597 // for SecItemAdd, or a kSecMatchItemList array for SecItemCopyMatching et al,
2598 // so add the item reference to those arrays here.
2599 if (itemParams->useItems) {
2600 CFArrayRef tmpItems = itemParams->useItems;
2601 itemParams->useItems = (CFArrayRef) CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, tmpItems);
2602 CFRelease(tmpItems);
2603 } else {
2604 itemParams->useItems = (CFArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2605 }
2606 if (itemParams->itemRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->useItems, itemParams->itemRef);
2607 if (itemParams->itemPersistentRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->useItems, itemParams->itemPersistentRef);
2608
2609 if (itemParams->itemList) {
2610 CFArrayRef tmpItems = itemParams->itemList;
2611 itemParams->itemList = (CFArrayRef) CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, tmpItems);
2612 CFRelease(tmpItems);
2613 } else {
2614 itemParams->itemList = (CFArrayRef) CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2615 }
2616 if (itemParams->itemRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->itemList, itemParams->itemRef);
2617 if (itemParams->itemPersistentRef) CFArrayAppendValue((CFMutableArrayRef)itemParams->itemList, itemParams->itemPersistentRef);
2618 }
2619
2620 // determine how to return the result
2621 itemParams->numResultTypes = 0;
2622 itemParams->returningRef = CFDictionaryGetValueIfPresent(dict, kSecReturnRef, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2623 if (itemParams->returningRef) ++itemParams->numResultTypes;
2624 itemParams->returningPersistentRef = CFDictionaryGetValueIfPresent(dict, kSecReturnPersistentRef, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2625 if (itemParams->returningPersistentRef) ++itemParams->numResultTypes;
2626 itemParams->returningAttributes = CFDictionaryGetValueIfPresent(dict, kSecReturnAttributes, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2627 if (itemParams->returningAttributes) ++itemParams->numResultTypes;
2628 itemParams->returningData = CFDictionaryGetValueIfPresent(dict, kSecReturnData, (const void **)&value) && value && CFEqual(kCFBooleanTrue, value);
2629 if (itemParams->returningData) ++itemParams->numResultTypes;
2630
2631 // default is kSecReturnRef if no result types were specified
2632 if (!itemParams->numResultTypes) {
2633 itemParams->returningRef = TRUE;
2634 itemParams->numResultTypes = 1;
2635 }
2636
2637 // determine if one, some or all matches should be returned (default is kSecMatchLimitOne)
2638 itemParams->maxMatches = 1;
2639 itemParams->returnAllMatches = FALSE;
2640 if (itemParams->matchLimit) {
2641 if (CFStringGetTypeID() == CFGetTypeID(itemParams->matchLimit)) {
2642 itemParams->returnAllMatches = CFEqual(kSecMatchLimitAll, itemParams->matchLimit);
2643 }
2644 else if (CFNumberGetTypeID() == CFGetTypeID(itemParams->matchLimit)) {
2645 CFNumberGetValue((CFNumberRef)itemParams->matchLimit, kCFNumberIntType, &itemParams->maxMatches);
2646 require_action(!(itemParams->maxMatches < 0), error_exit, status = errSecMatchLimitUnsupported);
2647 }
2648 }
2649 if (itemParams->returnAllMatches) {
2650 itemParams->maxMatches = INT32_MAX;
2651 // if we're returning all matches, then we don't support getting passwords as data (which could require authentication for each)
2652 if ((itemParams->itemClass==kSecInternetPasswordItemClass || itemParams->itemClass==kSecGenericPasswordItemClass) && itemParams->returningData)
2653 status = errSecReturnDataUnsupported;
2654 require_noerr(status, error_exit);
2655 }
2656
2657 // if useItems was provided, we don't need an attribute list or a search reference for adding, although we definitely need one for searching
2658 if (itemParams->useItems && itemParams->itemClass == 0) {
2659 require_action(false, error_exit, status = noErr); // all done here
2660 }
2661
2662 // build a SecKeychainAttributeList from the query dictionary for the specified item class
2663 require_noerr(status = _CreateSecKeychainAttributeListFromDictionary(dict, itemParams->itemClass, &itemParams->attrList), error_exit);
2664
2665 // create a search reference (either a SecKeychainSearchRef or a SecIdentitySearchRef)
2666 if ((itemParams->itemClass == kSecCertificateItemClass) && itemParams->emailAddrToMatch) {
2667 // searching for certificates by email address
2668 char *nameBuf = (char*)malloc(MAXPATHLEN);
2669 if (!nameBuf) {
2670 status = memFullErr;
2671 }
2672 else if (CFStringGetCString((CFStringRef)itemParams->emailAddrToMatch, nameBuf, (CFIndex)MAXPATHLEN-1, kCFStringEncodingUTF8)) {
2673 status = SecKeychainSearchCreateForCertificateByEmail(itemParams->searchList, (const char *)nameBuf, (SecKeychainSearchRef*)&itemParams->search);
2674 }
2675 else {
2676 status = errSecItemInvalidValue;
2677 }
2678 if (nameBuf) free(nameBuf);
2679 }
2680 else if ((itemParams->itemClass == kSecCertificateItemClass) && itemParams->issuerAndSNToMatch) {
2681 // searching for certificates by issuer and serial number
2682 status = SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(itemParams->searchList,
2683 (CFDataRef)itemParams->issuer,
2684 (CFDataRef)itemParams->serialNumber,
2685 (SecKeychainSearchRef*)&itemParams->search);
2686 }
2687 else if (itemParams->returnIdentity && itemParams->policy) {
2688 // searching for identities by policy
2689 status = SecIdentitySearchCreateWithPolicy(itemParams->policy,
2690 (CFStringRef)itemParams->service,
2691 itemParams->keyUsage,
2692 itemParams->searchList,
2693 itemParams->trustedOnly,
2694 (SecIdentitySearchRef*)&itemParams->search);
2695 }
2696 else if (itemParams->returnIdentity) {
2697 // searching for identities
2698 status = SecIdentitySearchCreate(itemParams->searchList,
2699 itemParams->keyUsage,
2700 (SecIdentitySearchRef*)&itemParams->search);
2701 }
2702 else {
2703 // normal keychain item search
2704 status = SecKeychainSearchCreateFromAttributes(itemParams->searchList,
2705 itemParams->itemClass,
2706 (itemParams->attrList->count == 0) ? NULL : itemParams->attrList,
2707 (SecKeychainSearchRef*)&itemParams->search);
2708 }
2709
2710 error_exit:
2711 if (status) {
2712 _FreeSecItemParams(itemParams);
2713 itemParams = NULL;
2714 }
2715 if (error) {
2716 *error = status;
2717 }
2718 return itemParams;
2719 }
2720
2721
2722 OSStatus
2723 _ImportKey(
2724 SecKeyRef keyRef,
2725 SecKeychainRef keychainRef,
2726 SecAccessRef accessRef,
2727 SecKeychainAttributeList *attrList,
2728 SecKeychainItemRef *outItemRef)
2729 {
2730 BEGIN_SECAPI
2731
2732 // We must specify the access, since a free-floating key won't have one yet by default
2733 SecPointer<Access> access;
2734 if (accessRef) {
2735 access = Access::required(accessRef);
2736 }
2737 else {
2738 CFStringRef descriptor = NULL;
2739 if (attrList) {
2740 for (UInt32 index=0; index < attrList->count; index++) {
2741 SecKeychainAttribute attr = attrList->attr[index];
2742 if (attr.tag == kSecKeyPrintName) {
2743 descriptor = CFStringCreateWithBytes(NULL, (const UInt8 *)attr.data, attr.length, kCFStringEncodingUTF8, FALSE);
2744 break;
2745 }
2746 }
2747 }
2748 if (descriptor == NULL) {
2749 descriptor = (CFStringRef) CFRetain(CFSTR("<unknown>"));
2750 }
2751 access = new Access(cfString(descriptor));
2752 CFRelease(descriptor);
2753 }
2754
2755 KeyItem *key = KeyItem::required(keyRef);
2756 Item item = key->importTo(Keychain::optional(keychainRef), access, attrList);
2757 if (outItemRef)
2758 *outItemRef = item->handle();
2759
2760 END_SECAPI
2761 }
2762
2763 Boolean
2764 _CanIgnoreLeafStatusCodes(CSSM_TP_APPLE_EVIDENCE_INFO *evidence)
2765 {
2766 /* Check for ignorable status codes in leaf certificate's evidence */
2767 Boolean result = true;
2768 unsigned int i;
2769 for (i=0; i < evidence->NumStatusCodes; i++) {
2770 CSSM_RETURN scode = evidence->StatusCodes[i];
2771 if (scode == CSSMERR_APPLETP_INVALID_CA) {
2772 // the TP has rejected this CA cert because it's in the leaf position
2773 result = true;
2774 }
2775 else if (ignorableRevocationStatusCode(scode)) {
2776 result = true;
2777 }
2778 else {
2779 result = false;
2780 break;
2781 }
2782 }
2783 return result;
2784 }
2785
2786 OSStatus
2787 _FilterWithPolicy(SecPolicyRef policy, SecCertificateRef cert)
2788 {
2789 CFDictionaryRef props = NULL;
2790 CFArrayRef keychains = NULL;
2791 CFArrayRef anchors = NULL;
2792 CFArrayRef certs = NULL;
2793 CFArrayRef chain = NULL;
2794 SecTrustRef trust = NULL;
2795
2796 SecTrustResultType trustResult;
2797 CSSM_TP_APPLE_EVIDENCE_INFO *evidence = NULL;
2798 Boolean needChain = false;
2799 OSStatus status;
2800 if (!policy || !cert) return paramErr;
2801
2802 certs = CFArrayCreate(NULL, (const void **)&cert, (CFIndex)1, &kCFTypeArrayCallBacks);
2803 status = SecTrustCreateWithCertificates(certs, policy, &trust);
2804 if(status) goto cleanup;
2805
2806 /* Check whether this is the X509 Basic policy, which means chain building */
2807 props = SecPolicyCopyProperties(policy);
2808 if (props) {
2809 CFTypeRef oid = (CFTypeRef) CFDictionaryGetValue(props, kSecPolicyOid);
2810 if (oid && CFEqual(oid, kSecPolicyAppleX509Basic)) {
2811 needChain = true;
2812 }
2813 }
2814
2815 if (!needChain) {
2816 /* To make the evaluation as lightweight as possible, specify an empty array
2817 * of keychains which will be searched for certificates.
2818 */
2819 keychains = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
2820 status = SecTrustSetKeychains(trust, keychains);
2821 if(status) goto cleanup;
2822
2823 /* To make the evaluation as lightweight as possible, specify an empty array
2824 * of trusted anchors.
2825 */
2826 anchors = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
2827 status = SecTrustSetAnchorCertificates(trust, anchors);
2828 if(status) goto cleanup;
2829 }
2830
2831 /* All parameters are locked and loaded, ready to evaluate! */
2832 status = SecTrustEvaluate(trust, &trustResult);
2833 if(status) goto cleanup;
2834
2835 /* If we didn't provide trust anchors or a way to look for them,
2836 * the evaluation will fail with kSecTrustResultRecoverableTrustFailure.
2837 * However, we can tell whether the policy evaluation succeeded by
2838 * looking at the per-cert status codes in the returned evidence.
2839 */
2840 status = SecTrustGetResult(trust, &trustResult, &chain, &evidence);
2841 if(status) goto cleanup;
2842
2843 if (!(trustResult == kSecTrustResultProceed ||
2844 trustResult == kSecTrustResultUnspecified ||
2845 trustResult == kSecTrustResultRecoverableTrustFailure)) {
2846 /* The evaluation failed in a non-recoverable way */
2847 status = errSecCertificateCannotOperate;
2848 goto cleanup;
2849 }
2850
2851 /* If there are no per-cert policy status codes,
2852 * and the cert has not expired, consider it valid for the policy.
2853 */
2854 if((evidence != NULL) && _CanIgnoreLeafStatusCodes(evidence) &&
2855 ((evidence[0].StatusBits & CSSM_CERT_STATUS_EXPIRED) == 0) &&
2856 ((evidence[0].StatusBits & CSSM_CERT_STATUS_NOT_VALID_YET) == 0)) {
2857 status = noErr;
2858 }
2859 else {
2860 status = errSecCertificateCannotOperate;
2861 }
2862
2863 cleanup:
2864 if(props) CFRelease(props);
2865 if(chain) CFRelease(chain);
2866 if(anchors) CFRelease(anchors);
2867 if(keychains) CFRelease(keychains);
2868 if(certs) CFRelease(certs);
2869 if(trust) CFRelease(trust);
2870
2871 return status;
2872 }
2873
2874 OSStatus
2875 _FilterWithDate(CFTypeRef validOnDate, SecCertificateRef cert)
2876 {
2877 if (!validOnDate || !cert) return paramErr;
2878
2879 CFAbsoluteTime at, nb, na;
2880 if (CFGetTypeID(validOnDate) == CFDateGetTypeID())
2881 at = CFDateGetAbsoluteTime((CFDateRef)validOnDate);
2882 else
2883 at = CFAbsoluteTimeGetCurrent();
2884
2885 OSStatus status = noErr;
2886 SecCertificateRefP certP = NULL;
2887 CFDataRef certData = SecCertificateCopyData(cert);
2888 if (certData) {
2889 certP = SecCertificateCreateWithDataP(kCFAllocatorDefault, certData);
2890 }
2891 if (certP) {
2892 nb = SecCertificateNotValidBefore(certP);
2893 na = SecCertificateNotValidAfter(certP);
2894
2895 if(at < nb)
2896 status = errSecCertificateNotValidYet;
2897 else if (at > na)
2898 status = errSecCertificateExpired;
2899 }
2900 else {
2901 status = errSecCertificateCannotOperate;
2902 }
2903
2904 if(certData) CFRelease(certData);
2905 if(certP) CFRelease(certP);
2906 return status;
2907 }
2908
2909 OSStatus
2910 _FilterWithTrust(Boolean trustedOnly, SecCertificateRef cert)
2911 {
2912 if (!cert) return paramErr;
2913 if (!trustedOnly) return noErr;
2914
2915 CFArrayRef certArray = CFArrayCreate(NULL, (const void**)&cert, 1, &kCFTypeArrayCallBacks);
2916 SecPolicyRef policy = SecPolicyCreateWithOID(kSecPolicyAppleX509Basic);
2917 OSStatus status = (policy == NULL) ? errSecPolicyNotFound : errSecSuccess;
2918
2919 if (!status) {
2920 SecTrustRef trust = NULL;
2921 status = SecTrustCreateWithCertificates(certArray, policy, &trust);
2922 if (!status) {
2923 SecTrustResultType trustResult;
2924 status = SecTrustEvaluate(trust, &trustResult);
2925 if (!status) {
2926 if (!(trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified)) {
2927 status = (trustResult == kSecTrustResultDeny) ? errSecTrustSettingDeny : errSecNotTrusted;
2928 }
2929 }
2930 CFRelease(trust);
2931 }
2932 CFRelease(policy);
2933 }
2934 if (certArray) {
2935 CFRelease(certArray);
2936 }
2937
2938 return status;
2939 }
2940
2941 OSStatus
2942 UpdateKeychainSearchAndCopyNext(SecItemParams *params, CFTypeRef *item)
2943 {
2944 // This function refreshes the search parameters in the specific case where
2945 // the caller is searching for kSecClassKey items but did not provide the
2946 // kSecAttrKeyClass. In that case, params->assumedKeyClass will be set, and
2947 // we must perform separate searches to obtain all results.
2948
2949 OSStatus status = errSecItemNotFound;
2950 if (!params || !params->assumedKeyClass || !params->query || !item)
2951 return status;
2952
2953 // Free the previous search reference and attribute list.
2954 if (params->search)
2955 CFRelease(params->search);
2956 params->search = NULL;
2957 _FreeAttrList(params->attrList);
2958 params->attrList = NULL;
2959
2960 // Make a copy of the query dictionary so we can set the key class parameter.
2961 CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(NULL, 0, params->query);
2962 CFRelease(params->query);
2963 params->query = dict;
2964 CFDictionarySetValue(dict, kSecAttrKeyClass, params->assumedKeyClass);
2965
2966 // Determine the current item class for this search, and the next assumed key class.
2967 if (CFEqual(params->assumedKeyClass, kSecAttrKeyClassSymmetric)) {
2968 params->itemClass = kSecSymmetricKeyItemClass;
2969 params->assumedKeyClass = kSecAttrKeyClassPublic;
2970 } else if (CFEqual(params->assumedKeyClass, kSecAttrKeyClassPublic)) {
2971 params->itemClass = kSecPublicKeyItemClass;
2972 params->assumedKeyClass = kSecAttrKeyClassPrivate;
2973 } else {
2974 params->itemClass = kSecPrivateKeyItemClass;
2975 params->assumedKeyClass = NULL;
2976 }
2977
2978 // Rebuild the attribute list for the new key class.
2979 if (_CreateSecKeychainAttributeListFromDictionary(dict, params->itemClass, &params->attrList) == noErr) {
2980 // Create a new search reference for the new attribute list.
2981 if (SecKeychainSearchCreateFromAttributes(params->searchList,
2982 params->itemClass,
2983 (params->attrList->count == 0) ? NULL : params->attrList,
2984 (SecKeychainSearchRef*)&params->search) == noErr) {
2985 // Return the first matching item from the new search.
2986 // We won't come back here again until there are no more matching items for this search.
2987 status = SecKeychainSearchCopyNext((SecKeychainSearchRef)params->search, (SecKeychainItemRef*)item);
2988 }
2989 }
2990 return status;
2991 }
2992
2993
2994 OSStatus
2995 SecItemSearchCopyNext(SecItemParams *params, CFTypeRef *item)
2996 {
2997 // Generic "copy next match" function for SecKeychainSearchRef or SecIdentitySearchRef.
2998 // Returns either a SecKeychainItemRef or a SecIdentityRef in the output parameter,
2999 // depending on the type of search reference.
3000
3001 OSStatus status;
3002 CFTypeRef search = (params) ? params->search : NULL;
3003 CFTypeID typeID = (search) ? CFGetTypeID(search) : 0;
3004 if (typeID == SecIdentitySearchGetTypeID()) {
3005 status = SecIdentitySearchCopyNext((SecIdentitySearchRef)search, (SecIdentityRef*)item);
3006 }
3007 else if (typeID == SecKeychainSearchGetTypeID()) {
3008 status = SecKeychainSearchCopyNext((SecKeychainSearchRef)search, (SecKeychainItemRef*)item);
3009 // Check if we need to refresh the search for the next key class
3010 while (status == errSecItemNotFound && params->assumedKeyClass != NULL)
3011 status = UpdateKeychainSearchAndCopyNext(params, item);
3012 }
3013 else {
3014 status = errSecItemNotFound;
3015 }
3016 return status;
3017 }
3018
3019 OSStatus
3020 FilterCandidateItem(CFTypeRef *item, SecItemParams *itemParams, SecIdentityRef *identity)
3021 {
3022 if (!item || *item == NULL || !itemParams)
3023 return errSecItemNotFound;
3024
3025 OSStatus status;
3026 CFStringRef commonName = NULL;
3027 SecIdentityRef foundIdentity = NULL;
3028 if (CFGetTypeID(*item) == SecIdentityGetTypeID()) {
3029 // we found a SecIdentityRef, rather than a SecKeychainItemRef;
3030 // replace the found "item" with its associated certificate (which is the
3031 // item we actually want for purposes of getting attributes, data, or a
3032 // persistent data reference), and return the identity separately.
3033 SecCertificateRef certificate;
3034 status = SecIdentityCopyCertificate((SecIdentityRef) *item, &certificate);
3035 if (itemParams->returnIdentity) {
3036 foundIdentity = (SecIdentityRef) *item;
3037 if (identity) {
3038 *identity = foundIdentity;
3039 }
3040 }
3041 else {
3042 CFRelease(*item);
3043 }
3044 *item = (CFTypeRef)certificate;
3045 }
3046
3047 CFDictionaryRef query = itemParams->query;
3048
3049 if (itemParams->itemClass == kSecCertificateItemClass) {
3050 // perform string comparisons first
3051 CFStringCompareFlags flags = _StringCompareFlagsFromQuery(query);
3052 CFStringRef nameContains, nameStarts, nameEnds, nameExact;
3053 if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectContains, (const void **)&nameContains))
3054 nameContains = NULL;
3055 if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectStartsWith, (const void **)&nameStarts))
3056 nameStarts = NULL;
3057 if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectEndsWith, (const void **)&nameEnds))
3058 nameEnds = NULL;
3059 if (!CFDictionaryGetValueIfPresent(query, kSecMatchSubjectWholeString, (const void **)&nameExact))
3060 nameExact = NULL;
3061 if (nameContains || nameStarts || nameEnds || nameExact) {
3062 status = SecCertificateCopyCommonName((SecCertificateRef)*item, &commonName);
3063 if (status || !commonName) goto filterOut;
3064 }
3065 if (nameContains) {
3066 CFRange range = CFStringFind(commonName, nameContains, flags);
3067 if (range.length < 1)
3068 goto filterOut;
3069 // certificate item contains string; proceed to next check
3070 }
3071 if (nameStarts) {
3072 CFRange range = CFStringFind(commonName, nameStarts, flags);
3073 if (range.length < 1 || range.location > 1)
3074 goto filterOut;
3075 // certificate item starts with string; proceed to next check
3076 }
3077 if (nameEnds) {
3078 CFRange range = CFStringFind(commonName, nameEnds, flags);
3079 if (range.length < 1 || range.location != (CFStringGetLength(commonName) - CFStringGetLength(nameEnds)))
3080 goto filterOut;
3081 // certificate item ends with string; proceed to next check
3082 }
3083 if (nameExact) {
3084 CFRange range = CFStringFind(commonName, nameExact, flags);
3085 if (range.length < 1 || (CFStringGetLength(commonName) != CFStringGetLength(nameExact)))
3086 goto filterOut;
3087 // certificate item exactly matches string; proceed to next check
3088 }
3089 if (itemParams->returnIdentity) {
3090 // if we already found and returned the identity, we can skip this
3091 if (!foundIdentity) {
3092 status = SecIdentityCreateWithCertificate(itemParams->searchList, (SecCertificateRef) *item, identity);
3093 if (status) goto filterOut;
3094 }
3095 // certificate item is part of an identity; proceed to next check
3096 }
3097 if (itemParams->policy) {
3098 status = _FilterWithPolicy(itemParams->policy, (SecCertificateRef) *item);
3099 if (status) goto filterOut;
3100 // certificate item is valid for specified policy
3101 }
3102 if (itemParams->validOnDate) {
3103 status = _FilterWithDate(itemParams->validOnDate, (SecCertificateRef) *item);
3104 if (status) goto filterOut;
3105 // certificate item is valid for specified date
3106 }
3107 if (itemParams->trustedOnly) {
3108 // if we are getting candidate items from a SecIdentitySearchCreateWithPolicy search,
3109 // their trust has already been validated and we can skip this part.
3110 if (!(foundIdentity && itemParams->returnIdentity && itemParams->policy)) {
3111 status = _FilterWithTrust(itemParams->trustedOnly, (SecCertificateRef) *item);
3112 if (status) goto filterOut;
3113 }
3114 // certificate item is trusted on this system
3115 }
3116 }
3117 if (itemParams->itemList) {
3118 Boolean foundMatch = FALSE;
3119 CFIndex idx, count = CFArrayGetCount(itemParams->itemList);
3120 for (idx=0; idx<count; idx++) {
3121 CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(itemParams->itemList, idx);
3122 SecKeychainItemRef realItem = NULL;
3123 SecCertificateRef aCert = NULL;
3124 if (anItem == NULL) {
3125 continue;
3126 }
3127 if (CFDataGetTypeID() == CFGetTypeID(anItem) &&
3128 noErr == SecKeychainItemCopyFromPersistentReference((CFDataRef)anItem, &realItem)) {
3129 anItem = realItem;
3130 }
3131 if (SecIdentityGetTypeID() == CFGetTypeID(anItem) &&
3132 noErr == SecIdentityCopyCertificate((SecIdentityRef)anItem, &aCert)) {
3133 anItem = aCert;
3134 }
3135 if (CFEqual(anItem, (CFTypeRef) *item)) {
3136 foundMatch = TRUE;
3137 }
3138 if (aCert) {
3139 CFRelease(aCert);
3140 }
3141 if (realItem) {
3142 CFRelease(realItem);
3143 }
3144 if (foundMatch) {
3145 break;
3146 }
3147 }
3148 if (!foundMatch) goto filterOut;
3149 // item was found on provided list
3150 }
3151
3152 if (foundIdentity && !identity) {
3153 CFRelease(foundIdentity);
3154 }
3155 if (commonName) {
3156 CFRelease(commonName);
3157 }
3158
3159 // if we get here, consider the item a match
3160 return noErr;
3161
3162 filterOut:
3163 if (commonName) {
3164 CFRelease(commonName);
3165 }
3166 CFRelease(*item);
3167 *item = NULL;
3168 if (foundIdentity) {
3169 CFRelease(foundIdentity);
3170 if (identity) {
3171 *identity = NULL;
3172 }
3173 }
3174 return errSecItemNotFound;
3175 }
3176
3177 OSStatus
3178 AddItemResults(SecKeychainItemRef item,
3179 SecIdentityRef identity,
3180 SecItemParams *itemParams,
3181 CFAllocatorRef allocator,
3182 CFMutableArrayRef *items,
3183 CFTypeRef *result)
3184 {
3185 // Given a found item (which may also be an identity), this function adds
3186 // the requested result types (specified in itemParams) to the appropriate
3187 // container as follows:
3188 //
3189 // 1. If there is only one result type (numResultTypes == 1) and only one
3190 // match requested (maxMatches == 1), set *result directly.
3191 //
3192 // 2. If there are multiple result types (numResultTypes > 1), and only one
3193 // match requested (maxMatches == 1), add each result type to itemDict
3194 // and set itemDict as the value of *result.
3195 //
3196 // 3. If there is only one result type (numResultTypes == 1) and multiple
3197 // possible matches (maxMatches > 1), add the result type to *items
3198 // and set *items as the value of *result.
3199 //
3200 // 4. If there are multiple result types (numResultTypes > 1) and multiple
3201 // possible matches (maxMatches > 1), add each result type to itemDict,
3202 // add itemDict to *items, and set *items as the value of *result.
3203 //
3204 // Note that we allocate *items if needed.
3205
3206 if (!item || !itemParams || !result)
3207 return paramErr;
3208
3209 if (itemParams->maxMatches > 1) {
3210 // if we can return more than one item, we must have an array
3211 if (!items)
3212 return paramErr;
3213 else if (*items == NULL)
3214 *items = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
3215 }
3216
3217 OSStatus tmpStatus, status = noErr;
3218 CFMutableArrayRef itemArray = (items) ? *items : NULL;
3219 CFMutableDictionaryRef itemDict = NULL;
3220 if (itemParams->numResultTypes > 1) {
3221 // if we're returning more than one result type, each item we return must be a dictionary
3222 itemDict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
3223 }
3224
3225 if (itemParams->returningRef) {
3226 const void* itemRef = (identity) ? (const void*)identity : (const void*)item;
3227 if (itemDict) {
3228 CFDictionaryAddValue(itemDict, kSecValueRef, itemRef);
3229 }
3230 else if (itemArray) {
3231 CFArrayAppendValue(itemArray, itemRef);
3232 }
3233 else {
3234 *result = CFRetain((CFTypeRef)itemRef);
3235 }
3236 }
3237
3238 if (itemParams->returningPersistentRef) {
3239 CFDataRef persistentRef;
3240 tmpStatus = SecKeychainItemCreatePersistentReference(item, &persistentRef);
3241 if (tmpStatus == noErr) {
3242 if (itemDict) {
3243 CFDictionaryAddValue(itemDict, kSecValuePersistentRef, persistentRef);
3244 }
3245 else if (itemArray) {
3246 CFArrayAppendValue(itemArray, persistentRef);
3247 }
3248 else {
3249 *result = CFRetain(persistentRef);
3250 }
3251 CFRelease(persistentRef);
3252 }
3253 else if (status == noErr) {
3254 status = tmpStatus;
3255 }
3256 }
3257
3258 if (itemParams->returningData) {
3259 UInt32 length;
3260 void *data;
3261 tmpStatus = SecKeychainItemCopyContent(item, NULL, NULL, &length, &data);
3262 if (tmpStatus == noErr) {
3263 CFDataRef dataRef = CFDataCreate(allocator, (UInt8 *)data, length);
3264 if (itemDict) {
3265 CFDictionaryAddValue(itemDict, kSecValueData, dataRef);
3266 }
3267 else if (itemArray) {
3268 CFArrayAppendValue(itemArray, dataRef);
3269 }
3270 else {
3271 *result = CFRetain(dataRef);
3272 }
3273 CFRelease(dataRef);
3274 (void) SecKeychainItemFreeContent(NULL, data);
3275 }
3276 else if (status == noErr) {
3277 status = tmpStatus;
3278 }
3279 }
3280
3281 if (itemParams->returningAttributes) {
3282 CFDictionaryRef attrsDict = NULL;
3283 SecItemClass itemClass;
3284 // since we have an item, allow its actual class to override the query-specified item class
3285 tmpStatus = SecKeychainItemCopyAttributesAndData(item, NULL, &itemClass, NULL, NULL, NULL);
3286 if (tmpStatus) {
3287 itemClass = itemParams->itemClass;
3288 }
3289 tmpStatus = _CreateAttributesDictionaryFromItem(allocator, itemClass, item, &attrsDict);
3290 if (attrsDict) {
3291 if (itemDict) {
3292 // add all keys and values from attrsDict to the item dictionary
3293 CFDictionaryApplyFunction(attrsDict, _AddDictValueToOtherDict, &itemDict);
3294 }
3295 else if (itemArray) {
3296 CFArrayAppendValue(itemArray, attrsDict);
3297 }
3298 else {
3299 *result = CFRetain(attrsDict);
3300 }
3301 CFRelease(attrsDict);
3302 }
3303 if (tmpStatus && (status == noErr)) {
3304 status = tmpStatus;
3305 }
3306 }
3307
3308 if (itemDict) {
3309 if (itemArray) {
3310 CFArrayAppendValue(itemArray, itemDict);
3311 CFRelease(itemDict);
3312 *result = itemArray;
3313 }
3314 else {
3315 *result = itemDict;
3316 }
3317 }
3318 else if (itemArray) {
3319 *result = itemArray;
3320 }
3321
3322 return status;
3323 }
3324
3325
3326 /******************************************************************************/
3327 #pragma mark SecItem API functions
3328 /******************************************************************************/
3329
3330 static Boolean SecItemSynchronizable(CFDictionaryRef query)
3331 {
3332 static dispatch_once_t onceToken;
3333 static Boolean synchronizable = false;
3334
3335 //sudo defaults write /Library/Preferences/com.apple.security SecItemSynchronizable -bool YES
3336 dispatch_once(&onceToken, ^{
3337 CFTypeRef sync = (CFNumberRef)CFPreferencesCopyValue(CFSTR("SecItemSynchronizable"), CFSTR("com.apple.security"), kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
3338
3339 if (sync && CFGetTypeID(sync) == CFBooleanGetTypeID()) {
3340 synchronizable = CFBooleanGetValue((CFBooleanRef)sync);
3341 CFRelease(sync);
3342 }
3343 });
3344
3345 if (synchronizable) {
3346 CFTypeRef value = NULL;
3347 return (_ValidateDictionaryEntry(query, kSecAttrSynchronizable, (const void**)&value, CFBooleanGetTypeID(), NULL) == noErr && value && CFEqual(kCFBooleanTrue, value));
3348 }
3349
3350 return synchronizable;
3351 }
3352
3353 OSStatus
3354 SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result)
3355 {
3356 if (!query || !result)
3357 return paramErr;
3358
3359 if (SecItemSynchronizable(query)) {
3360 return SecItemCopyMatching_ios(query, result);
3361 }
3362
3363 return SecItemCopyMatching_osx(query, result);
3364 }
3365
3366 OSStatus
3367 SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)
3368 {
3369 if (!attributes)
3370 return paramErr;
3371 else if (result)
3372 *result = NULL;
3373
3374 if (SecItemSynchronizable(attributes)) {
3375 return SecItemAdd_ios(attributes, result);
3376 }
3377
3378 return SecItemAdd_osx(attributes, result);
3379 }
3380
3381 OSStatus
3382 SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
3383 {
3384 if (!query || !attributesToUpdate)
3385 return paramErr;
3386
3387 if (SecItemSynchronizable(query)) {
3388 return SecItemUpdate_ios(query, attributesToUpdate);
3389 }
3390
3391 return SecItemUpdate_osx(query, attributesToUpdate);
3392 }
3393
3394 OSStatus
3395 SecItemDelete(CFDictionaryRef query)
3396 {
3397 if (!query)
3398 return paramErr;
3399
3400 if (SecItemSynchronizable(query)) {
3401 return SecItemDelete_ios(query);
3402 }
3403
3404 return SecItemDelete_osx(query);
3405 }
3406
3407 OSStatus
3408 SecItemCopyMatching_osx(
3409 CFDictionaryRef query,
3410 CFTypeRef *result)
3411 {
3412 if (!query || !result)
3413 return paramErr;
3414 else
3415 *result = NULL;
3416
3417 CFAllocatorRef allocator = CFGetAllocator(query);
3418 CFIndex matchCount = 0;
3419 CFMutableArrayRef itemArray = NULL;
3420 SecKeychainItemRef item = NULL;
3421 SecIdentityRef identity = NULL;
3422 OSStatus tmpStatus, status = noErr;
3423
3424 // validate input query parameters and create the search reference
3425 SecItemParams *itemParams = _CreateSecItemParamsFromDictionary(query, &status);
3426 require_action(itemParams != NULL, error_exit, itemParams = NULL);
3427
3428 // find the next match until we hit maxMatches, or no more matches found
3429 while ( !(!itemParams->returnAllMatches && matchCount >= itemParams->maxMatches) &&
3430 SecItemSearchCopyNext(itemParams, (CFTypeRef*)&item) == noErr) {
3431
3432 if (FilterCandidateItem((CFTypeRef*)&item, itemParams, &identity))
3433 continue; // move on to next item
3434
3435 ++matchCount; // we have a match
3436
3437 tmpStatus = AddItemResults(item, identity, itemParams, allocator, &itemArray, result);
3438 if (tmpStatus && (status == noErr))
3439 status = tmpStatus;
3440
3441 if (item) {
3442 CFRelease(item);
3443 item = NULL;
3444 }
3445 if (identity) {
3446 CFRelease(identity);
3447 identity = NULL;
3448 }
3449 }
3450
3451 if (status == noErr)
3452 status = (matchCount > 0) ? errSecSuccess : errSecItemNotFound;
3453
3454 error_exit:
3455 if (status != noErr && result != NULL && *result != NULL) {
3456 CFRelease(*result);
3457 *result = NULL;
3458 }
3459 _FreeSecItemParams(itemParams);
3460
3461 return status;
3462 }
3463
3464 OSStatus
3465 SecItemCopyDisplayNames(
3466 CFArrayRef items,
3467 CFArrayRef *displayNames)
3468 {
3469 BEGIN_SECAPI
3470 Required(items);
3471 Required(displayNames);
3472 //%%%TBI
3473 return unimpErr;
3474 END_SECAPI
3475 }
3476
3477 OSStatus
3478 SecItemAdd_osx(
3479 CFDictionaryRef attributes,
3480 CFTypeRef *result)
3481 {
3482 if (!attributes)
3483 return paramErr;
3484 else if (result)
3485 *result = NULL;
3486
3487 CFAllocatorRef allocator = CFGetAllocator(attributes);
3488 CFMutableArrayRef itemArray = NULL;
3489 SecKeychainItemRef item = NULL;
3490 OSStatus tmpStatus, status = noErr;
3491
3492 // validate input attribute parameters
3493 SecItemParams *itemParams = _CreateSecItemParamsFromDictionary(attributes, &status);
3494 require_action(itemParams != NULL, error_exit, itemParams = NULL);
3495
3496 // currently, we don't support adding SecIdentityRef items (an aggregate item class),
3497 // since the private key should already be in a keychain by definition. We could support
3498 // this as a copy operation for the private key if a different keychain is specified,
3499 // but in any case it should try to add the certificate. See <rdar://8317887>.
3500 require_action(!itemParams->returnIdentity, error_exit, status = errSecItemInvalidValue);
3501
3502 if (!itemParams->useItems) {
3503 // create a single keychain item specified by the input attributes
3504 status = SecKeychainItemCreateFromContent(itemParams->itemClass,
3505 itemParams->attrList,
3506 (itemParams->itemData) ? CFDataGetLength(itemParams->itemData) : 0,
3507 (itemParams->itemData) ? CFDataGetBytePtrVoid(itemParams->itemData) : NULL,
3508 itemParams->keychain,
3509 itemParams->access,
3510 &item);
3511 require_noerr(status, error_exit);
3512
3513 // return results (if requested)
3514 if (result) {
3515 itemParams->maxMatches = 1; // in case kSecMatchLimit was set to > 1
3516 tmpStatus = AddItemResults(item, NULL, itemParams, allocator, &itemArray, result);
3517 if (tmpStatus && (status == noErr))
3518 status = tmpStatus;
3519 }
3520 CFRelease(item);
3521 }
3522 else {
3523 // add multiple items which are specified in the itemParams->useItems array.
3524 // -- SecCertificateRef or SecKeyRef items may or may not be in a keychain.
3525 // -- SecKeychainItemRef items are in a keychain (by definition), but may be copied to another keychain.
3526 // -- CFDataRef items are a persistent reference; the represented item may be copied to another keychain.
3527 //
3528 OSStatus aggregateStatus = noErr;
3529 CFIndex ix, count = CFArrayGetCount(itemParams->useItems);
3530 itemParams->maxMatches = (count > 1) ? count : 2; // force results to always be returned as an array
3531 for (ix=0; ix < count; ix++) {
3532 CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(itemParams->useItems, ix);
3533 if (anItem) {
3534 if (SecCertificateGetTypeID() == CFGetTypeID(anItem)) {
3535 // SecCertificateRef item
3536 tmpStatus = SecCertificateAddToKeychain((SecCertificateRef)anItem, itemParams->keychain);
3537 if (!tmpStatus && result) {
3538 tmpStatus = AddItemResults((SecKeychainItemRef)anItem, NULL, itemParams, allocator, &itemArray, result);
3539 }
3540 aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
3541 }
3542 else if (SecKeyGetTypeID() == CFGetTypeID(anItem)) {
3543 // SecKeyRef item
3544 SecKeychainRef itemKeychain = NULL;
3545 tmpStatus = SecKeychainItemCopyKeychain((SecKeychainItemRef)anItem, &itemKeychain);
3546 if (tmpStatus == noErr) {
3547 // key was in a keychain, so we can attempt to copy it
3548 SecKeychainItemRef itemCopy = NULL;
3549 tmpStatus = SecKeychainItemCreateCopy((SecKeychainItemRef)anItem, itemParams->keychain, itemParams->access, &itemCopy);
3550 if (!tmpStatus && result) {
3551 tmpStatus = AddItemResults(itemCopy, NULL, itemParams, allocator, &itemArray, result);
3552 }
3553 if (itemCopy) {
3554 CFRelease(itemCopy);
3555 }
3556 }
3557 else {
3558 // key was not in any keychain, so must be imported
3559 SecKeychainItemRef keyItem = NULL;
3560 tmpStatus = _ImportKey((SecKeyRef)anItem, itemParams->keychain, itemParams->access, itemParams->attrList, &keyItem);
3561 if (!tmpStatus && result) {
3562 tmpStatus = AddItemResults(keyItem, NULL, itemParams, allocator, &itemArray, result);
3563 }
3564 if (keyItem) {
3565 CFRelease(keyItem);
3566 }
3567 }
3568 if (itemKeychain) {
3569 CFRelease(itemKeychain);
3570 }
3571 aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
3572 }
3573 else if (SecKeychainItemGetTypeID() == CFGetTypeID(anItem)) {
3574 // SecKeychainItemRef item
3575 SecKeychainItemRef itemCopy = NULL;
3576 tmpStatus = SecKeychainItemCreateCopy((SecKeychainItemRef)anItem, itemParams->keychain, itemParams->access, &itemCopy);
3577 if (!tmpStatus && result) {
3578 tmpStatus = AddItemResults(itemCopy, NULL, itemParams, allocator, &itemArray, result);
3579 }
3580 if (itemCopy) {
3581 CFRelease(itemCopy);
3582 }
3583 aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
3584 }
3585 else if (CFDataGetTypeID() == CFGetTypeID(anItem)) {
3586 // CFDataRef item (persistent reference)
3587 SecKeychainItemRef realItem = NULL;
3588 tmpStatus = SecKeychainItemCopyFromPersistentReference((CFDataRef)anItem, &realItem);
3589 if (tmpStatus == noErr) {
3590 // persistent reference resolved to a keychain item, so we can attempt to copy it
3591 SecKeychainItemRef itemCopy = NULL;
3592 tmpStatus = SecKeychainItemCreateCopy(realItem, itemParams->keychain, itemParams->access, &itemCopy);
3593 if (!tmpStatus && result) {
3594 tmpStatus = AddItemResults(itemCopy, NULL, itemParams, allocator, &itemArray, result);
3595 }
3596 if (itemCopy) {
3597 CFRelease(itemCopy);
3598 }
3599 }
3600 if (realItem) {
3601 CFRelease(realItem);
3602 }
3603 aggregateStatus = _UpdateAggregateStatus(tmpStatus, aggregateStatus, errSecDuplicateItem);
3604 }
3605 }
3606 } // end of itemList array loop
3607 status = aggregateStatus;
3608 } // end processing multiple items
3609
3610 error_exit:
3611 if (status != noErr && result != NULL && *result != NULL) {
3612 CFRelease(*result);
3613 *result = NULL;
3614 }
3615 _FreeSecItemParams(itemParams);
3616
3617 return status;
3618 }
3619
3620 OSStatus
3621 SecItemUpdate_osx(
3622 CFDictionaryRef query,
3623 CFDictionaryRef attributesToUpdate)
3624 {
3625 if (!query || !attributesToUpdate)
3626 return paramErr;
3627
3628 // run the provided query to get a list of items to update
3629 CFTypeRef results = NULL;
3630 OSStatus status = SecItemCopyMatching(query, &results);
3631 if (status != noErr)
3632 return status; // nothing was matched, or the query was bad
3633
3634 CFArrayRef items = NULL;
3635 if (CFArrayGetTypeID() == CFGetTypeID(results)) {
3636 items = (CFArrayRef) results;
3637 }
3638 else {
3639 items = CFArrayCreate(NULL, &results, 1, &kCFTypeArrayCallBacks);
3640 CFRelease(results);
3641 }
3642
3643 OSStatus result = noErr;
3644 CFIndex ix, count = CFArrayGetCount(items);
3645 for (ix=0; ix < count; ix++) {
3646 CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(items, ix);
3647 if (anItem) {
3648 status = _UpdateKeychainItem(anItem, attributesToUpdate);
3649 result = _UpdateAggregateStatus(status, result, noErr);
3650 }
3651 }
3652
3653 if (items) {
3654 CFRelease(items);
3655 }
3656 return result;
3657 }
3658
3659 OSStatus
3660 SecItemDelete_osx(
3661 CFDictionaryRef query)
3662 {
3663 if (!query)
3664 return paramErr;
3665
3666 // run the provided query to get a list of items to delete
3667 CFTypeRef results = NULL;
3668 OSStatus status = SecItemCopyMatching(query, &results);
3669 if (status != noErr)
3670 return status; // nothing was matched, or the query was bad
3671
3672 CFArrayRef items = NULL;
3673 if (CFArrayGetTypeID() == CFGetTypeID(results)) {
3674 items = (CFArrayRef) results;
3675 }
3676 else {
3677 items = CFArrayCreate(NULL, &results, 1, &kCFTypeArrayCallBacks);
3678 CFRelease(results);
3679 }
3680
3681 OSStatus result = noErr;
3682 CFIndex ix, count = CFArrayGetCount(items);
3683 for (ix=0; ix < count; ix++) {
3684 CFTypeRef anItem = (CFTypeRef) CFArrayGetValueAtIndex(items, ix);
3685 if (anItem) {
3686 if (SecIdentityGetTypeID() == CFGetTypeID(anItem)) {
3687 status = _DeleteIdentity((SecIdentityRef)anItem);
3688 }
3689 else {
3690 status = _DeleteKeychainItem(anItem);
3691 }
3692 result = _UpdateAggregateStatus(status, result, noErr);
3693 }
3694 }
3695
3696 if (items)
3697 CFRelease(items);
3698
3699 return result;
3700 }