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