SecKeychainItemExtendedAttributes.cpp [plain text]
#include <security_utilities/casts.h>
#include "SecKeychainItemExtendedAttributes.h"
#include "SecKeychainItemPriv.h"
#include "ExtendedAttribute.h"
#include "SecBridge.h"
#include "StorageManager.h"
#include "KCCursor.h"
#include <os/activity.h>
#include "LegacyAPICounts.h"
extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
static void isItemRefCapable(
SecKeychainItemRef itemRef)
{
CFTypeID id = CFGetTypeID(itemRef);
if((id == gTypes().ItemImpl.typeID) ||
(id == gTypes().Certificate.typeID) ||
(id == SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef)itemRef))) {
return;
}
else {
MacOSError::throwMe(errSecNoSuchAttr);
}
}
static void cfStringToData(
CFStringRef cfStr,
CssmOwnedData &dst)
{
CFDataRef cfData = CFStringCreateExternalRepresentation(NULL, cfStr,
kCFStringEncodingUTF8, 0);
if(cfData == NULL) {
MacOSError::throwMe(errSecParam);
}
dst.copy(CFDataGetBytePtr(cfData), CFDataGetLength(cfData));
CFRelease(cfData);
}
static bool lookupExtendedAttr(
SecKeychainItemRef itemRef,
CFStringRef attrName,
Item &foundItem)
{
isItemRefCapable(itemRef);
Item inItem = ItemImpl::required(itemRef);
const CssmData &itemID = inItem->itemID();
CSSM_DB_RECORDTYPE recType = inItem->recordType();
if(!inItem->keychain()) {
MacOSError::throwMe(errSecNoSuchAttr);
}
CssmAutoData nameData(Allocator::standard());
cfStringToData(attrName, nameData);
CssmData nameCData = nameData;
SecKeychainAttribute attrs[3];
attrs[0].tag = kExtendedAttrRecordTypeAttr;
attrs[0].length = sizeof(UInt32);
attrs[0].data = (void *)&recType;
attrs[1].tag = kExtendedAttrItemIDAttr;
attrs[1].length = (UInt32)itemID.Length;
attrs[1].data = itemID.Data;
attrs[2].tag = kExtendedAttrAttributeNameAttr;
attrs[2].length = (UInt32)nameCData.Length;
attrs[2].data = nameCData.Data;
SecKeychainAttributeList attrList = {3, attrs};
StorageManager::KeychainList kcList;
kcList.push_back(inItem->keychain());
KCCursor cursor(kcList, (SecItemClass) CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE, &attrList);
try {
return cursor->next(foundItem);
}
catch(const CssmError &err) {
if(err.error == CSSMERR_DL_INVALID_RECORDTYPE) {
return false;
}
else {
throw;
}
}
}
OSStatus SecKeychainItemSetExtendedAttribute(
SecKeychainItemRef itemRef,
CFStringRef attrName,
CFDataRef attrValue)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemSetExtendedAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
if((itemRef == NULL) || (attrName == NULL)) {
return errSecParam;
}
Item foundItem;
bool haveMatch = lookupExtendedAttr(itemRef, attrName, foundItem);
if(attrValue == NULL) {
if(!foundItem) {
return errSecNoSuchAttr;
}
foundItem->keychain()->deleteItem(foundItem);
return errSecSuccess;
}
CSSM_DATA attrCValue = {int_cast<CFIndex, CSSM_SIZE>(CFDataGetLength(attrValue)), (uint8 *)CFDataGetBytePtr(attrValue)};
if(haveMatch) {
CssmDbAttributeInfo attrInfo(kExtendedAttrAttributeValueAttr, CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
foundItem->setAttribute(attrInfo, attrCValue);
foundItem->update();
}
else {
Item inItem = ItemImpl::required(itemRef);
CssmAutoData nameData(Allocator::standard());
cfStringToData(attrName, nameData);
CssmData nameCData = nameData;
SecPointer<ExtendedAttribute> extAttr(new ExtendedAttribute(
inItem->recordType(), inItem->itemID(), nameCData,
CssmData::overlay(attrCValue)));
Item outItem(extAttr);
inItem->keychain()->add(outItem);
}
END_SECAPI
}
OSStatus SecKeychainItemCopyExtendedAttribute(
SecKeychainItemRef itemRef,
CFStringRef attrName,
CFDataRef *attrValue)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyExtendedAttribute", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
if((itemRef == NULL) || (attrName == NULL) || (attrValue == NULL)) {
return errSecParam;
}
Item foundItem;
if(!lookupExtendedAttr(itemRef, attrName, foundItem)) {
return errSecNoSuchAttr;
}
UInt32 tag = kExtendedAttrAttributeValueAttr;
UInt32 format = 0;
SecKeychainAttributeInfo attrInfo = {1, &tag, &format};
SecKeychainAttributeList *attrList = NULL;
foundItem->getAttributesAndData(&attrInfo, NULL, &attrList, NULL, NULL);
if((attrList == NULL) || (attrList->count != 1)) {
MacOSError::throwMe(errSecNoSuchAttr);
}
*attrValue = CFDataCreate(NULL, (const UInt8 *)attrList->attr->data,
attrList->attr->length);
ItemImpl::freeAttributesAndData(attrList, NULL);
END_SECAPI
}
OSStatus SecKeychainItemCopyAllExtendedAttributes(
SecKeychainItemRef itemRef,
CFArrayRef *attrNames,
CFArrayRef *attrValues)
{
BEGIN_SECAPI
os_activity_t activity = os_activity_create("SecKeychainItemCopyAllExtendedAttributes", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
os_activity_scope(activity);
os_release(activity);
if((itemRef == NULL) || (attrNames == NULL)) {
return errSecParam;
}
isItemRefCapable(itemRef);
Item inItem = ItemImpl::required(itemRef);
const CssmData &itemID = inItem->itemID();
CSSM_DB_RECORDTYPE recType = inItem->recordType();
if(!inItem->keychain()) {
MacOSError::throwMe(errSecNoSuchAttr);
}
SecKeychainAttribute attrs[2];
attrs[0].tag = kExtendedAttrRecordTypeAttr;
attrs[0].length = sizeof(UInt32);
attrs[0].data = (void *)&recType;
attrs[1].tag = kExtendedAttrItemIDAttr;
attrs[1].length = (UInt32)itemID.Length;
attrs[1].data = itemID.Data;
SecKeychainAttributeList attrList = {2, attrs};
StorageManager::KeychainList kcList;
kcList.push_back(inItem->keychain());
CFMutableArrayRef outNames = NULL;
CFMutableArrayRef outValues = NULL;
OSStatus ourRtn = errSecSuccess;
KCCursor cursor(kcList, (SecItemClass) CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE, &attrList);
for(;;) {
bool gotOne = false;
Item foundItem;
try {
gotOne = cursor->next(foundItem);
}
catch(...) {
break;
}
if(!gotOne) {
break;
}
UInt32 tags[2] = { kExtendedAttrAttributeNameAttr, kExtendedAttrAttributeValueAttr };
UInt32 formats[2] = {0};
SecKeychainAttributeInfo attrInfo = {2, tags, formats};
SecKeychainAttributeList *attrList = NULL;
foundItem->getAttributesAndData(&attrInfo, NULL, &attrList, NULL, NULL);
if((attrList == NULL) || (attrList->count != 2)) {
ourRtn = errSecNoSuchAttr;
break;
}
if(outNames == NULL) {
outNames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
if((outValues == NULL) && (attrValues != NULL)) {
outValues = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
for(unsigned dex=0; dex<2; dex++) {
SecKeychainAttribute *attr = &attrList->attr[dex];
CFDataRef cfd = NULL;
CFStringRef cfs = NULL;
switch(attr->tag) {
case kExtendedAttrAttributeNameAttr:
cfd = CFDataCreate(NULL, (const UInt8 *)attr->data, attr->length);
cfs = CFStringCreateFromExternalRepresentation(NULL, cfd, kCFStringEncodingUTF8);
CFArrayAppendValue(outNames, cfs);
CFRelease(cfd);
CFRelease(cfs);
break;
case kExtendedAttrAttributeValueAttr:
if(outValues == NULL) {
break;
}
cfd = CFDataCreate(NULL, (const UInt8 *)attr->data, attr->length);
CFArrayAppendValue(outValues, cfd);
CFRelease(cfd);
break;
default:
MacOSError::throwMe(errSecInternalComponent);
}
}
ItemImpl::freeAttributesAndData(attrList, NULL);
}
if(ourRtn) {
if(outNames) {
CFRelease(outNames);
}
if(outValues) {
CFRelease(outValues);
}
MacOSError::throwMe(ourRtn);
}
if(outNames == NULL) {
return errSecNoSuchAttr;
}
*attrNames = outNames;
if(outValues) {
*attrValues = outValues;
}
END_SECAPI
}