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>
41 #include <os/activity.h>
43 #include "SecBridge.h"
44 #include "KCExceptions.h"
46 #include "SecKeychainItemExtendedAttributes.h"
48 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
51 // Given a polymorphic Sec type object, return
52 // its AclBearer component.
53 // Note: Login ACLs are not hooked into this layer;
54 // modules or attachments have no Sec* layer representation.
57 RefPointer
<AclBearer
> aclBearer(CFTypeRef itemRef
)
59 // well, exactly what kind of something are you?
60 CFTypeID id
= CFGetTypeID(itemRef
);
61 if (id
== gTypes().ItemImpl
.typeID
) {
62 // keychain item. If it's in a protected group, return the group key
63 if (SSGroup group
= ItemImpl::required(SecKeychainItemRef(itemRef
))->group())
65 } else if (id
== SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef
)itemRef
)) {
66 // key item, return the key itself.
67 if (CssmClient::Key key
= KeyItem::required(SecKeyRef(itemRef
))->key())
69 } else if (id
== gTypes().KeychainImpl
.typeID
) {
70 // keychain (this yields the database ACL)
71 //@@@ not hooked up yet
74 MacOSError::throwMe(errSecNoAccessForItem
);
79 SecKeychainItemGetTypeID(void)
83 return gTypes().ItemImpl
.typeID
;
85 END_SECAPI1(_kCFRuntimeNotATypeID
)
90 SecKeychainItemCreateFromContent(SecItemClass itemClass
, SecKeychainAttributeList
*attrList
,
91 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
92 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
)
95 os_activity_t activity
= os_activity_create("SecKeychainItemCreateFromContent", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
96 os_activity_scope(activity
);
99 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
100 Item
item(itemClass
, attrList
, length
, data
);
102 item
->setAccess(Access::required(initialAccess
));
104 Keychain keychain
= nil
;
107 keychain
= Keychain::optional(keychainRef
);
108 if ( !keychain
->exists() )
110 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
115 keychain
= globals().storageManager
.defaultKeychainUI(item
);
120 *itemRef
= item
->handle();
128 SecKeychainItemModifyContent(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
131 os_activity_t activity
= os_activity_create("SecKeychainItemModifyContent", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
132 os_activity_scope(activity
);
133 os_release(activity
);
135 Item item
= ItemImpl::required(__itemImplRef
);
136 item
->modifyContent(attrList
, length
, data
);
143 SecKeychainItemCopyContent(SecKeychainItemRef itemRef
, SecItemClass
*itemClass
, SecKeychainAttributeList
*attrList
, UInt32
*length
, void **outData
)
146 os_activity_t activity
= os_activity_create("SecKeychainItemCopyContent", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
147 os_activity_scope(activity
);
148 os_release(activity
);
150 Item item
= ItemImpl::required(__itemImplRef
);
151 item
->getContent(itemClass
, attrList
, length
, outData
);
158 SecKeychainItemFreeContent(SecKeychainAttributeList
*attrList
, void *data
)
161 os_activity_t activity
= os_activity_create("SecKeychainItemFreeContent", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
162 os_activity_scope(activity
);
163 os_release(activity
);
165 ItemImpl::freeContent(attrList
, data
);
172 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef
, const SecKeychainAttributeList
*attrList
, UInt32 length
, const void *data
)
175 os_activity_t activity
= os_activity_create("SecKeychainItemModifyAttributesAndData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
176 os_activity_scope(activity
);
177 os_release(activity
);
179 Item item
= ItemImpl::required(__itemImplRef
);
180 item
->modifyAttributesAndData(attrList
, length
, data
);
187 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
, SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
, UInt32
*length
, void **outData
)
191 Item item
= ItemImpl::required(__itemImplRef
);
192 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
199 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList
*attrList
, void *data
)
203 ItemImpl::freeAttributesAndData(attrList
, data
);
210 SecKeychainItemDelete(SecKeychainItemRef itemRef
)
213 os_activity_t activity
= os_activity_create("SecKeychainItemDelete", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
214 os_activity_scope(activity
);
215 os_release(activity
);
217 Item item
= ItemImpl::required(__itemImplRef
);
218 Keychain keychain
= item
->keychain();
219 // item must be persistent.
220 KCThrowIf_( !keychain
, errSecInvalidItemRef
);
223 * Before deleting the item, delete any existing Extended Attributes.
226 CFArrayRef attrNames
= NULL
;
227 ortn
= SecKeychainItemCopyAllExtendedAttributes(__itemImplRef
, &attrNames
, NULL
);
228 if(ortn
== errSecSuccess
) {
229 CFIndex numAttrs
= CFArrayGetCount(attrNames
);
230 for(CFIndex dex
=0; dex
<numAttrs
; dex
++) {
231 CFStringRef attrName
= (CFStringRef
)CFArrayGetValueAtIndex(attrNames
, dex
);
232 /* setting value to NULL ==> delete */
233 SecKeychainItemSetExtendedAttribute(__itemImplRef
, attrName
, NULL
);
237 /* now delete the item */
238 keychain
->deleteItem( item
);
245 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef
, SecKeychainRef
* keychainRef
)
249 // make sure this item has a keychain
250 Keychain kc
= ItemImpl::required(__itemImplRef
)->keychain();
253 MacOSError::throwMe(errSecNoSuchKeychain
);
256 Required(keychainRef
) = kc
->handle();
263 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef
, SecKeychainRef destKeychainRef
,
264 SecAccessRef initialAccess
, SecKeychainItemRef
*itemCopy
)
267 os_activity_t activity
= os_activity_create("SecKeychainItemCreateCopy", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
268 os_activity_scope(activity
);
269 os_release(activity
);
271 Item copy
= ItemImpl::required(__itemImplRef
)->copyTo(Keychain::optional(destKeychainRef
), Access::optional(initialAccess
));
273 *itemCopy
= copy
->handle();
281 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef
, const CSSM_DB_UNIQUE_RECORD
**uniqueRecordID
)
284 os_activity_t activity
= os_activity_create("SecKeychainItemGetUniqueRecordID", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
285 os_activity_scope(activity
);
286 os_release(activity
);
288 Required(uniqueRecordID
) = ItemImpl::required(__itemImplRef
)->dbUniqueRecord();
295 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef
, CSSM_DL_DB_HANDLE
* dldbHandle
)
298 os_activity_t activity
= os_activity_create("SecKeychainItemGetDLDBHandle", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
299 os_activity_scope(activity
);
300 os_release(activity
);
302 *dldbHandle
= ItemImpl::required(__itemImplRef
)->keychain()->database()->handle();
309 OSStatus
SecAccessCreateFromObject(CFTypeRef sourceRef
,
310 SecAccessRef
*accessRef
)
314 Required(accessRef
); // preflight
315 SecPointer
<Access
> access
= new Access(*aclBearer(sourceRef
));
316 *accessRef
= access
->handle();
325 OSStatus
SecAccessModifyObject(SecAccessRef accessRef
, CFTypeRef sourceRef
)
329 Access::required(accessRef
)->setAccess(*aclBearer(sourceRef
), true);
336 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef
, SecAccessRef
* accessRef
)
339 os_activity_t activity
= os_activity_create("SecKeychainItemCopyAccess", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
340 os_activity_scope(activity
);
341 os_release(activity
);
343 Required(accessRef
); // preflight
344 SecPointer
<Access
> access
= new Access(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)));
345 *accessRef
= access
->handle();
352 SecKeychainItemSetAccess(SecKeychainItemRef itemRef
, SecAccessRef accessRef
)
355 os_activity_t activity
= os_activity_create("SecKeychainItemSetAccess", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
356 os_activity_scope(activity
);
357 os_release(activity
);
359 Access::required(accessRef
)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)), true);
361 ItemImpl::required(__itemImplRef
)->postItemEvent(kSecUpdateEvent
);
366 OSStatus
SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef
, SecAccessRef accessRef
, UInt32 passwordLength
, const void * password
)
369 os_activity_t activity
= os_activity_create("SecKeychainItemSetAccessWithPassword", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
370 os_activity_scope(activity
);
371 os_release(activity
);
379 // try to unlock the keychain with this password first
380 SecKeychainRef kc
= NULL
;
381 result
= SecKeychainItemCopyKeychain(__itemImplRef
, &kc
);
383 SecKeychainUnlock(kc
, passwordLength
, password
, true);
389 // Create some credentials with this password
390 CssmAutoData
data(Allocator::standard(), password
, passwordLength
);
391 AclFactory::PassphraseUnlockCredentials
cred(data
, Allocator::standard());
393 Access::required(accessRef
)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)), true, cred
.getAccessCredentials());
394 ItemImpl::required(itemRef
)->postItemEvent (kSecUpdateEvent
);
400 /* Sets an item's data for legacy "KC" CoreServices APIs.
401 Note this version sets the data, but doesn't update the item
402 as the KC behavior dictates.
404 OSStatus
SecKeychainItemSetData(SecKeychainItemRef itemRef
, UInt32 length
, const void* data
)
407 os_activity_t activity
= os_activity_create("SecKeychainItemSetData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
408 os_activity_scope(activity
);
409 os_release(activity
);
411 ItemImpl::required(__itemImplRef
)->setData(length
, data
);
416 /* Gets an item's data for legacy "KC" CoreServices APIs.
417 Note this version doesn't take a SecItemClass parameter.
419 OSStatus
SecKeychainItemGetData(SecKeychainItemRef itemRef
, UInt32 maxLength
, void* data
, UInt32
* actualLength
)
422 os_activity_t activity
= os_activity_create("SecKeychainItemGetData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
423 os_activity_scope(activity
);
424 os_release(activity
);
426 /* The caller either needs to specify data and maxLength or an actualLength,
427 * so we return either the data itself or the actual length of the data or both.
429 if (!((data
&& maxLength
) || actualLength
)) {
430 MacOSError::throwMe(errSecParam
);
432 CssmDataContainer aData
;
433 ItemImpl::required(__itemImplRef
)->getData(aData
);
435 *actualLength
= (UInt32
)aData
.length();
438 // Make sure the buffer is big enough
439 if (aData
.length() > maxLength
) {
440 MacOSError::throwMe(errSecBufferTooSmall
);
442 memcpy(data
, aData
.data(), aData
.length());
448 /* Update a keychain item for legacy "KC" CoreServices APIs.
449 The "KC" API's do a 'set attribute', then an 'update'.
451 OSStatus
SecKeychainItemUpdate(SecKeychainItemRef itemRef
)
454 os_activity_t activity
= os_activity_create("SecKeychainItemUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
455 os_activity_scope(activity
);
456 os_release(activity
);
458 ItemImpl::required(__itemImplRef
)->update();
463 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
465 OSStatus
SecKeychainItemAddNoUI(SecKeychainRef keychainRef
, SecKeychainItemRef itemRef
)
468 os_activity_t activity
= os_activity_create("SecKeychainItemAddNoUI", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
469 os_activity_scope(activity
);
470 os_release(activity
);
472 Item item
= ItemImpl::required(__itemImplRef
);
473 Keychain::optional(keychainRef
)->add(item
);
478 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
480 OSStatus
SecKeychainItemAdd(SecKeychainItemRef itemRef
)
483 os_activity_t activity
= os_activity_create("SecKeychainItemAdd", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
484 os_activity_scope(activity
);
485 os_release(activity
);
487 Item item
= ItemImpl::required(__itemImplRef
);
488 Keychain defaultKeychain
= globals().storageManager
.defaultKeychainUI(item
);
489 defaultKeychain
->add(item
);
494 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
496 OSStatus
SecKeychainItemCreateNew(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, SecKeychainItemRef
* itemRef
)
499 os_activity_t activity
= os_activity_create("SecKeychainItemCreateNew", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
500 os_activity_scope(activity
);
501 os_release(activity
);
503 RequiredParam(itemRef
) = Item(itemClass
, itemCreator
, length
, data
, false)->handle();
508 /* Gets an individual attribute for legacy "KC" CoreServices APIs
510 OSStatus
SecKeychainItemGetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
, UInt32
* actualLength
)
513 os_activity_t activity
= os_activity_create("SecKeychainItemGetAttribute", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
514 os_activity_scope(activity
);
515 os_release(activity
);
517 ItemImpl::required(__itemImplRef
)->getAttribute(RequiredParam(attribute
), actualLength
);
522 /* Sets an individual attribute for legacy "KC" CoreServices APIs
524 OSStatus
SecKeychainItemSetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
)
527 os_activity_t activity
= os_activity_create("SecKeychainItemSetAttribute", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
528 os_activity_scope(activity
);
529 os_release(activity
);
531 ItemImpl::required(__itemImplRef
)->setAttribute(RequiredParam(attribute
));
536 /* Finds a keychain item for legacy "KC" CoreServices APIs.
537 Note: This version doesn't take a SecItemClass because
538 SecKeychainSearchCreateFromAttributes() requires it.
539 @@@ This should move to SecKeychainSearch.cpp
541 OSStatus
SecKeychainItemFindFirst(SecKeychainRef keychainRef
, const SecKeychainAttributeList
*attrList
, SecKeychainSearchRef
*searchRef
, SecKeychainItemRef
*itemRef
)
544 os_activity_t activity
= os_activity_create("SecKeychainItemFindFirst", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
545 os_activity_scope(activity
);
546 os_release(activity
);
550 cursor
= KeychainImpl::required(keychainRef
)->createCursor(attrList
);
552 cursor
= globals().storageManager
.createCursor(attrList
);
556 if (!cursor
->next(item
))
557 return errSecItemNotFound
;
559 *itemRef
=item
->handle();
561 *searchRef
=cursor
->handle();
567 static OSStatus
SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef
,
568 CFDataRef
*persistentItemRef
, Boolean isIdentity
)
570 OSStatus __secapiresult
;
571 if (!certRef
|| !persistentItemRef
) {
575 // If we already have a keychain item, we won't need to look it up by serial and issuer
576 SecKeychainItemRef kcItem
= NULL
;
577 if (SecCertificateIsItemImplInstance(certRef
)) {
578 kcItem
= (SecKeychainItemRef
) CFRetain(certRef
);
581 kcItem
= (SecKeychainItemRef
) SecCertificateCopyKeychainItem(certRef
);
584 __secapiresult
= errSecParam
;
586 Item item
= ItemImpl::required((kcItem
));
587 item
->copyPersistentReference(*persistentItemRef
, isIdentity
);
588 __secapiresult
= errSecSuccess
;
592 if (__secapiresult
== errSecSuccess
) {
593 return __secapiresult
;
597 // Certificate does not have a keychain item reference; look it up by serial and issuer
598 SecCertificateRef certItem
= NULL
;
599 if (SecCertificateIsItemImplInstance(certRef
)) {
600 certItem
= SecCertificateCreateFromItemImplInstance(certRef
);
603 certItem
= (SecCertificateRef
) CFRetain(certRef
);
606 CFErrorRef errorRef
= NULL
;
607 CFDataRef serialData
= SecCertificateCopySerialNumberData(certItem
, &errorRef
);
609 CFIndex err
= CFErrorGetCode(errorRef
);
611 if (serialData
) { CFRelease(serialData
); }
612 if (certItem
) { CFRelease(certItem
); }
613 return (OSStatus
)err
;
615 CFDataRef issuerData
= SecCertificateCopyNormalizedIssuerContent(certItem
, &errorRef
);
617 CFIndex err
= CFErrorGetCode(errorRef
);
619 if (serialData
) { CFRelease(serialData
); }
620 if (issuerData
) { CFRelease(issuerData
); }
621 if (certItem
) { CFRelease(certItem
); }
622 return (OSStatus
)err
;
626 // look up ItemImpl cert in keychain by normalized issuer and serial number
627 StorageManager::KeychainList keychains
;
628 globals().storageManager
.optionalSearchList(NULL
, keychains
);
629 KCCursor
cursor(Certificate::cursorForIssuerAndSN_CF(keychains
, issuerData
, serialData
));
631 if (!cursor
->next(item
)) {
632 MacOSError::throwMe(errSecItemNotFound
);
634 item
->copyPersistentReference(*persistentItemRef
, false);
635 __secapiresult
= errSecSuccess
;
637 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
638 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
639 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
640 catch (...) { __secapiresult
=errSecInternalComponent
; }
643 CFRelease(serialData
);
645 CFRelease(issuerData
);
649 return __secapiresult
;
652 OSStatus
SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef
, CFDataRef
*persistentItemRef
)
654 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */
655 if (!itemRef
|| !persistentItemRef
) {
658 // first, query the iOS keychain
660 const void *keys
[] = { kSecValueRef
, kSecReturnPersistentRef
, kSecUseDataProtectionKeychain
};
661 const void *values
[] = { itemRef
, kCFBooleanTrue
, kCFBooleanTrue
};
662 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
663 sizeof(keys
) / sizeof(*keys
),
664 &kCFTypeDictionaryKeyCallBacks
,
665 &kCFTypeDictionaryValueCallBacks
);
666 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)persistentItemRef
);
667 if (status
== errSecSuccess
) {
671 // otherwise, handle certificate
672 SecCertificateRef certRef
= NULL
;
673 CFTypeID itemType
= CFGetTypeID(itemRef
);
674 bool isIdentity
= false;
675 if (itemType
== SecIdentityGetTypeID()) {
676 SecIdentityCopyCertificate((SecIdentityRef
)itemRef
, &certRef
);
679 else if (itemType
== SecCertificateGetTypeID()) {
680 certRef
= (SecCertificateRef
) CFRetain(itemRef
);
683 OSStatus status
= SecKeychainItemCreatePersistentReferenceFromCertificate(certRef
, persistentItemRef
, isIdentity
);
687 // otherwise, not a certificate, so proceed as usual for keychain item
690 os_activity_t activity
= os_activity_create("SecKeychainItemCreatePersistentReference", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
691 os_activity_scope(activity
);
692 os_release(activity
);
693 Item item
= ItemImpl::required(itemRef
);
694 item
->copyPersistentReference(*persistentItemRef
, false);
698 OSStatus
SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef
, SecKeychainItemRef
*itemRef
)
701 os_activity_t activity
= os_activity_create("SecKeychainItemCopyFromPersistentReference", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
702 os_activity_scope(activity
);
703 os_release(activity
);
705 KCThrowParamErrIf_(!persistentItemRef
|| !itemRef
);
706 // first, query the iOS keychain
708 const void *keys
[] = { kSecValuePersistentRef
, kSecReturnRef
, kSecUseDataProtectionKeychain
};
709 const void *values
[] = { persistentItemRef
, kCFBooleanTrue
, kCFBooleanTrue
};
710 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
711 sizeof(keys
) / sizeof(*keys
),
712 &kCFTypeDictionaryKeyCallBacks
,
713 &kCFTypeDictionaryValueCallBacks
);
714 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)itemRef
);
715 if (status
== errSecSuccess
) {
719 // otherwise, proceed as usual for keychain item
720 CFTypeRef result
= NULL
;
721 bool isIdentityRef
= false;
722 Item item
= ItemImpl::makeFromPersistentReference(persistentItemRef
, &isIdentityRef
);
724 // item was stored as an identity, attempt to reconstitute it
725 SecPointer
<Certificate
> certificatePtr(static_cast<Certificate
*>(item
.get()));
726 StorageManager::KeychainList keychains
;
727 globals().storageManager
.optionalSearchList(NULL
, keychains
);
728 SecPointer
<Identity
> identityPtr(new Identity(keychains
, certificatePtr
));
729 result
= identityPtr
->handle();
730 KCThrowIf_( !result
, errSecItemNotFound
);
733 result
= item
->handle();
735 *itemRef
= (SecKeychainItemRef
) result
;
737 /* see if we should convert outgoing item to a unified SecCertificateRef */
738 SecItemClass tmpItemClass
= Schema::itemClassFor(item
->recordType());
739 if (tmpItemClass
== kSecCertificateItemClass
&& !isIdentityRef
) {
740 SecPointer
<Certificate
> certificate(static_cast<Certificate
*>(&*item
));
741 CssmData certData
= certificate
->data();
742 CFDataRef data
= NULL
;
743 if (certData
.Data
&& certData
.Length
) {
744 data
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
748 if (certData
.Data
&& !certData
.Length
) {
749 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)",
750 (uintptr_t)certData
.Data
);
751 return errSecDataNotAvailable
;
754 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)",
755 (long)certData
.Length
, (uintptr_t)certData
.Data
);
756 return errSecInternal
;
759 SecKeychainItemRef tmpRef
= *itemRef
;
760 *itemRef
= (SecKeychainItemRef
) SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
);
770 OSStatus
SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef
, CFDataRef
*recordIdentifier
)
773 os_activity_t activity
= os_activity_create("SecKeychainItemCopyRecordIdentifier", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
774 os_activity_scope(activity
);
775 os_release(activity
);
778 RequiredParam (recordIdentifier
);
779 Item item
= ItemImpl::required(__itemImplRef
);
780 item
->copyRecordIdentifier (data
);
781 *recordIdentifier
= ::CFDataCreate(kCFAllocatorDefault
, (UInt8
*) data
.Data
, data
.Length
);
788 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef
,
789 SecKeychainItemRef
*itemRef
,
790 CFDataRef recordIdentifier
)
793 os_activity_t activity
= os_activity_create("SecKeychainItemCopyFromRecordIdentifier", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
794 os_activity_scope(activity
);
795 os_release(activity
);
797 // make a local Keychain reference
798 RequiredParam (keychainRef
);
799 Keychain keychain
= KeychainImpl::optional (keychainRef
);
800 RequiredParam (itemRef
);
801 RequiredParam (recordIdentifier
);
803 Db
db(keychain
->database());
805 // make a raw database call to get the data
806 CSSM_DL_DB_HANDLE dbHandle
= db
.handle ();
807 CSSM_DB_UNIQUE_RECORD uniqueRecord
;
809 // according to source, we should be able to reconsitute the uniqueRecord
810 // from the data we earlier retained
812 // prepare the record id
813 memset (&uniqueRecord
, 0, sizeof (uniqueRecord
));
814 uniqueRecord
.RecordIdentifier
.Data
= (uint8
*) CFDataGetBytePtr (recordIdentifier
);
815 uniqueRecord
.RecordIdentifier
.Length
= CFDataGetLength (recordIdentifier
);
817 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
818 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr
;
820 result
= CSSM_DL_PassThrough (dbHandle
, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER
, &uniqueRecord
, (void**) &outputUniqueRecordPtr
);
821 KCThrowIf_(result
!= 0, errSecItemNotFound
);
823 // from this, get the record type
824 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData
;
825 memset (&attributeData
, 0, sizeof (attributeData
));
827 result
= CSSM_DL_DataGetFromUniqueRecordId (dbHandle
, outputUniqueRecordPtr
, &attributeData
, NULL
);
828 KCThrowIf_(result
!= 0, errSecItemNotFound
);
829 CSSM_DB_RECORDTYPE recordType
= attributeData
.DataRecordType
;
831 // make the unique record item -- precursor to creation of a SecKeychainItemRef
832 DbUniqueRecord
unique(db
);
833 CSSM_DB_UNIQUE_RECORD_PTR
*uniquePtr
= unique
;
834 *uniquePtr
= outputUniqueRecordPtr
;
837 Item item
= keychain
->item (recordType
, unique
);
840 *itemRef
= item
->handle();
846 OSStatus
SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass
,
847 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
848 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
, CFDataRef
*localID
)
851 os_activity_t activity
= os_activity_create("SecKeychainItemCreateFromEncryptedContent", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
852 os_activity_scope(activity
);
853 os_release(activity
);
855 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
856 RequiredParam (localID
);
857 RequiredParam (keychainRef
);
859 Item
item(itemClass
, (uint32
) 0, length
, data
, true);
861 item
->setAccess(Access::required(initialAccess
));
863 Keychain keychain
= Keychain::optional(keychainRef
);
864 if (!keychain
->exists())
866 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
869 item
->doNotEncrypt ();
874 catch (const CommonError
&err
)
876 if (err
.osStatus () == errSecNoSuchClass
)
878 // the only time this should happen is if the item is a certificate (for keychain syncing)
879 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
)
881 // create the certificate relation
882 Db
db(keychain
->database());
884 db
->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
885 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
886 Schema::X509CertificateSchemaAttributeCount
,
887 Schema::X509CertificateSchemaAttributeList
,
888 Schema::X509CertificateSchemaIndexCount
,
889 Schema::X509CertificateSchemaIndexList
);
890 keychain
->keychainSchema()->didCreateRelation(
891 CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
892 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
893 Schema::X509CertificateSchemaAttributeCount
,
894 Schema::X509CertificateSchemaAttributeList
,
895 Schema::X509CertificateSchemaIndexCount
,
896 Schema::X509CertificateSchemaIndexList
);
898 // add the item again
909 *itemRef
= item
->handle();
912 item
->copyRecordIdentifier (recordID
);
914 *localID
= CFDataCreate(kCFAllocatorDefault
, (UInt8
*) recordID
.Data
, recordID
.Length
);
915 free (recordID
.Data
);
920 OSStatus
SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
,
921 SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
,
922 UInt32
*length
, void **outData
)
925 os_activity_t activity
= os_activity_create("SecKeychainItemCopyAttributesAndEncryptedData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
926 os_activity_scope(activity
);
927 os_release(activity
);
929 Item item
= ItemImpl::required(__itemImplRef
);
930 item
->doNotEncrypt ();
931 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
936 OSStatus
SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef
, UInt32 length
, const void *data
)
939 os_activity_t activity
= os_activity_create("SecKeychainItemModifyEncryptedData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
940 os_activity_scope(activity
);
941 os_release(activity
);
943 Item item
= ItemImpl::required(__itemImplRef
);
944 item
->doNotEncrypt ();
945 item
->modifyAttributesAndData(NULL
, length
, data
);