SecKeychainItem.cpp [plain text]
#include <Security/SecBase.h>
#include <Security/SecKeychainItem.h>
#include <Security/SecKeychainItemPriv.h>
#include <Security/SecCertificatePriv.h>
#include <Security/SecItemPriv.h>
#include <security_keychain/Keychains.h>
#include <security_keychain/KeyItem.h>
#include <security_keychain/Item.h>
#include <security_keychain/Certificate.h>
#include <security_keychain/Identity.h>
#include <security_keychain/KCCursor.h> // @@@ Remove this when SecKeychainItemFindFirst moves to SecKeychainSearch
#include <securityd_client/dictionary.h>
#include <security_cdsa_utilities/Schema.h>
#include <Security/cssmapplePriv.h>
#include <syslog.h>
#include <os/activity.h>
#include "SecBridge.h"
#include "KCExceptions.h"
#include "Access.h"
#include "SecKeychainItemExtendedAttributes.h"
extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
static
RefPointer<AclBearer> aclBearer(CFTypeRef itemRef)
{
CFTypeID id = CFGetTypeID(itemRef);
if (id == gTypes().ItemImpl.typeID) {
if (SSGroup group = ItemImpl::required(SecKeychainItemRef(itemRef))->group())
return &*group;
} else if (id == SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef)itemRef)) {
if (CssmClient::Key key = KeyItem::required(SecKeyRef(itemRef))->key())
return &*key;
} else if (id == gTypes().KeychainImpl.typeID) {
}
MacOSError::throwMe(errSecNoAccessForItem);
}
CFTypeID
SecKeychainItemGetTypeID(void)
{
BEGIN_SECAPI
return gTypes().ItemImpl.typeID;
END_SECAPI1(_kCFRuntimeNotATypeID)
}
OSStatus
SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeList *attrList,
UInt32 length, const void *data, SecKeychainRef keychainRef,
SecAccessRef initialAccess, SecKeychainItemRef *itemRef)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCreateFromContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
KCThrowParamErrIf_(length!=0 && data==NULL);
Item item(itemClass, attrList, length, data);
if (initialAccess) {
item->setAccess(Access::required(initialAccess));
}
Keychain keychain = nil;
try
{
keychain = Keychain::optional(keychainRef);
if ( !keychain->exists() )
{
MacOSError::throwMe(errSecNoSuchKeychain); }
}
catch(...)
{
keychain = globals().storageManager.defaultKeychainUI(item);
}
keychain->add(item);
if (itemRef) {
*itemRef = item->handle();
}
END_SECAPI
}
OSStatus
SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemModifyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
item->modifyContent(attrList, length, data);
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
item->getContent(itemClass, attrList, length, outData);
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemFreeContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
ItemImpl::freeContent(attrList, data);
END_SECAPI
}
OSStatus
SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemModifyAttributesAndData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
item->modifyAttributesAndData(attrList, length, data);
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, SecItemClass *itemClass, SecKeychainAttributeList **attrList, UInt32 *length, void **outData)
{
BEGIN_SECKCITEMAPI
Item item = ItemImpl::required(__itemImplRef);
item->getAttributesAndData(info, itemClass, attrList, length, outData);
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *data)
{
BEGIN_SECAPI
ItemImpl::freeAttributesAndData(attrList, data);
END_SECAPI
}
OSStatus
SecKeychainItemDelete(SecKeychainItemRef itemRef)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
Keychain keychain = item->keychain();
KCThrowIf_( !keychain, errSecInvalidItemRef );
OSStatus ortn;
CFArrayRef attrNames = NULL;
ortn = SecKeychainItemCopyAllExtendedAttributes(__itemImplRef, &attrNames, NULL);
if(ortn == errSecSuccess) {
CFIndex numAttrs = CFArrayGetCount(attrNames);
for(CFIndex dex=0; dex<numAttrs; dex++) {
CFStringRef attrName = (CFStringRef)CFArrayGetValueAtIndex(attrNames, dex);
SecKeychainItemSetExtendedAttribute(__itemImplRef, attrName, NULL);
}
}
keychain->deleteItem( item );
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef* keychainRef)
{
BEGIN_SECKCITEMAPI
Keychain kc = ItemImpl::required(__itemImplRef)->keychain();
if (kc == NULL)
{
MacOSError::throwMe(errSecNoSuchKeychain);
}
Required(keychainRef) = kc->handle();
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychainRef,
SecAccessRef initialAccess, SecKeychainItemRef *itemCopy)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemCreateCopy", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item copy = ItemImpl::required(__itemImplRef)->copyTo(Keychain::optional(destKeychainRef), Access::optional(initialAccess));
if (itemCopy) {
*itemCopy = copy->handle();
}
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM_DB_UNIQUE_RECORD **uniqueRecordID)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemGetUniqueRecordID", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Required(uniqueRecordID) = ItemImpl::required(__itemImplRef)->dbUniqueRecord();
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldbHandle)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
*dldbHandle = ItemImpl::required(__itemImplRef)->keychain()->database()->handle();
END_SECKCITEMAPI
}
#if 0
static
OSStatus SecAccessCreateFromObject(CFTypeRef sourceRef,
SecAccessRef *accessRef)
{
BEGIN_SECAPI
Required(accessRef); SecPointer<Access> access = new Access(*aclBearer(sourceRef));
*accessRef = access->handle();
END_SECAPI
}
static
OSStatus SecAccessModifyObject(SecAccessRef accessRef, CFTypeRef sourceRef)
{
BEGIN_SECAPI
Access::required(accessRef)->setAccess(*aclBearer(sourceRef), true);
END_SECAPI
}
#endif
OSStatus
SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Required(accessRef); SecPointer<Access> access = new Access(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)));
*accessRef = access->handle();
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef accessRef)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemSetAccess", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Access::required(accessRef)->setAccess(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)), true);
ItemImpl::required(__itemImplRef)->postItemEvent(kSecUpdateEvent);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemSetAccessWithPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
OSStatus result;
if(!__itemImplRef) {
return errSecParam;
}
SecKeychainRef kc = NULL;
result = SecKeychainItemCopyKeychain(__itemImplRef, &kc);
if(!result) {
SecKeychainUnlock(kc, passwordLength, password, true);
if(kc) {
CFRelease(kc);
}
}
CssmAutoData data(Allocator::standard(), password, passwordLength);
AclFactory::PassphraseUnlockCredentials cred(data, Allocator::standard());
Access::required(accessRef)->editAccess(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef)), true, cred.getAccessCredentials());
ItemImpl::required(itemRef)->postItemEvent (kSecUpdateEvent);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemSetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
ItemImpl::required(__itemImplRef)->setData(length, data);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemGetData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
if (!((data && maxLength) || actualLength)) {
MacOSError::throwMe(errSecParam);
}
CssmDataContainer aData;
ItemImpl::required(__itemImplRef)->getData(aData);
if (actualLength) {
*actualLength = (UInt32)aData.length();
}
if (data) {
if (aData.length() > maxLength) {
MacOSError::throwMe(errSecBufferTooSmall);
}
memcpy(data, aData.data(), aData.length());
}
END_SECKCITEMAPI
}
OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemUpdate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
ItemImpl::required(__itemImplRef)->update();
END_SECKCITEMAPI
}
OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemAddNoUI", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
Keychain::optional(keychainRef)->add(item);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemAdd", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
Keychain defaultKeychain = globals().storageManager.defaultKeychainUI(item);
defaultKeychain->add(item);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
RequiredParam(itemRef) = Item(itemClass, itemCreator, length, data, false)->handle();
END_SECAPI
}
OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemGetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
ItemImpl::required(__itemImplRef)->getAttribute(RequiredParam(attribute), actualLength);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemSetAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
ItemImpl::required(__itemImplRef)->setAttribute(RequiredParam(attribute));
END_SECKCITEMAPI
}
OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemFindFirst", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
KCCursor cursor;
if (keychainRef) {
cursor = KeychainImpl::required(keychainRef)->createCursor(attrList);
} else {
cursor = globals().storageManager.createCursor(attrList);
}
Item item;
if (!cursor->next(item))
return errSecItemNotFound;
*itemRef=item->handle();
if (searchRef) {
*searchRef=cursor->handle();
}
END_SECAPI
}
static OSStatus SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef,
CFDataRef *persistentItemRef, Boolean isIdentity)
{
OSStatus __secapiresult;
if (!certRef || !persistentItemRef) {
return errSecParam;
}
SecKeychainItemRef kcItem = NULL;
if (SecCertificateIsItemImplInstance(certRef)) {
kcItem = (SecKeychainItemRef) CFRetain(certRef);
}
else {
kcItem = (SecKeychainItemRef) SecCertificateCopyKeychainItem(certRef);
}
if (kcItem) {
__secapiresult = errSecParam;
try {
Item item = ItemImpl::required((kcItem));
item->copyPersistentReference(*persistentItemRef, isIdentity);
__secapiresult = errSecSuccess;
}
catch(...) {}
CFRelease(kcItem);
if (__secapiresult == errSecSuccess) {
return __secapiresult;
}
}
SecCertificateRef certItem = NULL;
if (SecCertificateIsItemImplInstance(certRef)) {
certItem = SecCertificateCreateFromItemImplInstance(certRef);
}
else {
certItem = (SecCertificateRef) CFRetain(certRef);
}
CFErrorRef errorRef = NULL;
CFDataRef serialData = SecCertificateCopySerialNumberData(certItem, &errorRef);
if (errorRef) {
CFIndex err = CFErrorGetCode(errorRef);
CFRelease(errorRef);
if (serialData) { CFRelease(serialData); }
if (certItem) { CFRelease(certItem); }
return (OSStatus)err;
}
CFDataRef issuerData = SecCertificateCopyNormalizedIssuerContent(certItem, &errorRef);
if (errorRef) {
CFIndex err = CFErrorGetCode(errorRef);
CFRelease(errorRef);
if (serialData) { CFRelease(serialData); }
if (issuerData) { CFRelease(issuerData); }
if (certItem) { CFRelease(certItem); }
return (OSStatus)err;
}
try {
StorageManager::KeychainList keychains;
globals().storageManager.optionalSearchList(NULL, keychains);
KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuerData, serialData));
Item item;
if (!cursor->next(item)) {
MacOSError::throwMe(errSecItemNotFound);
}
item->copyPersistentReference(*persistentItemRef, false);
__secapiresult = errSecSuccess;
}
catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
catch (...) { __secapiresult=errSecInternalComponent; }
if (serialData)
CFRelease(serialData);
if (issuerData)
CFRelease(issuerData);
if (certItem)
CFRelease(certItem);
return __secapiresult;
}
OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef *persistentItemRef)
{
if (!itemRef || !persistentItemRef) {
return errSecParam;
}
{
const void *keys[] = { kSecValueRef, kSecReturnPersistentRef, kSecAttrNoLegacy };
const void *values[] = { itemRef, kCFBooleanTrue, kCFBooleanTrue };
CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
sizeof(keys) / sizeof(*keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)persistentItemRef);
if (status == errSecSuccess) {
return status;
}
}
SecCertificateRef certRef = NULL;
CFTypeID itemType = CFGetTypeID(itemRef);
bool isIdentity = false;
if (itemType == SecIdentityGetTypeID()) {
SecIdentityCopyCertificate((SecIdentityRef)itemRef, &certRef);
isIdentity = true;
}
else if (itemType == SecCertificateGetTypeID()) {
certRef = (SecCertificateRef) CFRetain(itemRef);
}
if (certRef) {
OSStatus status = SecKeychainItemCreatePersistentReferenceFromCertificate(certRef, persistentItemRef, isIdentity);
CFRelease(certRef);
return status;
}
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCreatePersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(itemRef);
item->copyPersistentReference(*persistentItemRef, false);
END_SECAPI
}
OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyFromPersistentReference", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
KCThrowParamErrIf_(!persistentItemRef || !itemRef);
{
const void *keys[] = { kSecValuePersistentRef, kSecReturnRef, kSecAttrNoLegacy};
const void *values[] = { persistentItemRef, kCFBooleanTrue, kCFBooleanTrue };
CFRef<CFDictionaryRef> query = CFDictionaryCreate(kCFAllocatorDefault, keys, values,
sizeof(keys) / sizeof(*keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)itemRef);
if (status == errSecSuccess) {
return status;
}
}
CFTypeRef result = NULL;
bool isIdentityRef = false;
Item item = ItemImpl::makeFromPersistentReference(persistentItemRef, &isIdentityRef);
if (isIdentityRef) {
SecPointer<Certificate> certificatePtr(static_cast<Certificate *>(item.get()));
StorageManager::KeychainList keychains;
globals().storageManager.optionalSearchList(NULL, keychains);
SecPointer<Identity> identityPtr(new Identity(keychains, certificatePtr));
result = identityPtr->handle();
KCThrowIf_( !result, errSecItemNotFound );
}
if (!result) {
result = item->handle();
}
*itemRef = (SecKeychainItemRef) result;
SecItemClass tmpItemClass = Schema::itemClassFor(item->recordType());
if (tmpItemClass == kSecCertificateItemClass && !isIdentityRef) {
SecPointer<Certificate> certificate(static_cast<Certificate *>(&*item));
CssmData certData = certificate->data();
CFDataRef data = NULL;
if (certData.Data && certData.Length) {
data = CFDataCreate(NULL, certData.Data, certData.Length);
}
if (!data) {
*itemRef = NULL;
if (certData.Data && !certData.Length) {
syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference skipped a zero-length certificate (data=0x%lX)",
(uintptr_t)certData.Data);
return errSecDataNotAvailable;
}
else {
syslog(LOG_ERR, "WARNING: SecKeychainItemCopyFromPersistentReference failed to retrieve certificate data (length=%ld, data=0x%lX)",
(long)certData.Length, (uintptr_t)certData.Data);
return errSecInternal;
}
}
SecKeychainItemRef tmpRef = *itemRef;
*itemRef = (SecKeychainItemRef) SecCertificateCreateWithKeychainItem(NULL, data, tmpRef);
if (data)
CFRelease(data);
if (tmpRef)
CFRelease(tmpRef);
}
END_SECAPI
}
OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
CSSM_DATA data;
RequiredParam (recordIdentifier);
Item item = ItemImpl::required(__itemImplRef);
item->copyRecordIdentifier (data);
*recordIdentifier = ::CFDataCreate(kCFAllocatorDefault, (UInt8*) data.Data, data.Length);
free (data.Data);
END_SECKCITEMAPI
}
OSStatus
SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychainRef,
SecKeychainItemRef *itemRef,
CFDataRef recordIdentifier)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyFromRecordIdentifier", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
RequiredParam (keychainRef);
Keychain keychain = KeychainImpl::optional (keychainRef);
RequiredParam (itemRef);
RequiredParam (recordIdentifier);
Db db(keychain->database());
CSSM_DL_DB_HANDLE dbHandle = db.handle ();
CSSM_DB_UNIQUE_RECORD uniqueRecord;
memset (&uniqueRecord, 0, sizeof (uniqueRecord));
uniqueRecord.RecordIdentifier.Data = (uint8*) CFDataGetBytePtr (recordIdentifier);
uniqueRecord.RecordIdentifier.Length = CFDataGetLength (recordIdentifier);
CSSM_DB_UNIQUE_RECORD_PTR outputUniqueRecordPtr;
CSSM_RETURN result;
result = CSSM_DL_PassThrough (dbHandle, CSSM_APPLECSPDL_DB_CONVERT_RECORD_IDENTIFIER, &uniqueRecord, (void**) &outputUniqueRecordPtr);
KCThrowIf_(result != 0, errSecItemNotFound);
CSSM_DB_RECORD_ATTRIBUTE_DATA attributeData;
memset (&attributeData, 0, sizeof (attributeData));
result = CSSM_DL_DataGetFromUniqueRecordId (dbHandle, outputUniqueRecordPtr, &attributeData, NULL);
KCThrowIf_(result != 0, errSecItemNotFound);
CSSM_DB_RECORDTYPE recordType = attributeData.DataRecordType;
DbUniqueRecord unique(db);
CSSM_DB_UNIQUE_RECORD_PTR *uniquePtr = unique;
*uniquePtr = outputUniqueRecordPtr;
unique->activate ();
Item item = keychain->item (recordType, unique);
if (itemRef)
{
*itemRef = item->handle();
}
END_SECAPI
}
OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass,
UInt32 length, const void *data, SecKeychainRef keychainRef,
SecAccessRef initialAccess, SecKeychainItemRef *itemRef, CFDataRef *localID)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCreateFromEncryptedContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
KCThrowParamErrIf_(length!=0 && data==NULL);
RequiredParam (localID);
RequiredParam (keychainRef);
Item item(itemClass, (uint32) 0, length, data, true);
if (initialAccess)
item->setAccess(Access::required(initialAccess));
Keychain keychain = Keychain::optional(keychainRef);
if (!keychain->exists())
{
MacOSError::throwMe(errSecNoSuchKeychain); }
item->doNotEncrypt ();
try
{
keychain->add(item);
}
catch (const CommonError &err)
{
if (err.osStatus () == errSecNoSuchClass)
{
if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE)
{
Db db(keychain->database());
db->createRelation(CSSM_DL_DB_RECORD_X509_CERTIFICATE,
"CSSM_DL_DB_RECORD_X509_CERTIFICATE",
Schema::X509CertificateSchemaAttributeCount,
Schema::X509CertificateSchemaAttributeList,
Schema::X509CertificateSchemaIndexCount,
Schema::X509CertificateSchemaIndexList);
keychain->keychainSchema()->didCreateRelation(
CSSM_DL_DB_RECORD_X509_CERTIFICATE,
"CSSM_DL_DB_RECORD_X509_CERTIFICATE",
Schema::X509CertificateSchemaAttributeCount,
Schema::X509CertificateSchemaAttributeList,
Schema::X509CertificateSchemaIndexCount,
Schema::X509CertificateSchemaIndexList);
keychain->add(item);
}
}
else
{
throw;
}
}
if (itemRef)
*itemRef = item->handle();
CSSM_DATA recordID;
item->copyRecordIdentifier (recordID);
*localID = CFDataCreate(kCFAllocatorDefault, (UInt8*) recordID.Data, recordID.Length);
free (recordID.Data);
END_SECAPI
}
OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
SecItemClass *itemClass, SecKeychainAttributeList **attrList,
UInt32 *length, void **outData)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyAttributesAndEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
item->doNotEncrypt ();
item->getAttributesAndData(info, itemClass, attrList, length, outData);
END_SECKCITEMAPI
}
OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data)
{
BEGIN_SECKCITEMAPI
os_activity_t activity = os_activity_create("SecKeychainItemModifyEncryptedData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
Item item = ItemImpl::required(__itemImplRef);
item->doNotEncrypt ();
item->modifyAttributesAndData(NULL, length, data);
END_SECKCITEMAPI
}