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"
47 #include "LegacyAPICounts.h"
49 extern "C" Boolean
SecKeyIsCDSAKey(SecKeyRef ref
);
52 // Given a polymorphic Sec type object, return
53 // its AclBearer component.
54 // Note: Login ACLs are not hooked into this layer;
55 // modules or attachments have no Sec* layer representation.
58 RefPointer
<AclBearer
> aclBearer(CFTypeRef itemRef
)
60 // well, exactly what kind of something are you?
61 CFTypeID id
= CFGetTypeID(itemRef
);
62 if (id
== gTypes().ItemImpl
.typeID
) {
63 // keychain item. If it's in a protected group, return the group key
64 if (SSGroup group
= ItemImpl::required(SecKeychainItemRef(itemRef
))->group())
66 } else if (id
== SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef
)itemRef
)) {
67 // key item, return the key itself.
68 if (CssmClient::Key key
= KeyItem::required(SecKeyRef(itemRef
))->key())
70 } else if (id
== gTypes().KeychainImpl
.typeID
) {
71 // keychain (this yields the database ACL)
72 //@@@ not hooked up yet
75 MacOSError::throwMe(errSecNoAccessForItem
);
80 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
)
202 ItemImpl::freeAttributesAndData(attrList
, data
);
209 SecKeychainItemDelete(SecKeychainItemRef itemRef
)
212 os_activity_t activity
= os_activity_create("SecKeychainItemDelete", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
213 os_activity_scope(activity
);
214 os_release(activity
);
216 Item item
= ItemImpl::required(__itemImplRef
);
217 Keychain keychain
= item
->keychain();
218 // item must be persistent.
219 KCThrowIf_( !keychain
, errSecInvalidItemRef
);
222 * Before deleting the item, delete any existing Extended Attributes.
225 CFArrayRef attrNames
= NULL
;
226 ortn
= SecKeychainItemCopyAllExtendedAttributes(__itemImplRef
, &attrNames
, NULL
);
227 if(ortn
== errSecSuccess
) {
228 CFIndex numAttrs
= CFArrayGetCount(attrNames
);
229 for(CFIndex dex
=0; dex
<numAttrs
; dex
++) {
230 CFStringRef attrName
= (CFStringRef
)CFArrayGetValueAtIndex(attrNames
, dex
);
231 /* setting value to NULL ==> delete */
232 SecKeychainItemSetExtendedAttribute(__itemImplRef
, attrName
, NULL
);
236 /* now delete the item */
237 keychain
->deleteItem( item
);
244 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef
, SecKeychainRef
* keychainRef
)
248 // make sure this item has a keychain
249 Keychain kc
= ItemImpl::required(__itemImplRef
)->keychain();
252 MacOSError::throwMe(errSecNoSuchKeychain
);
255 Required(keychainRef
) = kc
->handle();
262 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef
, SecKeychainRef destKeychainRef
,
263 SecAccessRef initialAccess
, SecKeychainItemRef
*itemCopy
)
266 os_activity_t activity
= os_activity_create("SecKeychainItemCreateCopy", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
267 os_activity_scope(activity
);
268 os_release(activity
);
270 Item copy
= ItemImpl::required(__itemImplRef
)->copyTo(Keychain::optional(destKeychainRef
), Access::optional(initialAccess
));
272 *itemCopy
= copy
->handle();
280 SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef
, const CSSM_DB_UNIQUE_RECORD
**uniqueRecordID
)
283 os_activity_t activity
= os_activity_create("SecKeychainItemGetUniqueRecordID", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
284 os_activity_scope(activity
);
285 os_release(activity
);
287 Required(uniqueRecordID
) = ItemImpl::required(__itemImplRef
)->dbUniqueRecord();
294 SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef
, CSSM_DL_DB_HANDLE
* dldbHandle
)
297 os_activity_t activity
= os_activity_create("SecKeychainItemGetDLDBHandle", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
298 os_activity_scope(activity
);
299 os_release(activity
);
301 *dldbHandle
= ItemImpl::required(__itemImplRef
)->keychain()->database()->handle();
307 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef
, SecAccessRef
* accessRef
)
310 os_activity_t activity
= os_activity_create("SecKeychainItemCopyAccess", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
311 os_activity_scope(activity
);
312 os_release(activity
);
314 Required(accessRef
); // preflight
315 SecPointer
<Access
> access
= new Access(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)));
316 *accessRef
= access
->handle();
323 SecKeychainItemSetAccess(SecKeychainItemRef itemRef
, SecAccessRef accessRef
)
326 os_activity_t activity
= os_activity_create("SecKeychainItemSetAccess", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
327 os_activity_scope(activity
);
328 os_release(activity
);
330 Access::required(accessRef
)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)), true);
332 ItemImpl::required(__itemImplRef
)->postItemEvent(kSecUpdateEvent
);
337 OSStatus
SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef
, SecAccessRef accessRef
, UInt32 passwordLength
, const void * password
)
340 os_activity_t activity
= os_activity_create("SecKeychainItemSetAccessWithPassword", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
341 os_activity_scope(activity
);
342 os_release(activity
);
350 // try to unlock the keychain with this password first
351 SecKeychainRef kc
= NULL
;
352 result
= SecKeychainItemCopyKeychain(__itemImplRef
, &kc
);
354 SecKeychainUnlock(kc
, passwordLength
, password
, true);
360 // Create some credentials with this password
361 CssmAutoData
data(Allocator::standard(), password
, passwordLength
);
362 AclFactory::PassphraseUnlockCredentials
cred(data
, Allocator::standard());
364 Access::required(accessRef
)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef
>(__itemImplRef
)), true, cred
.getAccessCredentials());
365 ItemImpl::required(itemRef
)->postItemEvent (kSecUpdateEvent
);
371 /* Sets an item's data for legacy "KC" CoreServices APIs.
372 Note this version sets the data, but doesn't update the item
373 as the KC behavior dictates.
375 OSStatus
SecKeychainItemSetData(SecKeychainItemRef itemRef
, UInt32 length
, const void* data
)
378 os_activity_t activity
= os_activity_create("SecKeychainItemSetData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
379 os_activity_scope(activity
);
380 os_release(activity
);
382 ItemImpl::required(__itemImplRef
)->setData(length
, data
);
387 /* Gets an item's data for legacy "KC" CoreServices APIs.
388 Note this version doesn't take a SecItemClass parameter.
390 OSStatus
SecKeychainItemGetData(SecKeychainItemRef itemRef
, UInt32 maxLength
, void* data
, UInt32
* actualLength
)
393 os_activity_t activity
= os_activity_create("SecKeychainItemGetData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
394 os_activity_scope(activity
);
395 os_release(activity
);
397 /* The caller either needs to specify data and maxLength or an actualLength,
398 * so we return either the data itself or the actual length of the data or both.
400 if (!((data
&& maxLength
) || actualLength
)) {
401 MacOSError::throwMe(errSecParam
);
403 CssmDataContainer aData
;
404 ItemImpl::required(__itemImplRef
)->getData(aData
);
406 *actualLength
= (UInt32
)aData
.length();
409 // Make sure the buffer is big enough
410 if (aData
.length() > maxLength
) {
411 MacOSError::throwMe(errSecBufferTooSmall
);
413 memcpy(data
, aData
.data(), aData
.length());
419 /* Update a keychain item for legacy "KC" CoreServices APIs.
420 The "KC" API's do a 'set attribute', then an 'update'.
422 OSStatus
SecKeychainItemUpdate(SecKeychainItemRef itemRef
)
425 os_activity_t activity
= os_activity_create("SecKeychainItemUpdate", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
426 os_activity_scope(activity
);
427 os_release(activity
);
429 ItemImpl::required(__itemImplRef
)->update();
434 /* Add a 'floating' keychain item without UI for legacy "KC" CoreServices APIs.
436 OSStatus
SecKeychainItemAddNoUI(SecKeychainRef keychainRef
, SecKeychainItemRef itemRef
)
439 os_activity_t activity
= os_activity_create("SecKeychainItemAddNoUI", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
440 os_activity_scope(activity
);
441 os_release(activity
);
443 Item item
= ItemImpl::required(__itemImplRef
);
444 Keychain::optional(keychainRef
)->add(item
);
449 /* Add a 'floating' keychain item to the default keychain with possible UI for legacy "KC" Carbon APIs.
451 OSStatus
SecKeychainItemAdd(SecKeychainItemRef itemRef
)
454 os_activity_t activity
= os_activity_create("SecKeychainItemAdd", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
455 os_activity_scope(activity
);
456 os_release(activity
);
458 Item item
= ItemImpl::required(__itemImplRef
);
459 Keychain defaultKeychain
= globals().storageManager
.defaultKeychainUI(item
);
460 defaultKeychain
->add(item
);
465 /* Creates a floating keychain item for legacy "KC" CoreServices APIs
467 OSStatus
SecKeychainItemCreateNew(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, SecKeychainItemRef
* itemRef
)
470 os_activity_t activity
= os_activity_create("SecKeychainItemCreateNew", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
471 os_activity_scope(activity
);
472 os_release(activity
);
474 RequiredParam(itemRef
) = Item(itemClass
, itemCreator
, length
, data
, false)->handle();
479 /* Gets an individual attribute for legacy "KC" CoreServices APIs
481 OSStatus
SecKeychainItemGetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
, UInt32
* actualLength
)
484 os_activity_t activity
= os_activity_create("SecKeychainItemGetAttribute", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
485 os_activity_scope(activity
);
486 os_release(activity
);
488 ItemImpl::required(__itemImplRef
)->getAttribute(RequiredParam(attribute
), actualLength
);
493 /* Sets an individual attribute for legacy "KC" CoreServices APIs
495 OSStatus
SecKeychainItemSetAttribute(SecKeychainItemRef itemRef
, SecKeychainAttribute
* attribute
)
498 os_activity_t activity
= os_activity_create("SecKeychainItemSetAttribute", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
499 os_activity_scope(activity
);
500 os_release(activity
);
502 ItemImpl::required(__itemImplRef
)->setAttribute(RequiredParam(attribute
));
507 /* Finds a keychain item for legacy "KC" CoreServices APIs.
508 Note: This version doesn't take a SecItemClass because
509 SecKeychainSearchCreateFromAttributes() requires it.
510 @@@ This should move to SecKeychainSearch.cpp
512 OSStatus
SecKeychainItemFindFirst(SecKeychainRef keychainRef
, const SecKeychainAttributeList
*attrList
, SecKeychainSearchRef
*searchRef
, SecKeychainItemRef
*itemRef
)
515 os_activity_t activity
= os_activity_create("SecKeychainItemFindFirst", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
516 os_activity_scope(activity
);
517 os_release(activity
);
521 cursor
= KeychainImpl::required(keychainRef
)->createCursor(attrList
);
523 cursor
= globals().storageManager
.createCursor(attrList
);
527 if (!cursor
->next(item
))
528 return errSecItemNotFound
;
530 *itemRef
=item
->handle();
532 *searchRef
=cursor
->handle();
538 static OSStatus
SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef
,
539 CFDataRef
*persistentItemRef
, Boolean isIdentity
)
542 OSStatus __secapiresult
;
543 if (!certRef
|| !persistentItemRef
) {
547 // If we already have a keychain item, we won't need to look it up by serial and issuer
548 SecKeychainItemRef kcItem
= NULL
;
549 if (SecCertificateIsItemImplInstance(certRef
)) {
550 kcItem
= (SecKeychainItemRef
) CFRetain(certRef
);
553 kcItem
= (SecKeychainItemRef
) SecCertificateCopyKeychainItem(certRef
);
556 __secapiresult
= errSecParam
;
558 Item item
= ItemImpl::required((kcItem
));
559 item
->copyPersistentReference(*persistentItemRef
, isIdentity
);
560 __secapiresult
= errSecSuccess
;
564 if (__secapiresult
== errSecSuccess
) {
565 return __secapiresult
;
569 // Certificate does not have a keychain item reference; look it up by serial and issuer
570 SecCertificateRef certItem
= NULL
;
571 if (SecCertificateIsItemImplInstance(certRef
)) {
572 certItem
= SecCertificateCreateFromItemImplInstance(certRef
);
575 certItem
= (SecCertificateRef
) CFRetain(certRef
);
578 CFErrorRef errorRef
= NULL
;
579 CFDataRef serialData
= SecCertificateCopySerialNumberData(certItem
, &errorRef
);
581 CFIndex err
= CFErrorGetCode(errorRef
);
583 if (serialData
) { CFRelease(serialData
); }
584 if (certItem
) { CFRelease(certItem
); }
585 return (OSStatus
)err
;
587 CFDataRef issuerData
= SecCertificateCopyNormalizedIssuerContent(certItem
, &errorRef
);
589 CFIndex err
= CFErrorGetCode(errorRef
);
591 if (serialData
) { CFRelease(serialData
); }
592 if (issuerData
) { CFRelease(issuerData
); }
593 if (certItem
) { CFRelease(certItem
); }
594 return (OSStatus
)err
;
598 // look up ItemImpl cert in keychain by normalized issuer and serial number
599 StorageManager::KeychainList keychains
;
600 globals().storageManager
.optionalSearchList(NULL
, keychains
);
601 KCCursor
cursor(Certificate::cursorForIssuerAndSN_CF(keychains
, issuerData
, serialData
));
603 if (!cursor
->next(item
)) {
604 MacOSError::throwMe(errSecItemNotFound
);
606 item
->copyPersistentReference(*persistentItemRef
, false);
607 __secapiresult
= errSecSuccess
;
609 catch (const MacOSError
&err
) { __secapiresult
=err
.osStatus(); }
610 catch (const CommonError
&err
) { __secapiresult
=SecKeychainErrFromOSStatus(err
.osStatus()); }
611 catch (const std::bad_alloc
&) { __secapiresult
=errSecAllocate
; }
612 catch (...) { __secapiresult
=errSecInternalComponent
; }
615 CFRelease(serialData
);
617 CFRelease(issuerData
);
621 return __secapiresult
;
624 OSStatus
SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef
, CFDataRef
*persistentItemRef
)
626 /* We're in the unified world, where SecCertificateRef is not a SecKeychainItemRef. */
627 if (!itemRef
|| !persistentItemRef
) {
630 // first, query the iOS keychain
632 const void *keys
[] = { kSecValueRef
, kSecReturnPersistentRef
, kSecUseDataProtectionKeychain
};
633 const void *values
[] = { itemRef
, kCFBooleanTrue
, kCFBooleanTrue
};
634 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
635 sizeof(keys
) / sizeof(*keys
),
636 &kCFTypeDictionaryKeyCallBacks
,
637 &kCFTypeDictionaryValueCallBacks
);
638 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)persistentItemRef
);
639 if (status
== errSecSuccess
) {
643 // otherwise, handle certificate
644 SecCertificateRef certRef
= NULL
;
645 CFTypeID itemType
= CFGetTypeID(itemRef
);
646 bool isIdentity
= false;
647 if (itemType
== SecIdentityGetTypeID()) {
648 SecIdentityCopyCertificate((SecIdentityRef
)itemRef
, &certRef
);
651 else if (itemType
== SecCertificateGetTypeID()) {
652 certRef
= (SecCertificateRef
) CFRetain(itemRef
);
655 OSStatus status
= SecKeychainItemCreatePersistentReferenceFromCertificate(certRef
, persistentItemRef
, isIdentity
);
659 // otherwise, not a certificate, so proceed as usual for keychain item
662 os_activity_t activity
= os_activity_create("SecKeychainItemCreatePersistentReference", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
663 os_activity_scope(activity
);
664 os_release(activity
);
665 Item item
= ItemImpl::required(itemRef
);
666 item
->copyPersistentReference(*persistentItemRef
, false);
670 OSStatus
SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef
, SecKeychainItemRef
*itemRef
)
673 os_activity_t activity
= os_activity_create("SecKeychainItemCopyFromPersistentReference", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
674 os_activity_scope(activity
);
675 os_release(activity
);
677 KCThrowParamErrIf_(!persistentItemRef
|| !itemRef
);
678 // first, query the iOS keychain
680 const void *keys
[] = { kSecValuePersistentRef
, kSecReturnRef
, kSecUseDataProtectionKeychain
};
681 const void *values
[] = { persistentItemRef
, kCFBooleanTrue
, kCFBooleanTrue
};
682 CFRef
<CFDictionaryRef
> query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
,
683 sizeof(keys
) / sizeof(*keys
),
684 &kCFTypeDictionaryKeyCallBacks
,
685 &kCFTypeDictionaryValueCallBacks
);
686 OSStatus status
= SecItemCopyMatching(query
, (CFTypeRef
*)itemRef
);
687 if (status
== errSecSuccess
) {
691 // otherwise, proceed as usual for keychain item
692 CFTypeRef result
= NULL
;
693 bool isIdentityRef
= false;
694 Item item
= ItemImpl::makeFromPersistentReference(persistentItemRef
, &isIdentityRef
);
696 // item was stored as an identity, attempt to reconstitute it
697 SecPointer
<Certificate
> certificatePtr(static_cast<Certificate
*>(item
.get()));
698 StorageManager::KeychainList keychains
;
699 globals().storageManager
.optionalSearchList(NULL
, keychains
);
700 SecPointer
<Identity
> identityPtr(new Identity(keychains
, certificatePtr
));
701 result
= identityPtr
->handle();
702 KCThrowIf_( !result
, errSecItemNotFound
);
705 result
= item
->handle();
707 *itemRef
= (SecKeychainItemRef
) result
;
709 /* see if we should convert outgoing item to a unified SecCertificateRef */
710 SecItemClass tmpItemClass
= Schema::itemClassFor(item
->recordType());
711 if (tmpItemClass
== kSecCertificateItemClass
&& !isIdentityRef
) {
712 SecPointer
<Certificate
> certificate(static_cast<Certificate
*>(&*item
));
713 CssmData certData
= certificate
->data();
714 CFDataRef data
= NULL
;
715 if (certData
.Data
&& certData
.Length
) {
716 data
= CFDataCreate(NULL
, certData
.Data
, certData
.Length
);
720 if (certData
.Data
&& !certData
.Length
) {
721 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)",
722 (uintptr_t)certData
.Data
);
723 return errSecDataNotAvailable
;
726 syslog(LOG_ERR
, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)",
727 (long)certData
.Length
, (uintptr_t)certData
.Data
);
728 return errSecInternal
;
731 SecKeychainItemRef tmpRef
= *itemRef
;
732 *itemRef
= (SecKeychainItemRef
) SecCertificateCreateWithKeychainItem(NULL
, data
, tmpRef
);
742 OSStatus
SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef
, CFDataRef
*recordIdentifier
)
745 os_activity_t activity
= os_activity_create("SecKeychainItemCopyRecordIdentifier", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
746 os_activity_scope(activity
);
747 os_release(activity
);
750 RequiredParam (recordIdentifier
);
751 Item item
= ItemImpl::required(__itemImplRef
);
752 item
->copyRecordIdentifier (data
);
753 *recordIdentifier
= ::CFDataCreate(kCFAllocatorDefault
, (UInt8
*) data
.Data
, data
.Length
);
760 SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef
,
761 SecKeychainItemRef
*itemRef
,
762 CFDataRef recordIdentifier
)
765 os_activity_t activity
= os_activity_create("SecKeychainItemCopyFromRecordIdentifier", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
766 os_activity_scope(activity
);
767 os_release(activity
);
769 // make a local Keychain reference
770 RequiredParam (keychainRef
);
771 Keychain keychain
= KeychainImpl::optional (keychainRef
);
772 RequiredParam (itemRef
);
773 RequiredParam (recordIdentifier
);
775 Db
db(keychain
->database());
777 // make a raw database call to get the data
778 CSSM_DL_DB_HANDLE dbHandle
= db
.handle ();
779 CSSM_DB_UNIQUE_RECORD uniqueRecord
;
781 // according to source, we should be able to reconsitute the uniqueRecord
782 // from the data we earlier retained
784 // prepare the record id
785 memset (&uniqueRecord
, 0, sizeof (uniqueRecord
));
786 uniqueRecord
.RecordIdentifier
.Data
= (uint8
*) CFDataGetBytePtr (recordIdentifier
);
787 uniqueRecord
.RecordIdentifier
.Length
= CFDataGetLength (recordIdentifier
);
789 // convert this unique id to a CSSM_DB_UNIQUE_RECORD that works for the CSP/DL
790 CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr
;
792 result
= CSSM_DL_PassThrough (dbHandle
, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER
, &uniqueRecord
, (void**) &outputUniqueRecordPtr
);
793 KCThrowIf_(result
!= 0, errSecItemNotFound
);
795 // from this, get the record type
796 CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData
;
797 memset (&attributeData
, 0, sizeof (attributeData
));
799 result
= CSSM_DL_DataGetFromUniqueRecordId (dbHandle
, outputUniqueRecordPtr
, &attributeData
, NULL
);
800 KCThrowIf_(result
!= 0, errSecItemNotFound
);
801 CSSM_DB_RECORDTYPE recordType
= attributeData
.DataRecordType
;
803 // make the unique record item -- precursor to creation of a SecKeychainItemRef
804 DbUniqueRecord
unique(db
);
805 CSSM_DB_UNIQUE_RECORD_PTR
*uniquePtr
= unique
;
806 *uniquePtr
= outputUniqueRecordPtr
;
809 Item item
= keychain
->item (recordType
, unique
);
812 *itemRef
= item
->handle();
818 OSStatus
SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass
,
819 UInt32 length
, const void *data
, SecKeychainRef keychainRef
,
820 SecAccessRef initialAccess
, SecKeychainItemRef
*itemRef
, CFDataRef
*localID
)
823 os_activity_t activity
= os_activity_create("SecKeychainItemCreateFromEncryptedContent", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
824 os_activity_scope(activity
);
825 os_release(activity
);
827 KCThrowParamErrIf_(length
!=0 && data
==NULL
);
828 RequiredParam (localID
);
829 RequiredParam (keychainRef
);
831 Item
item(itemClass
, (uint32
) 0, length
, data
, true);
833 item
->setAccess(Access::required(initialAccess
));
835 Keychain keychain
= Keychain::optional(keychainRef
);
836 if (!keychain
->exists())
838 MacOSError::throwMe(errSecNoSuchKeychain
); // Might be deleted or not available at this time.
841 item
->doNotEncrypt ();
846 catch (const CommonError
&err
)
848 if (err
.osStatus () == errSecNoSuchClass
)
850 // the only time this should happen is if the item is a certificate (for keychain syncing)
851 if (itemClass
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
)
853 // create the certificate relation
854 Db
db(keychain
->database());
856 db
->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
857 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
858 Schema::X509CertificateSchemaAttributeCount
,
859 Schema::X509CertificateSchemaAttributeList
,
860 Schema::X509CertificateSchemaIndexCount
,
861 Schema::X509CertificateSchemaIndexList
);
862 keychain
->keychainSchema()->didCreateRelation(
863 CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
864 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
865 Schema::X509CertificateSchemaAttributeCount
,
866 Schema::X509CertificateSchemaAttributeList
,
867 Schema::X509CertificateSchemaIndexCount
,
868 Schema::X509CertificateSchemaIndexList
);
870 // add the item again
881 *itemRef
= item
->handle();
884 item
->copyRecordIdentifier (recordID
);
886 *localID
= CFDataCreate(kCFAllocatorDefault
, (UInt8
*) recordID
.Data
, recordID
.Length
);
887 free (recordID
.Data
);
892 OSStatus
SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef
, SecKeychainAttributeInfo
*info
,
893 SecItemClass
*itemClass
, SecKeychainAttributeList
**attrList
,
894 UInt32
*length
, void **outData
)
897 os_activity_t activity
= os_activity_create("SecKeychainItemCopyAttributesAndEncryptedData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
898 os_activity_scope(activity
);
899 os_release(activity
);
901 Item item
= ItemImpl::required(__itemImplRef
);
902 item
->doNotEncrypt ();
903 item
->getAttributesAndData(info
, itemClass
, attrList
, length
, outData
);
908 OSStatus
SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef
, UInt32 length
, const void *data
)
911 os_activity_t activity
= os_activity_create("SecKeychainItemModifyEncryptedData", OS_ACTIVITY_CURRENT
, OS_ACTIVITY_FLAG_IF_NONE_PRESENT
);
912 os_activity_scope(activity
);
913 os_release(activity
);
915 Item item
= ItemImpl::required(__itemImplRef
);
916 item
->doNotEncrypt ();
917 item
->modifyAttributesAndData(NULL
, length
, data
);