#include "Token.h"
#include "Cursor.h"
#include "KeyHandle.h"
#include "RecordHandle.h"
#include "Schema.h"
#include <memory>
#include <security_cdsa_utilities/cssmaclpod.h>
#include <security_utilities/unix++.h>
#include <security_utilities/logging.h>
#define BEGIN try {
#define END(SS) \
return CSSM_OK; \
} catch (const CommonError &err) { \
return CssmError::cssmError(err, CSSM_##SS##_BASE_ERROR); \
} catch (...) { \
return CSSM_ERRCODE_INTERNAL_ERROR; \
}
Tokend::Token *token;
namespace Tokend
{
Token::Token() : mSchema(NULL), mTokenContext(NULL)
{
}
Token::~Token()
{
}
CSSM_RETURN Token::_initial()
{
BEGIN
token->initial();
secdebug("tokend", "using reader %s",
token->startupReaderInfo()->szReader);
END(CSSM)
}
CSSM_RETURN Token::_probe(SecTokendProbeFlags flags, uint32 *score,
char tokenUid[TOKEND_MAX_UID])
{
BEGIN
*score = token->probe(flags, tokenUid);
secdebug("tokend", "flags=%ld returning score=%ld uid='%s'",
flags, *score, tokenUid);
END(CSSM)
}
CSSM_RETURN Token::_establish(const CSSM_GUID *guid, uint32 subserviceID,
SecTokendEstablishFlags flags, const char *cacheDirectory,
const char *workDirectory, char mdsDirectory[PATH_MAX],
char printName[PATH_MAX])
{
BEGIN
secdebug("tokend", "establish(%s,%ld,0x%lX)",
Guid::required(guid).toString().c_str(), subserviceID, flags);
token->establish(guid, subserviceID, flags, cacheDirectory, workDirectory,
mdsDirectory, printName);
END(CSSM)
}
CSSM_RETURN Token::_terminate(uint32 reason, uint32 options)
{
BEGIN
secdebug("tokend", "terminate(%ld,0x%ld)", reason, options);
token->terminate(reason, options);
END(CSSM)
}
CSSM_RETURN Token::_findFirst(const CSSM_QUERY *query,
TOKEND_RETURN_DATA *data, CSSM_HANDLE *hSearch)
{
BEGIN
secdebug("tokend", "findFirst()");
std::auto_ptr<Cursor> curs(token->createCursor(query));
TokenContext *tokenContext = token->tokenContext();
std::auto_ptr<RecordHandle> rh(curs->next(tokenContext));
if (!rh.get())
{
secdebug("tokend", "findFirst() returning: CSSMERR_DL_ENDOFDATA");
#if 1
data->record = 0;
data->keyhandle = 0;
return 0;
#else
return CSSMERR_DL_ENDOFDATA;
#endif
}
rh->get(tokenContext, *data);
rh.release();
*hSearch = curs->handle();
curs.release();
secdebug("tokend", "end findFirst() returned: %ld", *hSearch);
END(DL)
}
CSSM_RETURN Token::_findNext(CSSM_HANDLE hSearch, TOKEND_RETURN_DATA *data)
{
BEGIN
secdebug("tokend", "findNext(%ld)", hSearch);
Cursor& curs = Security::HandleObject::find<Cursor>(hSearch,
CSSMERR_DL_RECORD_NOT_FOUND);
TokenContext *tokenContext = token->tokenContext();
std::auto_ptr<RecordHandle> rh(curs.next(tokenContext));
if (!rh.get())
{
secdebug("tokend", "findNext(%ld) returning: CSSMERR_DL_ENDOFDATA",
hSearch);
#if 1
data->record = 0;
data->keyhandle = 0;
return 0;
#else
return CSSMERR_DL_ENDOFDATA;
#endif
}
rh->get(tokenContext, *data);
rh.release();
END(DL)
}
CSSM_RETURN Token::_findRecordHandle(CSSM_HANDLE hRecord,
TOKEND_RETURN_DATA *data)
{
BEGIN
secdebug("tokend", "findRecordHandle(%ld)", hRecord);
RecordHandle &rh = Security::HandleObject::find<RecordHandle>(hRecord,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
rh.get(token->tokenContext(), *data);
END(DL)
}
CSSM_RETURN Token::_insertRecord(CSSM_DB_RECORDTYPE recordType,
const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes, const CSSM_DATA *data,
CSSM_HANDLE *hRecord)
{
BEGIN
secdebug("tokend", "insertRecord");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
END(DL)
}
CSSM_RETURN Token::_modifyRecord(CSSM_DB_RECORDTYPE recordType,
CSSM_HANDLE *hRecord, const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes,
const CSSM_DATA *data, CSSM_DB_MODIFY_MODE modifyMode)
{
BEGIN
secdebug("tokend", "modifyRecord");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
END(DL)
}
CSSM_RETURN Token::_deleteRecord(CSSM_HANDLE hRecord)
{
BEGIN
secdebug("tokend", "deleteRecord");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
END(DL)
}
CSSM_RETURN Token::_releaseSearch(CSSM_HANDLE hSearch)
{
BEGIN
secdebug("tokend", "releaseSearch(%ld)", hSearch);
Security::HandleObject::findAndKill<Cursor>(hSearch,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
END(DL)
}
CSSM_RETURN Token::_releaseRecord(CSSM_HANDLE hRecord)
{
BEGIN
secdebug("tokend", "releaseRecord(%ld)", hRecord);
Security::HandleObject::findAndKill<RecordHandle>(hRecord,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
END(DL)
}
CSSM_RETURN Token::_freeRetrievedData(TOKEND_RETURN_DATA *data)
{
BEGIN
secdebug("tokend", "freeRetrievedData");
END(DL)
}
CSSM_RETURN Token::_releaseKey(CSSM_HANDLE hKey)
{
BEGIN
secdebug("tokend", "releaseKey(%ld)", hKey);
Security::HandleObject::findAndKill<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
END(CSP)
}
CSSM_RETURN Token::_getKeySize(CSSM_HANDLE hKey, CSSM_KEY_SIZE *size)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.getKeySize(Required(size));
END(CSP)
}
CSSM_RETURN Token::_getOutputSize(const CSSM_CONTEXT *context,
CSSM_HANDLE hKey, uint32 inputSize, CSSM_BOOL encrypting,
uint32 *outputSize)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
Required(outputSize) = key.getOutputSize(Context::required(context),
inputSize, encrypting);
END(CSP)
}
CSSM_RETURN Token::_generateSignature(const CSSM_CONTEXT *context,
CSSM_HANDLE hKey, CSSM_ALGORITHMS signOnly, const CSSM_DATA *input,
CSSM_DATA *signature)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.generateSignature(Context::required(context), signOnly,
CssmData::required(input), CssmData::required(signature));
END(CSP)
}
CSSM_RETURN Token::_verifySignature(const CSSM_CONTEXT *context,
CSSM_HANDLE hKey, CSSM_ALGORITHMS signOnly, const CSSM_DATA *input,
const CSSM_DATA *signature)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.verifySignature(Context::required(context), signOnly,
CssmData::required(input), CssmData::required(signature));
END(CSP)
}
CSSM_RETURN Token::_generateMac(const CSSM_CONTEXT *context, CSSM_HANDLE hKey,
const CSSM_DATA *input, CSSM_DATA *output)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.generateMac(Context::required(context), CssmData::required(input),
CssmData::required(output));
END(CSP)
}
CSSM_RETURN Token::_verifyMac(const CSSM_CONTEXT *context, CSSM_HANDLE hKey,
const CSSM_DATA *input, const CSSM_DATA *compare)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.verifyMac(Context::required(context), CssmData::required(input),
CssmData::required(compare));
END(CSP)
}
CSSM_RETURN Token::_encrypt(const CSSM_CONTEXT *context, CSSM_HANDLE hKey,
const CSSM_DATA *clear, CSSM_DATA *cipher)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.encrypt(Context::required(context), CssmData::required(clear),
CssmData::required(cipher));
END(CSP)
}
CSSM_RETURN Token::_decrypt(const CSSM_CONTEXT *context, CSSM_HANDLE hKey,
const CSSM_DATA *cipher, CSSM_DATA *clear)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.decrypt(Context::required(context), CssmData::required(cipher),
CssmData::required(clear));
END(CSP)
}
CSSM_RETURN Token::_generateKey(const CSSM_CONTEXT *context,
const CSSM_ACCESS_CREDENTIALS *creds,
const CSSM_ACL_ENTRY_PROTOTYPE *owner, CSSM_KEYUSE usage,
CSSM_KEYATTR_FLAGS attrs, CSSM_HANDLE *hKey, CSSM_KEY *header)
{
BEGIN
secdebug("tokend", "generateKey");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
END(CSP)
}
CSSM_RETURN Token::_generateKeyPair(const CSSM_CONTEXT *context,
const CSSM_ACCESS_CREDENTIALS *creds,
const CSSM_ACL_ENTRY_PROTOTYPE *owner,
CSSM_KEYUSE pubUsage, CSSM_KEYATTR_FLAGS pubAttrs,
CSSM_KEYUSE privUsage, CSSM_KEYATTR_FLAGS privAttrs,
CSSM_HANDLE *hPubKey, CSSM_KEY *pubHeader,
CSSM_HANDLE *hPrivKey, CSSM_KEY *privHeader)
{
BEGIN
secdebug("tokend", "generateKeyPair");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
END(CSP)
}
CSSM_RETURN Token::_wrapKey(const CSSM_CONTEXT *context,
CSSM_HANDLE hWrappingKey, const CSSM_KEY *wrappingKey,
const CSSM_ACCESS_CREDENTIALS *cred,
CSSM_HANDLE hSubjectKey, const CSSM_KEY *subjectKey,
const CSSM_DATA *descriptiveData, CSSM_KEY *wrappedKey)
{
BEGIN
KeyHandle *subjectKeyHandle = hSubjectKey
? &Security::HandleObject::find<KeyHandle>(hSubjectKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE) : NULL;
KeyHandle *wrappingKeyHandle = hWrappingKey
? &Security::HandleObject::find<KeyHandle>(hWrappingKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE) : NULL;
if (subjectKeyHandle)
{
subjectKeyHandle->wrapUsingKey(Context::required(context),
AccessCredentials::optional(cred),
wrappingKeyHandle, CssmKey::optional(wrappingKey),
CssmData::optional(descriptiveData),
CssmKey::required(wrappedKey));
}
else if (wrappingKeyHandle)
{
wrappingKeyHandle->wrapKey(Context::required(context),
CssmKey::required(subjectKey),
CssmData::optional(descriptiveData),
CssmKey::required(wrappedKey));
}
else
{
secdebug("tokend",
"wrapKey without a reference subject or wrapping key not supported"
);
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
END(CSP)
}
CSSM_RETURN Token::_unwrapKey(const CSSM_CONTEXT *context,
CSSM_HANDLE hWrappingKey, const CSSM_KEY *wrappingKey,
const CSSM_ACCESS_CREDENTIALS *cred,
const CSSM_ACL_ENTRY_PROTOTYPE *access,
CSSM_HANDLE hPublicKey, const CSSM_KEY *publicKey,
const CSSM_KEY *wrappedKey, CSSM_KEYUSE usage,
CSSM_KEYATTR_FLAGS attributes, CSSM_DATA *descriptiveData,
CSSM_HANDLE *hUnwrappedKey, CSSM_KEY *unwrappedKey)
{
BEGIN
if (hWrappingKey)
{
KeyHandle &unwrappingKey =
Security::HandleObject::find<KeyHandle>(hWrappingKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
if (hPublicKey)
{
secdebug("tokend", "unwrapKey with a public key not supported");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
unwrappingKey.unwrapKey(Context::required(context),
AccessCredentials::optional(cred),
AclEntryPrototype::optional(access), CssmKey::required(wrappedKey),
usage, attributes, CssmData::optional(descriptiveData),
*hUnwrappedKey, CssmKey::required(unwrappedKey));
}
else
{
secdebug("tokend",
"unwrapKey without a wrapping key not supported (import)");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
END(CSP)
}
CSSM_RETURN Token::_deriveKey(const CSSM_CONTEXT *context,
CSSM_HANDLE hSourceKey, const CSSM_KEY *sourceKey,
const CSSM_ACCESS_CREDENTIALS *cred,
const CSSM_ACL_ENTRY_PROTOTYPE *access, CSSM_DATA *parameters,
CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attributes,
CSSM_HANDLE *hKey, CSSM_KEY *key)
{
BEGIN
secdebug("tokend", "deriveKey");
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
END(CSP)
}
CSSM_RETURN Token::_getObjectOwner(CSSM_HANDLE hRecord,
CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
secdebug("tokend", "getObjectOwner");
RecordHandle &rh = Security::HandleObject::find<RecordHandle>(hRecord,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
rh.getOwner(AclOwnerPrototype::required(owner));
END(DL)
}
CSSM_RETURN Token::_getObjectAcl(CSSM_HANDLE hRecord,
const char *tag, uint32 *count, CSSM_ACL_ENTRY_INFO **entries)
{
BEGIN
secdebug("tokend", "getObjectAcl");
RecordHandle &rh = Security::HandleObject::find<RecordHandle>(hRecord,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
rh.getAcl(tag, Required(count), AclEntryInfo::overlayVar(*entries));
END(DL)
}
CSSM_RETURN Token::_getDatabaseOwner(CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
token->getOwner(AclOwnerPrototype::required(owner));
END(DL)
}
CSSM_RETURN Token::_getDatabaseAcl(const char *tag, uint32 *count,
CSSM_ACL_ENTRY_INFO **entries)
{
BEGIN
token->getAcl(tag, *count, AclEntryInfo::overlayVar(*entries));
END(DL)
}
CSSM_RETURN Token::_getKeyOwner(CSSM_HANDLE hKey,
CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.getOwner(AclOwnerPrototype::required(owner));
END(CSP)
}
CSSM_RETURN Token::_getKeyAcl(CSSM_HANDLE hKey,
const char *tag, uint32 *count, CSSM_ACL_ENTRY_INFO **entries)
{
BEGIN
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.getAcl(tag, Required(count), AclEntryInfo::overlayVar(*entries));
END(CSP)
}
CSSM_RETURN Token::_freeOwnerData(CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
END(CSP)
}
CSSM_RETURN Token::_freeAclData(uint32 count, CSSM_ACL_ENTRY_INFO *entries)
{
BEGIN
#if 0
AutoAclEntryInfoList aclList(&Allocator::standard());
*static_cast<uint32 *>(aclList) = count;
*static_cast<CSSM_ACL_ENTRY_INFO_PTR *>(aclList) = entries;
#endif
END(CSP)
}
CSSM_RETURN Token::_authenticateDatabase(CSSM_DB_ACCESS_TYPE mode,
const CSSM_ACCESS_CREDENTIALS *cred)
{
BEGIN
secdebug("tokend", "authenticateDatabase");
token->authenticate(mode, AccessCredentials::overlay(cred));
END(DL)
}
CSSM_RETURN Token::_changeDatabaseOwner(const CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
secdebug("tokend", "changeDatabaseOwner");
token->changeOwner(AclOwnerPrototype::required(owner));
END(DL)
}
CSSM_RETURN Token::_changeDatabaseAcl(const CSSM_ACCESS_CREDENTIALS *cred,
const CSSM_ACL_EDIT *edit)
{
BEGIN
secdebug("tokend", "changeDatabaseAcl");
token->changeAcl(AccessCredentials::required(cred),
AclEdit::required(edit));
END(DL)
}
CSSM_RETURN Token::_changeObjectOwner(CSSM_HANDLE hRecord,
const CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
secdebug("tokend", "changeObjectOwner");
RecordHandle &rh = Security::HandleObject::find<RecordHandle>(hRecord,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
rh.changeOwner(AclOwnerPrototype::required(owner));
END(DL)
}
CSSM_RETURN Token::_changeObjectAcl(CSSM_HANDLE hRecord,
const CSSM_ACCESS_CREDENTIALS *cred, const CSSM_ACL_EDIT *edit)
{
BEGIN
secdebug("tokend", "changeObjectAcl");
RecordHandle &rh = Security::HandleObject::find<RecordHandle>(hRecord,
CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
rh.changeAcl(AccessCredentials::required(cred), AclEdit::required(edit));
END(DL)
}
CSSM_RETURN Token::_changeKeyOwner(CSSM_HANDLE hKey,
const CSSM_ACL_OWNER_PROTOTYPE *owner)
{
BEGIN
secdebug("tokend", "changeKeyOwner");
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.changeOwner(AclOwnerPrototype::required(owner));
END(CSP)
}
CSSM_RETURN Token::_changeKeyAcl(CSSM_HANDLE hKey,
const CSSM_ACCESS_CREDENTIALS *cred, const CSSM_ACL_EDIT *edit)
{
BEGIN
secdebug("tokend", "changeKeyAcl");
KeyHandle &key = Security::HandleObject::find<KeyHandle>(hKey,
CSSMERR_CSP_INVALID_KEY_REFERENCE);
key.changeAcl(AccessCredentials::required(cred), AclEdit::required(edit));
END(CSP)
}
CSSM_RETURN Token::_generateRandom(const CSSM_CONTEXT *context,
CSSM_DATA *result)
{
BEGIN
secdebug("tokend", "generateRandom");
token->generateRandom(Context::required(context),
CssmData::required(result));
END(CSP)
}
CSSM_RETURN Token::_getStatistics(CSSM_CSP_OPERATIONAL_STATISTICS *result)
{
BEGIN
secdebug("tokend", "getStatistics");
token->getStatistics(Required(result));
END(CSP)
}
CSSM_RETURN Token::_getTime(CSSM_ALGORITHMS algorithm, CSSM_DATA *result)
{
BEGIN
secdebug("tokend", "getTime");
token->getTime(algorithm, CssmData::required(result));
END(CSP)
}
CSSM_RETURN Token::_getCounter(CSSM_DATA *result)
{
BEGIN
secdebug("tokend", "getCounter");
token->getCounter(CssmData::required(result));
END(CSP)
}
CSSM_RETURN Token::_selfVerify()
{
BEGIN
secdebug("tokend", "selfVerify");
token->selfVerify();
END(CSP)
}
CSSM_RETURN Token::_cspPassThrough(uint32 id, const CSSM_CONTEXT *context,
CSSM_HANDLE hKey, const CSSM_KEY *key, const CSSM_DATA *input,
CSSM_DATA *output)
{
BEGIN
secdebug("tokend", "cspPassThrough");
CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
END(CSP)
}
CSSM_RETURN Token::_dlPassThrough(uint32 id, const CSSM_DATA *input,
CSSM_DATA *output)
{
BEGIN
secdebug("tokend", "dlPassThrough");
CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID);
END(DL)
}
CSSM_RETURN Token::_isLocked(uint32 *locked)
{
BEGIN
secdebug("tokend", "_isLocked");
Required(locked) = token->isLocked();
END(DL)
}
const SecTokendCallbacks Token::mCallbacks = {
kSecTokendCallbackVersion,
kSecTokendCallbacksDefault,
_initial, _probe, _establish, _terminate,
_findFirst, _findNext, _findRecordHandle,
_insertRecord, _modifyRecord, _deleteRecord,
_releaseSearch, _releaseRecord,
_freeRetrievedData,
_releaseKey, _getKeySize, _getOutputSize,
_generateSignature, _verifySignature,
_generateMac, _verifyMac,
_encrypt, _decrypt,
_generateKey, _generateKeyPair,
_wrapKey, _unwrapKey, _deriveKey,
_getDatabaseOwner, _getDatabaseAcl,
_getObjectOwner, _getObjectAcl,
_getKeyOwner, _getKeyAcl,
_freeOwnerData, _freeAclData,
_authenticateDatabase,
_changeDatabaseOwner, _changeDatabaseAcl,
_changeObjectOwner, _changeObjectAcl,
_changeKeyOwner, _changeKeyAcl,
_generateRandom, _getStatistics,
_getTime, _getCounter,
_selfVerify,
_cspPassThrough, _dlPassThrough,
_isLocked
};
const SecTokendCallbacks *Token::callbacks()
{
return &mCallbacks;
}
SecTokendSupport *Token::support()
{
return this;
}
void Token::initial()
{
}
void Token::terminate(uint32 reason, uint32 options)
{
}
void Token::establish(const CSSM_GUID *guid, uint32 subserviceId,
SecTokendEstablishFlags flags, const char *cacheDirectory,
const char *workDirectory, char mdsDirectory[PATH_MAX],
char printName[PATH_MAX])
{
secdebug("establish", "cacheDirectory %s", cacheDirectory);
mGuid = *guid;
mSubserviceId = subserviceId;
mCacheDirectory = cacheDirectory;
}
bool Token::cachedObject(CSSM_DB_RECORDTYPE relationId,
const std::string &name, CssmData &object) const
{
try
{
UnixPlusPlus::AutoFileDesc fd(cachedObjectPath(relationId, name));
object.Length = fd.fileSize();
object.Data = reinterpret_cast<uint8 *>(malloc(object.Length));
object.Length = fd.readAll(object.Data, object.Length);
}
catch (const UnixError &error)
{
return false;
}
return true;
}
void Token::cacheObject(CSSM_DB_RECORDTYPE relationId, const std::string &name,
const CssmData &object) const
{
std::string path(cachedObjectPath(relationId, name));
try
{
UnixPlusPlus::AutoFileDesc fd(path, O_WRONLY|O_CREAT|O_TRUNC);
fd.writeAll(object.Data, object.Length);
}
catch (const UnixError &e)
{
Syslog::error("error writing cache file: %s: %s\n", path.c_str(),
strerror(e.unixError()));
::unlink(path.c_str());
}
}
std::string Token::cachedObjectPath(CSSM_DB_RECORDTYPE relationId,
const std::string &name) const
{
char buffer[9];
sprintf(buffer, "%lX", relationId);
return mCacheDirectory + "/" + buffer + "-" + name;
}
Cursor *Token::createCursor(const CSSM_QUERY *inQuery)
{
if (!inQuery || inQuery->RecordType == CSSM_DL_DB_RECORD_ANY
|| inQuery->RecordType == CSSM_DL_DB_RECORD_ALL_KEYS)
{
return new MultiCursor(inQuery, *mSchema);
}
const Relation &relation = mSchema->findRelation(inQuery->RecordType);
return new LinearCursor(inQuery, relation);
}
void Token::authenticate(CSSM_DB_ACCESS_TYPE mode,
const AccessCredentials *cred)
{
int pinNum;
if (!cred || sscanf(cred->EntryTag, "PIN%d", &pinNum) != 1)
pinNum = -1;
if (mode == CSSM_DB_ACCESS_RESET)
{
secdebug("authenticate", "unverifying PIN%d", pinNum);
return unverifyPIN(pinNum);
}
else if (cred && pinNum > 0)
{ if (cred->size() != 1) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
const TypedList &sample = (*cred)[0];
switch (sample.type())
{
case CSSM_SAMPLE_TYPE_PASSWORD:
case CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD:
case CSSM_SAMPLE_TYPE_PROTECTED_PASSWORD:
{
CssmData &pin = sample[1].data();
return verifyPIN(pinNum, pin.Data, pin.Length);
}
default:
break;
}
CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
}
else
secdebug("authenticate", "ignoring non-PIN authentication request");
}
void Token::changeOwner(const AclOwnerPrototype &owner)
{
CssmError::throwMe(CSSM_ERRCODE_OBJECT_MANIP_AUTH_DENIED);
}
void Token::changeAcl(const AccessCredentials &cred, const AclEdit &edit)
{
switch (edit.mode())
{
case CSSM_ACL_EDIT_MODE_DELETE:
CssmError::throwMe(CSSM_ERRCODE_ACL_DELETE_FAILED);
case CSSM_ACL_EDIT_MODE_REPLACE:
break;
case CSSM_ACL_EDIT_MODE_ADD:
CssmError::throwMe(CSSM_ERRCODE_ACL_ADD_FAILED);
default:
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_EDIT_MODE);
}
#if 0
uint32 ix = edit.handle();
if (ix >= mAclEntries.size())
CssmError::throwMe(CSSM_ERRCODE_ACL_REPLACE_FAILED);
const AclEntryPrototype &oldProto = mAclEntries.at(ix).proto();
#endif
const AclEntryInput *newEntry = edit.newEntry();
if (!newEntry)
CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER);
const AclEntryPrototype &newProto = newEntry->proto();
unsigned int pinNum;
if (sscanf(newProto.EntryTag, "PIN%d", &pinNum) != 1)
CssmError::throwMe(CSSM_ERRCODE_OBJECT_ACL_NOT_SUPPORTED);
const TypedList &subject = newProto.subject();
switch (subject.type())
{
case CSSM_ACL_SUBJECT_TYPE_PASSWORD:
case CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD:
case CSSM_ACL_SUBJECT_TYPE_PROTECTED_PASSWORD:
break;
default:
CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED);
}
const CssmData &newPin = subject[1].data();
if (cred.size() != 1)
CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
const TypedList &value = cred[0].value();
switch (value.type())
{
case CSSM_SAMPLE_TYPE_PASSWORD:
case CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD:
case CSSM_SAMPLE_TYPE_PROTECTED_PASSWORD:
break;
default:
CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
}
const CssmData &oldPin = value[1].data();
secdebug("tokend", "CHANGE PIN%d from \"%.*s\" to \"%.*s\"",
pinNum, static_cast<int>(oldPin.Length), oldPin.Data,
static_cast<int>(newPin.Length), newPin.Data);
changePIN(pinNum, oldPin.Data, oldPin.Length, newPin.Data, newPin.Length);
}
void Token::generateRandom(const Context &context, CssmData &result)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void Token::getStatistics(CSSM_CSP_OPERATIONAL_STATISTICS &result)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void Token::getTime(CSSM_ALGORITHMS algorithm, CssmData &result)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void Token::getCounter(CssmData &result)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void Token::selfVerify()
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void Token::changePIN(int pinNum,
const unsigned char *oldPin, size_t oldPinLength,
const unsigned char *newPin, size_t newPinLength)
{
CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
}
uint32_t Token::pinStatus(int pinNum)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
void Token::verifyPIN(int pinNum,
const unsigned char *pin, size_t pinLength)
{
CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
}
void Token::unverifyPIN(int pinNum)
{
}
bool Token::isLocked()
{
return pinStatus(1) != 0x9000;
}
ISO7816Token::ISO7816Token()
{
}
ISO7816Token::~ISO7816Token()
{
}
uint32 ISO7816Token::probe(SecTokendProbeFlags flags,
char tokenUid[TOKEND_MAX_UID])
{
const SCARD_READERSTATE &readerState = *(*startupReaderInfo)();
connect(mSession, readerState.szReader);
return 0;
}
void ISO7816Token::establish(const CSSM_GUID *guid, uint32 subserviceId,
SecTokendEstablishFlags flags, const char *cacheDirectory,
const char *workDirectory, char mdsDirectory[PATH_MAX],
char printName[PATH_MAX])
{
secdebug("establish", "cacheDirectory %s, workDirectory: %s",
cacheDirectory, workDirectory);
Token::establish(guid, subserviceId, flags, cacheDirectory,
workDirectory, mdsDirectory, printName);
if (!isConnected())
{
const SCARD_READERSTATE &readerState = *(*startupReaderInfo)();
connect(mSession, readerState.szReader);
}
}
uint16_t ISO7816Token::transmitAPDU(uint8_t cla, uint8_t ins, uint8_t p1,
uint8_t p2, size_t dataSize, const uint8_t *data,
size_t outputLength, std::vector<uint8_t> *output)
{
std::vector<uint8_t> apdu;
uint32_t lc = data ? dataSize : 0;
apdu.reserve(10 + lc);
apdu.push_back(cla);
apdu.push_back(ins);
apdu.push_back(p1);
apdu.push_back(p2);
if (lc > 0)
{
if (lc < 0x100)
{
apdu.push_back(lc);
}
else if (lc < 0x10000)
{
apdu.push_back(0);
apdu.push_back(lc >> 8);
apdu.push_back(lc);
}
else
{
PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
}
apdu.insert(apdu.end(), data, data + dataSize);
}
if (output && outputLength > 0)
{
if (outputLength < 0x100)
{
apdu.push_back(outputLength);
}
else if (outputLength < 0x10000)
{
apdu.push_back(0);
apdu.push_back(outputLength >> 8);
apdu.push_back(outputLength);
}
else
{
PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
}
size_t oldSize = output->size();
output->resize(oldSize + outputLength + 2);
uint8_t *response = &output->at(oldSize);
size_t responseLength = outputLength + 2;
transmit(&apdu[0], apdu.size(), response, responseLength);
if (responseLength < 2)
{
output->resize(oldSize + responseLength);
PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
}
uint16_t sw = (response[responseLength - 2] << 8)
+ response[responseLength - 1];
output->resize(oldSize + responseLength - 2);
return sw;
}
else
{
uint8_t response[2];
size_t responseLength = sizeof(response);
transmit(&apdu[0], apdu.size(), response, responseLength);
if (responseLength < 2)
PCSC::Error::throwMe(SCARD_E_PROTO_MISMATCH);
return (response[responseLength - 2] << 8)
+ response[responseLength - 1];
}
}
}