2 * Copyright (c) 2000-2004,2011-2016 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>
28 #include <Security/SecItemPriv.h>
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
37 #include <securityd_client/dictionary.h>
38 #include <security_cdsa_utilities/Schema.h>
39 #include <Security/cssmapplePriv.h>
42 #include "SecBridge.h"
43 #include "KCExceptions.h"
45 #include "SecKeychainItemExtendedAttributes.h"
47 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
50 // Given a polymorphic Sec type object, return
51 // its AclBearer component.
52 // Note: Login ACLs are not hooked into this layer;
53 // modules or attachments have no Sec* layer representation.
56 RefPointer
<AclBearer
> aclBearer(CFTypeRef itemRef
)
58 // well, exactly what kind of something are you?
59 CFTypeID id
= CFGetTypeID(itemRef
);
60 if (id
== gTypes().ItemImpl
.typeID
) {
61 // keychain item. If it's in a protected group, return the group key
62 if (SSGroup group
= ItemImpl::required(SecKeychainItemRef(itemRef
))->group())
64 } else if (id
== SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef
)itemRef
)) {
65 // key item, return the key itself.
66 if (CssmClient::Key key
= KeyItem::required(SecKeyRef(itemRef
))->key())
68 } else if (id
== gTypes().KeychainImpl
.typeID
) {
69 // keychain (this yields the database ACL)
70 //@@@ not hooked up yet
73 MacOSError::throwMe(errSecNoAccessForItem
);
78 SecKeychainItemGetTypeID(void)
82 return gTypes().ItemImpl
.typeID
;
84 END_SECAPI1(_kCFRuntimeNotATypeID
)
89 SecKeychainItemCreateFromContent(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
,
90 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
91 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
)
95 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
96 Item
item(itemClass
, attrList
, length
, data
);
98 item
->setAccess(Access::required(initialAccess
));
100 Keychain keychain
= nil
;
103 keychain
= Keychain::optional(keychainRef
);
104 if ( !keychain
->exists() )
106 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
111 keychain
= globals().storageManager
.defaultKeychainUI(item
);
116 *itemRef
= item
->handle();
124 SecKeychainItemModifyContent(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
128 Item item
= ItemImpl::required(__itemImplRef
);
129 item
->modifyContent(attrList
, length
, data
);
136 SecKeychainItemCopyContent(SecKeychainItemRef itemRef
, SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
140 Item item
= ItemImpl::required(__itemImplRef
);
141 item
->getContent(itemClass
, attrList
, length
, outData
);
148 SecKeychainItemFreeContent(SecKeychainAttributeList
*attrList
, void *data
)
152 ItemImpl::freeContent(attrList
, data
);
159 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
163 Item item
= ItemImpl::required(__itemImplRef
);
164 item
->modifyAttributesAndData(attrList
, length
, data
);
171 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
175 Item item
= ItemImpl::required(__itemImplRef
);
176 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
183 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
187 ItemImpl::freeAttributesAndData(attrList
, data
);
194 SecKeychainItemDelete(SecKeychainItemRef itemRef
)
198 Item item
= ItemImpl::required(__itemImplRef
);
199 Keychain keychain
= item
->keychain();
200 // item must be persistent.
201 KCThrowIf_( !keychain
, errSecInvalidItemRef
);
204 * Before deleting the item, delete any existing Extended Attributes.
207 CFArrayRef attrNames
= NULL
;
208 ortn
= SecKeychainItemCopyAllExtendedAttributes(__itemImplRef
, &attrNames
, NULL
);
209 if(ortn
== errSecSuccess
) {
210 CFIndex numAttrs
= CFArrayGetCount(attrNames
);
211 for(CFIndex dex
=0; dex
<numAttrs
; dex
++) {
212 CFStringRef attrName
= (CFStringRef
)CFArrayGetValueAtIndex(attrNames
, dex
);
213 /* setting value to NULL ==> delete */
214 SecKeychainItemSetExtendedAttribute(__itemImplRef
, attrName
, NULL
);
218 /* now delete the item */
219 keychain
->deleteItem( item
);
226 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef
, SecKeychainRef
* keychainRef
)
230 // make sure this item has a keychain
231 Keychain kc
= ItemImpl::required(__itemImplRef
)->keychain();
234 MacOSError::throwMe(errSecNoSuchKeychain
);
237 Required(keychainRef
) = kc
->handle();
244 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef
, SecKeychainRef destKeychainRef
,
245 SecAccessRef initialAccess
, SecKeychainItemRef
*itemCopy
)
249 Item copy
= ItemImpl::required(__itemImplRef
)->copyTo(Keychain::optional(destKeychainRef
), Access::optional(initialAccess
));
251 *itemCopy
= copy
->handle();
259 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef
, const CSSM_DB_UNIQUE_RECORD
**uniqueRecordID
)
263 Required(uniqueRecordID
) = ItemImpl::required(__itemImplRef
)->dbUniqueRecord();
270 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef
, CSSM_DL_DB_HANDLE
* dldbHandle
)
274 *dldbHandle
= ItemImpl::required(__itemImplRef
)->keychain()->database()->handle();
281 OSStatus
SecAccessCreateFromObject(CFTypeRef sourceRef
,
282 SecAccessRef
*accessRef
)
286 Required(accessRef
); // preflight
287 SecPointer
<Access
> access
= new Access(*aclBearer(sourceRef
));
288 *accessRef
= access
->handle();
297 OSStatus
SecAccessModifyObject(SecAccessRef accessRef
, CFTypeRef sourceRef
)
301 Access::required(accessRef
)->setAccess(*aclBearer(sourceRef
), true);
308 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef
, SecAccessRef
* accessRef
)
312 Required(accessRef
); // preflight
313 SecPointer
<Access
> access
= new Access(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)));
314 *accessRef
= access
->handle();
321 SecKeychainItemSetAccess(SecKeychainItemRef itemRef
, SecAccessRef accessRef
)
325 Access::required(accessRef
)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)), true);
327 ItemImpl::required(__itemImplRef
)->postItemEvent(kSecUpdateEvent
);
332 OSStatus
SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef
, SecAccessRef accessRef
, UInt32 passwordLength
, const void * password
)
338 // try to unlock the keychain with this password first
339 SecKeychainRef kc
= NULL
;
340 result
= SecKeychainItemCopyKeychain(__itemImplRef
, &kc
);
342 SecKeychainUnlock(kc
, passwordLength
, password
, true);
348 // Create some credentials with this password
349 CssmAutoData
data(Allocator::standard(), password
, passwordLength
);
350 AclFactory::PassphraseUnlockCredentials
cred(data
, Allocator::standard());
352 Access::required(accessRef
)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)), true, cred
.getAccessCredentials());
353 ItemImpl::required(itemRef
)->postItemEvent (kSecUpdateEvent
);
359 /* Sets an item's data for legacy "KC" CoreServices APIs.
360 Note this version sets the data, but doesn't update the item
361 as the KC behavior dictates.
363 OSStatus
SecKeychainItemSetData(SecKeychainItemRef itemRef
, UInt32 length
, const void* data
)
367 ItemImpl::required(__itemImplRef
)->setData(length
, data
);
372 /* Gets an item's data for legacy "KC" CoreServices APIs.
373 Note this version doesn't take a SecItemClass parameter.
375 OSStatus
SecKeychainItemGetData(SecKeychainItemRef itemRef
, UInt32 maxLength
, void* data
, UInt32
* actualLength
)
379 /* The caller either needs to specify data and maxLength or an actualLength,
380 * so we return either the data itself or the actual length of the data or both.
382 if (!((data
&& maxLength
) || actualLength
)) {
383 MacOSError::throwMe(errSecParam
);
385 CssmDataContainer aData
;
386 ItemImpl::required(__itemImplRef
)->getData(aData
);
388 *actualLength
= (UInt32
)aData
.length();
391 // Make sure the buffer is big enough
392 if (aData
.length() > maxLength
) {
393 MacOSError::throwMe(errSecBufferTooSmall
);
395 memcpy(data
, aData
.data(), aData
.length());
401 /* Update a keychain item for legacy "KC" CoreServices APIs.
402 The "KC" API's do a 'set attribute', then an 'update'.
404 OSStatus
SecKeychainItemUpdate(SecKeychainItemRef itemRef
)
408 ItemImpl::required(__itemImplRef
)->update();
413 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
415 OSStatus
SecKeychainItemAddNoUI(SecKeychainRef keychainRef
, SecKeychainItemRef itemRef
)
419 Item item
= ItemImpl::required(__itemImplRef
);
420 Keychain::optional(keychainRef
)->add(item
);
425 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
427 OSStatus
SecKeychainItemAdd(SecKeychainItemRef itemRef
)
431 Item item
= ItemImpl::required(__itemImplRef
);
432 Keychain defaultKeychain
= globals().storageManager
.defaultKeychainUI(item
);
433 defaultKeychain
->add(item
);
438 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
440 OSStatus
SecKeychainItemCreateNew(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, SecKeychainItemRef
* itemRef
)
444 RequiredParam(itemRef
) = Item(itemClass
, itemCreator
, length
, data
, false)->handle();
449 /* Gets an individual attribute for legacy "KC" CoreServices APIs
451 OSStatus
SecKeychainItemGetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
, UInt32
* actualLength
)
455 ItemImpl::required(__itemImplRef
)->getAttribute(RequiredParam(attribute
), actualLength
);
460 /* Sets an individual attribute for legacy "KC" CoreServices APIs
462 OSStatus
SecKeychainItemSetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
)
466 ItemImpl::required(__itemImplRef
)->setAttribute(RequiredParam(attribute
));
471 /* Finds a keychain item for legacy "KC" CoreServices APIs.
472 Note: This version doesn't take a SecItemClass because
473 SecKeychainSearchCreateFromAttributes() requires it.
474 @@@ This should move to SecKeychainSearch.cpp
476 OSStatus
SecKeychainItemFindFirst(SecKeychainRef keychainRef
, const SecKeychainAttributeList
*attrList
, SecKeychainSearchRef
*searchRef
, SecKeychainItemRef
*itemRef
)
482 cursor
= KeychainImpl::required(keychainRef
)->createCursor(attrList
);
484 cursor
= globals().storageManager
.createCursor(attrList
);
488 if (!cursor
->next(item
))
489 return errSecItemNotFound
;
491 *itemRef
=item
->handle();
493 *searchRef
=cursor
->handle();
500 static OSStatus
SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef
,
501 CFDataRef
*persistentItemRef
, Boolean isIdentity
)
503 OSStatus __secapiresult
;
504 if (!certRef
|| !persistentItemRef
) {
508 // If we already have a keychain item, we won't need to look it up by serial and issuer
509 SecKeychainItemRef kcItem
= NULL
;
510 if (SecCertificateIsItemImplInstance(certRef
)) {
511 kcItem
= (SecKeychainItemRef
) CFRetain(certRef
);
514 kcItem
= (SecKeychainItemRef
) SecCertificateCopyKeychainItem(certRef
);
517 __secapiresult
= errSecParam
;
519 Item item
= ItemImpl::required((kcItem
));
520 item
->copyPersistentReference(*persistentItemRef
, isIdentity
);
521 __secapiresult
= errSecSuccess
;
525 if (__secapiresult
== errSecSuccess
) {
526 return __secapiresult
;
530 // Certificate does not have a keychain item reference; look it up by serial and issuer
531 SecCertificateRef certItem
= NULL
;
532 if (SecCertificateIsItemImplInstance(certRef
)) {
533 certItem
= SecCertificateCreateFromItemImplInstance(certRef
);
536 certItem
= (SecCertificateRef
) CFRetain(certRef
);
539 CFErrorRef errorRef
= NULL
;
540 CFDataRef serialData
= SecCertificateCopySerialNumber(certItem
, &errorRef
);
542 CFIndex err
= CFErrorGetCode(errorRef
);
544 if (serialData
) { CFRelease(serialData
); }
545 if (certItem
) { CFRelease(certItem
); }
546 return (OSStatus
)err
;
548 CFDataRef issuerData
= SecCertificateCopyNormalizedIssuerContent(certItem
, &errorRef
);
550 CFIndex err
= CFErrorGetCode(errorRef
);
552 if (serialData
) { CFRelease(serialData
); }
553 if (issuerData
) { CFRelease(issuerData
); }
554 if (certItem
) { CFRelease(certItem
); }
555 return (OSStatus
)err
;
559 // look up ItemImpl cert in keychain by normalized issuer and serial number
560 StorageManager::KeychainList keychains
;
561 globals().storageManager
.optionalSearchList(NULL
, keychains
);
562 KCCursor
cursor(Certificate::cursorForIssuerAndSN_CF(keychains
, issuerData
, serialData
));
564 if (!cursor
->next(item
)) {
565 MacOSError::throwMe(errSecItemNotFound
);
567 item
->copyPersistentReference(*persistentItemRef
, false);
568 __secapiresult
= errSecSuccess
;
570 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
571 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
572 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
573 catch (...) { __secapiresult
=errSecInternalComponent
; }
576 CFRelease(serialData
);
578 CFRelease(issuerData
);
582 return __secapiresult
;
586 OSStatus
SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef
, CFDataRef
*persistentItemRef
)
591 KCThrowParamErrIf_(!itemRef
|| !persistentItemRef
);
593 CFTypeID itemType
= (itemRef
) ? CFGetTypeID(itemRef
) ? 0;
594 bool isIdentityRef
= (itemType
== SecIdentityGetTypeID()) ? true : false;
595 bool isCertificateRef
= (itemType
== SecCertificateGetTypeID()) ? true : false;
597 SecPointer
<Certificate
> certificatePtr(Identity::required((SecIdentityRef
)itemRef
)->certificate());
598 SecCertificateRef certificateRef
= certificatePtr
->handle(false);
599 item
= ItemImpl::required((SecKeychainItemRef
)certificateRef
);
600 item
->copyPersistentReference(*persistentItemRef
, true);
602 else if (isCertificateRef
) {
603 item
= ItemImpl::required(itemRef
);
604 item
->copyPersistentReference(*persistentItemRef
, false);
607 item
= ItemImpl::required(itemRef
);
608 item
->copyPersistentReference(*persistentItemRef
, false);
613 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */
614 if (!itemRef
|| !persistentItemRef
) {
617 // first, query the iOS keychain
619 const void *keys
[] = { kSecValueRef
, kSecReturnPersistentRef
, kSecAttrNoLegacy
};
620 const void *values
[] = { itemRef
, kCFBooleanTrue
, kCFBooleanTrue
};
621 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
622 sizeof(keys
) / sizeof(*keys
),
623 &kCFTypeDictionaryKeyCallBacks
,
624 &kCFTypeDictionaryValueCallBacks
);
625 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)persistentItemRef
);
626 if (status
== errSecSuccess
) {
630 // otherwise, handle certificate
631 SecCertificateRef certRef
= NULL
;
632 CFTypeID itemType
= CFGetTypeID(itemRef
);
633 bool isIdentity
= false;
634 if (itemType
== SecIdentityGetTypeID()) {
635 SecIdentityCopyCertificate((SecIdentityRef
)itemRef
, &certRef
);
638 else if (itemType
== SecCertificateGetTypeID()) {
639 certRef
= (SecCertificateRef
) CFRetain(itemRef
);
642 OSStatus status
= SecKeychainItemCreatePersistentReferenceFromCertificate(certRef
, persistentItemRef
, isIdentity
);
646 // otherwise, not a certificate, so proceed as usual for keychain item
649 Item item
= ItemImpl::required(itemRef
);
650 item
->copyPersistentReference(*persistentItemRef
, false);
656 OSStatus
SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef
, SecKeychainItemRef
*itemRef
)
660 KCThrowParamErrIf_(!persistentItemRef
|| !itemRef
);
661 // first, query the iOS keychain
663 const void *keys
[] = { kSecValuePersistentRef
, kSecReturnRef
, kSecAttrNoLegacy
};
664 const void *values
[] = { persistentItemRef
, kCFBooleanTrue
, kCFBooleanTrue
};
665 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
666 sizeof(keys
) / sizeof(*keys
),
667 &kCFTypeDictionaryKeyCallBacks
,
668 &kCFTypeDictionaryValueCallBacks
);
669 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)itemRef
);
670 if (status
== errSecSuccess
) {
674 // otherwise, proceed as usual for keychain item
675 CFTypeRef result
= NULL
;
676 bool isIdentityRef
= false;
677 Item item
= ItemImpl::makeFromPersistentReference(persistentItemRef
, &isIdentityRef
);
679 // item was stored as an identity, attempt to reconstitute it
680 SecPointer
<Certificate
> certificatePtr(static_cast<Certificate
*>(item
.get()));
681 StorageManager::KeychainList keychains
;
682 globals().storageManager
.optionalSearchList(NULL
, keychains
);
683 SecPointer
<Identity
> identityPtr(new Identity(keychains
, certificatePtr
));
684 result
= identityPtr
->handle();
685 KCThrowIf_( !result
, errSecItemNotFound
);
688 result
= item
->handle();
690 *itemRef
= (SecKeychainItemRef
) result
;
693 /* see if we should convert outgoing item to a unified SecCertificateRef */
694 SecItemClass tmpItemClass
= Schema::itemClassFor(item
->recordType());
695 if (tmpItemClass
== kSecCertificateItemClass
&& !isIdentityRef
) {
696 SecPointer
<Certificate
> certificate(static_cast<Certificate
*>(&*item
));
697 CssmData certData
= certificate
->data();
698 CFDataRef data
= NULL
;
699 if (certData
.Data
&& certData
.Length
) {
700 data
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
704 if (certData
.Data
&& !certData
.Length
) {
705 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)",
706 (uintptr_t)certData
.Data
);
707 return errSecDataNotAvailable
;
710 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)",
711 (long)certData
.Length
, (uintptr_t)certData
.Data
);
712 return errSecInternal
;
715 SecKeychainItemRef tmpRef
= *itemRef
;
716 *itemRef
= (SecKeychainItemRef
) SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
);
727 OSStatus
SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef
, CFDataRef
*recordIdentifier
)
732 RequiredParam (recordIdentifier
);
733 Item item
= ItemImpl::required(__itemImplRef
);
734 item
->copyRecordIdentifier (data
);
735 *recordIdentifier
= ::CFDataCreate(kCFAllocatorDefault
, (UInt8
*) data
.Data
, data
.Length
);
742 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef
,
743 SecKeychainItemRef
*itemRef
,
744 CFDataRef recordIdentifier
)
748 // make a local Keychain reference
749 RequiredParam (keychainRef
);
750 Keychain keychain
= KeychainImpl::optional (keychainRef
);
751 RequiredParam (itemRef
);
752 RequiredParam (recordIdentifier
);
754 Db
db(keychain
->database());
756 // make a raw database call to get the data
757 CSSM_DL_DB_HANDLE dbHandle
= db
.handle ();
758 CSSM_DB_UNIQUE_RECORD uniqueRecord
;
760 // according to source, we should be able to reconsitute the uniqueRecord
761 // from the data we earlier retained
763 // prepare the record id
764 memset (&uniqueRecord
, 0, sizeof (uniqueRecord
));
765 uniqueRecord
.RecordIdentifier
.Data
= (uint8
*) CFDataGetBytePtr (recordIdentifier
);
766 uniqueRecord
.RecordIdentifier
.Length
= CFDataGetLength (recordIdentifier
);
768 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
769 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr
;
771 result
= CSSM_DL_PassThrough (dbHandle
, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER
, &uniqueRecord
, (void**) &outputUniqueRecordPtr
);
772 KCThrowIf_(result
!= 0, errSecItemNotFound
);
774 // from this, get the record type
775 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData
;
776 memset (&attributeData
, 0, sizeof (attributeData
));
778 result
= CSSM_DL_DataGetFromUniqueRecordId (dbHandle
, outputUniqueRecordPtr
, &attributeData
, NULL
);
779 KCThrowIf_(result
!= 0, errSecItemNotFound
);
780 CSSM_DB_RECORDTYPE recordType
= attributeData
.DataRecordType
;
782 // make the unique record item -- precursor to creation of a SecKeychainItemRef
783 DbUniqueRecord
unique(db
);
784 CSSM_DB_UNIQUE_RECORD_PTR
*uniquePtr
= unique
;
785 *uniquePtr
= outputUniqueRecordPtr
;
788 Item item
= keychain
->item (recordType
, unique
);
791 *itemRef
= item
->handle();
797 OSStatus
SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass
,
798 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
799 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
, CFDataRef
*localID
)
803 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
804 RequiredParam (localID
);
805 RequiredParam (keychainRef
);
807 Item
item(itemClass
, (uint32
) 0, length
, data
, true);
809 item
->setAccess(Access::required(initialAccess
));
811 Keychain keychain
= Keychain::optional(keychainRef
);
812 if (!keychain
->exists())
814 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
817 item
->doNotEncrypt ();
822 catch (const CommonError
&err
)
824 if (err
.osStatus () == errSecNoSuchClass
)
826 // the only time this should happen is if the item is a certificate (for keychain syncing)
827 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
)
829 // create the certificate relation
830 Db
db(keychain
->database());
832 db
->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
833 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
834 Schema::X509CertificateSchemaAttributeCount
,
835 Schema::X509CertificateSchemaAttributeList
,
836 Schema::X509CertificateSchemaIndexCount
,
837 Schema::X509CertificateSchemaIndexList
);
838 keychain
->keychainSchema()->didCreateRelation(
839 CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
840 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
841 Schema::X509CertificateSchemaAttributeCount
,
842 Schema::X509CertificateSchemaAttributeList
,
843 Schema::X509CertificateSchemaIndexCount
,
844 Schema::X509CertificateSchemaIndexList
);
846 // add the item again
857 *itemRef
= item
->handle();
860 item
->copyRecordIdentifier (recordID
);
862 *localID
= CFDataCreate(kCFAllocatorDefault
, (UInt8
*) recordID
.Data
, recordID
.Length
);
863 free (recordID
.Data
);
868 OSStatus
SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
,
869 SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
,
870 UInt32
*length
, void **outData
)
874 Item item
= ItemImpl::required(__itemImplRef
);
875 item
->doNotEncrypt ();
876 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
881 OSStatus
SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef
, UInt32 length
, const void *data
)
885 Item item
= ItemImpl::required(__itemImplRef
);
886 item
->doNotEncrypt ();
887 item
->modifyAttributesAndData(NULL
, length
, data
);