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