#include <security_keychain/KeyItem.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <Security/cssmtype.h>
#include <security_keychain/Access.h>
#include <security_keychain/Keychains.h>
#include <security_keychain/KeyItem.h>
#include <security_cdsa_client/wrapkey.h>
#include <security_cdsa_client/genkey.h>
#include <security_keychain/Globals.h>
#include "KCEventNotifier.h"
static CSSM_DB_NAME_ATTR(kInfoKeyPrintName, kSecKeyPrintName, "PrintName", 0, NULL, BLOB);
static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, "Label", 0, NULL, BLOB);
static CSSM_DB_NAME_ATTR(kInfoKeyApplicationTag, kSecKeyApplicationTag, "ApplicationTag", 0, NULL, BLOB);
using namespace KeychainCore;
KeyItem::KeyItem(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId) :
ItemImpl(keychain, primaryKey, uniqueId),
mKey(),
algid(NULL),
mPubKeyHash(Allocator::standard())
{
}
KeyItem::KeyItem(const Keychain &keychain, const PrimaryKey &primaryKey) :
ItemImpl(keychain, primaryKey),
mKey(),
algid(NULL),
mPubKeyHash(Allocator::standard())
{
}
KeyItem::KeyItem(KeyItem &keyItem) :
ItemImpl(keyItem),
mKey(),
algid(NULL),
mPubKeyHash(Allocator::standard())
{
}
KeyItem::KeyItem(const CssmClient::Key &key) :
ItemImpl(key->keyClass() + CSSM_DL_DB_RECORD_PUBLIC_KEY, (OSType)0, (UInt32)0, (const void*)NULL),
mKey(key),
algid(NULL),
mPubKeyHash(Allocator::standard())
{
if (key->keyClass() > CSSM_KEYCLASS_SESSION_KEY)
MacOSError::throwMe(paramErr);
}
KeyItem::~KeyItem() throw()
{
}
void
KeyItem::update()
{
ItemImpl::update();
}
Item
KeyItem::copyTo(const Keychain &keychain, Access *newAccess)
{
if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
MacOSError::throwMe(errSecInvalidKeychain);
SSDb ssDb(safe_cast<SSDbImpl *>(&(*keychain->database())));
key();
CssmClient::CSP appleCsp(gGuidAppleCSP);
CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
uint8 labelBytes[20];
CssmData label(labelBytes, sizeof(labelBytes));
random.generate(label, label.Length);
SecPointer<Access> access;
if (newAccess)
access = newAccess;
else
access = new Access(*mKey);
CssmClient::GenerateKey genKey(csp(), CSSM_ALGID_3DES_3KEY, 192);
CssmClient::Key wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
CSSM_KEYATTR_EXTRACTABLE )));
uint8 ivBytes[8];
CssmData iv(ivBytes, sizeof(ivBytes));
random.generate(iv, iv.length());
CssmClient::WrapKey wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE);
wrap.key(wrappingKey);
wrap.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, kSecCredentialTypeDefault));
wrap.mode(CSSM_ALGMODE_ECBPad);
wrap.padding(CSSM_PADDING_PKCS7);
wrap.initVector(iv);
CssmClient::Key wrappedKey(wrap(mKey));
CssmClient::UnwrapKey unwrap(keychain->csp(), CSSM_ALGID_3DES_3KEY_EDE);
unwrap.key(wrappingKey);
unwrap.mode(CSSM_ALGMODE_ECBPad);
unwrap.padding(CSSM_PADDING_PKCS7);
unwrap.initVector(iv);
unwrap.add(CSSM_ATTRIBUTE_DL_DB_HANDLE, ssDb->handle());
Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType);
ResourceControlContext rcc;
maker.initialOwner(rcc, NULL);
unwrap.owner(rcc.input());
uint32 usage = mKey->usage();
if (usage & CSSM_KEYUSE_ANY)
usage = CSSM_KEYUSE_ANY;
CssmClient::Key unwrappedKey(unwrap(wrappedKey, KeySpec(usage,
(mKey->attributes() | CSSM_KEYATTR_PERMANENT) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE),
label)));
DbUniqueRecord uniqueId;
SSDbCursor dbCursor(ssDb, 1);
dbCursor->recordType(recordType());
dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
CssmClient::Key copiedKey;
if (!dbCursor->nextKey(NULL, copiedKey, uniqueId))
MacOSError::throwMe(errSecItemNotFound);
dbUniqueRecord();
DbAttributes oldDbAttributes(mUniqueId->database(), 3);
oldDbAttributes.add(kInfoKeyLabel);
oldDbAttributes.add(kInfoKeyPrintName);
oldDbAttributes.add(kInfoKeyApplicationTag);
mUniqueId->get(&oldDbAttributes, NULL);
try
{
uniqueId->modify(recordType(), &oldDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
}
catch (CssmError e)
{
uniqueId->deleteRecord ();
throw;
}
access->setAccess(*unwrappedKey, maker);
Item item(keychain->item(recordType(), uniqueId));
KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, item);
return item;
}
void
KeyItem::didModify()
{
}
PrimaryKey
KeyItem::add(Keychain &keychain)
{
MacOSError::throwMe(unimpErr);
}
CssmClient::SSDbUniqueRecord
KeyItem::ssDbUniqueRecord()
{
DbUniqueRecordImpl *impl = &*dbUniqueRecord();
return CssmClient::SSDbUniqueRecord(safe_cast<Security::CssmClient::SSDbUniqueRecordImpl *>(impl));
}
CssmClient::Key &
KeyItem::key()
{
if (!mKey)
{
CssmClient::SSDbUniqueRecord uniqueId(ssDbUniqueRecord());
CssmDataContainer dataBlob(uniqueId->allocator());
uniqueId->get(NULL, &dataBlob);
mKey = CssmClient::Key(uniqueId->database()->csp(), *reinterpret_cast<CssmKey *>(dataBlob.Data));
}
return mKey;
}
CssmClient::CSP
KeyItem::csp()
{
return key()->csp();
}
const CSSM_X509_ALGORITHM_IDENTIFIER&
KeyItem::algorithmIdentifier()
{
#if 0
CssmKey *mKey;
CSSM_KEY_TYPE algorithm
CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)thisData->Data;
cssmKey->KeyHeader
static void printKeyHeader(
const CSSM_KEYHEADER &hdr)
{
printf(" Algorithm : ");
switch(hdr.AlgorithmId) {
CSSM_X509_ALGORITHM_IDENTIFIER algID;
CSSM_OID *CL_algToOid(
CSSM_ALGORITHMS algId)
typedef struct cssm_x509_algorithm_identifier {
CSSM_OID algorithm;
CSSM_DATA parameters;
} CSSM_X509_ALGORITHM_IDENTIFIER, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR;
#endif
abort();
}
const CssmData &KeyItem::itemID()
{
if(mPubKeyHash.length() == 0) {
UInt32 tag = kSecKeyLabel;
UInt32 format = 0;
SecKeychainAttributeInfo attrInfo = {1, &tag, &format};
SecKeychainAttributeList *attrList = NULL;
getAttributesAndData(&attrInfo, NULL, &attrList, NULL, NULL);
if((attrList == NULL) || (attrList->count != 1)) {
MacOSError::throwMe(errSecNoSuchAttr);
}
mPubKeyHash.copy(attrList->attr->data, attrList->attr->length);
freeAttributesAndData(attrList, NULL);
}
return mPubKeyHash;
}
unsigned int
KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER *algid)
{
CSSM_KEY_SIZE keySize = {};
CSSM_RETURN rv = CSSM_QueryKeySizeInBits (csp()->handle(),
CSSM_INVALID_HANDLE,
key(),
&keySize);
if (rv)
return 0;
return keySize.LogicalKeySizeInBits;
}
const AccessCredentials *
KeyItem::getCredentials(
CSSM_ACL_AUTHORIZATION_TAG operation,
SecCredentialType credentialType)
{
AclFactory factory;
switch (credentialType)
{
case kSecCredentialTypeDefault:
return globals().credentials();
case kSecCredentialTypeWithUI:
return factory.promptCred();
case kSecCredentialTypeNoUI:
return factory.nullCred();
default:
MacOSError::throwMe(paramErr);
}
}
bool
KeyItem::operator == (const KeyItem &other) const
{
if (mKey && *mKey)
{
return this == &other;
}
Keychain otherKeychain = other.keychain();
return (mKeychain && otherKeychain && (*mKeychain == *otherKeychain));
}
void
KeyItem::createPair(
Keychain keychain,
CSSM_ALGORITHMS algorithm,
uint32 keySizeInBits,
CSSM_CC_HANDLE contextHandle,
CSSM_KEYUSE publicKeyUsage,
uint32 publicKeyAttr,
CSSM_KEYUSE privateKeyUsage,
uint32 privateKeyAttr,
SecPointer<Access> initialAccess,
SecPointer<KeyItem> &outPublicKey,
SecPointer<KeyItem> &outPrivateKey)
{
bool freeKeys = false;
bool deleteContext = false;
if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
MacOSError::throwMe(errSecInvalidKeychain);
SSDb ssDb(safe_cast<SSDbImpl *>(&(*keychain->database())));
CssmClient::CSP csp(keychain->csp());
CssmClient::CSP appleCsp(gGuidAppleCSP);
CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
uint8 labelBytes[20];
CssmData label(labelBytes, sizeof(labelBytes));
random.generate(label, label.Length);
ResourceControlContext rcc;
memset(&rcc, 0, sizeof(rcc));
Access::Maker maker;
maker.initialOwner(rcc);
const AccessCredentials *cred = maker.cred();
CSSM_KEY publicCssmKey, privateCssmKey;
memset(&publicCssmKey, 0, sizeof(publicCssmKey));
memset(&privateCssmKey, 0, sizeof(privateCssmKey));
CSSM_CC_HANDLE ccHandle = 0;
Item publicKeyItem, privateKeyItem;
try
{
CSSM_RETURN status;
if (contextHandle)
ccHandle = contextHandle;
else
{
status = CSSM_CSP_CreateKeyGenContext(csp->handle(), algorithm, keySizeInBits, NULL, NULL, NULL, NULL, NULL, &ccHandle);
if (status)
CssmError::throwMe(status);
deleteContext = true;
}
CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle();
CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle;
CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } };
status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes);
if (status)
CssmError::throwMe(status);
status = CSSM_GenerateKeyPair(ccHandle, publicKeyUsage, publicKeyAttr, &label, &publicCssmKey, privateKeyUsage, privateKeyAttr, &label, &rcc, &privateCssmKey);
if (status)
CssmError::throwMe(status);
freeKeys = true;
DbAttributes pubDbAttributes;
DbUniqueRecord pubUniqueId;
SSDbCursor dbPubCursor(ssDb, 1);
dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY);
dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
CssmClient::Key publicKey;
if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId))
MacOSError::throwMe(errSecItemNotFound);
DbAttributes privDbAttributes;
DbUniqueRecord privUniqueId;
SSDbCursor dbPrivCursor(ssDb, 1);
dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY);
dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
CssmClient::Key privateKey;
if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId))
MacOSError::throwMe(errSecItemNotFound);
CssmClient::WrapKey wrap(csp, CSSM_ALGID_NONE);
wrap.cred(cred);
CssmClient::Key rawPubKey = wrap(publicKey);
CssmClient::PassThrough passThrough(appleCsp);
void *outData;
CssmData *cssmData;
passThrough.key(rawPubKey);
passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData);
cssmData = reinterpret_cast<CssmData *>(outData);
CssmData &pubKeyHash = *cssmData;
auto_ptr<string>privDescription;
auto_ptr<string>pubDescription;
try {
privDescription.reset(new string(initialAccess->promptDescription()));
pubDescription.reset(new string(initialAccess->promptDescription()));
}
catch(...) {
privDescription.reset(new string("Private key"));
pubDescription.reset(new string("Public key"));
}
pubDbAttributes.add(kInfoKeyLabel, pubKeyHash);
pubDbAttributes.add(kInfoKeyPrintName, *pubDescription);
pubUniqueId->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY, &pubDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
privDbAttributes.add(kInfoKeyLabel, pubKeyHash);
privDbAttributes.add(kInfoKeyPrintName, *privDescription);
privUniqueId->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY, &privDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
csp.allocator().free(cssmData->Data);
csp.allocator().free(cssmData);
initialAccess->setAccess(*privateKey, maker);
if(publicKeyAttr & CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT) {
SecPointer<Access> pubKeyAccess(new Access());
pubKeyAccess->setAccess(*publicKey, maker);
}
publicKeyItem = keychain->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, pubUniqueId);
privateKeyItem = keychain->item(CSSM_DL_DB_RECORD_PRIVATE_KEY, privUniqueId);
outPublicKey = safe_cast<KeyItem*>(&(*publicKeyItem));
outPrivateKey = safe_cast<KeyItem*>(&(*privateKeyItem));
}
catch (...)
{
if (freeKeys)
{
CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, TRUE);
CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, TRUE);
}
if (deleteContext)
CSSM_DeleteContext(ccHandle);
throw;
}
if (freeKeys)
{
CSSM_FreeKey(csp->handle(), NULL, &publicCssmKey, FALSE);
CSSM_FreeKey(csp->handle(), NULL, &privateCssmKey, FALSE);
}
if (deleteContext)
CSSM_DeleteContext(ccHandle);
if (keychain && publicKeyItem && privateKeyItem)
{
keychain->postEvent(kSecAddEvent, publicKeyItem);
keychain->postEvent(kSecAddEvent, privateKeyItem);
}
}
void
KeyItem::importPair(
Keychain keychain,
const CSSM_KEY &publicWrappedKey,
const CSSM_KEY &privateWrappedKey,
SecPointer<Access> initialAccess,
SecPointer<KeyItem> &outPublicKey,
SecPointer<KeyItem> &outPrivateKey)
{
bool freePublicKey = false;
bool freePrivateKey = false;
bool deleteContext = false;
if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
MacOSError::throwMe(errSecInvalidKeychain);
SSDb ssDb(safe_cast<SSDbImpl *>(&(*keychain->database())));
CssmClient::CSP csp(keychain->csp());
CssmClient::CSP appleCsp(gGuidAppleCSP);
ResourceControlContext rcc;
memset(&rcc, 0, sizeof(rcc));
Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType);
maker.initialOwner(rcc);
const AccessCredentials *cred = maker.cred();
CSSM_KEY publicCssmKey, privateCssmKey;
memset(&publicCssmKey, 0, sizeof(publicCssmKey));
memset(&privateCssmKey, 0, sizeof(privateCssmKey));
CSSM_CC_HANDLE ccHandle = 0;
Item publicKeyItem, privateKeyItem;
try
{
CSSM_RETURN status;
CssmClient::PassThrough passThrough(appleCsp);
void *outData;
CssmData *cssmData;
passThrough.key(&publicWrappedKey);
passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData);
cssmData = reinterpret_cast<CssmData *>(outData);
CssmData &pubKeyHash = *cssmData;
status = CSSM_CSP_CreateSymmetricContext(csp->handle(), publicWrappedKey.KeyHeader.WrapAlgorithmId, CSSM_ALGMODE_NONE, NULL, NULL, NULL, CSSM_PADDING_NONE, NULL, &ccHandle);
if (status)
CssmError::throwMe(status);
deleteContext = true;
CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle();
CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle;
CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } };
status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes);
if (status)
CssmError::throwMe(status);
CSSM_DATA descriptiveData = {0, NULL};
status = CSSM_UnwrapKey(
ccHandle,
NULL,
&publicWrappedKey,
publicWrappedKey.KeyHeader.KeyUsage,
publicWrappedKey.KeyHeader.KeyAttr | CSSM_KEYATTR_PERMANENT,
&pubKeyHash,
&rcc,
&publicCssmKey,
&descriptiveData);
if (status)
CssmError::throwMe(status);
freePublicKey = true;
if (descriptiveData.Data != NULL)
free (descriptiveData.Data);
status = CSSM_UnwrapKey(
ccHandle,
NULL,
&privateWrappedKey,
privateWrappedKey.KeyHeader.KeyUsage,
privateWrappedKey.KeyHeader.KeyAttr | CSSM_KEYATTR_PERMANENT,
&pubKeyHash,
&rcc,
&privateCssmKey,
&descriptiveData);
if (status)
CssmError::throwMe(status);
if (descriptiveData.Data != NULL)
free (descriptiveData.Data);
freePrivateKey = true;
DbAttributes pubDbAttributes;
DbUniqueRecord pubUniqueId;
SSDbCursor dbPubCursor(ssDb, 1);
dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY);
dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, pubKeyHash);
CssmClient::Key publicKey;
if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId))
MacOSError::throwMe(errSecItemNotFound);
DbAttributes privDbAttributes;
DbUniqueRecord privUniqueId;
SSDbCursor dbPrivCursor(ssDb, 1);
dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY);
dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, pubKeyHash);
CssmClient::Key privateKey;
if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId))
MacOSError::throwMe(errSecItemNotFound);
csp.allocator().free(cssmData->Data);
csp.allocator().free(cssmData);
auto_ptr<string>privDescription;
auto_ptr<string>pubDescription;
try {
privDescription.reset(new string(initialAccess->promptDescription()));
pubDescription.reset(new string(initialAccess->promptDescription()));
}
catch(...) {
privDescription.reset(new string("Private key"));
pubDescription.reset(new string("Public key"));
}
pubDbAttributes.add(kInfoKeyPrintName, *pubDescription);
pubUniqueId->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY, &pubDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
privDbAttributes.add(kInfoKeyPrintName, *privDescription);
privUniqueId->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY, &privDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
initialAccess->setAccess(*privateKey, maker);
SecPointer<Access> pubKeyAccess(new Access());
pubKeyAccess->setAccess(*publicKey, maker);
publicKeyItem = keychain->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, pubUniqueId);
privateKeyItem = keychain->item(CSSM_DL_DB_RECORD_PRIVATE_KEY, privUniqueId);
outPublicKey = safe_cast<KeyItem*>(&(*publicKeyItem));
outPrivateKey = safe_cast<KeyItem*>(&(*privateKeyItem));
}
catch (...)
{
if (freePublicKey)
CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, TRUE);
if (freePrivateKey)
CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, TRUE);
if (deleteContext)
CSSM_DeleteContext(ccHandle);
throw;
}
if (freePublicKey)
CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, FALSE);
if (freePrivateKey)
CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, FALSE);
if (deleteContext)
CSSM_DeleteContext(ccHandle);
if (keychain && publicKeyItem && privateKeyItem)
{
KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, publicKeyItem);
KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, privateKeyItem);
}
}
SecPointer<KeyItem>
KeyItem::generate(Keychain keychain,
CSSM_ALGORITHMS algorithm,
uint32 keySizeInBits,
CSSM_CC_HANDLE contextHandle,
CSSM_KEYUSE keyUsage,
uint32 keyAttr,
SecPointer<Access> initialAccess)
{
CssmClient::CSP appleCsp(gGuidAppleCSP);
CssmClient::CSP csp(NULL);
SSDb ssDb(NULL);
uint8 labelBytes[20];
CssmData label(labelBytes, sizeof(labelBytes));
bool freeKey = false;
bool deleteContext = false;
const CSSM_DATA *plabel = NULL;
if (keychain)
{
if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
MacOSError::throwMe(errSecInvalidKeychain);
ssDb = SSDb(safe_cast<SSDbImpl *>(&(*keychain->database())));
csp = keychain->csp();
CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
random.generate(label, label.Length);
plabel = &label;
}
else
{
csp = appleCsp;
}
ResourceControlContext *prcc = NULL, rcc;
const AccessCredentials *cred = NULL;
Access::Maker maker;
if (keychain && initialAccess)
{
memset(&rcc, 0, sizeof(rcc));
maker.initialOwner(rcc);
cred = maker.cred();
prcc = &rcc;
}
CSSM_KEY cssmKey;
CSSM_CC_HANDLE ccHandle = 0;
Item keyItem;
try
{
CSSM_RETURN status;
if (contextHandle)
ccHandle = contextHandle;
else
{
status = CSSM_CSP_CreateKeyGenContext(csp->handle(), algorithm, keySizeInBits, NULL, NULL, NULL, NULL, NULL, &ccHandle);
if (status)
CssmError::throwMe(status);
deleteContext = true;
}
if (ssDb)
{
CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle();
CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle;
CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } };
status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes);
if (status)
CssmError::throwMe(status);
keyAttr |= CSSM_KEYATTR_PERMANENT;
}
status = CSSM_GenerateKey(ccHandle, keyUsage, keyAttr, plabel, prcc, &cssmKey);
if (status)
CssmError::throwMe(status);
if (ssDb)
{
freeKey = true;
DbAttributes dbAttributes;
DbUniqueRecord uniqueId;
SSDbCursor dbCursor(ssDb, 1);
dbCursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY);
dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
CssmClient::Key key;
if (!dbCursor->nextKey(&dbAttributes, key, uniqueId))
MacOSError::throwMe(errSecItemNotFound);
if (initialAccess)
initialAccess->setAccess(*key, maker);
keyItem = keychain->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY, uniqueId);
}
else
{
CssmClient::Key tempKey(csp, cssmKey);
keyItem = new KeyItem(tempKey);
}
}
catch (...)
{
if (freeKey)
{
CSSM_FreeKey(csp->handle(), cred, &cssmKey, TRUE);
}
if (deleteContext)
CSSM_DeleteContext(ccHandle);
throw;
}
if (freeKey)
{
CSSM_FreeKey(csp->handle(), NULL, &cssmKey, FALSE);
}
if (deleteContext)
CSSM_DeleteContext(ccHandle);
if (keychain && keyItem)
keychain->postEvent(kSecAddEvent, keyItem);
return safe_cast<KeyItem*> (&*keyItem);
}