VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common/SecurityToken.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/SecurityToken.cpp')
-rw-r--r--src/Common/SecurityToken.cpp1570
1 files changed, 785 insertions, 785 deletions
diff --git a/src/Common/SecurityToken.cpp b/src/Common/SecurityToken.cpp
index db80ff0d..8909059d 100644
--- a/src/Common/SecurityToken.cpp
+++ b/src/Common/SecurityToken.cpp
@@ -1,787 +1,787 @@
-/*
- 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-2016 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
-
-#include "SecurityToken.h"
-
-#ifndef burn
-# define burn Memory::Erase
-#endif
-
-using namespace std;
-
-namespace VeraCrypt
-{
- SecurityTokenKeyfile::SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path, char* pin)
- {
- 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();
-
- 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 (&SlotId, Id, pin);
-
- if (keyfiles.empty())
- throw SecurityTokenKeyfileNotFound();
-
- *this = keyfiles.front();
- }
-
- SecurityTokenKeyfile::operator SecurityTokenKeyfilePath () const
- {
- wstringstream path;
- path << TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"/" << 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.SlotId);
-
- CK_RV status = Pkcs11Functions->C_DestroyObject (Sessions[keyfile.SlotId].Handle, keyfile.Handle);
- if (status != CKR_OK)
- throw Pkcs11Exception (status);
- }
-
- vector <SecurityTokenKeyfile> SecurityToken::GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter, const wstring keyfileIdFilter, char* pin)
- {
- bool unrecognizedTokenPresent = false;
- vector <SecurityTokenKeyfile> keyfiles;
-
- foreach (const CK_SLOT_ID &slotId, GetTokenSlots())
- {
- SecurityTokenInfo token;
-
- if (slotIdFilter && *slotIdFilter != slotId)
- continue;
-
- try
- {
- LoginUserIfRequired (slotId, pin);
- 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.SlotId = slotId;
- keyfile.Token = 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 SecurityToken::GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector <byte> &keyfileData)
- {
- GetKeyfileData (keyfile, nullptr, keyfileData);
- }
-
- void SecurityToken::GetKeyfileData (const SecurityTokenKeyfile &keyfile, char* pin, vector <byte> &keyfileData)
- {
- LoginUserIfRequired (keyfile.SlotId, pin);
- GetObjectAttribute (keyfile.SlotId, keyfile.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, char* cmdPin)
- {
- 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 if (cmdPin && cmdPin [0])
- {
- Login (slotId, cmdPin);
- }
- 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))
- {
- if (cmdPin && cmdPin [0])
- {
- // clear wrong PIN
- size_t cmdPinLen = strlen (cmdPin);
- burn (cmdPin, cmdPinLen);
- }
- (*WarningCallback) (Pkcs11Exception (CKR_PIN_INCORRECT));
- continue;
- }
-
- throw;
- }
- }
- }
-
-#ifdef TC_WINDOWS
- void SecurityToken::InitLibrary (const wstring &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback)
-#else
- void SecurityToken::InitLibrary (const string &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback)
-#endif
- {
- if (Initialized)
- CloseLibrary();
-
-#ifdef TC_WINDOWS
+/*
+ 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-2016 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
+
+#include "SecurityToken.h"
+
+#ifndef burn
+# define burn Memory::Erase
+#endif
+
+using namespace std;
+
+namespace VeraCrypt
+{
+ SecurityTokenKeyfile::SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path, char* pin)
+ {
+ 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();
+
+ 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 (&SlotId, Id, pin);
+
+ if (keyfiles.empty())
+ throw SecurityTokenKeyfileNotFound();
+
+ *this = keyfiles.front();
+ }
+
+ SecurityTokenKeyfile::operator SecurityTokenKeyfilePath () const
+ {
+ wstringstream path;
+ path << TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"/" << 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.SlotId);
+
+ CK_RV status = Pkcs11Functions->C_DestroyObject (Sessions[keyfile.SlotId].Handle, keyfile.Handle);
+ if (status != CKR_OK)
+ throw Pkcs11Exception (status);
+ }
+
+ vector <SecurityTokenKeyfile> SecurityToken::GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter, const wstring keyfileIdFilter, char* pin)
+ {
+ bool unrecognizedTokenPresent = false;
+ vector <SecurityTokenKeyfile> keyfiles;
+
+ foreach (const CK_SLOT_ID &slotId, GetTokenSlots())
+ {
+ SecurityTokenInfo token;
+
+ if (slotIdFilter && *slotIdFilter != slotId)
+ continue;
+
+ try
+ {
+ LoginUserIfRequired (slotId, pin);
+ 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.SlotId = slotId;
+ keyfile.Token = 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 SecurityToken::GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector <byte> &keyfileData)
+ {
+ GetKeyfileData (keyfile, nullptr, keyfileData);
+ }
+
+ void SecurityToken::GetKeyfileData (const SecurityTokenKeyfile &keyfile, char* pin, vector <byte> &keyfileData)
+ {
+ LoginUserIfRequired (keyfile.SlotId, pin);
+ GetObjectAttribute (keyfile.SlotId, keyfile.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, char* cmdPin)
+ {
+ 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 if (cmdPin && cmdPin [0])
+ {
+ Login (slotId, cmdPin);
+ }
+ 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))
+ {
+ if (cmdPin && cmdPin [0])
+ {
+ // clear wrong PIN
+ size_t cmdPinLen = strlen (cmdPin);
+ burn (cmdPin, cmdPinLen);
+ }
+ (*WarningCallback) (Pkcs11Exception (CKR_PIN_INCORRECT));
+ continue;
+ }
+
+ throw;
+ }
+ }
+ }
+
+#ifdef TC_WINDOWS
+ void SecurityToken::InitLibrary (const wstring &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback)
+#else
+ void SecurityToken::InitLibrary (const string &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback)
+#endif
+ {
+ if (Initialized)
+ CloseLibrary();
+
+#ifdef TC_WINDOWS
Pkcs11LibraryHandle = LoadLibraryW (pkcs11LibraryPath.c_str());
- throw_sys_if (!Pkcs11LibraryHandle);
-#else
+ 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 = pinCallback;
- WarningCallback = 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
-
- auto_ptr <GetPinFunctor> SecurityToken::PinCallback;
- auto_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
-}
+ 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 = pinCallback;
+ WarningCallback = 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
+
+ auto_ptr <GetPinFunctor> SecurityToken::PinCallback;
+ auto_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
+}