1
0
mirror of https://github.com/veracrypt/VeraCrypt.git synced 2025-11-12 03:18:26 -06:00
Files
VeraCrypt/src/Common/SecurityToken.cpp
mmauv 502ab9112a Add EMV functionality (#1080)
* Add basic strcture needed for EMV implementation

* Add demo EMV functionality with C code pasted in a very dirty and unsafe way. NOT FINAL

* Refactor IccExtractor Structure

* Fix Makefile

* fix include file

* move global variables from h to c

* revert to memcpy

* fix icc data recovery functions

* Add EMV functionalities on windows

* Make EMVToken structures like SecurityToken

* Define constants instead of hard coded values

* Token structures created with inheritance

* refactor TokenKeyfile to use inherit. + polymor.

* add Token.h + Token.cpp in modules in VS2010

* Add a comment at each use of SecurityToken class or objects

* SecurityTokenKeyfilesDialog preparation

* Implemennt GetAvailableTokens in Token class on windows

* merge

* up (patching for Windows)

* foreach Token.cpp corrected

* Display EMV keyfiles on first window in graphic interface

* Add token to Windows UI

* EMVToken selection on OKButton on Linux

* Keyfile.cpp optimization

* Move getKeyfileData in the token class

* EMV::Token GetAvailableKeyfiles() base

* Move getKeyfileData in the token class on unix

* Remove test comments

* Warnings resolved

* RemoveeSecurityTokenLibraryNotInitialized exception if at least one emv token is detected

* Adding new files

* Remove old files and add the new version to the windows project

* Change make_shared to shared_ptr constructor

* IccExtractor integration working on linux

* Throwing card not EMV execption

* catch error when not EMV type in EMVToken::GetAvailableKeyfiles

* Change types to compile on windows

* list all keyfiles, security keyfiles and emv keyfiles in command line

* Change type to be coherent and remove old todo comments

* Remove todo comments

* Change indentation and resolve a bug from previous commit

* Use polymorphism for GetKeyfileData and add export option for EMVTokens on Linux

* Linux : Allow to export EMV Tokens in command lines, Windows : Disable the delete button when EMV Keyfiles are selected

* Remove SlotId from TokenInfo as it is already in Token

* Correct errors on Linux

* Disable delete option if one EMV Token is selected on Linux

* Fix bug enabling delete button if nothing is selected

* emv data used as reference then burnt

* use of normal files in linux corrected

* help updated

* help updated for export functionnality

* option EMV added to graphic interface but not yet working

* Bug fix : Allow to use multiple EMV on windows

* EMV Option added to UserPreferences

* EMV Option working for Linux

* EMV option added to Windows (not working yet)

* [NOT TESTED] EMV option for Windows

* Working EMV option on Windows

* EMV Option for data extraction working for volume creation

* EMV Option for data extraction working for Mount

* EMV Option for data extraction working for mounting favorites volumes

* EMV Option for extraction working for Changing volume password, Set Derivation Key Algorithm and Add or remove keyfile from volume

* Windows : re-checking EMV Option when getting data

* Removing error catches in the IccDataExtractor classe (It only throws error now). Changing GetPan signature to resemble the other functions signatures more

* Changing EMV errors

- Only throwing ICCExtractionException from outside of the ICC module.
- Catching all TLVExceptions and PCSCExceptions to throw the right ICCExtractionException

- Deleting APDU exceptions.

* First version of the documentation

* Adding function pointers for winscard library (but it crashes VeraCrypt)

* Debugging function pointers

* The import of the library on windows work as expected now

* Reverting EMVToken.cpp changes used to test to library import

* Searching for the System32 path instead of hard codding it

* Fixing the bug were VeraCrypt crashes if there is no readers when  "add Token files" is clicked

* Winscard library not initialized in object constructor anymore to delay it after EMVOption check

* Remove winscard lib from windows dependencies

* Properly displaying errors

* Adding a dot in Language.xml

* Catching TLVException

* Removing unused code

* Remove unusefull comments

* Trying to fix 0x1f error

* Update IccDataExtractor.cpp

* Delete History.xml

* Fix get data without get pan

* Cleanup code

* changes for linux compilation but linking not working

* error handling for linux

* erasing emv data

* Burn PAN

* Burn PAN from memory

* Uncomment selfcheck before merging master

* burn corrected

* EMV errors handling for Linux

* EMV working for Linux CLI

* Doc : Winscard Linux package and VeraCrypt versions

---------

Co-authored-by: doriandu45 <d45.poubelle@gmail.com>
Co-authored-by: red4game <redemgaiming@gmail.com>
Co-authored-by: Brice.Namy <brice.namy@insa-rennes.fr>
Co-authored-by: vocthor <pieceo108@gmail.com>
Co-authored-by: vocthor <67202139+vocthor@users.noreply.github.com>
Co-authored-by: Andrei COCAN <andrei.cocan@insa-rennes.fr>
Co-authored-by: AndreiCocan <95496161+AndreiCocan@users.noreply.github.com>
Co-authored-by: francoisLEROUX <francois3443@gmail.com>
2023-06-28 22:51:43 +02:00

782 lines
21 KiB
C++

/*
Derived from source code of TrueCrypt 7.1a, which is
Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
by the TrueCrypt License 3.0.
Modifications and additions to the original source code (contained in this file)
and all other portions of this file are Copyright (c) 2013-2017 IDRIX
and are governed by the Apache License 2.0 the full text of which is
contained in the file License.txt included in VeraCrypt binary and source
code distribution packages.
*/
#include "Platform/Finally.h"
#include "Platform/ForEach.h"
#if !defined (TC_WINDOWS) || defined (TC_PROTOTYPE)
# include "Platform/SerializerFactory.h"
# include "Platform/StringConverter.h"
# include "Platform/SystemException.h"
#else
# include "Dictionary.h"
# include "Language.h"
#endif
#ifdef TC_UNIX
# include <dlfcn.h>
#endif
#ifdef TC_WINDOWS
#define move_ptr std::move
#endif
#include "SecurityToken.h"
using namespace std;
namespace VeraCrypt
{
SecurityTokenKeyfile::SecurityTokenKeyfile(): Handle(CK_INVALID_HANDLE) {
SecurityTokenInfo* token = new SecurityTokenInfo();
Token = shared_ptr<SecurityTokenInfo>(token);
Token->SlotId = CK_UNAVAILABLE_INFORMATION;
token->Flags = 0;
}
SecurityTokenKeyfile::SecurityTokenKeyfile(const TokenKeyfilePath& path)
{
Token = shared_ptr<SecurityTokenInfo>(new SecurityTokenInfo());
wstring pathStr = path;
unsigned long slotId;
if (swscanf(pathStr.c_str(), TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"/%lu", &slotId) != 1)
throw InvalidSecurityTokenKeyfilePath();
Token->SlotId = slotId;
size_t keyIdPos = pathStr.find(L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/");
if (keyIdPos == wstring::npos)
throw InvalidSecurityTokenKeyfilePath();
Id = pathStr.substr(keyIdPos + wstring(L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/").size());
vector <SecurityTokenKeyfile> keyfiles = SecurityToken::GetAvailableKeyfiles(&Token->SlotId, Id);
if (keyfiles.empty())
throw SecurityTokenKeyfileNotFound();
*this = keyfiles.front();
}
SecurityTokenKeyfile::operator TokenKeyfilePath () const
{
wstringstream path;
path << TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"/" << Token->SlotId << L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/" << Id;
return path.str();
}
void SecurityToken::CheckLibraryStatus()
{
if (!Initialized)
throw SecurityTokenLibraryNotInitialized();
}
void SecurityToken::CloseLibrary()
{
if (Initialized)
{
CloseAllSessions();
Pkcs11Functions->C_Finalize(NULL_PTR);
#ifdef TC_WINDOWS
FreeLibrary(Pkcs11LibraryHandle);
#else
dlclose(Pkcs11LibraryHandle);
#endif
Initialized = false;
}
}
void SecurityToken::CloseAllSessions() throw ()
{
if (!Initialized)
return;
typedef pair <CK_SLOT_ID, Pkcs11Session> SessionMapPair;
foreach(SessionMapPair p, Sessions)
{
try
{
CloseSession(p.first);
}
catch (...) {}
}
}
void SecurityToken::CloseSession(CK_SLOT_ID slotId)
{
if (Sessions.find(slotId) == Sessions.end())
throw ParameterIncorrect(SRC_POS);
Pkcs11Functions->C_CloseSession(Sessions[slotId].Handle);
Sessions.erase(Sessions.find(slotId));
}
void SecurityToken::CreateKeyfile(CK_SLOT_ID slotId, vector <byte>& keyfileData, const string& name)
{
if (name.empty())
throw ParameterIncorrect(SRC_POS);
LoginUserIfRequired(slotId);
foreach(const SecurityTokenKeyfile & keyfile, GetAvailableKeyfiles(&slotId))
{
if (keyfile.IdUtf8 == name)
throw SecurityTokenKeyfileAlreadyExists();
}
CK_OBJECT_CLASS dataClass = CKO_DATA;
CK_BBOOL trueVal = CK_TRUE;
CK_ATTRIBUTE keyfileTemplate[] =
{
{ CKA_CLASS, &dataClass, sizeof(dataClass) },
{ CKA_TOKEN, &trueVal, sizeof(trueVal) },
{ CKA_PRIVATE, &trueVal, sizeof(trueVal) },
{ CKA_LABEL, (CK_UTF8CHAR*)name.c_str(), (CK_ULONG)name.size() },
{ CKA_VALUE, &keyfileData.front(), (CK_ULONG)keyfileData.size() }
};
CK_OBJECT_HANDLE keyfileHandle;
CK_RV status = Pkcs11Functions->C_CreateObject(Sessions[slotId].Handle, keyfileTemplate, array_capacity(keyfileTemplate), &keyfileHandle);
switch (status)
{
case CKR_DATA_LEN_RANGE:
status = CKR_DEVICE_MEMORY;
break;
case CKR_SESSION_READ_ONLY:
status = CKR_TOKEN_WRITE_PROTECTED;
break;
}
if (status != CKR_OK)
throw Pkcs11Exception(status);
// Some tokens report success even if the new object was truncated to fit in the available memory
vector <byte> objectData;
GetObjectAttribute(slotId, keyfileHandle, CKA_VALUE, objectData);
finally_do_arg(vector <byte> *, &objectData, { if (!finally_arg->empty()) burn(&finally_arg->front(), finally_arg->size()); });
if (objectData.size() != keyfileData.size())
{
Pkcs11Functions->C_DestroyObject(Sessions[slotId].Handle, keyfileHandle);
throw Pkcs11Exception(CKR_DEVICE_MEMORY);
}
}
void SecurityToken::DeleteKeyfile(const SecurityTokenKeyfile& keyfile)
{
LoginUserIfRequired(keyfile.Token->SlotId);
CK_RV status = Pkcs11Functions->C_DestroyObject(Sessions[keyfile.Token->SlotId].Handle, keyfile.Handle);
if (status != CKR_OK)
throw Pkcs11Exception(status);
}
vector <SecurityTokenKeyfile> SecurityToken::GetAvailableKeyfiles(CK_SLOT_ID* slotIdFilter, const wstring keyfileIdFilter)
{
bool unrecognizedTokenPresent = false;
vector <SecurityTokenKeyfile> keyfiles;
foreach(const CK_SLOT_ID & slotId, GetTokenSlots())
{
SecurityTokenInfo token;
if (slotIdFilter && *slotIdFilter != slotId)
continue;
try
{
LoginUserIfRequired(slotId);
token = GetTokenInfo(slotId);
}
catch (UserAbort&)
{
continue;
}
catch (Pkcs11Exception& e)
{
if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED)
{
unrecognizedTokenPresent = true;
continue;
}
throw;
}
foreach(const CK_OBJECT_HANDLE & dataHandle, GetObjects(slotId, CKO_DATA))
{
SecurityTokenKeyfile keyfile;
keyfile.Handle = dataHandle;
keyfile.Token->SlotId = slotId;
keyfile.Token = shared_ptr<SecurityTokenInfo>(new SecurityTokenInfo(token));
vector <byte> privateAttrib;
GetObjectAttribute(slotId, dataHandle, CKA_PRIVATE, privateAttrib);
if (privateAttrib.size() == sizeof(CK_BBOOL) && *(CK_BBOOL*)&privateAttrib.front() != CK_TRUE)
continue;
vector <byte> label;
GetObjectAttribute(slotId, dataHandle, CKA_LABEL, label);
label.push_back(0);
keyfile.IdUtf8 = (char*)&label.front();
#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE)
keyfile.Id = Utf8StringToWide((const char*)&label.front());
#else
keyfile.Id = StringConverter::ToWide((const char*)&label.front());
#endif
if (keyfile.Id.empty() || (!keyfileIdFilter.empty() && keyfileIdFilter != keyfile.Id))
continue;
keyfiles.push_back(keyfile);
if (!keyfileIdFilter.empty())
break;
}
}
if (keyfiles.empty() && unrecognizedTokenPresent)
throw Pkcs11Exception(CKR_TOKEN_NOT_RECOGNIZED);
return keyfiles;
}
list <SecurityTokenInfo> SecurityToken::GetAvailableTokens()
{
bool unrecognizedTokenPresent = false;
list <SecurityTokenInfo> tokens;
foreach(const CK_SLOT_ID & slotId, GetTokenSlots())
{
try
{
tokens.push_back(GetTokenInfo(slotId));
}
catch (Pkcs11Exception& e)
{
if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED)
{
unrecognizedTokenPresent = true;
continue;
}
throw;
}
}
if (tokens.empty() && unrecognizedTokenPresent)
throw Pkcs11Exception(CKR_TOKEN_NOT_RECOGNIZED);
return tokens;
}
SecurityTokenInfo SecurityToken::GetTokenInfo(CK_SLOT_ID slotId)
{
CK_TOKEN_INFO info;
CK_RV status = Pkcs11Functions->C_GetTokenInfo(slotId, &info);
if (status != CKR_OK)
throw Pkcs11Exception(status);
SecurityTokenInfo token;
token.SlotId = slotId;
token.Flags = info.flags;
char label[sizeof(info.label) + 1];
memset(label, 0, sizeof(label));
memcpy(label, info.label, sizeof(info.label));
token.LabelUtf8 = label;
size_t lastSpace = token.LabelUtf8.find_last_not_of(' ');
if (lastSpace == string::npos)
token.LabelUtf8.clear();
else
token.LabelUtf8 = token.LabelUtf8.substr(0, lastSpace + 1);
#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE)
token.Label = Utf8StringToWide(token.LabelUtf8);
#else
token.Label = StringConverter::ToWide(token.LabelUtf8);
#endif
return token;
}
void SecurityTokenKeyfile::GetKeyfileData(vector <byte>& keyfileData) const
{
SecurityToken::LoginUserIfRequired(Token->SlotId);
SecurityToken::GetObjectAttribute(Token->SlotId, Handle, CKA_VALUE, keyfileData);
}
vector <CK_OBJECT_HANDLE> SecurityToken::GetObjects(CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass)
{
if (Sessions.find(slotId) == Sessions.end())
throw ParameterIncorrect(SRC_POS);
CK_ATTRIBUTE findTemplate;
findTemplate.type = CKA_CLASS;
findTemplate.pValue = &objectClass;
findTemplate.ulValueLen = sizeof(objectClass);
CK_RV status = Pkcs11Functions->C_FindObjectsInit(Sessions[slotId].Handle, &findTemplate, 1);
if (status != CKR_OK)
throw Pkcs11Exception(status);
finally_do_arg(CK_SLOT_ID, slotId, { Pkcs11Functions->C_FindObjectsFinal(Sessions[finally_arg].Handle); });
CK_ULONG objectCount;
vector <CK_OBJECT_HANDLE> objects;
while (true)
{
CK_OBJECT_HANDLE object;
CK_RV status = Pkcs11Functions->C_FindObjects(Sessions[slotId].Handle, &object, 1, &objectCount);
if (status != CKR_OK)
throw Pkcs11Exception(status);
if (objectCount != 1)
break;
objects.push_back(object);
}
return objects;
}
void SecurityToken::GetObjectAttribute(CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector <byte>& attributeValue)
{
attributeValue.clear();
if (Sessions.find(slotId) == Sessions.end())
throw ParameterIncorrect(SRC_POS);
CK_ATTRIBUTE attribute;
attribute.type = attributeType;
attribute.pValue = NULL_PTR;
CK_RV status = Pkcs11Functions->C_GetAttributeValue(Sessions[slotId].Handle, tokenObject, &attribute, 1);
if (status != CKR_OK)
throw Pkcs11Exception(status);
if (attribute.ulValueLen == 0)
return;
attributeValue = vector <byte>(attribute.ulValueLen);
attribute.pValue = &attributeValue.front();
status = Pkcs11Functions->C_GetAttributeValue(Sessions[slotId].Handle, tokenObject, &attribute, 1);
if (status != CKR_OK)
throw Pkcs11Exception(status);
}
list <CK_SLOT_ID> SecurityToken::GetTokenSlots()
{
CheckLibraryStatus();
list <CK_SLOT_ID> slots;
CK_ULONG slotCount;
CK_RV status = Pkcs11Functions->C_GetSlotList(TRUE, NULL_PTR, &slotCount);
if (status != CKR_OK)
throw Pkcs11Exception(status);
if (slotCount > 0)
{
vector <CK_SLOT_ID> slotArray(slotCount);
status = Pkcs11Functions->C_GetSlotList(TRUE, &slotArray.front(), &slotCount);
if (status != CKR_OK)
throw Pkcs11Exception(status);
for (size_t i = 0; i < slotCount; i++)
{
CK_SLOT_INFO slotInfo;
status = Pkcs11Functions->C_GetSlotInfo(slotArray[i], &slotInfo);
if (status != CKR_OK || !(slotInfo.flags & CKF_TOKEN_PRESENT))
continue;
slots.push_back(slotArray[i]);
}
}
return slots;
}
bool SecurityToken::IsKeyfilePathValid(const wstring& securityTokenKeyfilePath)
{
return securityTokenKeyfilePath.find(TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX) == 0;
}
void SecurityToken::Login(CK_SLOT_ID slotId, const char* pin)
{
if (Sessions.find(slotId) == Sessions.end())
OpenSession(slotId);
else if (Sessions[slotId].UserLoggedIn)
return;
size_t pinLen = pin ? strlen(pin) : 0;
CK_RV status = Pkcs11Functions->C_Login(Sessions[slotId].Handle, CKU_USER, (CK_CHAR_PTR)pin, (CK_ULONG)pinLen);
if (status != CKR_OK)
throw Pkcs11Exception(status);
Sessions[slotId].UserLoggedIn = true;
}
void SecurityToken::LoginUserIfRequired(CK_SLOT_ID slotId)
{
CheckLibraryStatus();
CK_RV status;
if (Sessions.find(slotId) == Sessions.end())
{
OpenSession(slotId);
}
else
{
CK_SESSION_INFO sessionInfo;
status = Pkcs11Functions->C_GetSessionInfo(Sessions[slotId].Handle, &sessionInfo);
if (status == CKR_OK)
{
Sessions[slotId].UserLoggedIn = (sessionInfo.state == CKS_RO_USER_FUNCTIONS || sessionInfo.state == CKS_RW_USER_FUNCTIONS);
}
else
{
try
{
CloseSession(slotId);
}
catch (...) {}
OpenSession(slotId);
}
}
SecurityTokenInfo tokenInfo = GetTokenInfo(slotId);
while (!Sessions[slotId].UserLoggedIn && (tokenInfo.Flags & CKF_LOGIN_REQUIRED))
{
try
{
if (tokenInfo.Flags & CKF_PROTECTED_AUTHENTICATION_PATH)
{
status = Pkcs11Functions->C_Login(Sessions[slotId].Handle, CKU_USER, NULL_PTR, 0);
if (status != CKR_OK)
throw Pkcs11Exception(status);
}
else
{
string pin = tokenInfo.LabelUtf8;
if (tokenInfo.Label.empty())
{
stringstream s;
s << "#" << slotId;
pin = s.str();
}
finally_do_arg(string*, &pin, { burn((void*)finally_arg->c_str(), finally_arg->size()); });
(*PinCallback) (pin);
Login(slotId, pin.c_str());
}
Sessions[slotId].UserLoggedIn = true;
}
catch (Pkcs11Exception& e)
{
CK_RV error = e.GetErrorCode();
if (error == CKR_USER_ALREADY_LOGGED_IN)
{
break;
}
else if (error == CKR_PIN_INCORRECT && !(tokenInfo.Flags & CKF_PROTECTED_AUTHENTICATION_PATH))
{
PinCallback->notifyIncorrectPin();
(*WarningCallback) (Pkcs11Exception(CKR_PIN_INCORRECT));
continue;
}
throw;
}
}
}
#ifdef TC_WINDOWS
void SecurityToken::InitLibrary(const wstring& pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback)
#else
void SecurityToken::InitLibrary(const string& pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback)
#endif
{
if (Initialized)
CloseLibrary();
#ifdef TC_WINDOWS
Pkcs11LibraryHandle = LoadLibraryW(pkcs11LibraryPath.c_str());
throw_sys_if(!Pkcs11LibraryHandle);
#else
Pkcs11LibraryHandle = dlopen(pkcs11LibraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
throw_sys_sub_if(!Pkcs11LibraryHandle, dlerror());
#endif
typedef CK_RV(*C_GetFunctionList_t) (CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
#ifdef TC_WINDOWS
C_GetFunctionList_t C_GetFunctionList = (C_GetFunctionList_t)GetProcAddress(Pkcs11LibraryHandle, "C_GetFunctionList");
#else
C_GetFunctionList_t C_GetFunctionList = (C_GetFunctionList_t)dlsym(Pkcs11LibraryHandle, "C_GetFunctionList");
#endif
if (!C_GetFunctionList)
throw SecurityTokenLibraryNotInitialized();
CK_RV status = C_GetFunctionList(&Pkcs11Functions);
if (status != CKR_OK)
throw Pkcs11Exception(status);
status = Pkcs11Functions->C_Initialize(NULL_PTR);
if (status != CKR_OK)
throw Pkcs11Exception(status);
PinCallback = move_ptr(pinCallback);
WarningCallback = move_ptr(warningCallback);
Initialized = true;
}
void SecurityToken::OpenSession(CK_SLOT_ID slotId)
{
if (Sessions.find(slotId) != Sessions.end())
return;
CK_SESSION_HANDLE session;
CK_FLAGS flags = CKF_SERIAL_SESSION;
if (!(GetTokenInfo(slotId).Flags & CKF_WRITE_PROTECTED))
flags |= CKF_RW_SESSION;
CK_RV status = Pkcs11Functions->C_OpenSession(slotId, flags, NULL_PTR, NULL_PTR, &session);
if (status != CKR_OK)
throw Pkcs11Exception(status);
Sessions[slotId].Handle = session;
}
Pkcs11Exception::operator string () const
{
if (ErrorCode == CKR_OK)
return string();
static const struct
{
CK_RV ErrorCode;
const char* ErrorString;
} ErrorStrings[] =
{
# define TC_TOKEN_ERR(CODE) { CODE, #CODE },
TC_TOKEN_ERR(CKR_CANCEL)
TC_TOKEN_ERR(CKR_HOST_MEMORY)
TC_TOKEN_ERR(CKR_SLOT_ID_INVALID)
TC_TOKEN_ERR(CKR_GENERAL_ERROR)
TC_TOKEN_ERR(CKR_FUNCTION_FAILED)
TC_TOKEN_ERR(CKR_ARGUMENTS_BAD)
TC_TOKEN_ERR(CKR_NO_EVENT)
TC_TOKEN_ERR(CKR_NEED_TO_CREATE_THREADS)
TC_TOKEN_ERR(CKR_CANT_LOCK)
TC_TOKEN_ERR(CKR_ATTRIBUTE_READ_ONLY)
TC_TOKEN_ERR(CKR_ATTRIBUTE_SENSITIVE)
TC_TOKEN_ERR(CKR_ATTRIBUTE_TYPE_INVALID)
TC_TOKEN_ERR(CKR_ATTRIBUTE_VALUE_INVALID)
TC_TOKEN_ERR(CKR_DATA_INVALID)
TC_TOKEN_ERR(CKR_DATA_LEN_RANGE)
TC_TOKEN_ERR(CKR_DEVICE_ERROR)
TC_TOKEN_ERR(CKR_DEVICE_MEMORY)
TC_TOKEN_ERR(CKR_DEVICE_REMOVED)
TC_TOKEN_ERR(CKR_ENCRYPTED_DATA_INVALID)
TC_TOKEN_ERR(CKR_ENCRYPTED_DATA_LEN_RANGE)
TC_TOKEN_ERR(CKR_FUNCTION_CANCELED)
TC_TOKEN_ERR(CKR_FUNCTION_NOT_PARALLEL)
TC_TOKEN_ERR(CKR_FUNCTION_NOT_SUPPORTED)
TC_TOKEN_ERR(CKR_KEY_HANDLE_INVALID)
TC_TOKEN_ERR(CKR_KEY_SIZE_RANGE)
TC_TOKEN_ERR(CKR_KEY_TYPE_INCONSISTENT)
TC_TOKEN_ERR(CKR_KEY_NOT_NEEDED)
TC_TOKEN_ERR(CKR_KEY_CHANGED)
TC_TOKEN_ERR(CKR_KEY_NEEDED)
TC_TOKEN_ERR(CKR_KEY_INDIGESTIBLE)
TC_TOKEN_ERR(CKR_KEY_FUNCTION_NOT_PERMITTED)
TC_TOKEN_ERR(CKR_KEY_NOT_WRAPPABLE)
TC_TOKEN_ERR(CKR_KEY_UNEXTRACTABLE)
TC_TOKEN_ERR(CKR_MECHANISM_INVALID)
TC_TOKEN_ERR(CKR_MECHANISM_PARAM_INVALID)
TC_TOKEN_ERR(CKR_OBJECT_HANDLE_INVALID)
TC_TOKEN_ERR(CKR_OPERATION_ACTIVE)
TC_TOKEN_ERR(CKR_OPERATION_NOT_INITIALIZED)
TC_TOKEN_ERR(CKR_PIN_INCORRECT)
TC_TOKEN_ERR(CKR_PIN_INVALID)
TC_TOKEN_ERR(CKR_PIN_LEN_RANGE)
TC_TOKEN_ERR(CKR_PIN_EXPIRED)
TC_TOKEN_ERR(CKR_PIN_LOCKED)
TC_TOKEN_ERR(CKR_SESSION_CLOSED)
TC_TOKEN_ERR(CKR_SESSION_COUNT)
TC_TOKEN_ERR(CKR_SESSION_HANDLE_INVALID)
TC_TOKEN_ERR(CKR_SESSION_PARALLEL_NOT_SUPPORTED)
TC_TOKEN_ERR(CKR_SESSION_READ_ONLY)
TC_TOKEN_ERR(CKR_SESSION_EXISTS)
TC_TOKEN_ERR(CKR_SESSION_READ_ONLY_EXISTS)
TC_TOKEN_ERR(CKR_SESSION_READ_WRITE_SO_EXISTS)
TC_TOKEN_ERR(CKR_SIGNATURE_INVALID)
TC_TOKEN_ERR(CKR_SIGNATURE_LEN_RANGE)
TC_TOKEN_ERR(CKR_TEMPLATE_INCOMPLETE)
TC_TOKEN_ERR(CKR_TEMPLATE_INCONSISTENT)
TC_TOKEN_ERR(CKR_TOKEN_NOT_PRESENT)
TC_TOKEN_ERR(CKR_TOKEN_NOT_RECOGNIZED)
TC_TOKEN_ERR(CKR_TOKEN_WRITE_PROTECTED)
TC_TOKEN_ERR(CKR_UNWRAPPING_KEY_HANDLE_INVALID)
TC_TOKEN_ERR(CKR_UNWRAPPING_KEY_SIZE_RANGE)
TC_TOKEN_ERR(CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT)
TC_TOKEN_ERR(CKR_USER_ALREADY_LOGGED_IN)
TC_TOKEN_ERR(CKR_USER_NOT_LOGGED_IN)
TC_TOKEN_ERR(CKR_USER_PIN_NOT_INITIALIZED)
TC_TOKEN_ERR(CKR_USER_TYPE_INVALID)
TC_TOKEN_ERR(CKR_USER_ANOTHER_ALREADY_LOGGED_IN)
TC_TOKEN_ERR(CKR_USER_TOO_MANY_TYPES)
TC_TOKEN_ERR(CKR_WRAPPED_KEY_INVALID)
TC_TOKEN_ERR(CKR_WRAPPED_KEY_LEN_RANGE)
TC_TOKEN_ERR(CKR_WRAPPING_KEY_HANDLE_INVALID)
TC_TOKEN_ERR(CKR_WRAPPING_KEY_SIZE_RANGE)
TC_TOKEN_ERR(CKR_WRAPPING_KEY_TYPE_INCONSISTENT)
TC_TOKEN_ERR(CKR_RANDOM_SEED_NOT_SUPPORTED)
TC_TOKEN_ERR(CKR_RANDOM_NO_RNG)
TC_TOKEN_ERR(CKR_DOMAIN_PARAMS_INVALID)
TC_TOKEN_ERR(CKR_BUFFER_TOO_SMALL)
TC_TOKEN_ERR(CKR_SAVED_STATE_INVALID)
TC_TOKEN_ERR(CKR_INFORMATION_SENSITIVE)
TC_TOKEN_ERR(CKR_STATE_UNSAVEABLE)
TC_TOKEN_ERR(CKR_CRYPTOKI_NOT_INITIALIZED)
TC_TOKEN_ERR(CKR_CRYPTOKI_ALREADY_INITIALIZED)
TC_TOKEN_ERR(CKR_MUTEX_BAD)
TC_TOKEN_ERR(CKR_MUTEX_NOT_LOCKED)
TC_TOKEN_ERR(CKR_NEW_PIN_MODE)
TC_TOKEN_ERR(CKR_NEXT_OTP)
TC_TOKEN_ERR(CKR_FUNCTION_REJECTED)
#undef TC_TOKEN_ERR
};
for (size_t i = 0; i < array_capacity(ErrorStrings); ++i)
{
if (ErrorStrings[i].ErrorCode == ErrorCode)
return ErrorStrings[i].ErrorString;
}
stringstream s;
s << "0x" << hex << ErrorCode;
return s.str();
}
#ifdef TC_HEADER_Common_Exception
void Pkcs11Exception::Show(HWND parent) const
{
string errorString = string(*this);
if (!errorString.empty())
{
wstringstream subjectErrorCode;
if (SubjectErrorCodeValid)
subjectErrorCode << L": " << SubjectErrorCode;
if (!GetDictionaryValue(errorString.c_str()))
{
if (errorString.find("CKR_") == 0)
{
errorString = errorString.substr(4);
for (size_t i = 0; i < errorString.size(); ++i)
{
if (errorString[i] == '_')
errorString[i] = ' ';
}
}
wchar_t err[8192];
StringCbPrintfW(err, sizeof(err), L"%s:\n\n%hs%s", GetString("SECURITY_TOKEN_ERROR"), errorString.c_str(), subjectErrorCode.str().c_str());
ErrorDirect(err, parent);
}
else
{
wstring err = GetString(errorString.c_str());
if (SubjectErrorCodeValid)
err += L"\n\nError code" + subjectErrorCode.str();
ErrorDirect(err.c_str(), parent);
}
}
}
#endif // TC_HEADER_Common_Exception
unique_ptr <GetPinFunctor> SecurityToken::PinCallback;
unique_ptr <SendExceptionFunctor> SecurityToken::WarningCallback;
bool SecurityToken::Initialized;
CK_FUNCTION_LIST_PTR SecurityToken::Pkcs11Functions;
map <CK_SLOT_ID, Pkcs11Session> SecurityToken::Sessions;
#ifdef TC_WINDOWS
HMODULE SecurityToken::Pkcs11LibraryHandle;
#else
void* SecurityToken::Pkcs11LibraryHandle;
#endif
#ifdef TC_HEADER_Platform_Exception
void Pkcs11Exception::Deserialize(shared_ptr <Stream> stream)
{
Exception::Deserialize(stream);
Serializer sr(stream);
uint64 code;
sr.Deserialize("ErrorCode", code);
sr.Deserialize("SubjectErrorCodeValid", SubjectErrorCodeValid);
sr.Deserialize("SubjectErrorCode", SubjectErrorCode);
ErrorCode = (CK_RV)code;
}
void Pkcs11Exception::Serialize(shared_ptr <Stream> stream) const
{
Exception::Serialize(stream);
Serializer sr(stream);
sr.Serialize("ErrorCode", (uint64)ErrorCode);
sr.Serialize("SubjectErrorCodeValid", SubjectErrorCodeValid);
sr.Serialize("SubjectErrorCode", SubjectErrorCode);
}
# define TC_EXCEPTION(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE)
# undef TC_EXCEPTION_NODECL
# define TC_EXCEPTION_NODECL(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE)
TC_SERIALIZER_FACTORY_ADD_EXCEPTION_SET(SecurityTokenException);
#endif
}