📄 securitytoken.cpp
字号:
/*
Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
Governed by the TrueCrypt License 2.6 the full text of which is contained
in the file License.txt included in TrueCrypt 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 TrueCrypt
{
SecurityTokenKeyfile::SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path)
{
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 == string::npos)
throw InvalidSecurityTokenKeyfilePath();
Id = pathStr.substr (keyIdPos + wstring (L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/").size());
vector <SecurityTokenKeyfile> keyfiles = SecurityToken::GetAvailableKeyfiles (&SlotId, Id);
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(), name.size() },
{ CKA_VALUE, &keyfileData.front(), 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, { 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)
{
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.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)
{
LoginUserIfRequired (keyfile.SlotId);
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -