#include "tdtransit.h"
#include "tokend.h"
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
namespace Security {
namespace Tokend {
static void copyDataFromIPC(void *dataPtr, mach_msg_type_number_t dataLength, CssmData *outData);
using MachPlusPlus::VMGuard;
void ClientSession::check(kern_return_t rc)
{
switch (rc) {
case KERN_SUCCESS:
return;
case MIG_SERVER_DIED:
fault();
CssmError::throwMe(CSSM_ERRCODE_DEVICE_FAILED);
default:
MachPlusPlus::check(rc);
}
}
DataOutput::~DataOutput()
{
VMGuard _(mData, mLength);
if (mData) { if (argument) { if (argument.length() < mLength)
CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR);
argument.length(mLength);
} else { argument = CssmData(allocator.malloc(mLength), mLength);
}
memcpy(argument.data(), mData, mLength);
}
}
SendContext::SendContext(const Security::Context &ctx) : context(ctx)
{
CssmCryptoData cryptoDataValue; IFDEBUG(uint32 cryptoDataUsed = 0);
Context::Builder builder(Allocator::standard());
for (unsigned n = 0; n < ctx.attributesInUse(); n++) {
switch (ctx[n].baseType()) {
case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA: {
CssmCryptoData &data = ctx[n]; cryptoDataValue = data(); builder.setup(&cryptoDataValue); IFDEBUG(cryptoDataUsed++);
break;
}
default:
builder.setup(ctx[n]);
break;
}
}
attributeSize = builder.make();
for (unsigned n = 0; n < ctx.attributesInUse(); n++) {
const Context::Attr &attr = ctx[n];
switch (attr.baseType()) {
case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA:
builder.put(attr.type(), &cryptoDataValue);
break;
default:
builder.put(attr);
break;
}
}
uint32 count; builder.done(attributes, count);
assert(cryptoDataUsed <= 1); }
void ClientSession::probe(Score &score, std::string &tokenUid)
{
char uid[PATH_MAX];
IPC(tokend_client_probe(TOKEND_ARGS, &score, uid));
tokenUid = uid;
}
void ClientSession::establish(Guid &guid, uint32 ssid,
uint32 flags, const char *cacheDirectory, const char *workDirectory,
char mdsDirectory[PATH_MAX], char printName[PATH_MAX])
{
IPC(tokend_client_establish(TOKEND_ARGS, guid, ssid,
flags, cacheDirectory, workDirectory, mdsDirectory, printName));
}
void ClientSession::terminate(uint32 reason, uint32 options)
{
IPC((rcode = CSSM_OK, tokend_client_terminate(mServicePort, reason, options)));
}
RecordHandle ClientSession::findFirst(const CssmQuery &query,
CssmDbRecordAttributeData *inAttributes, size_t inAttributesLength,
SearchHandle &hSearch, CssmData *outData, KeyHandle &hKey,
CssmDbRecordAttributeData *&outAttributes, mach_msg_type_number_t &outAttributesLength)
{
Copier<CssmQuery> theQuery(&query, internalAllocator);
void *dataPtr; mach_msg_type_number_t dataLength;
RecordHandle hRecord;
CssmDbRecordAttributeData *outAttributesBase;
CssmDbRecordAttributeData *tmpOutAttributes = NULL;
IPC(tokend_client_findFirst(TOKEND_ARGS, COPY(theQuery), COPYFLAT(inAttributes),
outData != NULL, &dataPtr, &dataLength, &hKey,
&tmpOutAttributes, &outAttributesLength, &outAttributesBase,
&hSearch, &hRecord));
if (outAttributesLength)
{
outAttributes = static_cast<CssmDbRecordAttributeData *>(malloc(outAttributesLength));
memcpy(outAttributes, tmpOutAttributes, outAttributesLength);
relocate(outAttributes, outAttributesBase);
}
else
outAttributes = NULL;
copyDataFromIPC(dataPtr, dataLength, outData);
if (tmpOutAttributes)
mig_deallocate(reinterpret_cast<vm_address_t>(tmpOutAttributes), outAttributesLength);
return hRecord;
}
RecordHandle ClientSession::findNext(SearchHandle hSearch,
CssmDbRecordAttributeData *inAttributes, size_t inAttributesLength,
CssmData *outData, KeyHandle &hKey,
CssmDbRecordAttributeData *&outAttributes, mach_msg_type_number_t &outAttributesLength)
{
void *dataPtr; mach_msg_type_number_t dataLength;
RecordHandle hRecord;
CssmDbRecordAttributeData *outAttributesBase;
CssmDbRecordAttributeData *tmpOutAttributes = NULL;
IPC(tokend_client_findNext(TOKEND_ARGS, hSearch, COPYFLAT(inAttributes),
outData != NULL, &dataPtr, &dataLength, &hKey,
&tmpOutAttributes, &outAttributesLength, &outAttributesBase,
&hRecord));
if (outAttributesLength)
{
outAttributes = static_cast<CssmDbRecordAttributeData *>(malloc(outAttributesLength));
memcpy(outAttributes, tmpOutAttributes, outAttributesLength);
relocate(outAttributes, outAttributesBase);
}
else
outAttributes = NULL;
copyDataFromIPC(dataPtr, dataLength, outData);
if (tmpOutAttributes)
mig_deallocate(reinterpret_cast<vm_address_t>(tmpOutAttributes), outAttributesLength);
return hRecord;
}
void ClientSession::findRecordHandle(RecordHandle hRecord,
CssmDbRecordAttributeData *inAttributes, size_t inAttributesLength,
CssmData *outData, KeyHandle &hKey,
CssmDbRecordAttributeData *&outAttributes, mach_msg_type_number_t &outAttributesLength)
{
void *dataPtr; mach_msg_type_number_t dataLength;
CssmDbRecordAttributeData *outAttributesBase;
CssmDbRecordAttributeData *tmpOutAttributes = NULL;
IPC(tokend_client_findRecordHandle(TOKEND_ARGS, hRecord, COPYFLAT(inAttributes),
outData != NULL, &dataPtr, &dataLength, &hKey,
&tmpOutAttributes, &outAttributesLength, &outAttributesBase));
if (outAttributesLength)
{
outAttributes = static_cast<CssmDbRecordAttributeData *>(malloc(outAttributesLength));
memcpy(outAttributes, tmpOutAttributes, outAttributesLength);
relocate(outAttributes, outAttributesBase);
}
else
outAttributes = NULL;
if (tmpOutAttributes)
mig_deallocate(reinterpret_cast<vm_address_t>(tmpOutAttributes), outAttributesLength);
copyDataFromIPC(dataPtr, dataLength, outData);
}
void ClientSession::insertRecord(CSSM_DB_RECORDTYPE recordType,
const CssmDbRecordAttributeData *inAttributes, size_t attributesLength,
const CssmData &data, RecordHandle &hRecord)
{
CssmDbRecordAttributeData *attributes = const_cast<CssmDbRecordAttributeData*>(inAttributes);
IPC(tokend_client_insertRecord(TOKEND_ARGS, recordType, COPYFLAT(attributes),
DATA(data), &hRecord));
}
void ClientSession::modifyRecord(CSSM_DB_RECORDTYPE recordType, RecordHandle &hRecord,
const CssmDbRecordAttributeData *inAttributes, size_t attributesLength,
const CssmData *data, CSSM_DB_MODIFY_MODE modifyMode)
{
CssmDbRecordAttributeData *attributes = const_cast<CssmDbRecordAttributeData*>(inAttributes);
IPC(tokend_client_modifyRecord(TOKEND_ARGS, recordType, &hRecord, COPYFLAT(attributes),
data != NULL, OPTIONALDATA(data), modifyMode));
}
void ClientSession::deleteRecord(RecordHandle hRecord)
{
IPC(tokend_client_deleteRecord(TOKEND_ARGS, hRecord));
}
void ClientSession::releaseSearch(SearchHandle hSearch)
{
IPC(tokend_client_releaseSearch(TOKEND_ARGS, hSearch));
}
void ClientSession::releaseRecord(RecordHandle hRecord)
{
IPC(tokend_client_releaseRecord(TOKEND_ARGS, hRecord));
}
void ClientSession::releaseKey(KeyHandle hKey)
{
IPC(tokend_client_releaseKey(TOKEND_ARGS, hKey));
}
void ClientSession::queryKeySizeInBits(KeyHandle hKey, CssmKeySize &result)
{
IPC(tokend_client_queryKeySizeInBits(TOKEND_ARGS, hKey, &result));
}
void ClientSession::getOutputSize(const Context &context, KeyHandle hKey,
uint32 inputSize, bool encrypt, uint32 &result)
{
SendContext ctx(context);
IPC(tokend_client_getOutputSize(TOKEND_ARGS, CONTEXT(ctx), hKey, inputSize, encrypt, &result));
}
void ClientSession::generateSignature(const Context &context, KeyHandle hKey,
const CssmData &data, CssmData &signature, CSSM_ALGORITHMS signOnlyAlgorithm)
{
SendContext ctx(context);
DataOutput sig(signature, returnAllocator);
IPC(tokend_client_generateSignature(TOKEND_ARGS, CONTEXT(ctx), hKey, signOnlyAlgorithm,
DATA(data), DATA(sig)));
}
void ClientSession::verifySignature(const Context &context, KeyHandle hKey,
const CssmData &data, const CssmData &signature, CSSM_ALGORITHMS verifyOnlyAlgorithm)
{
SendContext ctx(context);
IPC(tokend_client_verifySignature(TOKEND_ARGS, CONTEXT(ctx), hKey, verifyOnlyAlgorithm,
DATA(data), DATA(signature)));
}
void ClientSession::generateMac(const Context &context, KeyHandle hKey,
const CssmData &data, CssmData &signature)
{
SendContext ctx(context);
DataOutput sig(signature, returnAllocator);
IPC(tokend_client_generateMac(TOKEND_ARGS, CONTEXT(ctx), hKey,
DATA(data), DATA(sig)));
}
void ClientSession::verifyMac(const Context &context, KeyHandle hKey,
const CssmData &data, const CssmData &signature)
{
SendContext ctx(context);
IPC(tokend_client_verifyMac(TOKEND_ARGS, CONTEXT(ctx), hKey,
DATA(data), DATA(signature)));
}
void ClientSession::encrypt(const Context &context, KeyHandle hKey,
const CssmData &clear, CssmData &cipher)
{
SendContext ctx(context);
DataOutput cipherOut(cipher, returnAllocator);
IPC(tokend_client_encrypt(TOKEND_ARGS, CONTEXT(ctx), hKey, DATA(clear), DATA(cipherOut)));
}
void ClientSession::decrypt(const Context &context, KeyHandle hKey,
const CssmData &cipher, CssmData &clear)
{
SendContext ctx(context);
DataOutput clearOut(clear, returnAllocator);
IPC(tokend_client_decrypt(TOKEND_ARGS, CONTEXT(ctx), hKey, DATA(cipher), DATA(clearOut)));
}
void ClientSession::generateKey(const Security::Context &context,
const AccessCredentials *cred, const AclEntryPrototype *proto,
uint32 keyUsage, uint32 keyAttr,
KeyHandle &hKey, CssmKey *&key)
{
SendContext ctx(context);
Copier<AccessCredentials> creds(cred, internalAllocator);
Copier<AclEntryPrototype> owner(proto, internalAllocator);
CssmKey *keyBase; mach_msg_type_number_t keyLength;
IPC(tokend_client_generateKey(TOKEND_ARGS, CONTEXT(ctx),
COPY(creds), COPY(owner), keyUsage, keyAttr, &hKey, COPY_OUT(key)));
relocate(key, keyBase);
}
void ClientSession::generateKey(const Security::Context &context,
const AccessCredentials *cred, const AclEntryPrototype *proto,
CSSM_KEYUSE pubKeyUsage, CSSM_KEYATTR_FLAGS pubKeyAttr,
CSSM_KEYUSE privKeyUsage, CSSM_KEYATTR_FLAGS privKeyAttr,
KeyHandle &hPubKey, CssmKey *&pubKey,
KeyHandle &hPrivKey, CssmKey *&privKey)
{
SendContext ctx(context);
Copier<AccessCredentials> creds(cred, internalAllocator);
Copier<AclEntryPrototype> owner(proto, internalAllocator);
CssmKey *pubKeyBase; mach_msg_type_number_t pubKeyLength;
CssmKey *privKeyBase; mach_msg_type_number_t privKeyLength;
IPC(tokend_client_generateKeyPair(TOKEND_ARGS, CONTEXT(ctx),
COPY(creds), COPY(owner),
pubKeyUsage, pubKeyAttr, privKeyUsage, privKeyAttr,
&hPubKey, COPY_OUT(pubKey), &hPrivKey, COPY_OUT(privKey)));
relocate(pubKey, pubKeyBase);
relocate(privKey, privKeyBase);
}
void ClientSession::wrapKey(const Context &context, const AccessCredentials *cred,
KeyHandle hWrappingKey, const CssmKey *wrappingKey,
KeyHandle hSubjectKey, const CssmKey *subjectKey,
const CssmData &descriptiveData, CssmWrappedKey *&wrappedKey)
{
SendContext ctx(context);
Copier<AccessCredentials> creds(cred, internalAllocator);
Copier<CssmKey> cWrappingKey(wrappingKey, internalAllocator);
Copier<CssmKey> cSubjectKey(subjectKey, internalAllocator);
CssmKey *wrappedKeyBase; mach_msg_type_number_t wrappedKeyLength;
IPC(tokend_client_wrapKey(TOKEND_ARGS, CONTEXT(ctx), hWrappingKey, COPY(cWrappingKey), COPY(creds),
hSubjectKey, COPY(cSubjectKey), DATA(descriptiveData), COPY_OUT(wrappedKey)))
}
void ClientSession::unwrapKey(const Security::Context &context,
const AccessCredentials *cred, const AclEntryPrototype *proto,
KeyHandle hWrappingKey, const CssmKey *wrappingKey,
KeyHandle hPublicKey, const CssmKey *publicKey,
const CssmWrappedKey &wrappedKey, uint32 usage, uint32 attrs,
CssmData &descriptiveData, KeyHandle &hKey, CssmKey *&key)
{
SendContext ctx(context);
Copier<AccessCredentials> creds(cred, internalAllocator);
Copier<AclEntryPrototype> owner(proto, internalAllocator);
Copier<CssmKey> cWrappingKey(wrappingKey, internalAllocator);
Copier<CssmKey> cPublicKey(publicKey, internalAllocator);
Copier<CssmWrappedKey> cWrappedKey(&wrappedKey, internalAllocator);
CssmKey *tmpKeyBase; mach_msg_type_number_t tmpKeyLength;
CssmKey *tmpKey;
DataOutput descriptor(descriptiveData, returnAllocator);
IPC(tokend_client_unwrapKey(TOKEND_ARGS, CONTEXT(ctx), hWrappingKey, COPY(cWrappingKey),
COPY(creds), COPY(owner), hPublicKey, COPY(cPublicKey),
COPY(cWrappedKey), usage, attrs, DATA(descriptor),
&hKey, COPY_OUT(tmpKey)));
relocate(tmpKey, tmpKeyBase);
key = chunkCopy(tmpKey);
}
void ClientSession::deriveKey(DbHandle db, const Context &context,
KeyHandle hBaseKey, const CssmKey *baseKey,
uint32 keyUsage, uint32 keyAttr, CssmData ¶m,
const AccessCredentials *cred, const AclEntryPrototype *proto,
KeyHandle &hKey, CssmKey *&key)
{
SendContext ctx(context);
Copier<AccessCredentials> creds(cred, internalAllocator);
Copier<AclEntryPrototype> owner(proto, internalAllocator);
Copier<CssmKey> cBaseKey(baseKey, internalAllocator);
CssmDeriveData inForm(param, context.algorithm());
Copier<CssmDeriveData> inParam(&inForm, internalAllocator);
CssmKey *keyBase; mach_msg_type_number_t keyLength;
DataOutput paramOutput(param, returnAllocator);
IPC(tokend_client_deriveKey(TOKEND_ARGS, CONTEXT(ctx), hBaseKey, COPY(cBaseKey),
COPY(creds), COPY(owner), COPY(inParam), DATA(paramOutput),
keyUsage, keyAttr, &hKey, COPY_OUT(key)));
}
void ClientSession::getAcl(AclKind kind, GenericHandle key, const char *tag,
uint32 &count, AclEntryInfo * &info)
{
AclEntryInfo *infoBase;
mach_msg_type_number_t infoLength;
IPC(tokend_client_getAcl(TOKEND_ARGS, kind, key,
(tag != NULL), tag ? tag : "",
&count, COPY_OUT(info)));
ReconstituteWalker relocator(info, infoBase);
for (uint32 n = 0; n < count; n++)
walk(relocator, info[n]);
}
void ClientSession::changeAcl(AclKind kind, GenericHandle key,
const AccessCredentials &cred, const AclEdit &edit)
{
Copier<AccessCredentials> creds(&cred, internalAllocator);
Copier<AclEntryInput> infos(edit.newEntry(), internalAllocator);
IPC(tokend_client_changeAcl(TOKEND_ARGS, kind, key, COPY(creds),
edit.mode(), edit.handle(), COPY(infos)));
}
void ClientSession::getOwner(AclKind kind, GenericHandle handle, AclOwnerPrototype *&owner)
{
AclOwnerPrototype *ownerBase; mach_msg_type_number_t ownerLength;
IPC(tokend_client_getOwner(TOKEND_ARGS, kind, handle, COPY_OUT(owner)));
relocate(owner, ownerBase);
}
void ClientSession::changeOwner(AclKind kind, GenericHandle key, const AccessCredentials &cred,
const AclOwnerPrototype &edit)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void ClientSession::authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred)
{
Copier<AccessCredentials> creds(cred, internalAllocator);
IPC(tokend_client_authenticate(TOKEND_ARGS, mode, COPY(creds)));
}
bool ClientSession::isLocked()
{
uint32 locked = 0;
IPC(tokend_client_isLocked(TOKEND_ARGS, &locked));
return locked;
}
static void copyDataFromIPC(void *dataPtr, mach_msg_type_number_t dataLength, CssmData *outData)
{
if (!outData || !dataPtr)
return;
void *newData = malloc(dataLength);
if (newData == NULL)
CssmError::throwMe(CSSM_ERRCODE_MEMORY_ERROR);
memcpy(newData, dataPtr, dataLength);
*outData = CssmData(newData, dataLength);
mig_deallocate(reinterpret_cast<vm_address_t>(dataPtr), (vm_size_t)dataLength);
}
} }