2 * Copyright (c) 2000-2004,2011-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <Security/SecBase.h>
25 #include <Security/SecKeychainItem.h>
26 #include <Security/SecKeychainItemPriv.h>
27 #include <Security/SecCertificatePriv.h>
29 #include <security_keychain/Keychains.h>
30 #include <security_keychain/KeyItem.h>
31 #include <security_keychain/Item.h>
32 #include <security_keychain/Certificate.h>
33 #include <security_keychain/Identity.h>
34 #include <security_keychain/KCCursor.h> // @@@ Remove this when SecKeychainItemFindFirst moves to SecKeychainSearch
36 #include <securityd_client/dictionary.h>
37 #include <security_cdsa_utilities/Schema.h>
38 #include <Security/cssmapplePriv.h>
41 #include "SecBridge.h"
42 #include "KCExceptions.h"
44 #include "SecKeychainItemExtendedAttributes.h"
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.
54 RefPointer
<AclBearer
> aclBearer(CFTypeRef itemRef
)
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())
62 } else if (id
== gTypes().KeyItem
.typeID
) {
63 // key item, return the key itself.
64 if (CssmClient::Key key
= KeyItem::required(SecKeyRef(itemRef
))->key())
66 } else if (id
== gTypes().KeychainImpl
.typeID
) {
67 // keychain (this yields the database ACL)
68 //@@@ not hooked up yet
71 MacOSError::throwMe(errSecNoAccessForItem
);
76 SecKeychainItemGetTypeID(void)
80 return gTypes().ItemImpl
.typeID
;
82 END_SECAPI1(_kCFRuntimeNotATypeID
)
87 SecKeychainItemCreateFromContent(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
,
88 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
89 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
)
92 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
93 Item
item(itemClass
, attrList
, length
, data
);
95 item
->setAccess(Access::required(initialAccess
));
97 Keychain keychain
= nil
;
100 keychain
= Keychain::optional(keychainRef
);
101 if ( !keychain
->exists() )
103 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
108 keychain
= globals().storageManager
.defaultKeychainUI(item
);
113 *itemRef
= item
->handle();
119 SecKeychainItemModifyContent(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
122 Item item
= ItemImpl::required(itemRef
);
123 item
->modifyContent(attrList
, length
, data
);
129 SecKeychainItemCopyContent(SecKeychainItemRef itemRef
, SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
133 Item item
= ItemImpl::required(itemRef
);
134 item
->getContent(itemClass
, attrList
, length
, outData
);
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
);
144 itemImplRef
= (SecKeychainItemRef
) SecCertificateCreateItemImplInstance((SecCertificateRef
)itemRef
);
146 isCertificate
= true;
149 itemImplRef
= (SecKeychainItemRef
)((itemRef
) ? CFRetain(itemRef
) : NULL
);
154 Item item
= ItemImpl::required(itemImplRef
);
155 item
->getContent(itemClass
, attrList
, (isCertificate
) ? NULL
: length
, (isCertificate
) ? NULL
: outData
);
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
; }
163 if (isCertificate
&& outData
&& *outData
== NULL
) {
164 // copy the data here
165 __secapiresult
= errSecAllocate
;
166 CFDataRef dataRef
= SecCertificateCopyData((SecCertificateRef
)itemRef
);
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
;
180 CFRelease(itemImplRef
);
182 return __secapiresult
;
188 SecKeychainItemFreeContent(SecKeychainAttributeList
*attrList
, void *data
)
191 ItemImpl::freeContent(attrList
, data
);
197 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
200 Item item
= ItemImpl::required(itemRef
);
201 item
->modifyAttributesAndData(attrList
, length
, data
);
207 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
211 Item item
= ItemImpl::required(itemRef
);
212 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
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
);
222 itemImplRef
= (SecKeychainItemRef
) SecCertificateCreateItemImplInstance((SecCertificateRef
)itemRef
);
226 itemImplRef
= (SecKeychainItemRef
)((itemRef
) ? CFRetain(itemRef
) : NULL
);
231 Item item
= ItemImpl::required(itemImplRef
);
232 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
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
; }
241 CFRelease(itemImplRef
);
243 return __secapiresult
;
249 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
252 ItemImpl::freeAttributesAndData(attrList
, data
);
258 SecKeychainItemDelete(SecKeychainItemRef itemRef
)
262 Item item
= ItemImpl::required( itemRef
);
263 Keychain keychain
= item
->keychain();
264 // item must be persistent.
265 KCThrowIf_( !keychain
, errSecInvalidItemRef
);
268 * Before deleting the item, delete any existing Extended Attributes.
271 CFArrayRef attrNames
= NULL
;
272 ortn
= SecKeychainItemCopyAllExtendedAttributes(itemRef
, &attrNames
, NULL
);
273 if(ortn
== errSecSuccess
) {
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
);
282 /* now delete the item */
283 keychain
->deleteItem( item
);
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
);
293 itemImplRef
= (SecKeychainItemRef
) SecCertificateCreateItemImplInstance((SecCertificateRef
)itemRef
);
297 itemImplRef
= (SecKeychainItemRef
)((itemRef
) ? CFRetain(itemRef
) : NULL
);
302 Item item
= ItemImpl::required( itemImplRef
);
303 Keychain keychain
= item
->keychain();
304 // item must be persistent.
305 KCThrowIf_( !keychain
, errSecInvalidItemRef
);
308 * Before deleting the item, delete any existing Extended Attributes.
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
);
322 /* now delete the item */
323 keychain
->deleteItem( item
);
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
; }
332 CFRelease(itemImplRef
);
334 return __secapiresult
;
340 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef
, SecKeychainRef
* keychainRef
)
344 // make sure this item has a keychain
345 Keychain kc
= ItemImpl::required(itemRef
)->keychain ();
348 MacOSError::throwMe(errSecNoSuchKeychain
);
351 Required(keychainRef
) = kc
->handle();
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
);
361 itemImplRef
= (SecKeychainItemRef
) SecCertificateCreateItemImplInstance((SecCertificateRef
)itemRef
);
365 itemImplRef
= (SecKeychainItemRef
)((itemRef
) ? CFRetain(itemRef
) : NULL
);
370 // make sure this item has a keychain
371 Keychain kc
= ItemImpl::required(itemImplRef
)->keychain();
374 MacOSError::throwMe(errSecNoSuchKeychain
);
377 Required(keychainRef
) = kc
->handle();
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
; }
386 CFRelease(itemImplRef
);
388 return __secapiresult
;
394 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef
, SecKeychainRef destKeychainRef
,
395 SecAccessRef initialAccess
, SecKeychainItemRef
*itemCopy
)
398 // bridge code for certificate items
399 if (itemRef
&& CFGetTypeID(itemRef
) == SecCertificateGetTypeID()) {
400 return SecCertificateAddToKeychain((SecCertificateRef
)itemRef
, destKeychainRef
);
405 Item copy
= ItemImpl::required(itemRef
)->copyTo(Keychain::optional(destKeychainRef
), Access::optional(initialAccess
));
407 *itemCopy
= copy
->handle();
413 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef
, const CSSM_DB_UNIQUE_RECORD
**uniqueRecordID
)
416 Required(uniqueRecordID
) = ItemImpl::required(itemRef
)->dbUniqueRecord();
422 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef
, CSSM_DL_DB_HANDLE
* dldbHandle
)
425 *dldbHandle
= ItemImpl::required(itemRef
)->keychain()->database()->handle();
431 OSStatus
SecAccessCreateFromObject(CFTypeRef sourceRef
,
432 SecAccessRef
*accessRef
)
435 Required(accessRef
); // preflight
436 SecPointer
<Access
> access
= new Access(*aclBearer(sourceRef
));
437 *accessRef
= access
->handle();
445 OSStatus
SecAccessModifyObject(SecAccessRef accessRef
, CFTypeRef sourceRef
)
448 Access::required(accessRef
)->setAccess(*aclBearer(sourceRef
), true);
454 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef
, SecAccessRef
* accessRef
)
458 Required(accessRef
); // preflight
459 SecPointer
<Access
> access
= new Access(*aclBearer(reinterpret_cast<CFTypeRef
>(itemRef
)));
460 *accessRef
= access
->handle();
467 SecKeychainItemSetAccess(SecKeychainItemRef itemRef
, SecAccessRef accessRef
)
471 Access::required(accessRef
)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(itemRef
)), true);
473 ItemImpl::required(itemRef
)->postItemEvent (kSecUpdateEvent
);
478 /* Sets an item's data for legacy "KC" CoreServices APIs.
479 Note this version sets the data, but doesn't update the item
480 as the KC behavior dictates.
482 OSStatus
SecKeychainItemSetData(SecKeychainItemRef itemRef
, UInt32 length
, const void* data
)
485 ItemImpl::required(itemRef
)->setData(length
, data
);
489 /* Gets an item's data for legacy "KC" CoreServices APIs.
490 Note this version doesn't take a SecItemClass parameter.
492 OSStatus
SecKeychainItemGetData(SecKeychainItemRef itemRef
, UInt32 maxLength
, void* data
, UInt32
* actualLength
)
495 /* 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. */
496 if (!((data
&& maxLength
) || actualLength
))
497 MacOSError::throwMe(errSecParam
);
499 CssmDataContainer aData
;
500 ItemImpl::required(itemRef
)->getData(aData
);
502 *actualLength
= (UInt32
)aData
.length();
506 // Make sure the buffer is big enough
507 if (aData
.length() > maxLength
)
508 MacOSError::throwMe(errSecBufferTooSmall
);
509 memcpy(data
, aData
.data(), aData
.length());
514 /* Update a keychain item for legacy "KC" CoreServices APIs.
515 The "KC" API's do a 'set attribute', then an 'update'.
517 OSStatus
SecKeychainItemUpdate(SecKeychainItemRef itemRef
)
520 ItemImpl::required(itemRef
)->update();
524 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
526 OSStatus
SecKeychainItemAddNoUI(SecKeychainRef keychainRef
, SecKeychainItemRef itemRef
)
529 Item item
= ItemImpl::required(itemRef
);
530 Keychain::optional(keychainRef
)->add(item
);
534 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
536 OSStatus
SecKeychainItemAdd(SecKeychainItemRef itemRef
)
539 Item item
= ItemImpl::required(itemRef
);
540 Keychain defaultKeychain
= globals().storageManager
.defaultKeychainUI(item
);
541 defaultKeychain
->add(item
);
545 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
547 OSStatus
SecKeychainItemCreateNew(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, SecKeychainItemRef
* itemRef
)
550 RequiredParam(itemRef
) = Item(itemClass
, itemCreator
, length
, data
, false)->handle();
554 /* Gets an individual attribute for legacy "KC" CoreServices APIs
556 OSStatus
SecKeychainItemGetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
, UInt32
* actualLength
)
559 ItemImpl::required(itemRef
)->getAttribute(RequiredParam(attribute
), actualLength
);
563 /* Sets an individual attribute for legacy "KC" CoreServices APIs
565 OSStatus
SecKeychainItemSetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
)
568 ItemImpl::required(itemRef
)->setAttribute(RequiredParam(attribute
));
572 /* Finds a keychain item for legacy "KC" CoreServices APIs.
573 Note: This version doesn't take a SecItemClass because
574 SecKeychainSearchCreateFromAttributes() requires it.
575 @@@ This should move to SecKeychainSearch.cpp
577 OSStatus
SecKeychainItemFindFirst(SecKeychainRef keychainRef
, const SecKeychainAttributeList
*attrList
, SecKeychainSearchRef
*searchRef
, SecKeychainItemRef
*itemRef
)
582 cursor
= KeychainImpl::required(keychainRef
)->createCursor(attrList
);
584 cursor
= globals().storageManager
.createCursor(attrList
);
587 if (!cursor
->next(item
))
588 return errSecItemNotFound
;
590 *itemRef
=item
->handle();
592 *searchRef
=cursor
->handle();
597 static OSStatus
SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef
,
598 CFDataRef
*persistentItemRef
)
600 if (!certRef
|| !persistentItemRef
)
603 OSStatus __secapiresult
;
604 CFErrorRef errorRef
= NULL
;
605 CFDataRef serialData
= SecCertificateCopySerialNumber(certRef
, &errorRef
);
607 CFIndex err
= CFErrorGetCode(errorRef
);
609 if (serialData
) { CFRelease(serialData
); }
610 return (OSStatus
)err
;
612 CFDataRef issuerData
= SecCertificateCopyNormalizedIssuerContent(certRef
, &errorRef
);
614 CFIndex err
= CFErrorGetCode(errorRef
);
616 if (serialData
) { CFRelease(serialData
); }
617 if (issuerData
) { CFRelease(issuerData
); }
618 return (OSStatus
)err
;
622 // look up ItemImpl cert in keychain by normalized issuer and serial number
623 StorageManager::KeychainList keychains
;
624 globals().storageManager
.optionalSearchList(NULL
, keychains
);
625 KCCursor
cursor(Certificate::cursorForIssuerAndSN_CF(keychains
, issuerData
, serialData
));
627 if (!cursor
->next(item
)) {
628 MacOSError::throwMe(errSecItemNotFound
);
630 item
->copyPersistentReference(*persistentItemRef
, false);
631 __secapiresult
= errSecSuccess
;
633 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
634 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
635 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
636 catch (...) { __secapiresult
=errSecInternalComponent
; }
639 CFRelease(serialData
);
641 CFRelease(issuerData
);
643 return __secapiresult
;
647 OSStatus
SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef
, CFDataRef
*persistentItemRef
)
652 KCThrowParamErrIf_(!itemRef
|| !persistentItemRef
);
654 bool isIdentityRef
= (CFGetTypeID(itemRef
) == SecIdentityGetTypeID()) ? true : false;
655 bool isCertificateRef
= (CFGetTypeID(itemRef
) == SecCertificateGetTypeID()) ? true : false;
657 SecPointer
<Certificate
> certificatePtr(Identity::required((SecIdentityRef
)itemRef
)->certificate());
658 SecCertificateRef certificateRef
= certificatePtr
->handle(false);
659 item
= ItemImpl::required((SecKeychainItemRef
)certificateRef
);
660 item
->copyPersistentReference(*persistentItemRef
, true);
662 else if (isCertificateRef
) {
663 item
= ItemImpl::required(itemRef
);
664 item
->copyPersistentReference(*persistentItemRef
, false);
667 item
= ItemImpl::required(itemRef
);
668 item
->copyPersistentReference(*persistentItemRef
, false);
673 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */
674 if (!itemRef
|| !persistentItemRef
) {
677 bool isIdentityRef
= (CFGetTypeID(itemRef
) == SecIdentityGetTypeID()) ? true : false;
678 bool isCertificateRef
= (CFGetTypeID(itemRef
) == SecCertificateGetTypeID()) ? true : false;
679 SecCertificateRef certRef
= NULL
;
681 SecIdentityCopyCertificate((SecIdentityRef
)itemRef
, &certRef
);
683 else if (isCertificateRef
) {
684 certRef
= (SecCertificateRef
) CFRetain(itemRef
);
687 OSStatus status
= SecKeychainItemCreatePersistentReferenceFromCertificate(certRef
, persistentItemRef
);
691 // otherwise, not a certificate, so proceed as usual for keychain item
694 Item item
= ItemImpl::required(itemRef
);
695 item
->copyPersistentReference(*persistentItemRef
, false);
701 OSStatus
SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef
, SecKeychainItemRef
*itemRef
)
705 KCThrowParamErrIf_(!persistentItemRef
|| !itemRef
);
706 CFTypeRef result
= NULL
;
707 bool isIdentityRef
= false;
708 Item item
= ItemImpl::makeFromPersistentReference(persistentItemRef
, &isIdentityRef
);
710 // item was stored as an identity, attempt to reconstitute it
711 SecPointer
<Certificate
> certificatePtr(static_cast<Certificate
*>(item
.get()));
712 StorageManager::KeychainList keychains
;
713 globals().storageManager
.optionalSearchList(NULL
, keychains
);
714 SecPointer
<Identity
> identityPtr(new Identity(keychains
, certificatePtr
));
715 result
= identityPtr
->handle();
716 KCThrowIf_( !result
, errSecItemNotFound
);
719 result
= item
->handle();
721 *itemRef
= (SecKeychainItemRef
) result
;
724 /* see if we should convert outgoing item to a unified SecCertificateRef */
725 SecItemClass tmpItemClass
= Schema::itemClassFor(item
->recordType());
726 if (tmpItemClass
== kSecCertificateItemClass
) {
727 SecPointer
<Certificate
> certificate(static_cast<Certificate
*>(&*item
));
728 CssmData certData
= certificate
->data();
729 CFDataRef data
= NULL
;
730 if (certData
.Data
&& certData
.Length
) {
731 data
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
735 if (certData
.Data
&& !certData
.Length
) {
736 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)",
737 (uintptr_t)certData
.Data
);
738 return errSecDataNotAvailable
;
741 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)",
742 (long)certData
.Length
, (uintptr_t)certData
.Data
);
743 return errSecInternal
;
746 SecKeychainItemRef tmpRef
= *itemRef
;
747 *itemRef
= (SecKeychainItemRef
) SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
);
758 OSStatus
SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef
, CFDataRef
*recordIdentifier
)
762 RequiredParam (recordIdentifier
);
763 Item item
= ItemImpl::required(itemRef
);
764 item
->copyRecordIdentifier (data
);
765 *recordIdentifier
= ::CFDataCreate(kCFAllocatorDefault
, (UInt8
*) data
.Data
, data
.Length
);
771 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef
,
772 SecKeychainItemRef
*itemRef
,
773 CFDataRef recordIdentifier
)
776 // make a local Keychain reference
777 RequiredParam (keychainRef
);
778 Keychain keychain
= KeychainImpl::optional (keychainRef
);
779 RequiredParam (itemRef
);
780 RequiredParam (recordIdentifier
);
782 Db
db(keychain
->database());
784 // make a raw database call to get the data
785 CSSM_DL_DB_HANDLE dbHandle
= db
.handle ();
786 CSSM_DB_UNIQUE_RECORD uniqueRecord
;
788 // according to source, we should be able to reconsitute the uniqueRecord
789 // from the data we earlier retained
791 // prepare the record id
792 memset (&uniqueRecord
, 0, sizeof (uniqueRecord
));
793 uniqueRecord
.RecordIdentifier
.Data
= (uint8
*) CFDataGetBytePtr (recordIdentifier
);
794 uniqueRecord
.RecordIdentifier
.Length
= CFDataGetLength (recordIdentifier
);
796 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
797 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr
;
799 result
= CSSM_DL_PassThrough (dbHandle
, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER
, &uniqueRecord
, (void**) &outputUniqueRecordPtr
);
800 KCThrowIf_(result
!= 0, errSecItemNotFound
);
802 // from this, get the record type
803 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData
;
804 memset (&attributeData
, 0, sizeof (attributeData
));
806 result
= CSSM_DL_DataGetFromUniqueRecordId (dbHandle
, outputUniqueRecordPtr
, &attributeData
, NULL
);
807 KCThrowIf_(result
!= 0, errSecItemNotFound
);
808 CSSM_DB_RECORDTYPE recordType
= attributeData
.DataRecordType
;
810 // make the unique record item -- precursor to creation of a SecKeychainItemRef
811 DbUniqueRecord
unique(db
);
812 CSSM_DB_UNIQUE_RECORD_PTR
*uniquePtr
= unique
;
813 *uniquePtr
= outputUniqueRecordPtr
;
816 Item item
= keychain
->item (recordType
, unique
);
819 *itemRef
= item
->handle();
824 OSStatus
SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass
,
825 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
826 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
, CFDataRef
*localID
)
829 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
831 RequiredParam (localID
);
832 RequiredParam (keychainRef
);
834 Item
item(itemClass
, (uint32
) 0, length
, data
, true);
836 item
->setAccess(Access::required(initialAccess
));
838 Keychain keychain
= Keychain::optional(keychainRef
);
839 if (!keychain
->exists())
841 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
844 item
->doNotEncrypt ();
849 catch (const CommonError
&err
)
851 if (err
.osStatus () == errSecNoSuchClass
)
853 // the only time this should happen is if the item is a certificate (for keychain syncing)
854 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
)
856 // create the certificate relation
857 Db
db(keychain
->database());
859 db
->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
860 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
861 Schema::X509CertificateSchemaAttributeCount
,
862 Schema::X509CertificateSchemaAttributeList
,
863 Schema::X509CertificateSchemaIndexCount
,
864 Schema::X509CertificateSchemaIndexList
);
865 keychain
->keychainSchema()->didCreateRelation(
866 CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
867 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
868 Schema::X509CertificateSchemaAttributeCount
,
869 Schema::X509CertificateSchemaAttributeList
,
870 Schema::X509CertificateSchemaIndexCount
,
871 Schema::X509CertificateSchemaIndexList
);
873 // add the item again
884 *itemRef
= item
->handle();
887 item
->copyRecordIdentifier (recordID
);
889 *localID
= CFDataCreate(kCFAllocatorDefault
, (UInt8
*) recordID
.Data
, recordID
.Length
);
890 free (recordID
.Data
);
894 OSStatus
SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
,
895 SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
,
896 UInt32
*length
, void **outData
)
899 Item item
= ItemImpl::required(itemRef
);
900 item
->doNotEncrypt ();
901 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
905 OSStatus
SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef
, UInt32 length
, const void *data
)
908 Item item
= ItemImpl::required(itemRef
);
909 item
->doNotEncrypt ();
910 item
->modifyAttributesAndData(NULL
, length
, data
);