]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecKeychainItem.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecKeychainItem.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-2016 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 <Security/SecBase.h>
25 #include <Security/SecKeychainItem.h>
26 #include <Security/SecKeychainItemPriv.h>
27 #include <Security/SecCertificatePriv.h>
28 #include <Security/SecItemPriv.h>
29
30 #include <security_keychain/Keychains.h>
31 #include <security_keychain/KeyItem.h>
32 #include <security_keychain/Item.h>
33 #include <security_keychain/Certificate.h>
34 #include <security_keychain/Identity.h>
35 #include <security_keychain/KCCursor.h> // @@@ Remove this when SecKeychainItemFindFirst moves to SecKeychainSearch
36
37 #include <securityd_client/dictionary.h>
38 #include <security_cdsa_utilities/Schema.h>
39 #include <Security/cssmapplePriv.h>
40 #include <syslog.h>
41 #include <os/activity.h>
42
43 #include "SecBridge.h"
44 #include "KCExceptions.h"
45 #include "Access.h"
46 #include "SecKeychainItemExtendedAttributes.h"
47 #include "LegacyAPICounts.h"
48
49 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
50
51 //
52 // Given a polymorphic Sec type object, return
53 // its AclBearer component.
54 // Note: Login ACLs are not hooked into this layer;
55 // modules or attachments have no Sec* layer representation.
56 //
57 static
58 RefPointer<AclBearer> aclBearer(CFTypeRef itemRef)
59 {
60 // well, exactly what kind of something are you?
61 CFTypeID id = CFGetTypeID(itemRef);
62 if (id == gTypes().ItemImpl.typeID) {
63 // keychain item. If it's in a protected group, return the group key
64 if (SSGroup group = ItemImpl::required(SecKeychainItemRef(itemRef))->group())
65 return &*group;
66 } else if (id == SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef)itemRef)) {
67 // key item, return the key itself.
68 if (CssmClient::Key key = KeyItem::required(SecKeyRef(itemRef))->key())
69 return &*key;
70 } else if (id == gTypes().KeychainImpl.typeID) {
71 // keychain (this yields the database ACL)
72 //@@@ not hooked up yet
73 }
74 // Guess not. Bummer
75 MacOSError::throwMe(errSecNoAccessForItem);
76 }
77
78
79 CFTypeID
80 SecKeychainItemGetTypeID(void)
81 {
82 BEGIN_SECAPI
83 return gTypes().ItemImpl.typeID;
84
85 END_SECAPI1(_kCFRuntimeNotATypeID)
86 }
87
88
89 OSStatus
90 SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeList *attrList,
91 UInt32 length, const void *data, SecKeychainRef keychainRef,
92 SecAccessRef initialAccess, SecKeychainItemRef *itemRef)
93 {
94 BEGIN_SECAPI
95 os_activity_t activity = os_activity_create("SecKeychainItemCreateFromContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
96 os_activity_scope(activity);
97 os_release(activity);
98
99 KCThrowParamErrIf_(length!=0 && data==NULL);
100 Item item(itemClass, attrList, length, data);
101 if (initialAccess) {
102 item->setAccess(Access::required(initialAccess));
103 }
104 Keychain keychain = nil;
105 try
106 {
107 keychain = Keychain::optional(keychainRef);
108 if ( !keychain->exists() )
109 {
110 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
111 }
112 }
113 catch(...)
114 {
115 keychain = globals().storageManager.defaultKeychainUI(item);
116 }
117
118 keychain->add(item);
119 if (itemRef) {
120 *itemRef = item->handle();
121 }
122
123 END_SECAPI
124 }
125
126
127 OSStatus
128 SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data)
129 {
130 BEGIN_SECKCITEMAPI
131 os_activity_t activity = os_activity_create("SecKeychainItemModifyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
132 os_activity_scope(activity);
133 os_release(activity);
134
135 Item item = ItemImpl::required(__itemImplRef);
136 item->modifyContent(attrList, length, data);
137
138 END_SECKCITEMAPI
139 }
140
141
142 OSStatus
143 SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData)
144 {
145 BEGIN_SECKCITEMAPI
146 os_activity_t activity = os_activity_create("SecKeychainItemCopyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
147 os_activity_scope(activity);
148 os_release(activity);
149
150 Item item = ItemImpl::required(__itemImplRef);
151 item->getContent(itemClass, attrList, length, outData);
152
153 END_SECKCITEMAPI
154 }
155
156
157 OSStatus
158 SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data)
159 {
160 BEGIN_SECAPI
161 os_activity_t activity = os_activity_create("SecKeychainItemFreeContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
162 os_activity_scope(activity);
163 os_release(activity);
164
165 ItemImpl::freeContent(attrList, data);
166
167 END_SECAPI
168 }
169
170
171 OSStatus
172 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data)
173 {
174 BEGIN_SECKCITEMAPI
175 os_activity_t activity = os_activity_create("SecKeychainItemModifyAttributesAndData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
176 os_activity_scope(activity);
177 os_release(activity);
178
179 Item item = ItemImpl::required(__itemImplRef);
180 item->modifyAttributesAndData(attrList, length, data);
181
182 END_SECKCITEMAPI
183 }
184
185
186 OSStatus
187 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, SecItemClass *itemClass, SecKeychainAttributeList **attrList, UInt32 *length, void **outData)
188 {
189 BEGIN_SECKCITEMAPI
190
191 Item item = ItemImpl::required(__itemImplRef);
192 item->getAttributesAndData(info, itemClass, attrList, length, outData);
193
194 END_SECKCITEMAPI
195 }
196
197
198 OSStatus
199 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *data)
200 {
201 BEGIN_SECAPI
202 ItemImpl::freeAttributesAndData(attrList, data);
203
204 END_SECAPI
205 }
206
207
208 OSStatus
209 SecKeychainItemDelete(SecKeychainItemRef itemRef)
210 {
211 BEGIN_SECKCITEMAPI
212 os_activity_t activity = os_activity_create("SecKeychainItemDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
213 os_activity_scope(activity);
214 os_release(activity);
215
216 Item item = ItemImpl::required(__itemImplRef);
217 Keychain keychain = item->keychain();
218 // item must be persistent.
219 KCThrowIf_( !keychain, errSecInvalidItemRef );
220
221 /*
222 * Before deleting the item, delete any existing Extended Attributes.
223 */
224 OSStatus ortn;
225 CFArrayRef attrNames = NULL;
226 ortn = SecKeychainItemCopyAllExtendedAttributes(__itemImplRef, &attrNames, NULL);
227 if(ortn == errSecSuccess) {
228 CFIndex numAttrs = CFArrayGetCount(attrNames);
229 for(CFIndex dex=0; dex<numAttrs; dex++) {
230 CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex);
231 /* setting value to NULL ==> delete */
232 SecKeychainItemSetExtendedAttribute(__itemImplRef, attrName, NULL);
233 }
234 }
235
236 /* now delete the item */
237 keychain->deleteItem( item );
238
239 END_SECKCITEMAPI
240 }
241
242
243 OSStatus
244 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef* keychainRef)
245 {
246 BEGIN_SECKCITEMAPI
247
248 // make sure this item has a keychain
249 Keychain kc = ItemImpl::required(__itemImplRef)->keychain();
250 if (kc == NULL)
251 {
252 MacOSError::throwMe(errSecNoSuchKeychain);
253 }
254
255 Required(keychainRef) = kc->handle();
256
257 END_SECKCITEMAPI
258 }
259
260
261 OSStatus
262 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychainRef,
263 SecAccessRef initialAccess, SecKeychainItemRef *itemCopy)
264 {
265 BEGIN_SECKCITEMAPI
266 os_activity_t activity = os_activity_create("SecKeychainItemCreateCopy", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
267 os_activity_scope(activity);
268 os_release(activity);
269
270 Item copy = ItemImpl::required(__itemImplRef)->copyTo(Keychain::optional(destKeychainRef), Access::optional(initialAccess));
271 if (itemCopy) {
272 *itemCopy = copy->handle();
273 }
274
275 END_SECKCITEMAPI
276 }
277
278
279 OSStatus
280 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM_DB_UNIQUE_RECORD **uniqueRecordID)
281 {
282 BEGIN_SECKCITEMAPI
283 os_activity_t activity = os_activity_create("SecKeychainItemGetUniqueRecordID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
284 os_activity_scope(activity);
285 os_release(activity);
286
287 Required(uniqueRecordID) = ItemImpl::required(__itemImplRef)->dbUniqueRecord();
288
289 END_SECKCITEMAPI
290 }
291
292
293 OSStatus
294 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldbHandle)
295 {
296 BEGIN_SECKCITEMAPI
297 os_activity_t activity = os_activity_create("SecKeychainItemGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
298 os_activity_scope(activity);
299 os_release(activity);
300
301 *dldbHandle = ItemImpl::required(__itemImplRef)->keychain()->database()->handle();
302
303 END_SECKCITEMAPI
304 }
305
306 OSStatus
307 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef)
308 {
309 BEGIN_SECKCITEMAPI
310 os_activity_t activity = os_activity_create("SecKeychainItemCopyAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
311 os_activity_scope(activity);
312 os_release(activity);
313
314 Required(accessRef); // preflight
315 SecPointer<Access> access = new Access(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)));
316 *accessRef = access->handle();
317
318 END_SECKCITEMAPI
319 }
320
321
322 OSStatus
323 SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef)
324 {
325 BEGIN_SECKCITEMAPI
326 os_activity_t activity = os_activity_create("SecKeychainItemSetAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
327 os_activity_scope(activity);
328 os_release(activity);
329
330 Access::required(accessRef)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)), true);
331
332 ItemImpl::required(__itemImplRef)->postItemEvent(kSecUpdateEvent);
333
334 END_SECKCITEMAPI
335 }
336
337 OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password)
338 {
339 BEGIN_SECKCITEMAPI
340 os_activity_t activity = os_activity_create("SecKeychainItemSetAccessWithPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
341 os_activity_scope(activity);
342 os_release(activity);
343
344 OSStatus result;
345
346 if(!__itemImplRef) {
347 return errSecParam;
348 }
349
350 // try to unlock the keychain with this password first
351 SecKeychainRef kc = NULL;
352 result = SecKeychainItemCopyKeychain(__itemImplRef, &kc);
353 if(!result) {
354 SecKeychainUnlock(kc, passwordLength, password, true);
355 if(kc) {
356 CFRelease(kc);
357 }
358 }
359
360 // Create some credentials with this password
361 CssmAutoData data(Allocator::standard(), password, passwordLength);
362 AclFactory::PassphraseUnlockCredentials cred(data, Allocator::standard());
363
364 Access::required(accessRef)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)), true, cred.getAccessCredentials());
365 ItemImpl::required(itemRef)->postItemEvent (kSecUpdateEvent);
366
367 END_SECKCITEMAPI
368 }
369
370
371 /* Sets an item's data for legacy "KC" CoreServices APIs.
372 Note this version sets the data, but doesn't update the item
373 as the KC behavior dictates.
374 */
375 OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data)
376 {
377 BEGIN_SECKCITEMAPI
378 os_activity_t activity = os_activity_create("SecKeychainItemSetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
379 os_activity_scope(activity);
380 os_release(activity);
381
382 ItemImpl::required(__itemImplRef)->setData(length, data);
383
384 END_SECKCITEMAPI
385 }
386
387 /* Gets an item's data for legacy "KC" CoreServices APIs.
388 Note this version doesn't take a SecItemClass parameter.
389 */
390 OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength)
391 {
392 BEGIN_SECKCITEMAPI
393 os_activity_t activity = os_activity_create("SecKeychainItemGetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
394 os_activity_scope(activity);
395 os_release(activity);
396
397 /* The caller either needs to specify data and maxLength or an actualLength,
398 * so we return either the data itself or the actual length of the data or both.
399 */
400 if (!((data && maxLength) || actualLength)) {
401 MacOSError::throwMe(errSecParam);
402 }
403 CssmDataContainer aData;
404 ItemImpl::required(__itemImplRef)->getData(aData);
405 if (actualLength) {
406 *actualLength = (UInt32)aData.length();
407 }
408 if (data) {
409 // Make sure the buffer is big enough
410 if (aData.length() > maxLength) {
411 MacOSError::throwMe(errSecBufferTooSmall);
412 }
413 memcpy(data, aData.data(), aData.length());
414 }
415
416 END_SECKCITEMAPI
417 }
418
419 /* Update a keychain item for legacy "KC" CoreServices APIs.
420 The "KC" API's do a 'set attribute', then an 'update'.
421 */
422 OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef)
423 {
424 BEGIN_SECKCITEMAPI
425 os_activity_t activity = os_activity_create("SecKeychainItemUpdate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
426 os_activity_scope(activity);
427 os_release(activity);
428
429 ItemImpl::required(__itemImplRef)->update();
430
431 END_SECKCITEMAPI
432 }
433
434 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
435 */
436 OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef)
437 {
438 BEGIN_SECKCITEMAPI
439 os_activity_t activity = os_activity_create("SecKeychainItemAddNoUI", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
440 os_activity_scope(activity);
441 os_release(activity);
442
443 Item item = ItemImpl::required(__itemImplRef);
444 Keychain::optional(keychainRef)->add(item);
445
446 END_SECKCITEMAPI
447 }
448
449 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
450 */
451 OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef)
452 {
453 BEGIN_SECKCITEMAPI
454 os_activity_t activity = os_activity_create("SecKeychainItemAdd", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
455 os_activity_scope(activity);
456 os_release(activity);
457
458 Item item = ItemImpl::required(__itemImplRef);
459 Keychain defaultKeychain = globals().storageManager.defaultKeychainUI(item);
460 defaultKeychain->add(item);
461
462 END_SECKCITEMAPI
463 }
464
465 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
466 */
467 OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef)
468 {
469 BEGIN_SECAPI
470 os_activity_t activity = os_activity_create("SecKeychainItemCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
471 os_activity_scope(activity);
472 os_release(activity);
473
474 RequiredParam(itemRef) = Item(itemClass, itemCreator, length, data, false)->handle();
475
476 END_SECAPI
477 }
478
479 /* Gets an individual attribute for legacy "KC" CoreServices APIs
480 */
481 OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength)
482 {
483 BEGIN_SECKCITEMAPI
484 os_activity_t activity = os_activity_create("SecKeychainItemGetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
485 os_activity_scope(activity);
486 os_release(activity);
487
488 ItemImpl::required(__itemImplRef)->getAttribute(RequiredParam(attribute), actualLength);
489
490 END_SECKCITEMAPI
491 }
492
493 /* Sets an individual attribute for legacy "KC" CoreServices APIs
494 */
495 OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute)
496 {
497 BEGIN_SECKCITEMAPI
498 os_activity_t activity = os_activity_create("SecKeychainItemSetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
499 os_activity_scope(activity);
500 os_release(activity);
501
502 ItemImpl::required(__itemImplRef)->setAttribute(RequiredParam(attribute));
503
504 END_SECKCITEMAPI
505 }
506
507 /* Finds a keychain item for legacy "KC" CoreServices APIs.
508 Note: This version doesn't take a SecItemClass because
509 SecKeychainSearchCreateFromAttributes() requires it.
510 @@@ This should move to SecKeychainSearch.cpp
511 */
512 OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef)
513 {
514 BEGIN_SECAPI
515 os_activity_t activity = os_activity_create("SecKeychainItemFindFirst", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
516 os_activity_scope(activity);
517 os_release(activity);
518
519 KCCursor cursor;
520 if (keychainRef) {
521 cursor = KeychainImpl::required(keychainRef)->createCursor(attrList);
522 } else {
523 cursor = globals().storageManager.createCursor(attrList);
524 }
525
526 Item item;
527 if (!cursor->next(item))
528 return errSecItemNotFound;
529
530 *itemRef=item->handle();
531 if (searchRef) {
532 *searchRef=cursor->handle();
533 }
534
535 END_SECAPI
536 }
537
538 static OSStatus SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef,
539 CFDataRef *persistentItemRef, Boolean isIdentity)
540 {
541 COUNTLEGACYAPI
542 OSStatus __secapiresult;
543 if (!certRef || !persistentItemRef) {
544 return errSecParam;
545 }
546
547 // If we already have a keychain item, we won't need to look it up by serial and issuer
548 SecKeychainItemRef kcItem = NULL;
549 if (SecCertificateIsItemImplInstance(certRef)) {
550 kcItem = (SecKeychainItemRef) CFRetain(certRef);
551 }
552 else {
553 kcItem = (SecKeychainItemRef) SecCertificateCopyKeychainItem(certRef);
554 }
555 if (kcItem) {
556 __secapiresult = errSecParam;
557 try {
558 Item item = ItemImpl::required((kcItem));
559 item->copyPersistentReference(*persistentItemRef, isIdentity);
560 __secapiresult = errSecSuccess;
561 }
562 catch(...) {}
563 CFRelease(kcItem);
564 if (__secapiresult == errSecSuccess) {
565 return __secapiresult;
566 }
567 }
568
569 // Certificate does not have a keychain item reference; look it up by serial and issuer
570 SecCertificateRef certItem = NULL;
571 if (SecCertificateIsItemImplInstance(certRef)) {
572 certItem = SecCertificateCreateFromItemImplInstance(certRef);
573 }
574 else {
575 certItem = (SecCertificateRef) CFRetain(certRef);
576 }
577
578 CFErrorRef errorRef = NULL;
579 CFDataRef serialData = SecCertificateCopySerialNumberData(certItem, &errorRef);
580 if (errorRef) {
581 CFIndex err = CFErrorGetCode(errorRef);
582 CFRelease(errorRef);
583 if (serialData) { CFRelease(serialData); }
584 if (certItem) { CFRelease(certItem); }
585 return (OSStatus)err;
586 }
587 CFDataRef issuerData = SecCertificateCopyNormalizedIssuerContent(certItem, &errorRef);
588 if (errorRef) {
589 CFIndex err = CFErrorGetCode(errorRef);
590 CFRelease(errorRef);
591 if (serialData) { CFRelease(serialData); }
592 if (issuerData) { CFRelease(issuerData); }
593 if (certItem) { CFRelease(certItem); }
594 return (OSStatus)err;
595 }
596
597 try {
598 // look up ItemImpl cert in keychain by normalized issuer and serial number
599 StorageManager::KeychainList keychains;
600 globals().storageManager.optionalSearchList(NULL, keychains);
601 KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuerData, serialData));
602 Item item;
603 if (!cursor->next(item)) {
604 MacOSError::throwMe(errSecItemNotFound);
605 }
606 item->copyPersistentReference(*persistentItemRef, false);
607 __secapiresult = errSecSuccess;
608 }
609 catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
610 catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
611 catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
612 catch (...) { __secapiresult=errSecInternalComponent; }
613
614 if (serialData)
615 CFRelease(serialData);
616 if (issuerData)
617 CFRelease(issuerData);
618 if (certItem)
619 CFRelease(certItem);
620
621 return __secapiresult;
622 }
623
624 OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef)
625 {
626 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */
627 if (!itemRef || !persistentItemRef) {
628 return errSecParam;
629 }
630 // first, query the iOS keychain
631 {
632 const void *keys[] = { kSecValueRef, kSecReturnPersistentRef, kSecUseDataProtectionKeychain };
633 const void *values[] = { itemRef, kCFBooleanTrue, kCFBooleanTrue };
634 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
635 sizeof(keys) / sizeof(*keys),
636 &kCFTypeDictionaryKeyCallBacks,
637 &kCFTypeDictionaryValueCallBacks);
638 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)persistentItemRef);
639 if (status == errSecSuccess) {
640 return status;
641 }
642 }
643 // otherwise, handle certificate
644 SecCertificateRef certRef = NULL;
645 CFTypeID itemType = CFGetTypeID(itemRef);
646 bool isIdentity = false;
647 if (itemType == SecIdentityGetTypeID()) {
648 SecIdentityCopyCertificate((SecIdentityRef)itemRef, &certRef);
649 isIdentity = true;
650 }
651 else if (itemType == SecCertificateGetTypeID()) {
652 certRef = (SecCertificateRef) CFRetain(itemRef);
653 }
654 if (certRef) {
655 OSStatus status = SecKeychainItemCreatePersistentReferenceFromCertificate(certRef, persistentItemRef, isIdentity);
656 CFRelease(certRef);
657 return status;
658 }
659 // otherwise, not a certificate, so proceed as usual for keychain item
660
661 BEGIN_SECAPI
662 os_activity_t activity = os_activity_create("SecKeychainItemCreatePersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
663 os_activity_scope(activity);
664 os_release(activity);
665 Item item = ItemImpl::required(itemRef);
666 item->copyPersistentReference(*persistentItemRef, false);
667 END_SECAPI
668 }
669
670 OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef)
671 {
672 BEGIN_SECAPI
673 os_activity_t activity = os_activity_create("SecKeychainItemCopyFromPersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
674 os_activity_scope(activity);
675 os_release(activity);
676
677 KCThrowParamErrIf_(!persistentItemRef || !itemRef);
678 // first, query the iOS keychain
679 {
680 const void *keys[] = { kSecValuePersistentRef, kSecReturnRef, kSecUseDataProtectionKeychain};
681 const void *values[] = { persistentItemRef, kCFBooleanTrue, kCFBooleanTrue };
682 CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
683 sizeof(keys) / sizeof(*keys),
684 &kCFTypeDictionaryKeyCallBacks,
685 &kCFTypeDictionaryValueCallBacks);
686 OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)itemRef);
687 if (status == errSecSuccess) {
688 return status;
689 }
690 }
691 // otherwise, proceed as usual for keychain item
692 CFTypeRef result = NULL;
693 bool isIdentityRef = false;
694 Item item = ItemImpl::makeFromPersistentReference(persistentItemRef, &isIdentityRef);
695 if (isIdentityRef) {
696 // item was stored as an identity, attempt to reconstitute it
697 SecPointer<Certificate> certificatePtr(static_cast<Certificate *>(item.get()));
698 StorageManager::KeychainList keychains;
699 globals().storageManager.optionalSearchList(NULL, keychains);
700 SecPointer<Identity> identityPtr(new Identity(keychains, certificatePtr));
701 result = identityPtr->handle();
702 KCThrowIf_( !result, errSecItemNotFound );
703 }
704 if (!result) {
705 result = item->handle();
706 }
707 *itemRef = (SecKeychainItemRef) result;
708
709 /* see if we should convert outgoing item to a unified SecCertificateRef */
710 SecItemClass tmpItemClass = Schema::itemClassFor(item->recordType());
711 if (tmpItemClass == kSecCertificateItemClass && !isIdentityRef) {
712 SecPointer<Certificate> certificate(static_cast<Certificate *>(&*item));
713 CssmData certData = certificate->data();
714 CFDataRef data = NULL;
715 if (certData.Data && certData.Length) {
716 data = CFDataCreate(NULL, certData.Data, certData.Length);
717 }
718 if (!data) {
719 *itemRef = NULL;
720 if (certData.Data && !certData.Length) {
721 syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)",
722 (uintptr_t)certData.Data);
723 return errSecDataNotAvailable;
724 }
725 else {
726 syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)",
727 (long)certData.Length, (uintptr_t)certData.Data);
728 return errSecInternal;
729 }
730 }
731 SecKeychainItemRef tmpRef = *itemRef;
732 *itemRef = (SecKeychainItemRef) SecCertificateCreateWithKeychainItem(NULL, data, tmpRef);
733 if (data)
734 CFRelease(data);
735 if (tmpRef)
736 CFRelease(tmpRef);
737 }
738
739 END_SECAPI
740 }
741
742 OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier)
743 {
744 BEGIN_SECKCITEMAPI
745 os_activity_t activity = os_activity_create("SecKeychainItemCopyRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
746 os_activity_scope(activity);
747 os_release(activity);
748
749 CSSM_DATA data;
750 RequiredParam (recordIdentifier);
751 Item item = ItemImpl::required(__itemImplRef);
752 item->copyRecordIdentifier (data);
753 *recordIdentifier = ::CFDataCreate(kCFAllocatorDefault, (UInt8*) data.Data, data.Length);
754 free (data.Data);
755
756 END_SECKCITEMAPI
757 }
758
759 OSStatus
760 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef,
761 SecKeychainItemRef *itemRef,
762 CFDataRef recordIdentifier)
763 {
764 BEGIN_SECAPI
765 os_activity_t activity = os_activity_create("SecKeychainItemCopyFromRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
766 os_activity_scope(activity);
767 os_release(activity);
768
769 // make a local Keychain reference
770 RequiredParam (keychainRef);
771 Keychain keychain = KeychainImpl::optional (keychainRef);
772 RequiredParam (itemRef);
773 RequiredParam (recordIdentifier);
774
775 Db db(keychain->database());
776
777 // make a raw database call to get the data
778 CSSM_DL_DB_HANDLE dbHandle = db.handle ();
779 CSSM_DB_UNIQUE_RECORD uniqueRecord;
780
781 // according to source, we should be able to reconsitute the uniqueRecord
782 // from the data we earlier retained
783
784 // prepare the record id
785 memset (&uniqueRecord, 0, sizeof (uniqueRecord));
786 uniqueRecord.RecordIdentifier.Data = (uint8*) CFDataGetBytePtr (recordIdentifier);
787 uniqueRecord.RecordIdentifier.Length = CFDataGetLength (recordIdentifier);
788
789 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
790 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr;
791 CSSM_RETURN result;
792 result = CSSM_DL_PassThrough (dbHandle, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER, &uniqueRecord, (void**) &outputUniqueRecordPtr);
793 KCThrowIf_(result != 0, errSecItemNotFound);
794
795 // from this, get the record type
796 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData;
797 memset (&attributeData, 0, sizeof (attributeData));
798
799 result = CSSM_DL_DataGetFromUniqueRecordId (dbHandle, outputUniqueRecordPtr, &attributeData, NULL);
800 KCThrowIf_(result != 0, errSecItemNotFound);
801 CSSM_DB_RECORDTYPE recordType = attributeData.DataRecordType;
802
803 // make the unique record item -- precursor to creation of a SecKeychainItemRef
804 DbUniqueRecord unique(db);
805 CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = unique;
806 *uniquePtr = outputUniqueRecordPtr;
807
808 unique->activate ();
809 Item item = keychain->item (recordType, unique);
810 if (itemRef)
811 {
812 *itemRef = item->handle();
813 }
814
815 END_SECAPI
816 }
817
818 OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass,
819 UInt32 length, const void *data, SecKeychainRef keychainRef,
820 SecAccessRef initialAccess, SecKeychainItemRef *itemRef, CFDataRef *localID)
821 {
822 BEGIN_SECAPI
823 os_activity_t activity = os_activity_create("SecKeychainItemCreateFromEncryptedContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
824 os_activity_scope(activity);
825 os_release(activity);
826
827 KCThrowParamErrIf_(length!=0 && data==NULL);
828 RequiredParam (localID);
829 RequiredParam (keychainRef);
830
831 Item item(itemClass, (uint32) 0, length, data, true);
832 if (initialAccess)
833 item->setAccess(Access::required(initialAccess));
834
835 Keychain keychain = Keychain::optional(keychainRef);
836 if (!keychain->exists())
837 {
838 MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
839 }
840
841 item->doNotEncrypt ();
842 try
843 {
844 keychain->add(item);
845 }
846 catch (const CommonError &err)
847 {
848 if (err.osStatus () == errSecNoSuchClass)
849 {
850 // the only time this should happen is if the item is a certificate (for keychain syncing)
851 if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE)
852 {
853 // create the certificate relation
854 Db db(keychain->database());
855
856 db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE,
857 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
858 Schema::X509CertificateSchemaAttributeCount,
859 Schema::X509CertificateSchemaAttributeList,
860 Schema::X509CertificateSchemaIndexCount,
861 Schema::X509CertificateSchemaIndexList);
862 keychain->keychainSchema()->didCreateRelation(
863 CSSM_DL_DB_RECORD_X509_CERTIFICATE,
864 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
865 Schema::X509CertificateSchemaAttributeCount,
866 Schema::X509CertificateSchemaAttributeList,
867 Schema::X509CertificateSchemaIndexCount,
868 Schema::X509CertificateSchemaIndexList);
869
870 // add the item again
871 keychain->add(item);
872 }
873 }
874 else
875 {
876 throw;
877 }
878 }
879
880 if (itemRef)
881 *itemRef = item->handle();
882
883 CSSM_DATA recordID;
884 item->copyRecordIdentifier (recordID);
885
886 *localID = CFDataCreate(kCFAllocatorDefault, (UInt8*) recordID.Data, recordID.Length);
887 free (recordID.Data);
888
889 END_SECAPI
890 }
891
892 OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
893 SecItemClass *itemClass, SecKeychainAttributeList **attrList,
894 UInt32 *length, void **outData)
895 {
896 BEGIN_SECKCITEMAPI
897 os_activity_t activity = os_activity_create("SecKeychainItemCopyAttributesAndEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
898 os_activity_scope(activity);
899 os_release(activity);
900
901 Item item = ItemImpl::required(__itemImplRef);
902 item->doNotEncrypt ();
903 item->getAttributesAndData(info, itemClass, attrList, length, outData);
904
905 END_SECKCITEMAPI
906 }
907
908 OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data)
909 {
910 BEGIN_SECKCITEMAPI
911 os_activity_t activity = os_activity_create("SecKeychainItemModifyEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
912 os_activity_scope(activity);
913 os_release(activity);
914
915 Item item = ItemImpl::required(__itemImplRef);
916 item->doNotEncrypt ();
917 item->modifyAttributesAndData(NULL, length, data);
918
919 END_SECKCITEMAPI
920 }