/* * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // // tdtransit - security tokend client library transition code. // #include "tdtransit.h" #include "tokend.h" #include namespace Security { namespace Tokend { 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 helper. // This happens "at the end" of a glue method, via the DataOutput destructor. // DataOutput::~DataOutput() { // @@@ Why are we setting up a VMGuard if mData is NULL? VMGuard _(mData, mLength); if (mData) { // was assigned to; IPC returned OK if (argument) { // buffer was provided if (argument.length() < mLength) CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); argument.length(mLength); } else { // allocate buffer argument = CssmData(allocator.malloc(mLength), mLength); } memcpy(argument.data(), mData, mLength); } } // // Create a packaged-up Context for IPC transmission. // In addition to collecting the context into a contiguous blob for transmission, // we also evaluate CssmCryptoData callbacks at this time. // SendContext::SendContext(const Security::Context &ctx) : context(ctx) { CssmCryptoData cryptoDataValue; // holding area for CssmCryptoData element 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]; // extract CssmCryptoData value cryptoDataValue = data(); // evaluate callback (if any) builder.setup(&cryptoDataValue); // use evaluted value 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; // not needed builder.done(attributes, count); assert(cryptoDataUsed <= 1); // no more than one slot converted } // // Setup and basic control // 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)); } // // The soft kiss-of-death. This is a one-way RPC; no reply is sent or received; // the call returns immediately. // void ClientSession::terminate(uint32 reason, uint32 options) { IPC((rcode = CSSM_OK, tokend_client_terminate(mServicePort, reason, options))); } // // Data search/retrieval interface // 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 theQuery(&query, internalAllocator); void *dataPtr; mach_msg_type_number_t dataLength; RecordHandle hRecord; CssmDbRecordAttributeData *outAttributesBase; IPC(tokend_client_findFirst(TOKEND_ARGS, COPY(theQuery), COPYFLAT(inAttributes), outData != NULL, &dataPtr, &dataLength, &hKey, &outAttributes, &outAttributesLength, &outAttributesBase, &hSearch, &hRecord)); relocate(outAttributes, outAttributesBase); if (outData) *outData = CssmData(dataPtr, dataLength); 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; IPC(tokend_client_findNext(TOKEND_ARGS, hSearch, COPYFLAT(inAttributes), outData != NULL, &dataPtr, &dataLength, &hKey, &outAttributes, &outAttributesLength, &outAttributesBase, &hRecord)); relocate(outAttributes, outAttributesBase); if (outData) *outData = CssmData(dataPtr, dataLength); 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; IPC(tokend_client_findRecordHandle(TOKEND_ARGS, hRecord, COPYFLAT(inAttributes), outData != NULL, &dataPtr, &dataLength, &hKey, &outAttributes, &outAttributesLength, &outAttributesBase)); relocate(outAttributes, outAttributesBase); if (outData) *outData = CssmData(dataPtr, dataLength); } void ClientSession::insertRecord(CSSM_DB_RECORDTYPE recordType, const CssmDbRecordAttributeData *inAttributes, size_t attributesLength, const CssmData &data, RecordHandle &hRecord) { CssmDbRecordAttributeData *attributes = const_cast(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(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)); } // // Key management and inquiry // 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)); } // // Signatures and MACs // 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))); } // // Encryption/Decryption // 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))); } // // Key generation // 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 creds(cred, internalAllocator); Copier 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 creds(cred, internalAllocator); Copier 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); } // // Key wrapping and unwrapping // 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 creds(cred, internalAllocator); Copier cWrappingKey(wrappingKey, internalAllocator); Copier 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 creds(cred, internalAllocator); Copier owner(proto, internalAllocator); Copier cWrappingKey(wrappingKey, internalAllocator); Copier cPublicKey(publicKey, internalAllocator); Copier cWrappedKey(&wrappedKey, internalAllocator); CssmKey *keyBase; mach_msg_type_number_t keyLength; 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(key))); relocate(key, keyBase); } // // Key derivation // 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 creds(cred, internalAllocator); Copier owner(proto, internalAllocator); Copier cBaseKey(baseKey, internalAllocator); CssmDeriveData inForm(param, context.algorithm()); Copier 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))); } // // ACL getting/setting interface. // Note that this layer, unlike the securityd-client one, does not return its // output data as separate allocated (chunked) copies. It returns its data // directly as a (relocated) flat blob. // 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))); // relocate incoming AclEntryInfo array 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 creds(&cred, internalAllocator); Copier 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))); // turn the returned AclOwnerPrototype into its proper output form 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 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; } } // namespace Tokend } // namespace Security