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 OSStatus
SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef
, SecAccessRef accessRef
, UInt32 passwordLength
, const void * password
) {
483 // try to unlock the keychain with this password first
484 SecKeychainRef kc
= NULL
;
485 result
= SecKeychainItemCopyKeychain(itemRef
, &kc
);
487 SecKeychainUnlock(kc
, passwordLength
, password
, true);
493 // Create some credentials with this password
494 CssmAutoData
data(Allocator::standard(), password
, passwordLength
);
495 AclFactory::PassphraseUnlockCredentials
cred(data
, Allocator::standard());
497 Access::required(accessRef
)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(itemRef
)), true, cred
.getAccessCredentials());
498 ItemImpl::required(itemRef
)->postItemEvent (kSecUpdateEvent
);
504 /* Sets an item's data for legacy "KC" CoreServices APIs.
505 Note this version sets the data, but doesn't update the item
506 as the KC behavior dictates.
508 OSStatus
SecKeychainItemSetData(SecKeychainItemRef itemRef
, UInt32 length
, const void* data
)
511 ItemImpl::required(itemRef
)->setData(length
, data
);
515 /* Gets an item's data for legacy "KC" CoreServices APIs.
516 Note this version doesn't take a SecItemClass parameter.
518 OSStatus
SecKeychainItemGetData(SecKeychainItemRef itemRef
, UInt32 maxLength
, void* data
, UInt32
* actualLength
)
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
))
523 MacOSError::throwMe(errSecParam
);
525 CssmDataContainer aData
;
526 ItemImpl::required(itemRef
)->getData(aData
);
528 *actualLength
= (UInt32
)aData
.length();
532 // Make sure the buffer is big enough
533 if (aData
.length() > maxLength
)
534 MacOSError::throwMe(errSecBufferTooSmall
);
535 memcpy(data
, aData
.data(), aData
.length());
540 /* Update a keychain item for legacy "KC" CoreServices APIs.
541 The "KC" API's do a 'set attribute', then an 'update'.
543 OSStatus
SecKeychainItemUpdate(SecKeychainItemRef itemRef
)
546 ItemImpl::required(itemRef
)->update();
550 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
552 OSStatus
SecKeychainItemAddNoUI(SecKeychainRef keychainRef
, SecKeychainItemRef itemRef
)
555 Item item
= ItemImpl::required(itemRef
);
556 Keychain::optional(keychainRef
)->add(item
);
560 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
562 OSStatus
SecKeychainItemAdd(SecKeychainItemRef itemRef
)
565 Item item
= ItemImpl::required(itemRef
);
566 Keychain defaultKeychain
= globals().storageManager
.defaultKeychainUI(item
);
567 defaultKeychain
->add(item
);
571 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
573 OSStatus
SecKeychainItemCreateNew(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, SecKeychainItemRef
* itemRef
)
576 RequiredParam(itemRef
) = Item(itemClass
, itemCreator
, length
, data
, false)->handle();
580 /* Gets an individual attribute for legacy "KC" CoreServices APIs
582 OSStatus
SecKeychainItemGetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
, UInt32
* actualLength
)
585 ItemImpl::required(itemRef
)->getAttribute(RequiredParam(attribute
), actualLength
);
589 /* Sets an individual attribute for legacy "KC" CoreServices APIs
591 OSStatus
SecKeychainItemSetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
)
594 ItemImpl::required(itemRef
)->setAttribute(RequiredParam(attribute
));
598 /* Finds a keychain item for legacy "KC" CoreServices APIs.
599 Note: This version doesn't take a SecItemClass because
600 SecKeychainSearchCreateFromAttributes() requires it.
601 @@@ This should move to SecKeychainSearch.cpp
603 OSStatus
SecKeychainItemFindFirst(SecKeychainRef keychainRef
, const SecKeychainAttributeList
*attrList
, SecKeychainSearchRef
*searchRef
, SecKeychainItemRef
*itemRef
)
608 cursor
= KeychainImpl::required(keychainRef
)->createCursor(attrList
);
610 cursor
= globals().storageManager
.createCursor(attrList
);
613 if (!cursor
->next(item
))
614 return errSecItemNotFound
;
616 *itemRef
=item
->handle();
618 *searchRef
=cursor
->handle();
623 static OSStatus
SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef
,
624 CFDataRef
*persistentItemRef
)
626 if (!certRef
|| !persistentItemRef
)
629 OSStatus __secapiresult
;
630 CFErrorRef errorRef
= NULL
;
631 CFDataRef serialData
= SecCertificateCopySerialNumber(certRef
, &errorRef
);
633 CFIndex err
= CFErrorGetCode(errorRef
);
635 if (serialData
) { CFRelease(serialData
); }
636 return (OSStatus
)err
;
638 CFDataRef issuerData
= SecCertificateCopyNormalizedIssuerContent(certRef
, &errorRef
);
640 CFIndex err
= CFErrorGetCode(errorRef
);
642 if (serialData
) { CFRelease(serialData
); }
643 if (issuerData
) { CFRelease(issuerData
); }
644 return (OSStatus
)err
;
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
));
653 if (!cursor
->next(item
)) {
654 MacOSError::throwMe(errSecItemNotFound
);
656 item
->copyPersistentReference(*persistentItemRef
, false);
657 __secapiresult
= errSecSuccess
;
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
; }
665 CFRelease(serialData
);
667 CFRelease(issuerData
);
669 return __secapiresult
;
673 OSStatus
SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef
, CFDataRef
*persistentItemRef
)
678 KCThrowParamErrIf_(!itemRef
|| !persistentItemRef
);
680 bool isIdentityRef
= (CFGetTypeID(itemRef
) == SecIdentityGetTypeID()) ? true : false;
681 bool isCertificateRef
= (CFGetTypeID(itemRef
) == SecCertificateGetTypeID()) ? true : false;
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);
688 else if (isCertificateRef
) {
689 item
= ItemImpl::required(itemRef
);
690 item
->copyPersistentReference(*persistentItemRef
, false);
693 item
= ItemImpl::required(itemRef
);
694 item
->copyPersistentReference(*persistentItemRef
, false);
699 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */
700 if (!itemRef
|| !persistentItemRef
) {
703 bool isIdentityRef
= (CFGetTypeID(itemRef
) == SecIdentityGetTypeID()) ? true : false;
704 bool isCertificateRef
= (CFGetTypeID(itemRef
) == SecCertificateGetTypeID()) ? true : false;
705 SecCertificateRef certRef
= NULL
;
707 SecIdentityCopyCertificate((SecIdentityRef
)itemRef
, &certRef
);
709 else if (isCertificateRef
) {
710 certRef
= (SecCertificateRef
) CFRetain(itemRef
);
713 OSStatus status
= SecKeychainItemCreatePersistentReferenceFromCertificate(certRef
, persistentItemRef
);
717 // otherwise, not a certificate, so proceed as usual for keychain item
720 Item item
= ItemImpl::required(itemRef
);
721 item
->copyPersistentReference(*persistentItemRef
, false);
727 OSStatus
SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef
, SecKeychainItemRef
*itemRef
)
731 KCThrowParamErrIf_(!persistentItemRef
|| !itemRef
);
732 CFTypeRef result
= NULL
;
733 bool isIdentityRef
= false;
734 Item item
= ItemImpl::makeFromPersistentReference(persistentItemRef
, &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
);
745 result
= item
->handle();
747 *itemRef
= (SecKeychainItemRef
) result
;
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
);
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
;
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
;
772 SecKeychainItemRef tmpRef
= *itemRef
;
773 *itemRef
= (SecKeychainItemRef
) SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
);
784 OSStatus
SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef
, CFDataRef
*recordIdentifier
)
788 RequiredParam (recordIdentifier
);
789 Item item
= ItemImpl::required(itemRef
);
790 item
->copyRecordIdentifier (data
);
791 *recordIdentifier
= ::CFDataCreate(kCFAllocatorDefault
, (UInt8
*) data
.Data
, data
.Length
);
797 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef
,
798 SecKeychainItemRef
*itemRef
,
799 CFDataRef recordIdentifier
)
802 // make a local Keychain reference
803 RequiredParam (keychainRef
);
804 Keychain keychain
= KeychainImpl::optional (keychainRef
);
805 RequiredParam (itemRef
);
806 RequiredParam (recordIdentifier
);
808 Db
db(keychain
->database());
810 // make a raw database call to get the data
811 CSSM_DL_DB_HANDLE dbHandle
= db
.handle ();
812 CSSM_DB_UNIQUE_RECORD uniqueRecord
;
814 // according to source, we should be able to reconsitute the uniqueRecord
815 // from the data we earlier retained
817 // prepare the record id
818 memset (&uniqueRecord
, 0, sizeof (uniqueRecord
));
819 uniqueRecord
.RecordIdentifier
.Data
= (uint8
*) CFDataGetBytePtr (recordIdentifier
);
820 uniqueRecord
.RecordIdentifier
.Length
= CFDataGetLength (recordIdentifier
);
822 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
823 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr
;
825 result
= CSSM_DL_PassThrough (dbHandle
, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER
, &uniqueRecord
, (void**) &outputUniqueRecordPtr
);
826 KCThrowIf_(result
!= 0, errSecItemNotFound
);
828 // from this, get the record type
829 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData
;
830 memset (&attributeData
, 0, sizeof (attributeData
));
832 result
= CSSM_DL_DataGetFromUniqueRecordId (dbHandle
, outputUniqueRecordPtr
, &attributeData
, NULL
);
833 KCThrowIf_(result
!= 0, errSecItemNotFound
);
834 CSSM_DB_RECORDTYPE recordType
= attributeData
.DataRecordType
;
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
;
842 Item item
= keychain
->item (recordType
, unique
);
845 *itemRef
= item
->handle();
850 OSStatus
SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass
,
851 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
852 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
, CFDataRef
*localID
)
855 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
857 RequiredParam (localID
);
858 RequiredParam (keychainRef
);
860 Item
item(itemClass
, (uint32
) 0, length
, data
, true);
862 item
->setAccess(Access::required(initialAccess
));
864 Keychain keychain
= Keychain::optional(keychainRef
);
865 if (!keychain
->exists())
867 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
870 item
->doNotEncrypt ();
875 catch (const CommonError
&err
)
877 if (err
.osStatus () == errSecNoSuchClass
)
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
)
882 // create the certificate relation
883 Db
db(keychain
->database());
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
);
899 // add the item again
910 *itemRef
= item
->handle();
913 item
->copyRecordIdentifier (recordID
);
915 *localID
= CFDataCreate(kCFAllocatorDefault
, (UInt8
*) recordID
.Data
, recordID
.Length
);
916 free (recordID
.Data
);
920 OSStatus
SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
,
921 SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
,
922 UInt32
*length
, void **outData
)
925 Item item
= ItemImpl::required(itemRef
);
926 item
->doNotEncrypt ();
927 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
931 OSStatus
SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef
, UInt32 length
, const void *data
)
934 Item item
= ItemImpl::required(itemRef
);
935 item
->doNotEncrypt ();
936 item
->modifyAttributesAndData(NULL
, length
, data
);