diff options
author | mmauv <99472743+mmauv@users.noreply.github.com> | 2023-06-28 22:51:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-28 22:51:43 +0200 |
commit | 502ab9112a7624dbd7c1c90c2e12ed45512b8b3c (patch) | |
tree | 951e70be174df6f1d214f37e5ca10c49519b7d73 /src/Common | |
parent | f4e109afcfcdd7ad067158b66d08787f371a6bc4 (diff) | |
download | VeraCrypt-502ab9112a7624dbd7c1c90c2e12ed45512b8b3c.tar.gz VeraCrypt-502ab9112a7624dbd7c1c90c2e12ed45512b8b3c.zip |
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>
Diffstat (limited to 'src/Common')
-rw-r--r-- | src/Common/Dlgcode.c | 58 | ||||
-rw-r--r-- | src/Common/Dlgcode.h | 1 | ||||
-rw-r--r-- | src/Common/EMVToken.cpp | 121 | ||||
-rw-r--r-- | src/Common/EMVToken.h | 50 | ||||
-rw-r--r-- | src/Common/IccDataExtractor.cpp | 777 | ||||
-rw-r--r-- | src/Common/IccDataExtractor.h | 231 | ||||
-rw-r--r-- | src/Common/Keyfiles.c | 15 | ||||
-rw-r--r-- | src/Common/Language.xml | 8 | ||||
-rw-r--r-- | src/Common/SecurityToken.cpp | 522 | ||||
-rw-r--r-- | src/Common/SecurityToken.h | 126 | ||||
-rw-r--r-- | src/Common/TLVParser.cpp | 179 | ||||
-rw-r--r-- | src/Common/TLVParser.h | 80 | ||||
-rw-r--r-- | src/Common/Token.cpp | 82 | ||||
-rw-r--r-- | src/Common/Token.h | 57 |
14 files changed, 1952 insertions, 355 deletions
diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index e1170d84..dfcc3d03 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -207,6 +207,7 @@ BOOL LastMountedVolumeDirty; BOOL MountVolumesAsSystemFavorite = FALSE; BOOL FavoriteMountOnArrivalInProgress = FALSE; BOOL MultipleMountOperationInProgress = FALSE; +BOOL ActivateEMVOption = FALSE; volatile BOOL NeedPeriodicDeviceListUpdate = FALSE; BOOL DisablePeriodicDeviceListUpdate = FALSE; @@ -12206,11 +12207,11 @@ static BOOL CALLBACK NewSecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPA WaitCursor(); finally_do ({ NormalCursor(); }); - list <SecurityTokenInfo> tokens; + list <shared_ptr<TokenInfo>> tokens; try { - tokens = SecurityToken::GetAvailableTokens(); + tokens = Token::GetAvailableTokens(); } catch (Exception &e) { @@ -12224,12 +12225,12 @@ static BOOL CALLBACK NewSecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPA return 1; } - foreach (const SecurityTokenInfo &token, tokens) + foreach (const shared_ptr<TokenInfo> token, tokens) { wstringstream tokenLabel; - tokenLabel << L"[" << token.SlotId << L"] " << token.Label; + tokenLabel << L"[" << token->SlotId << L"] " << token->Label; - AddComboPair (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), tokenLabel.str().c_str(), token.SlotId); + AddComboPair (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), tokenLabel.str().c_str(), token->SlotId); } ComboBox_SetCurSel (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), 0); @@ -12283,7 +12284,7 @@ static BOOL CALLBACK NewSecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPA } -static void SecurityTokenKeyfileDlgFillList (HWND hwndDlg, const vector <SecurityTokenKeyfile> &keyfiles) +static void SecurityTokenKeyfileDlgFillList (HWND hwndDlg, const vector <shared_ptr<TokenKeyfile>> &keyfiles) { HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST); LVITEMW lvItem; @@ -12291,18 +12292,18 @@ static void SecurityTokenKeyfileDlgFillList (HWND hwndDlg, const vector <Securit ListView_DeleteAllItems (tokenListControl); - foreach (const SecurityTokenKeyfile &keyfile, keyfiles) + foreach (const shared_ptr<TokenKeyfile> keyfile, keyfiles) { memset (&lvItem, 0, sizeof(lvItem)); lvItem.mask = LVIF_TEXT; lvItem.iItem = line++; wstringstream s; - s << keyfile.SlotId; + s << keyfile->Token->SlotId; ListItemAdd (tokenListControl, lvItem.iItem, (wchar_t *) s.str().c_str()); - ListSubItemSet (tokenListControl, lvItem.iItem, 1, (wchar_t *) keyfile.Token.Label.c_str()); - ListSubItemSet (tokenListControl, lvItem.iItem, 2, (wchar_t *) keyfile.Id.c_str()); + ListSubItemSet (tokenListControl, lvItem.iItem, 1, (wchar_t *) keyfile->Token->Label.c_str()); + ListSubItemSet (tokenListControl, lvItem.iItem, 2, (wchar_t *) keyfile->Id.c_str()); } BOOL selected = (ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST), -1, LVIS_SELECTED) != -1); @@ -12311,10 +12312,10 @@ static void SecurityTokenKeyfileDlgFillList (HWND hwndDlg, const vector <Securit } -static list <SecurityTokenKeyfile> SecurityTokenKeyfileDlgGetSelected (HWND hwndDlg, const vector <SecurityTokenKeyfile> &keyfiles) +static list <shared_ptr<TokenKeyfile>> SecurityTokenKeyfileDlgGetSelected (HWND hwndDlg, const vector <shared_ptr<TokenKeyfile>> &keyfiles) { HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST); - list <SecurityTokenKeyfile> selectedKeyfiles; + list <shared_ptr<TokenKeyfile>> selectedKeyfiles; int itemId = -1; while ((itemId = ListView_GetNextItem (tokenListControl, itemId, LVIS_SELECTED)) != -1) @@ -12328,8 +12329,8 @@ static list <SecurityTokenKeyfile> SecurityTokenKeyfileDlgGetSelected (HWND hwnd BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { - static list <SecurityTokenKeyfilePath> *selectedTokenKeyfiles; - static vector <SecurityTokenKeyfile> keyfiles; + static list <TokenKeyfilePath> *selectedTokenKeyfiles; + static vector <shared_ptr<TokenKeyfile>> keyfiles; WORD lw = LOWORD (wParam); @@ -12337,7 +12338,7 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam { case WM_INITDIALOG: { - selectedTokenKeyfiles = (list <SecurityTokenKeyfilePath> *) lParam; + selectedTokenKeyfiles = (list <TokenKeyfilePath> *) lParam; LVCOLUMNW LvCol; HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST); @@ -12372,7 +12373,7 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam WaitCursor(); finally_do ({ NormalCursor(); }); - keyfiles = SecurityToken::GetAvailableKeyfiles(); + keyfiles = Token::GetAvailableKeyfiles(ActivateEMVOption); } catch (UserAbort&) { @@ -12400,9 +12401,9 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam { if (selectedTokenKeyfiles) { - foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) + foreach (const shared_ptr<TokenKeyfile> &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) { - selectedTokenKeyfiles->push_back (SecurityTokenKeyfilePath (keyfile)); + selectedTokenKeyfiles->push_back (TokenKeyfilePath (*keyfile)); } } @@ -12413,8 +12414,15 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam if (msg == WM_NOTIFY && ((LPNMHDR) lParam)->code == LVN_ITEMCHANGED) { BOOL selected = (ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST), -1, LVIS_SELECTED) != -1); + BOOL deletable = selected; + foreach (const shared_ptr<TokenKeyfile> &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) + { + if( ! keyfile->Token->isEditable()){ + deletable = false; + } + } EnableWindow (GetDlgItem (hwndDlg, IDC_EXPORT), selected); - EnableWindow (GetDlgItem (hwndDlg, IDC_DELETE), selected); + EnableWindow (GetDlgItem (hwndDlg, IDC_DELETE), deletable); return 1; } @@ -12461,7 +12469,7 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam SecurityToken::CreateKeyfile (newParams.SlotId, keyfileDataVector, newParams.Name); - keyfiles = SecurityToken::GetAvailableKeyfiles(); + keyfiles = Token::GetAvailableKeyfiles(ActivateEMVOption); SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles); } catch (Exception &e) @@ -12489,7 +12497,7 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam { try { - foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) + foreach (const shared_ptr<TokenKeyfile> &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) { wchar_t keyfilePath[TC_MAX_PATH]; @@ -12502,7 +12510,7 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam vector <byte> keyfileData; - SecurityToken::GetKeyfileData (keyfile, keyfileData); + keyfile->GetKeyfileData (keyfileData); if (keyfileData.empty()) { @@ -12538,12 +12546,12 @@ BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam WaitCursor(); finally_do ({ NormalCursor(); }); - foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) + foreach (const shared_ptr<TokenKeyfile> keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) { - SecurityToken::DeleteKeyfile (keyfile); + SecurityToken::DeleteKeyfile (dynamic_cast<SecurityTokenKeyfile&>(*keyfile.get())); } - keyfiles = SecurityToken::GetAvailableKeyfiles(); + keyfiles = Token::GetAvailableKeyfiles(ActivateEMVOption); SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles); } catch (Exception &e) diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 362b2d6d..2004eb2a 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -166,6 +166,7 @@ extern BOOL LastMountedVolumeDirty; extern BOOL MountVolumesAsSystemFavorite; extern BOOL FavoriteMountOnArrivalInProgress; extern BOOL MultipleMountOperationInProgress; +extern BOOL ActivateEMVOption; extern volatile BOOL NeedPeriodicDeviceListUpdate; extern BOOL DisablePeriodicDeviceListUpdate; diff --git a/src/Common/EMVToken.cpp b/src/Common/EMVToken.cpp new file mode 100644 index 00000000..aac59a6a --- /dev/null +++ b/src/Common/EMVToken.cpp @@ -0,0 +1,121 @@ +#include "EMVToken.h" + +#include "Platform/Finally.h" +#include "Platform/ForEach.h" +#include <vector> +#include <iostream> + + + +#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 + + +using namespace std; + +namespace VeraCrypt +{ + + IccDataExtractor EMVToken::extractor; + + EMVTokenInfo::~EMVTokenInfo() + { + burn(&Label,Label.size()); + } + + EMVTokenKeyfile::EMVTokenKeyfile(const TokenKeyfilePath& path) + { + Id = EMV_CARDS_LABEL; + Token = shared_ptr<EMVTokenInfo>(new EMVTokenInfo()); + wstring pathStr = path; + unsigned long slotId; + + if (swscanf(pathStr.c_str(), TC_EMV_TOKEN_KEYFILE_URL_PREFIX TC_EMV_TOKEN_KEYFILE_URL_SLOT L"/%lu", &slotId) != 1) + throw InvalidEMVPath(); + + Token->SlotId = slotId; + } + + EMVTokenKeyfile::operator TokenKeyfilePath () const + { + wstringstream path; + path << TC_EMV_TOKEN_KEYFILE_URL_PREFIX TC_EMV_TOKEN_KEYFILE_URL_SLOT L"/" << Token->SlotId; + return path.str(); + } + + void EMVTokenKeyfile::GetKeyfileData(vector <byte>& keyfileData) const + { + #ifdef TC_WINDOWS + EMVToken::extractor.InitLibrary(); + #endif + + EMVToken::extractor.GetReaders(); + EMVToken::extractor.GettingAllCerts(Token->SlotId, keyfileData); + } + + bool EMVToken::IsKeyfilePathValid(const wstring& emvTokenKeyfilePath) + { + return emvTokenKeyfilePath.find(TC_EMV_TOKEN_KEYFILE_URL_PREFIX) == 0; + } + + vector<EMVTokenKeyfile> EMVToken::GetAvailableKeyfiles(unsigned long int* slotIdFilter, const wstring keyfileIdFilter) { + #ifdef TC_WINDOWS + EMVToken::extractor.InitLibrary(); + #endif + + vector <EMVTokenKeyfile> keyfiles; + unsigned long int nb = 0; + + nb = EMVToken::extractor.GetReaders(); + + + for(unsigned long int slotId = 0; slotId<nb; slotId++) + { + EMVTokenInfo token; + + if (slotIdFilter && *slotIdFilter != slotId) + continue; + + try{ + token = GetTokenInfo(slotId); + } catch(EMVUnknownCardType) { + continue; + }catch(PCSCException){ + + continue; + } + + EMVTokenKeyfile keyfile; + keyfile.Token->SlotId = slotId; + keyfile.Token = shared_ptr<TokenInfo>(new EMVTokenInfo(token)); + + keyfiles.push_back(keyfile); + + if (!keyfileIdFilter.empty()) + break; + } + + return keyfiles; + + } + + + EMVTokenInfo EMVToken::GetTokenInfo(unsigned long int slotId) { + EMVTokenInfo token; + token.SlotId = slotId; + //card numbers extraction + std::string pan; + EMVToken::extractor.GettingPAN(slotId, pan); + token.Label = L"EMV card **** "; + token.Label += wstring (pan.begin(), pan.end()); + burn(&pan[0],pan.size()); + return token; + } + +} diff --git a/src/Common/EMVToken.h b/src/Common/EMVToken.h new file mode 100644 index 00000000..1d84ec28 --- /dev/null +++ b/src/Common/EMVToken.h @@ -0,0 +1,50 @@ +#ifndef TC_HEADER_Common_EMVToken +#define TC_HEADER_Common_EMVToken + +#define TC_EMV_TOKEN_KEYFILE_URL_PREFIX L"emv://" +#define TC_EMV_TOKEN_KEYFILE_URL_SLOT L"slot" + +#define EMV_CARDS_LABEL L"EMV Certificates" + +#include "Platform/PlatformBase.h" +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) +# include "Exception.h" +#else +# include "Platform/Exception.h" +#endif + +#include "Token.h" +#include "IccDataExtractor.h" + +namespace VeraCrypt { + + struct EMVTokenInfo: TokenInfo + { + virtual ~EMVTokenInfo(); + virtual BOOL isEditable() const {return false;} + }; + + struct EMVTokenKeyfile: TokenKeyfile + { + EMVTokenKeyfile(){Id = EMV_CARDS_LABEL; Token = shared_ptr<EMVTokenInfo>(new EMVTokenInfo());}; + EMVTokenKeyfile(const TokenKeyfilePath& path); + + virtual operator TokenKeyfilePath () const; + virtual void GetKeyfileData(vector <byte>& keyfileData) const; + + }; + + class EMVToken { + private: + static IccDataExtractor extractor; + public: + static bool IsKeyfilePathValid(const wstring& emvTokenKeyfilePath); + static vector<EMVTokenKeyfile> GetAvailableKeyfiles(unsigned long int* slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); + static EMVTokenInfo GetTokenInfo(unsigned long int slotId); + + friend void EMVTokenKeyfile::GetKeyfileData(vector <byte>& keyfileData) const; + + }; +} + +#endif diff --git a/src/Common/IccDataExtractor.cpp b/src/Common/IccDataExtractor.cpp new file mode 100644 index 00000000..d98bc360 --- /dev/null +++ b/src/Common/IccDataExtractor.cpp @@ -0,0 +1,777 @@ +// +// Created by bshp on 1/14/23. +// + +#include "IccDataExtractor.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 + +#include "Tcdefs.h" + +namespace VeraCrypt +{ + + + #ifdef TC_WINDOWS + bool VeraCrypt::IccDataExtractor::Initialized; + #endif + //using namespace std; + const BYTE IccDataExtractor::SELECT_MASTERCARD[] = {00, 0xA4, 0x04, 00, 0x07, 0xA0, 00, 00, 00, 0x04, 0x10, 0x10}; + const BYTE IccDataExtractor::SELECT_VISA[] = {00, 0xA4, 0x04, 00, 0x07, 0xA0, 00, 00, 00, 0x03, 0x10, 0x10}; + const BYTE IccDataExtractor::SELECT_AMEX[] = {00, 0xA4, 0x04, 00, 0x07, 0xA0, 00, 00, 00, 00, 0x25, 0x10}; + const BYTE * IccDataExtractor::SELECT_TYPES[]={SELECT_MASTERCARD, SELECT_VISA, SELECT_AMEX}; + + IccDataExtractor::IccDataExtractor(){} + + IccDataExtractor::~IccDataExtractor(){ + /* Disconnect card if connected */ + if(hCard){ + #ifdef TC_WINDOWS + WSCardDisconnect(hContext,hCard); + #else + SCardDisconnect(hContext,hCard); + #endif + } + /* Release memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length + * designator*/ + if (mszReaders){ + #ifdef TC_WINDOWS + WSCardFreeMemory(hContext, mszReaders); + #else + SCardFreeMemory(hContext, mszReaders); + #endif + } + + /* Closing the established resource manager context freeing any resources allocated under that context + * including SCARDHANDLE objects and memory allocated using the SCARD_AUTOALLOCATE length designator*/ + if(hContext){ + #ifdef TC_WINDOWS + WSCardReleaseContext(hContext); + #else + SCardReleaseContext(hContext); + #endif + } + + /* Freeing winscard library */ + #ifdef TC_WINDOWS + FreeLibrary(WinscardLibraryHandle); + #endif + } + + #ifdef TC_WINDOWS + void IccDataExtractor::InitLibrary(){ + + if(Initialized) return; + + /* Getting the System32 directory */ + char sysDir[MAX_PATH-20]; + GetSystemDirectoryA(sysDir, MAX_PATH); + + /* Getting the winscard dll path directory */ + char winscardPath[MAX_PATH]; + sprintf_s(winscardPath, "%s\\Winscard.dll", sysDir); + + /* Loading the winscard dll from System32 */ + WinscardLibraryHandle = LoadLibraryA(winscardPath); + throw_sys_if(!WinscardLibraryHandle); + + /* Fetching the functions pointers from the dll */ + WSCardEstablishContext = (SCardEstablishContextPtr) GetProcAddress(WinscardLibraryHandle,"SCardEstablishContext"); + if(!WSCardEstablishContext) throw WinscardLibraryNotInitialized(); + + WSCardReleaseContext= (SCardReleaseContextPtr) GetProcAddress(WinscardLibraryHandle,"SCardReleaseContext"); + if(!WSCardReleaseContext) throw WinscardLibraryNotInitialized(); + + WSCardConnectA = (SCardConnectAPtr) GetProcAddress(WinscardLibraryHandle,"SCardConnectA"); + if(!WSCardConnectA) throw WinscardLibraryNotInitialized(); + + WSCardDisconnect = (SCardDisconnectPtr) GetProcAddress(WinscardLibraryHandle,"SCardDisconnect"); + if(!WSCardDisconnect) throw WinscardLibraryNotInitialized(); + + WSCardFreeMemory = ( SCardFreeMemoryPtr) GetProcAddress(WinscardLibraryHandle,"SCardFreeMemory"); + if(!WSCardFreeMemory) throw WinscardLibraryNotInitialized(); + + WSCardListReadersA = (SCardListReadersAPtr) GetProcAddress(WinscardLibraryHandle,"SCardListReadersA"); + if(!WSCardListReadersA) throw WinscardLibraryNotInitialized(); + + WSCardTransmit = ( SCardTransmitPtr) GetProcAddress(WinscardLibraryHandle,"SCardTransmit"); + if(!WSCardTransmit) throw WinscardLibraryNotInitialized(); + + Initialized = true; + + } + #endif + + /* Establishing the resource manager context (the scope) within which database operations are performed. + * The module of the smart card subsystem that manages access to multiple readers and smart cards. The + * resource manager identifies and tracks resources, allocates readers and resources across multiple + * applications,and supports transaction primitives for accessing services available on a given card.*/ + int IccDataExtractor::EstablishRSContext(){ + + #ifdef TC_WINDOWS + LONG returnValue = WSCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + #else + LONG returnValue = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); + #endif + + /* Check if the establishment of the context was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + return EXIT_SUCCESS; + } + + /* Detecting available readers and filling the reader table */ + unsigned long IccDataExtractor::GetReaders(){ + + #ifdef TC_WINDOWS + if(!Initialized) + throw WinscardLibraryNotInitialized(); + #endif + + EstablishRSContext(); + + /* Length of the mszReaders buffer in characters. If the buffer length is specified as + * SCARD_AUTOALLOCATE, then mszReaders is converted to a pointer to a byte pointer, and + * receives the address of a block of memory containing the multi-string structure */ + DWORD dwReaders = SCARD_AUTOALLOCATE; + + /* Retrieving the available readers list and putting it in mszReaders*/ // Use LPSTR on linux + #ifdef TC_WINDOWS + LONG returnValue = WSCardListReadersA(hContext, NULL, (LPSTR)&mszReaders, &dwReaders); + #else + LONG returnValue = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders); + #endif + + /* If the is no readers, return */ + if(returnValue == SCARD_E_NO_READERS_AVAILABLE) return 0; + + /* Check if the listing of the connected readers was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + nbReaders = 0; + LPSTR ReaderPtr = mszReaders; + + /* Getting the total number of readers */ + while (*ReaderPtr != '\0') + { + readers.push_back(ReaderPtr); + ReaderPtr += strlen((char*)ReaderPtr) + 1; + nbReaders++; + } + + return nbReaders; + } + + /* Connecting to the card in the given reader*/ + int IccDataExtractor::ConnectCard(unsigned long int reader_nb){ + + /* Check if the given reader slot number is possible */ + if (reader_nb < 0 || reader_nb >= nbReaders) + throw InvalidEMVPath(); + + dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED; + + #ifdef TC_WINDOWS + LONG returnValue = WSCardConnectA(hContext, readers[reader_nb], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); + #else + LONG returnValue = SCardConnect(hContext, readers[reader_nb], SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); + #endif + + /* Check is the card connection was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + return EXIT_SUCCESS; + } + + /* Disconnect the card currently connected*/ + int IccDataExtractor::DisconnectCard(){ + #ifdef TC_WINDOWS + LONG returnValue = WSCardDisconnect(hCard, SCARD_UNPOWER_CARD); + #else + LONG returnValue = SCardDisconnect(hCard, SCARD_UNPOWER_CARD); + #endif + + /* Check is the card deconnection was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + return EXIT_SUCCESS; + } + + /* Testing if the card contains the application of the given EMV type (0:Mastercard, 1:Visa, 2:Amex) */ + bool IccDataExtractor::TestingCardType(const int SELECT_TYPE_NUMBER){ + + const BYTE * SELECTED_TYPE = SELECT_TYPES[SELECT_TYPE_NUMBER]; + + BYTE pbRecvBuffer[64]; /* Buffer to receive the card response */ + + DWORD dwSendLength = SELECT_TYPE_SIZE; /* Set the size of the send buffer */ + DWORD dwRecvLength = sizeof(pbRecvBuffer); /* Set the size of the reception buffer */ + + /* Set up the io request */ + SCARD_IO_REQUEST ioRequest; + ioRequest.dwProtocol = dwActiveProtocol; + ioRequest.cbPciLength = sizeof(ioRequest); + + #ifdef TC_WINDOWS + LONG returnValue = WSCardTransmit(hCard, &ioRequest, SELECTED_TYPE, dwSendLength, NULL, pbRecvBuffer, &dwRecvLength); + #else + LONG returnValue = SCardTransmit(hCard, &ioRequest, SELECTED_TYPE, dwSendLength, NULL, pbRecvBuffer, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* It received a response. Check if it didn't get a recognisable response */ + if (dwRecvLength < 2) + return false; + + /* Check if the command successfully executed (the card is the type passed in the parameter) */ + if (pbRecvBuffer[0] == 0x61) + return true; + + return false; + } + + /* Getting the ICC Public Key Certificates and the Issuer Public Key Certificates by parsing the application + * (!NEED TO TEST CARD TYPE TO SELECT APPLICATION FIRST!)*/ + void IccDataExtractor::GetCerts(vector<byte> &CERTS){ + + CERTS.clear(); + + bool iccFound= false; + bool issuerFound= false; + + shared_ptr<TLVNode> node; + shared_ptr<TLVNode> ICC_Public_Key_Certificate; + shared_ptr<TLVNode> Issuer_PK_Certificate; + + BYTE pbRecvBuffer[64]; /* Buffer to receive the card response */ + BYTE pbRecvBufferFat[256]; /* Bigger buffer to receive the card response */ + + DWORD dwSendLength; /* Size of the send buffer */ + DWORD dwRecvLength; /* Size of the reception buffer */ + + /* Set up the io request */ + SCARD_IO_REQUEST ioRequest; + ioRequest.dwProtocol = dwActiveProtocol; + ioRequest.cbPciLength = sizeof(ioRequest); + + LONG returnValue; + + /* Parsing root folders */ + for (int sfi = 0; sfi < 32; sfi++) + { + /* Parsing sub folders */ + for (int rec = 0; rec < 17; rec++) + { + BYTE SELECT_APDU_FILE[] = {00, 0xB2, static_cast<unsigned char>(rec), static_cast<unsigned char>((sfi << 3) | 4), 0x00}; + + dwSendLength = sizeof(SELECT_APDU_FILE); + dwRecvLength = sizeof(pbRecvBuffer); + + /* Check if there is data in the folder */ + #ifdef TC_WINDOWS + returnValue = WSCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength,NULL, pbRecvBuffer, &dwRecvLength); + #else + returnValue = SCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength,NULL, pbRecvBuffer, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* There is no data in the folder */ + if (pbRecvBuffer[0] != 0x6C) + continue; + + /* It set the proper expected length of the data in the APDU */ + SELECT_APDU_FILE[4] = pbRecvBuffer[1]; + + dwRecvLength = sizeof(pbRecvBufferFat); + + /* Get the data from the folder */ + #ifdef TC_WINDOWS + returnValue = WSCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength, NULL, pbRecvBufferFat, &dwRecvLength); + #else + returnValue = SCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength, NULL, pbRecvBufferFat, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* It received a response. Check if it didn't get a recognisable response */ + if (dwRecvLength < 2) + continue; + + /* Parsing the TLV */ + try{ + node = TLVParser::TLV_Parse(pbRecvBufferFat,sizeof(pbRecvBufferFat)); + }catch(TLVException){ + continue; + } + + /* Finding the ICC_Public_Key_Certificate */ + try{ + ICC_Public_Key_Certificate = TLVParser::TLV_Find(node, 0x9F46); + }catch(TLVException){ + continue; + } + if(ICC_Public_Key_Certificate) { + iccFound=true; + for (int i = 0; i < ICC_Public_Key_Certificate->Length;i++) { + CERTS.push_back(static_cast<byte>(ICC_Public_Key_Certificate->Value[i])); + } + } + + /* Finding the Issuer_Public_Key_Certificate */ + try{ + Issuer_PK_Certificate = TLVParser::TLV_Find(node, 0x90); + }catch(TLVException){ + continue; + } + + if(Issuer_PK_Certificate) { + issuerFound=true; + for (int i = 0; i < Issuer_PK_Certificate->Length;i++) { + CERTS.push_back(static_cast<byte>(Issuer_PK_Certificate->Value[i])); + } + } + + /* Limiting the search to at least one occurrence of both PKs to speed up the process. + * There might be more certificates tho */ + if(iccFound && issuerFound){ + burn(pbRecvBuffer, sizeof(pbRecvBuffer)); + burn(pbRecvBufferFat, sizeof(pbRecvBufferFat)); + return; + } + } + } + burn(pbRecvBuffer, sizeof(pbRecvBuffer)); + burn(pbRecvBufferFat, sizeof(pbRecvBufferFat)); + throw EMVKeyfileDataNotFound(); + } + + /* Getting CPCL data from the card*/ + void IccDataExtractor::GetCPCL(vector<byte> &v){ + + BYTE SELECT_APDU_CPCL[] = {0x80,0xCA, 0x9F, 0x7F, 0x00}; + + BYTE pbRecvBuffer[64]; /* Buffer to receive the card response */ + BYTE pbRecvBufferFat[256]; /* Bigger buffer to receive the card response */ + + DWORD dwSendLength = sizeof (SELECT_APDU_CPCL); /* Set the size of the send buffer */ + DWORD dwRecvLength = sizeof(pbRecvBuffer); /* Set the size of the reception buffer */ + + /* Set up the io request */ + SCARD_IO_REQUEST ioRequest; + ioRequest.dwProtocol = dwActiveProtocol; + ioRequest.cbPciLength = sizeof(ioRequest); + + /* Check if there is the TAG for CPCL Data in the card */ + #ifdef TC_WINDOWS + LONG returnValue = WSCardTransmit(hCard, &ioRequest, SELECT_APDU_CPCL, dwSendLength, NULL, pbRecvBuffer, &dwRecvLength); + #else + LONG returnValue = SCardTransmit(hCard, &ioRequest, SELECT_APDU_CPCL, dwSendLength, NULL, pbRecvBuffer, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* Not the correct APDU response code */ + if (pbRecvBuffer[0] != 0x6C) + throw EMVKeyfileDataNotFound(); + + /* It set the proper expected length of the data in the APDU */ + SELECT_APDU_CPCL[4] = pbRecvBuffer[1]; + + dwRecvLength = sizeof(pbRecvBufferFat); + + /* Get the CPCL data */ + #ifdef TC_WINDOWS + returnValue = WSCardTransmit(hCard, &ioRequest, SELECT_APDU_CPCL, dwSendLength,NULL, pbRecvBufferFat, &dwRecvLength); + #else + returnValue = SCardTransmit(hCard, &ioRequest, SELECT_APDU_CPCL, dwSendLength,NULL, pbRecvBufferFat, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* It received a response. Check if it didn't get a recognisable response */ + if (dwRecvLength < 2) + throw EMVKeyfileDataNotFound(); + + /* We add CPCL data and crop the TAG and the data length at the start and the trailer at the end */ + for (unsigned long i = 3; i < dwRecvLength-2; i++) { + v.push_back(static_cast<byte>(pbRecvBufferFat[i])); + } + burn(pbRecvBuffer, sizeof(pbRecvBuffer)); + burn(pbRecvBufferFat, sizeof(pbRecvBufferFat)); + + } + + /* Getting an ICC Public Key Certificates and an Issuer Public Key Certificates for the first application with the cpcl + * data present on the card and finally merge it into one byte array */ + void IccDataExtractor::GettingAllCerts(int readerNumber, vector<byte> &v){ + + #ifdef TC_WINDOWS + if(!Initialized) + throw WinscardLibraryNotInitialized(); + #endif + + bool isEMV= false; + + ConnectCard(readerNumber); + + /* Test all the type of applications and get the certificates from the first one found */ + for(int i=0;i<sizeof(SELECT_TYPES)/sizeof(SELECT_TYPES[0]); i++){ + + /* The card does not contain this application (0:Mastercard, 1:Visa, 2:Amex) */ + if(!TestingCardType(i)) continue; + isEMV= true; + GetCerts(v); + break; + } + + /* Need to disconnect reconnect the card to access CPLC data (not located in any application) */ + DisconnectCard(); + + /* Check if the card is not an EMV one */ + if(!isEMV) + throw EMVUnknownCardType(); + + ConnectCard(readerNumber); + + GetCPCL(v); + + DisconnectCard(); + } + + /* Getting the PAN by parsing the application + * (!NEED TO TEST CARD TYPE TO SELECT APPLICATION FIRST!)*/ + void IccDataExtractor::GetPAN(vector<byte> &v) { + + bool PANFound= false; + shared_ptr<TLVNode> node; + shared_ptr<TLVNode> PAN; + + BYTE pbRecvBuffer[64]; /* Buffer to receive the card response */ + BYTE pbRecvBufferFat[256]; /* Bigger buffer to receive the card response */ + + DWORD dwSendLength; /* Size of the send buffer */ + DWORD dwRecvLength; /* Size of the reception buffer */ + + /* Set up the io request */ + SCARD_IO_REQUEST ioRequest; + ioRequest.dwProtocol = dwActiveProtocol; + ioRequest.cbPciLength = sizeof(ioRequest); + + LONG returnValue; + + /* Parsing root folders */ + for (int sfi = 0; sfi < 32; sfi++) + { + /* Parsing sub folders */ + for (int rec = 0; rec < 17; rec++) + { + BYTE SELECT_APDU_FILE[] = {00, 0xB2, static_cast<unsigned char>(rec), static_cast<unsigned char>((sfi << 3) | 4), 0x00}; + + dwSendLength = sizeof(SELECT_APDU_FILE); + dwRecvLength = sizeof(pbRecvBuffer); + + /* Check if there is data in the folder */ + #ifdef TC_WINDOWS + returnValue = WSCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength,NULL, pbRecvBuffer, &dwRecvLength); + #else + returnValue = SCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength,NULL, pbRecvBuffer, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* There is no data in the folder */ + if (pbRecvBuffer[0] != 0x6C) + continue; + + /* It set the proper expected length of the data in the APDU */ + SELECT_APDU_FILE[4] = pbRecvBuffer[1]; + + dwRecvLength = sizeof(pbRecvBufferFat); + + /* Get the data from the folder */ + #ifdef TC_WINDOWS + returnValue = WSCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength,NULL, pbRecvBufferFat, &dwRecvLength); + #else + returnValue = SCardTransmit(hCard, &ioRequest, SELECT_APDU_FILE, dwSendLength,NULL, pbRecvBufferFat, &dwRecvLength); + #endif + + /* Check if the transmission was unsuccessful */ + if (returnValue != SCARD_S_SUCCESS) + throw PCSCException(returnValue); + + /* It received a response. Check if it didn't get a recognisable response */ + if (dwRecvLength < 2) + continue; + + /* Parsing the TLV */ + try{ + node = TLVParser::TLV_Parse(pbRecvBufferFat,sizeof(pbRecvBufferFat)); + }catch(TLVException){ + continue; + } + + /* Finding the PAN */ + try{ + PAN = TLVParser::TLV_Find(node, 0x5A); + }catch(TLVException){ + continue; + } + if(PAN) { + PANFound=true; + if (PAN->Length >= 8){ + for (int i = 6; i < 8;i++) { + v.push_back(static_cast<byte>(PAN->Value[i])); + } + } + } + + if(PANFound){ + burn(pbRecvBuffer, sizeof(pbRecvBuffer)); + burn(pbRecvBufferFat, sizeof(pbRecvBufferFat)); + return ; + } + } + } + burn(pbRecvBuffer, sizeof(pbRecvBuffer)); + burn(pbRecvBufferFat, sizeof(pbRecvBufferFat)); + throw EMVPANNotFound(); + } + + /* Helper function to transform the PAN received (vector of byte) to a string */ + template<typename TInputIter> + void IccDataExtractor::make_hex_string(TInputIter first, TInputIter last, string& returnValue, bool use_uppercase, bool insert_spaces) { + ostringstream ss; + ss << hex << std::setfill('0'); + if (use_uppercase) + ss << uppercase; + while (first != last) + { + ss << setw(2) << static_cast<int>(*first++); + if (insert_spaces && first != last) + ss << " "; + } + + returnValue = ss.str(); + } + + /* Wrapper function to get the PAN of the card*/ + void IccDataExtractor::GettingPAN(int readerNumber, string& panString) { + + #ifdef TC_WINDOWS + if(!Initialized) + throw WinscardLibraryNotInitialized(); + #endif + + vector<byte> PAN; + + bool isEMV= false; + + ConnectCard(readerNumber); + + /* Test all the type of applications and get the PAN from the first one found */ + for(int i=0;i<sizeof(SELECT_TYPES)/sizeof(SELECT_TYPES[0]); i++){ + + /* The card does not contain this application (0:Mastercard, 1:Visa, 2:Amex) */ + if(!TestingCardType(i)) continue; + isEMV=true; + GetPAN(PAN); + break; + } + + DisconnectCard(); + + /* Check if the card is not an EMV one */ + if(!isEMV) + throw EMVUnknownCardType(); + + make_hex_string(PAN.begin(),PAN.end(),panString); + + burn(&PAN.front(),PAN.size()); + } + + PCSCException::operator string() const{ + if (ErrorCode == SCARD_S_SUCCESS) + return string(); + + static const struct{ + LONG ErrorCode; + const char* ErrorString; + } ErrorStrings[] = { + #define SC_ERR(CODE) { CODE, #CODE }, +#ifdef TC_WINDOWS + SC_ERR(ERROR_BROKEN_PIPE) + SC_ERR(SCARD_E_NO_PIN_CACHE) + SC_ERR(SCARD_E_PIN_CACHE_EXPIRED) + SC_ERR(SCARD_E_READ_ONLY_CARD) + SC_ERR(SCARD_W_CACHE_ITEM_NOT_FOUND) + SC_ERR(SCARD_W_CACHE_ITEM_STALE) + SC_ERR(SCARD_W_CACHE_ITEM_TOO_BIG) +#endif + SC_ERR(SCARD_E_BAD_SEEK) + SC_ERR(SCARD_E_CANCELLED) + SC_ERR(SCARD_E_CANT_DISPOSE) + SC_ERR(SCARD_E_CARD_UNSUPPORTED) + SC_ERR(SCARD_E_CERTIFICATE_UNAVAILABLE) + SC_ERR(SCARD_E_COMM_DATA_LOST) + SC_ERR(SCARD_E_COMM_DATA_LOST) + SC_ERR(SCARD_E_DIR_NOT_FOUND) + SC_ERR(SCARD_E_DUPLICATE_READER) + SC_ERR(SCARD_E_FILE_NOT_FOUND) + SC_ERR(SCARD_E_ICC_CREATEORDER) + SC_ERR(SCARD_E_ICC_INSTALLATION) + SC_ERR(SCARD_E_INSUFFICIENT_BUFFER) + SC_ERR(SCARD_E_INVALID_ATR) + SC_ERR(SCARD_E_INVALID_CHV) + SC_ERR(SCARD_E_INVALID_HANDLE) + SC_ERR(SCARD_E_INVALID_PARAMETER) + SC_ERR(SCARD_E_INVALID_TARGET) + SC_ERR(SCARD_E_INVALID_VALUE) + SC_ERR(SCARD_E_NO_ACCESS) + SC_ERR(SCARD_E_NO_DIR) + SC_ERR(SCARD_E_NO_FILE) + SC_ERR(SCARD_E_NO_KEY_CONTAINER) + SC_ERR(SCARD_E_NO_MEMORY) + SC_ERR(SCARD_E_NO_READERS_AVAILABLE) + SC_ERR(SCARD_E_NO_SERVICE) + SC_ERR(SCARD_E_NO_SMARTCARD) + SC_ERR(SCARD_E_NO_SUCH_CERTIFICATE) + SC_ERR(SCARD_E_NOT_READY) + SC_ERR(SCARD_E_NOT_TRANSACTED) + SC_ERR(SCARD_E_PCI_TOO_SMALL) + SC_ERR(SCARD_E_PROTO_MISMATCH) + SC_ERR(SCARD_E_READER_UNAVAILABLE) + SC_ERR(SCARD_E_READER_UNSUPPORTED) + SC_ERR(SCARD_E_SERVER_TOO_BUSY) + SC_ERR(SCARD_E_SERVICE_STOPPED) + SC_ERR(SCARD_E_SHARING_VIOLATION) + SC_ERR(SCARD_E_SYSTEM_CANCELLED) + SC_ERR(SCARD_E_TIMEOUT) + SC_ERR(SCARD_E_UNEXPECTED) + SC_ERR(SCARD_E_UNKNOWN_CARD) + SC_ERR(SCARD_E_UNKNOWN_READER) + SC_ERR(SCARD_E_UNKNOWN_RES_MNG) + SC_ERR(SCARD_E_UNSUPPORTED_FEATURE) + SC_ERR(SCARD_E_WRITE_TOO_MANY) + SC_ERR(SCARD_F_COMM_ERROR) + SC_ERR(SCARD_F_INTERNAL_ERROR) + SC_ERR(SCARD_F_UNKNOWN_ERROR) + SC_ERR(SCARD_W_CANCELLED_BY_USER) + SC_ERR(SCARD_W_CARD_NOT_AUTHENTICATED) + SC_ERR(SCARD_W_CHV_BLOCKED) + SC_ERR(SCARD_W_EOF) + SC_ERR(SCARD_W_REMOVED_CARD) + SC_ERR(SCARD_W_RESET_CARD) + SC_ERR(SCARD_W_SECURITY_VIOLATION) + SC_ERR(SCARD_W_UNPOWERED_CARD) + SC_ERR(SCARD_W_UNRESPONSIVE_CARD) + SC_ERR(SCARD_W_UNSUPPORTED_CARD) + SC_ERR(SCARD_W_WRONG_CHV) +#undef SC_ERR + }; + + for (size_t i = 0; i < array_capacity(ErrorStrings); ++i) + { + if (ErrorStrings[i].ErrorCode == ErrorCode) + return ErrorStrings[i].ErrorString; + } + + stringstream s; + s << "0x" << ErrorCode; + return s.str(); + } + + #ifdef TC_HEADER_Common_Exception + void PCSCException::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("SCARD_E_") == 0 || errorString.find("SCARD_F_") == 0 || errorString.find("SCARD_W_") == 0) + { + errorString = errorString.substr(8); + 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("PCSC_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 + +#ifdef TC_HEADER_Platform_Exception + + void PCSCException::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 = (LONG)code; + } + + void PCSCException::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(PCSCTokenException); + +#endif + +}
\ No newline at end of file diff --git a/src/Common/IccDataExtractor.h b/src/Common/IccDataExtractor.h new file mode 100644 index 00000000..777a3555 --- /dev/null +++ b/src/Common/IccDataExtractor.h @@ -0,0 +1,231 @@ +// +// Created by bshp on 1/14/23. +// + +#ifndef NEWEMV_ICCDATAEXTRACTOR_H +#define NEWEMV_ICCDATAEXTRACTOR_H + +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sstream> +#include <vector> +#include <iomanip> +#include <memory> +#include "Platform/PlatformBase.h" +#include "TLVParser.h" + +#ifdef __linux__ +#include <unistd.h> +#endif + +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) +# include "Exception.h" +#else +# include "Platform/Exception.h" +#endif + +#ifdef TC_WINDOWS +#include <winscard.h> +#include <windows.h> +#endif +#ifdef TC_UNIX +#undef BOOL +#include <PCSC/winscard.h> +using VeraCrypt::byte; +#define BOOL int +//#include <unistd.h> //Works without on windows +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif + +#ifdef _WIN64 +#define ssize_t __int64 +#else +#define ssize_t long +#endif + +#define SELECT_TYPE_SIZE 12 /* Size of the SELECT_TYPE APDU */ + +/* Winscard function pointers definitions for windows import */ +#ifdef TC_WINDOWS +typedef LONG (WINAPI *SCardEstablishContextPtr)(DWORD dwScope,LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext); +typedef LONG (WINAPI *SCardReleaseContextPtr)(SCARDCONTEXT hContext); +typedef LONG (WINAPI *SCardConnectAPtr)(SCARDCONTEXT hContext,LPCSTR szReader,DWORD dwShareMode,DWORD dwPreferredProtocols,LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol); +typedef LONG (WINAPI *SCardDisconnectPtr)(SCARDHANDLE hCard, DWORD dwDisposition); +typedef LONG (WINAPI *SCardTransmitPtr)(SCARDHANDLE hCard,LPCSCARD_IO_REQUEST pioSendPci,const BYTE* pbSendBuffer, DWORD cbSendLength,LPSCARD_IO_REQUEST pioRecvPci,BYTE* pbRecvBuffer, LPDWORD pcbRecvLength); +typedef LONG (WINAPI *SCardListReadersAPtr)(SCARDCONTEXT hContext,LPCSTR mszGroups,LPSTR mszReaders, LPDWORD pcchReaders); +typedef LONG (WINAPI *SCardFreeMemoryPtr)(SCARDCONTEXT hContext,LPCVOID pvMem); +#endif + +namespace VeraCrypt +{ + class IccDataExtractor { + private: + + /* Used for loading winscard on windows */ + #ifdef TC_WINDOWS + /* Winscard Library Handle */ + HMODULE WinscardLibraryHandle; + + /* Winscard function pointers */ + SCardEstablishContextPtr WSCardEstablishContext; + SCardReleaseContextPtr WSCardReleaseContext; + SCardConnectAPtr WSCardConnectA; + SCardDisconnectPtr WSCardDisconnect; + SCardFreeMemoryPtr WSCardFreeMemory; + SCardListReadersAPtr WSCardListReadersA; + SCardTransmitPtr WSCardTransmit; + + /* Is the winscard library loaded */ + static bool Initialized; + #endif + + /* SELECT_TYPES FOR DIFFERENT AIDs*/ + const static BYTE SELECT_MASTERCARD[SELECT_TYPE_SIZE]; + const static BYTE SELECT_VISA[SELECT_TYPE_SIZE]; + const static BYTE SELECT_AMEX[SELECT_TYPE_SIZE]; + const static BYTE * SELECT_TYPES[3]; + + + SCARDCONTEXT hContext; /* Handle that identifies the resource manager context.*/ + + SCARDHANDLE hCard; /* A handle that identifies the connection to the smart card in the designated reader*/ + + std::vector<char*> readers; /* Card reader list */ + + unsigned long int nbReaders; /* Number of connected (available) readers */ + + LPSTR mszReaders; /* Names of the reader groups defined to the system, as a multi-string. Use a NULL value to + * list all readers in the system */ + + DWORD dwActiveProtocol; /* A flag that indicates the established active protocol. + * SCARD_PROTOCOL_T0: An asynchronous, character-oriented half-duplex transmission protocol. + * SCARD_PROTOCOL_T1: An asynchronous, block-oriented half-duplex transmission protocol.*/ + + + /* Establishing the resource manager context (the scope) within which database operations are performed. + * The module of the smart card subsystem that manages access to multiple readers and smart cards. The + * resource manager identifies and tracks resources, allocates readers and resources across multiple + * applications,and supports transaction primitives for accessing services available on a given card.*/ + int EstablishRSContext(); + + /* Connecting to the card in the given reader*/ + int ConnectCard(unsigned long int reader_nb); + + /* Disconnect the card currently connected*/ + int DisconnectCard(); + + /* Testing if the card contains the application of the given EMV type */ + bool TestingCardType(const int SELECT_TYPE_NUMBER); + + /* Getting the ICC Public Key Certificates and the Issuer Public Key Certificates by parsing the application + * (!NEED TO TEST CARD TYPE TO SELECT APPLICATION FIRST!)*/ + void GetCerts(vector<byte> &CERTS); + + /* Getting CPCL data from the card and put it into a reference*/ + void GetCPCL(vector<byte> &v); + + /* Getting the PAN by parsing the application + * (!NEED TO TEST CARD TYPE TO SELECT APPLICATION FIRST!)*/ + void GetPAN(vector<byte> &v); + + /* Helper function to make a string from plain arrays and various standard containers of bytes */ + template<typename TInputIter> + void make_hex_string(TInputIter first, TInputIter last, std::string& panString, bool use_uppercase = true, bool insert_spaces = false); + + public: + IccDataExtractor(); + + ~IccDataExtractor(); + + /* Used to initialize the winscard library on windows to make sure the dll is in System32 */ + #ifdef TC_WINDOWS + void IccDataExtractor::InitLibrary(); + #endif + + /* Detecting available readers and filling the reader table. Returns + * the number of available readers */ + unsigned long GetReaders(); + + + /* Getting an ICC Public Key Certificates, an Issuer Public Key Certificates and the CPCL data + * from the card designated by the reader number. Appending them into a byte vector */ + void GettingAllCerts(int readerNumber, vector<byte> &v); + + /* Getting the PAN from the card designated by the reader number */ + void GettingPAN(int readerNumber, string& panString); + }; + + struct PCSCException: public Exception + { + PCSCException(LONG errorCode = (LONG) -1): ErrorCode(errorCode), SubjectErrorCodeValid(false), SubjectErrorCode((uint64)-1){} + PCSCException(LONG errorCode, uint64 subjectErrorCode): ErrorCode(errorCode), SubjectErrorCodeValid(true), SubjectErrorCode(subjectErrorCode){} + + #ifdef TC_HEADER_Platform_Exception + virtual ~PCSCException() throw () { } + TC_SERIALIZABLE_EXCEPTION(PCSCException); + #else + + void Show(HWND parent) const; + #endif + + operator string () const; + LONG GetErrorCode() const { return ErrorCode; } + + protected: + LONG ErrorCode; + bool SubjectErrorCodeValid; + uint64 SubjectErrorCode; + }; + + #ifdef TC_HEADER_Platform_Exception + + #define TC_EXCEPTION(NAME) TC_EXCEPTION_DECL(NAME,Exception) + + #undef TC_EXCEPTION_SET + #define TC_EXCEPTION_SET \ + TC_EXCEPTION_NODECL (PCSCException); \ + TC_EXCEPTION (WinscardLibraryNotInitialized); \ + TC_EXCEPTION (InvalidEMVPath); \ + TC_EXCEPTION (EMVKeyfileDataNotFound); \ + TC_EXCEPTION (EMVPANNotFound); \ + TC_EXCEPTION (EMVUnknownCardType); + TC_EXCEPTION_SET; + + #undef TC_EXCEPTION + + #else // !TC_HEADER_Platform_Exception + + struct WinscardLibraryNotInitialized: public Exception + { + void Show(HWND parent) const { Error("WINSCARD_MODULE_INIT_FAILED", parent); } + }; + + struct InvalidEMVPath: public Exception + { + void Show(HWND parent) const { Error("INVALID_EMV_PATH", parent); } + }; + + struct EMVKeyfileDataNotFound: public Exception + { + void Show(HWND parent) const { Error("EMV_KEYFILE_DATA_NOT_FOUND", parent); } + }; + + struct EMVPANNotFound: public Exception + { + void Show(HWND parent) const { Error("EMV_PAN_NOT_FOUND", parent); } + }; + + struct EMVUnknownCardType: public Exception + { + void Show(HWND parent) const { Error("EMV_UNKNOWN_CARD_TYPE", parent); } + }; + + #endif // !TC_HEADER_Platform_Exception +} + +#endif //NEWEMV_ICCDATAEXTRACTOR_H diff --git a/src/Common/Keyfiles.c b/src/Common/Keyfiles.c index 174aed92..d2207f5f 100644 --- a/src/Common/Keyfiles.c +++ b/src/Common/Keyfiles.c @@ -23,6 +23,7 @@ #include "Dlgcode.h" #include "Language.h" #include "SecurityToken.h" +#include "EMVToken.h" #include "Common/resource.h" #include "Platform/Finally.h" #include "Platform/ForEach.h" @@ -249,12 +250,12 @@ BOOL KeyFilesApply (HWND hwndDlg, Password *password, KeyFile *firstKeyFile, con // Determine whether it's a security token path try { - if (SecurityToken::IsKeyfilePathValid (kf->FileName)) + if (Token::IsKeyfilePathValid (kf->FileName, ActivateEMVOption)) { // Apply security token keyfile vector <byte> keyfileData; - SecurityTokenKeyfilePath secPath (kf->FileName); - SecurityToken::GetKeyfileData (SecurityTokenKeyfile (secPath), keyfileData); + TokenKeyfilePath secPath (kf->FileName); + Token::getTokenKeyfile (secPath)->GetKeyfileData (keyfileData); if (keyfileData.empty()) { @@ -551,10 +552,10 @@ BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa if (lw == IDC_TOKEN_FILES_ADD) { - list <SecurityTokenKeyfilePath> selectedTokenKeyfiles; + list <TokenKeyfilePath> selectedTokenKeyfiles; if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK) { - foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles) + foreach (const TokenKeyfilePath &keyPath, selectedTokenKeyfiles) { KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); if (kf) @@ -758,10 +759,10 @@ BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *par case IDM_KEYFILES_POPUP_ADD_TOKEN_FILES: { - list <SecurityTokenKeyfilePath> selectedTokenKeyfiles; + list <TokenKeyfilePath> selectedTokenKeyfiles; if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK) { - foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles) + foreach (const TokenKeyfilePath &keyPath, selectedTokenKeyfiles) { KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); if (kf) diff --git a/src/Common/Language.xml b/src/Common/Language.xml index 540f6867..cd996bce 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -113,6 +113,7 @@ <entry lang="en" key="IDC_CACHE">Cache passwords and keyfil&es in memory</entry> <entry lang="en" key="IDC_CLOSE_BKG_TASK_WHEN_NOVOL">Exit when there are no mounted volumes</entry> <entry lang="en" key="IDC_CLOSE_TOKEN_SESSION_AFTER_MOUNT">&Close token session (log out) after a volume is successfully mounted</entry> + <entry lang="en" key="IDC_ACTIVATE_EMV_OPTION">Activate EMV Option</entry> <entry lang="en" key="IDC_COPY_EXPANDER">Include VeraCrypt Volume Expander</entry> <entry lang="en" key="IDC_COPY_WIZARD">Include VeraCrypt Volume Creation Wizard</entry> <entry lang="en" key="IDC_CREATE">Create</entry> @@ -295,6 +296,7 @@ <entry lang="en" key="IDT_NEW_PKCS5_PRF">PKCS-5 PRF:</entry> <entry lang="en" key="IDT_PW_CACHE_OPTIONS">Password Cache</entry> <entry lang="en" key="IDT_SECURITY_OPTIONS">Security Options</entry> + <entry lang="en" key="IDT_EMV_OPTIONS">EMV Options</entry> <entry lang="en" key="IDT_TASKBAR_ICON">VeraCrypt Background Task</entry> <entry lang="en" key="IDT_TRAVELER_MOUNT">VeraCrypt volume to mount (relative to traveler disk root):</entry> <entry lang="en" key="IDT_TRAVEL_INSERTION">Upon insertion of traveler disk: </entry> @@ -1278,6 +1280,12 @@ <entry lang="en" key="CKR_PIN_INCORRECT">Password for security token is incorrect.</entry> <entry lang="en" key="CKR_DEVICE_MEMORY">The security token does not have enough memory/space to perform the requested operation.\n\nIf you are attempting to import a keyfile, you should select a smaller file or use a keyfile generated by VeraCrypt (select 'Tools' > 'Keyfile Generator').</entry> <entry lang="en" key="ALL_TOKEN_SESSIONS_CLOSED">All open security token sessions have been closed.</entry> + <entry lang="en" key="WINSCARD_MODULE_INIT_FAILED">Error when loading the winscard library.\n\nPlease make sure the WinSCard.dll is present in your System32 folder.</entry> + <entry lang="en" key="INVALID_EMV_PATH">EMV path is invalid.</entry> + <entry lang="en" key="EMV_KEYFILE_DATA_NOT_FOUND">Unable to build a keyfile from the EMV card's data.\n\nOne of the following is missing:\n- ICC Public Key Certificate.\n- Issuer Public Key Certificate.\n- CPCL data.</entry> + <entry lang="en" key="EMV_PAN_NOT_FOUND">No Primary Account Number (PAN) found in the EMV card.</entry> + <entry lang="en" key="EMV_UNKNOWN_CARD_TYPE">The card in the reader is not a supported EMV card.</entry> + <entry lang="en" key="SCARD_W_REMOVED_CARD">No card in the reader.\n\nPlease make sure the card is correctly slotted.</entry> <entry lang="en" key="SELECT_TOKEN_KEYFILES">Select Security Token Keyfiles</entry> <entry lang="en" key="TOKEN_SLOT_ID">Slot</entry> <entry lang="en" key="TOKEN_NAME">Token name</entry> diff --git a/src/Common/SecurityToken.cpp b/src/Common/SecurityToken.cpp index 8401a0eb..ad8ed33e 100644 --- a/src/Common/SecurityToken.cpp +++ b/src/Common/SecurityToken.cpp @@ -36,23 +36,31 @@ using namespace std; namespace VeraCrypt { - SecurityTokenKeyfile::SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path) + 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) + 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; + Token->SlotId = slotId; - size_t keyIdPos = pathStr.find (L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/"); + 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()); + Id = pathStr.substr(keyIdPos + wstring(L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/").size()); - vector <SecurityTokenKeyfile> keyfiles = SecurityToken::GetAvailableKeyfiles (&SlotId, Id); + vector <SecurityTokenKeyfile> keyfiles = SecurityToken::GetAvailableKeyfiles(&Token->SlotId, Id); if (keyfiles.empty()) throw SecurityTokenKeyfileNotFound(); @@ -60,69 +68,69 @@ namespace VeraCrypt *this = keyfiles.front(); } - SecurityTokenKeyfile::operator SecurityTokenKeyfilePath () const + SecurityTokenKeyfile::operator TokenKeyfilePath () 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; + 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 () + void SecurityToken::CheckLibraryStatus() { if (!Initialized) throw SecurityTokenLibraryNotInitialized(); } - void SecurityToken::CloseLibrary () + void SecurityToken::CloseLibrary() { if (Initialized) { CloseAllSessions(); - Pkcs11Functions->C_Finalize (NULL_PTR); + Pkcs11Functions->C_Finalize(NULL_PTR); #ifdef TC_WINDOWS - FreeLibrary (Pkcs11LibraryHandle); + FreeLibrary(Pkcs11LibraryHandle); #else - dlclose (Pkcs11LibraryHandle); + dlclose(Pkcs11LibraryHandle); #endif Initialized = false; } } - void SecurityToken::CloseAllSessions () throw () + void SecurityToken::CloseAllSessions() throw () { if (!Initialized) return; typedef pair <CK_SLOT_ID, Pkcs11Session> SessionMapPair; - foreach (SessionMapPair p, Sessions) + foreach(SessionMapPair p, Sessions) { try { - CloseSession (p.first); + CloseSession(p.first); } - catch (...) { } + catch (...) {} } } - void SecurityToken::CloseSession (CK_SLOT_ID slotId) + void SecurityToken::CloseSession(CK_SLOT_ID slotId) { - if (Sessions.find (slotId) == Sessions.end()) - throw ParameterIncorrect (SRC_POS); + if (Sessions.find(slotId) == Sessions.end()) + throw ParameterIncorrect(SRC_POS); - Pkcs11Functions->C_CloseSession (Sessions[slotId].Handle); - Sessions.erase (Sessions.find (slotId)); + Pkcs11Functions->C_CloseSession(Sessions[slotId].Handle); + Sessions.erase(Sessions.find(slotId)); } - void SecurityToken::CreateKeyfile (CK_SLOT_ID slotId, vector <byte> &keyfileData, const string &name) + void SecurityToken::CreateKeyfile(CK_SLOT_ID slotId, vector <byte>& keyfileData, const string& name) { if (name.empty()) - throw ParameterIncorrect (SRC_POS); + throw ParameterIncorrect(SRC_POS); - LoginUserIfRequired (slotId); + LoginUserIfRequired(slotId); - foreach (const SecurityTokenKeyfile &keyfile, GetAvailableKeyfiles (&slotId)) + foreach(const SecurityTokenKeyfile & keyfile, GetAvailableKeyfiles(&slotId)) { if (keyfile.IdUtf8 == name) throw SecurityTokenKeyfileAlreadyExists(); @@ -133,16 +141,16 @@ namespace VeraCrypt 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() } + { 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); + CK_RV status = Pkcs11Functions->C_CreateObject(Sessions[slotId].Handle, keyfileTemplate, array_capacity(keyfileTemplate), &keyfileHandle); switch (status) { @@ -156,36 +164,36 @@ namespace VeraCrypt } if (status != CKR_OK) - throw Pkcs11Exception (status); + 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()); }); + 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); + Pkcs11Functions->C_DestroyObject(Sessions[slotId].Handle, keyfileHandle); + throw Pkcs11Exception(CKR_DEVICE_MEMORY); } } - void SecurityToken::DeleteKeyfile (const SecurityTokenKeyfile &keyfile) + void SecurityToken::DeleteKeyfile(const SecurityTokenKeyfile& keyfile) { - LoginUserIfRequired (keyfile.SlotId); + LoginUserIfRequired(keyfile.Token->SlotId); - CK_RV status = Pkcs11Functions->C_DestroyObject (Sessions[keyfile.SlotId].Handle, keyfile.Handle); + CK_RV status = Pkcs11Functions->C_DestroyObject(Sessions[keyfile.Token->SlotId].Handle, keyfile.Handle); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); } - vector <SecurityTokenKeyfile> SecurityToken::GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter, const wstring keyfileIdFilter) + vector <SecurityTokenKeyfile> SecurityToken::GetAvailableKeyfiles(CK_SLOT_ID* slotIdFilter, const wstring keyfileIdFilter) { bool unrecognizedTokenPresent = false; vector <SecurityTokenKeyfile> keyfiles; - foreach (const CK_SLOT_ID &slotId, GetTokenSlots()) + foreach(const CK_SLOT_ID & slotId, GetTokenSlots()) { SecurityTokenInfo token; @@ -194,14 +202,14 @@ namespace VeraCrypt try { - LoginUserIfRequired (slotId); - token = GetTokenInfo (slotId); + LoginUserIfRequired(slotId); + token = GetTokenInfo(slotId); } - catch (UserAbort &) + catch (UserAbort&) { continue; } - catch (Pkcs11Exception &e) + catch (Pkcs11Exception& e) { if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED) { @@ -212,34 +220,34 @@ namespace VeraCrypt throw; } - foreach (const CK_OBJECT_HANDLE &dataHandle, GetObjects (slotId, CKO_DATA)) + foreach(const CK_OBJECT_HANDLE & dataHandle, GetObjects(slotId, CKO_DATA)) { SecurityTokenKeyfile keyfile; keyfile.Handle = dataHandle; - keyfile.SlotId = slotId; - keyfile.Token = token; + keyfile.Token->SlotId = slotId; + keyfile.Token = shared_ptr<SecurityTokenInfo>(new SecurityTokenInfo(token)); vector <byte> privateAttrib; - GetObjectAttribute (slotId, dataHandle, CKA_PRIVATE, privateAttrib); + GetObjectAttribute(slotId, dataHandle, CKA_PRIVATE, privateAttrib); - if (privateAttrib.size() == sizeof (CK_BBOOL) && *(CK_BBOOL *) &privateAttrib.front() != CK_TRUE) + 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); + GetObjectAttribute(slotId, dataHandle, CKA_LABEL, label); + label.push_back(0); - keyfile.IdUtf8 = (char *) &label.front(); + keyfile.IdUtf8 = (char*)&label.front(); #if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) - keyfile.Id = Utf8StringToWide ((const char *) &label.front()); + keyfile.Id = Utf8StringToWide((const char*)&label.front()); #else - keyfile.Id = StringConverter::ToWide ((const char *) &label.front()); + keyfile.Id = StringConverter::ToWide((const char*)&label.front()); #endif if (keyfile.Id.empty() || (!keyfileIdFilter.empty() && keyfileIdFilter != keyfile.Id)) continue; - keyfiles.push_back (keyfile); + keyfiles.push_back(keyfile); if (!keyfileIdFilter.empty()) break; @@ -247,23 +255,23 @@ namespace VeraCrypt } if (keyfiles.empty() && unrecognizedTokenPresent) - throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + throw Pkcs11Exception(CKR_TOKEN_NOT_RECOGNIZED); return keyfiles; } - list <SecurityTokenInfo> SecurityToken::GetAvailableTokens () + list <SecurityTokenInfo> SecurityToken::GetAvailableTokens() { bool unrecognizedTokenPresent = false; list <SecurityTokenInfo> tokens; - foreach (const CK_SLOT_ID &slotId, GetTokenSlots()) + foreach(const CK_SLOT_ID & slotId, GetTokenSlots()) { try { - tokens.push_back (GetTokenInfo (slotId)); + tokens.push_back(GetTokenInfo(slotId)); } - catch (Pkcs11Exception &e) + catch (Pkcs11Exception& e) { if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED) { @@ -276,63 +284,63 @@ namespace VeraCrypt } if (tokens.empty() && unrecognizedTokenPresent) - throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + throw Pkcs11Exception(CKR_TOKEN_NOT_RECOGNIZED); return tokens; } - SecurityTokenInfo SecurityToken::GetTokenInfo (CK_SLOT_ID slotId) + SecurityTokenInfo SecurityToken::GetTokenInfo(CK_SLOT_ID slotId) { CK_TOKEN_INFO info; - CK_RV status = Pkcs11Functions->C_GetTokenInfo (slotId, &info); + CK_RV status = Pkcs11Functions->C_GetTokenInfo(slotId, &info); if (status != CKR_OK) - throw Pkcs11Exception (status); + 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)); + 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 (' '); + 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); + token.LabelUtf8 = token.LabelUtf8.substr(0, lastSpace + 1); #if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) - token.Label = Utf8StringToWide (token.LabelUtf8); + token.Label = Utf8StringToWide(token.LabelUtf8); #else - token.Label = StringConverter::ToWide (token.LabelUtf8); + token.Label = StringConverter::ToWide(token.LabelUtf8); #endif return token; } - void SecurityToken::GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector <byte> &keyfileData) + void SecurityTokenKeyfile::GetKeyfileData(vector <byte>& keyfileData) const { - LoginUserIfRequired (keyfile.SlotId); - GetObjectAttribute (keyfile.SlotId, keyfile.Handle, CKA_VALUE, keyfileData); + 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) + vector <CK_OBJECT_HANDLE> SecurityToken::GetObjects(CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass) { - if (Sessions.find (slotId) == Sessions.end()) - throw ParameterIncorrect (SRC_POS); + if (Sessions.find(slotId) == Sessions.end()) + throw ParameterIncorrect(SRC_POS); CK_ATTRIBUTE findTemplate; findTemplate.type = CKA_CLASS; findTemplate.pValue = &objectClass; - findTemplate.ulValueLen = sizeof (objectClass); + findTemplate.ulValueLen = sizeof(objectClass); - CK_RV status = Pkcs11Functions->C_FindObjectsInit (Sessions[slotId].Handle, &findTemplate, 1); + CK_RV status = Pkcs11Functions->C_FindObjectsInit(Sessions[slotId].Handle, &findTemplate, 1); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); - finally_do_arg (CK_SLOT_ID, slotId, { Pkcs11Functions->C_FindObjectsFinal (Sessions[finally_arg].Handle); }); + finally_do_arg(CK_SLOT_ID, slotId, { Pkcs11Functions->C_FindObjectsFinal(Sessions[finally_arg].Handle); }); CK_ULONG objectCount; vector <CK_OBJECT_HANDLE> objects; @@ -340,112 +348,112 @@ namespace VeraCrypt while (true) { CK_OBJECT_HANDLE object; - CK_RV status = Pkcs11Functions->C_FindObjects (Sessions[slotId].Handle, &object, 1, &objectCount); + CK_RV status = Pkcs11Functions->C_FindObjects(Sessions[slotId].Handle, &object, 1, &objectCount); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); if (objectCount != 1) break; - objects.push_back (object); + objects.push_back(object); } return objects; } - void SecurityToken::GetObjectAttribute (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector <byte> &attributeValue) + 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); + 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); + CK_RV status = Pkcs11Functions->C_GetAttributeValue(Sessions[slotId].Handle, tokenObject, &attribute, 1); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); if (attribute.ulValueLen == 0) return; - attributeValue = vector <byte> (attribute.ulValueLen); + attributeValue = vector <byte>(attribute.ulValueLen); attribute.pValue = &attributeValue.front(); - status = Pkcs11Functions->C_GetAttributeValue (Sessions[slotId].Handle, tokenObject, &attribute, 1); + status = Pkcs11Functions->C_GetAttributeValue(Sessions[slotId].Handle, tokenObject, &attribute, 1); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); } - list <CK_SLOT_ID> SecurityToken::GetTokenSlots () + 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); + CK_RV status = Pkcs11Functions->C_GetSlotList(TRUE, NULL_PTR, &slotCount); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); if (slotCount > 0) { - vector <CK_SLOT_ID> slotArray (slotCount); - status = Pkcs11Functions->C_GetSlotList (TRUE, &slotArray.front(), &slotCount); + vector <CK_SLOT_ID> slotArray(slotCount); + status = Pkcs11Functions->C_GetSlotList(TRUE, &slotArray.front(), &slotCount); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); for (size_t i = 0; i < slotCount; i++) { CK_SLOT_INFO slotInfo; - status = Pkcs11Functions->C_GetSlotInfo (slotArray[i], &slotInfo); + status = Pkcs11Functions->C_GetSlotInfo(slotArray[i], &slotInfo); if (status != CKR_OK || !(slotInfo.flags & CKF_TOKEN_PRESENT)) continue; - slots.push_back (slotArray[i]); + slots.push_back(slotArray[i]); } } return slots; } - bool SecurityToken::IsKeyfilePathValid (const wstring &securityTokenKeyfilePath) + bool SecurityToken::IsKeyfilePathValid(const wstring& securityTokenKeyfilePath) { - return securityTokenKeyfilePath.find (TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX) == 0; + return securityTokenKeyfilePath.find(TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX) == 0; } - void SecurityToken::Login (CK_SLOT_ID slotId, const char* pin) + void SecurityToken::Login(CK_SLOT_ID slotId, const char* pin) { - if (Sessions.find (slotId) == Sessions.end()) - OpenSession (slotId); + 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); + 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); + throw Pkcs11Exception(status); Sessions[slotId].UserLoggedIn = true; } - void SecurityToken::LoginUserIfRequired (CK_SLOT_ID slotId) + void SecurityToken::LoginUserIfRequired(CK_SLOT_ID slotId) { CheckLibraryStatus(); CK_RV status; - if (Sessions.find (slotId) == Sessions.end()) + if (Sessions.find(slotId) == Sessions.end()) { - OpenSession (slotId); + OpenSession(slotId); } else { CK_SESSION_INFO sessionInfo; - status = Pkcs11Functions->C_GetSessionInfo (Sessions[slotId].Handle, &sessionInfo); + status = Pkcs11Functions->C_GetSessionInfo(Sessions[slotId].Handle, &sessionInfo); if (status == CKR_OK) { @@ -455,14 +463,14 @@ namespace VeraCrypt { try { - CloseSession (slotId); + CloseSession(slotId); } - catch (...) { } - OpenSession (slotId); + catch (...) {} + OpenSession(slotId); } } - SecurityTokenInfo tokenInfo = GetTokenInfo (slotId); + SecurityTokenInfo tokenInfo = GetTokenInfo(slotId); while (!Sessions[slotId].UserLoggedIn && (tokenInfo.Flags & CKF_LOGIN_REQUIRED)) { @@ -470,9 +478,9 @@ namespace VeraCrypt { if (tokenInfo.Flags & CKF_PROTECTED_AUTHENTICATION_PATH) { - status = Pkcs11Functions->C_Login (Sessions[slotId].Handle, CKU_USER, NULL_PTR, 0); + status = Pkcs11Functions->C_Login(Sessions[slotId].Handle, CKU_USER, NULL_PTR, 0); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); } else { @@ -484,15 +492,15 @@ namespace VeraCrypt pin = s.str(); } - finally_do_arg (string*, &pin, { burn ((void *) finally_arg->c_str(), finally_arg->size()); }); + finally_do_arg(string*, &pin, { burn((void*)finally_arg->c_str(), finally_arg->size()); }); (*PinCallback) (pin); - Login (slotId, pin.c_str()); + Login(slotId, pin.c_str()); } Sessions[slotId].UserLoggedIn = true; } - catch (Pkcs11Exception &e) + catch (Pkcs11Exception& e) { CK_RV error = e.GetErrorCode(); @@ -502,8 +510,8 @@ namespace VeraCrypt } else if (error == CKR_PIN_INCORRECT && !(tokenInfo.Flags & CKF_PROTECTED_AUTHENTICATION_PATH)) { - PinCallback->notifyIncorrectPin (); - (*WarningCallback) (Pkcs11Exception (CKR_PIN_INCORRECT)); + PinCallback->notifyIncorrectPin(); + (*WarningCallback) (Pkcs11Exception(CKR_PIN_INCORRECT)); continue; } @@ -513,40 +521,40 @@ namespace VeraCrypt } #ifdef TC_WINDOWS - void SecurityToken::InitLibrary (const wstring &pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback) + 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) + 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); + 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()); + 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); + 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"); + 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"); + C_GetFunctionList_t C_GetFunctionList = (C_GetFunctionList_t)dlsym(Pkcs11LibraryHandle, "C_GetFunctionList"); #endif if (!C_GetFunctionList) throw SecurityTokenLibraryNotInitialized(); - CK_RV status = C_GetFunctionList (&Pkcs11Functions); + CK_RV status = C_GetFunctionList(&Pkcs11Functions); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); - status = Pkcs11Functions->C_Initialize (NULL_PTR); + status = Pkcs11Functions->C_Initialize(NULL_PTR); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); PinCallback = move_ptr(pinCallback); WarningCallback = move_ptr(warningCallback); @@ -554,21 +562,21 @@ namespace VeraCrypt Initialized = true; } - void SecurityToken::OpenSession (CK_SLOT_ID slotId) + void SecurityToken::OpenSession(CK_SLOT_ID slotId) { - if (Sessions.find (slotId) != Sessions.end()) + 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; + if (!(GetTokenInfo(slotId).Flags & CKF_WRITE_PROTECTED)) + flags |= CKF_RW_SESSION; - CK_RV status = Pkcs11Functions->C_OpenSession (slotId, flags, NULL_PTR, NULL_PTR, &session); + CK_RV status = Pkcs11Functions->C_OpenSession(slotId, flags, NULL_PTR, NULL_PTR, &session); if (status != CKR_OK) - throw Pkcs11Exception (status); + throw Pkcs11Exception(status); Sessions[slotId].Handle = session; } @@ -581,103 +589,103 @@ namespace VeraCrypt static const struct { CK_RV ErrorCode; - const char *ErrorString; + 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) + 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) + for (size_t i = 0; i < array_capacity(ErrorStrings); ++i) { if (ErrorStrings[i].ErrorCode == ErrorCode) return ErrorStrings[i].ErrorString; @@ -690,9 +698,9 @@ namespace VeraCrypt } #ifdef TC_HEADER_Common_Exception - void Pkcs11Exception::Show (HWND parent) const + void Pkcs11Exception::Show(HWND parent) const { - string errorString = string (*this); + string errorString = string(*this); if (!errorString.empty()) { @@ -700,11 +708,11 @@ namespace VeraCrypt if (SubjectErrorCodeValid) subjectErrorCode << L": " << SubjectErrorCode; - if (!GetDictionaryValue (errorString.c_str())) + if (!GetDictionaryValue(errorString.c_str())) { - if (errorString.find ("CKR_") == 0) + if (errorString.find("CKR_") == 0) { - errorString = errorString.substr (4); + errorString = errorString.substr(4); for (size_t i = 0; i < errorString.size(); ++i) { if (errorString[i] == '_') @@ -712,17 +720,17 @@ namespace VeraCrypt } } 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); + 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()); + wstring err = GetString(errorString.c_str()); if (SubjectErrorCodeValid) err += L"\n\nError code" + subjectErrorCode.str(); - ErrorDirect (err.c_str(), parent); + ErrorDirect(err.c_str(), parent); } } } @@ -738,36 +746,36 @@ namespace VeraCrypt #ifdef TC_WINDOWS HMODULE SecurityToken::Pkcs11LibraryHandle; #else - void *SecurityToken::Pkcs11LibraryHandle; + void* SecurityToken::Pkcs11LibraryHandle; #endif #ifdef TC_HEADER_Platform_Exception - void Pkcs11Exception::Deserialize (shared_ptr <Stream> stream) + void Pkcs11Exception::Deserialize(shared_ptr <Stream> stream) { - Exception::Deserialize (stream); - Serializer sr (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; + sr.Deserialize("ErrorCode", code); + sr.Deserialize("SubjectErrorCodeValid", SubjectErrorCodeValid); + sr.Deserialize("SubjectErrorCode", SubjectErrorCode); + ErrorCode = (CK_RV)code; } - void Pkcs11Exception::Serialize (shared_ptr <Stream> stream) const + 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); + 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); + TC_SERIALIZER_FACTORY_ADD_EXCEPTION_SET(SecurityTokenException); #endif } diff --git a/src/Common/SecurityToken.h b/src/Common/SecurityToken.h index 6b228895..0d671dcc 100644 --- a/src/Common/SecurityToken.h +++ b/src/Common/SecurityToken.h @@ -53,62 +53,55 @@ #define TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"slot" #define TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"file" +#include "Token.h" + namespace VeraCrypt { - struct SecurityTokenInfo + struct SecurityTokenInfo: TokenInfo { - CK_SLOT_ID SlotId; + virtual BOOL isEditable() const {return true;} + CK_FLAGS Flags; - wstring Label; string LabelUtf8; }; - struct SecurityTokenKeyfilePath + struct SecurityTokenKeyfile: TokenKeyfile { - SecurityTokenKeyfilePath () { } - SecurityTokenKeyfilePath (const wstring &path) : Path (path) { } - operator wstring () const { return Path; } - wstring Path; - }; + SecurityTokenKeyfile(); - struct SecurityTokenKeyfile - { - SecurityTokenKeyfile () : Handle(CK_INVALID_HANDLE), SlotId(CK_UNAVAILABLE_INFORMATION) { Token.SlotId = CK_UNAVAILABLE_INFORMATION; Token.Flags = 0; } - SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path); + SecurityTokenKeyfile(const TokenKeyfilePath& path); + + operator TokenKeyfilePath () const; - operator SecurityTokenKeyfilePath () const; + void GetKeyfileData(vector<byte>& keyfileData) const; CK_OBJECT_HANDLE Handle; - wstring Id; - string IdUtf8; - CK_SLOT_ID SlotId; - SecurityTokenInfo Token; }; - struct Pkcs11Exception : public Exception + struct Pkcs11Exception: public Exception { - Pkcs11Exception (CK_RV errorCode = (CK_RV) -1) - : ErrorCode (errorCode), - SubjectErrorCodeValid (false), - SubjectErrorCode( (uint64) -1) + Pkcs11Exception(CK_RV errorCode = (CK_RV)-1) + : ErrorCode(errorCode), + SubjectErrorCodeValid(false), + SubjectErrorCode((uint64)-1) { } - Pkcs11Exception (CK_RV errorCode, uint64 subjectErrorCode) - : ErrorCode (errorCode), - SubjectErrorCodeValid (true), - SubjectErrorCode (subjectErrorCode) + Pkcs11Exception(CK_RV errorCode, uint64 subjectErrorCode) + : ErrorCode(errorCode), + SubjectErrorCodeValid(true), + SubjectErrorCode(subjectErrorCode) { } #ifdef TC_HEADER_Platform_Exception - virtual ~Pkcs11Exception () throw () { } - TC_SERIALIZABLE_EXCEPTION (Pkcs11Exception); + virtual ~Pkcs11Exception() throw () { } + TC_SERIALIZABLE_EXCEPTION(Pkcs11Exception); #else - void Show (HWND parent) const; + void Show(HWND parent) const; #endif operator string () const; - CK_RV GetErrorCode () const { return ErrorCode; } + CK_RV GetErrorCode() const { return ErrorCode; } protected: CK_RV ErrorCode; @@ -135,24 +128,24 @@ namespace VeraCrypt #else // !TC_HEADER_Platform_Exception - struct SecurityTokenLibraryNotInitialized : public Exception + struct SecurityTokenLibraryNotInitialized: public Exception { - void Show (HWND parent) const { Error (SecurityTokenLibraryPath[0] == 0 ? "NO_PKCS11_MODULE_SPECIFIED" : "PKCS11_MODULE_INIT_FAILED", parent); } + void Show(HWND parent) const { Error(SecurityTokenLibraryPath[0] == 0 ? "NO_PKCS11_MODULE_SPECIFIED" : "PKCS11_MODULE_INIT_FAILED", parent); } }; - struct InvalidSecurityTokenKeyfilePath : public Exception + struct InvalidSecurityTokenKeyfilePath: public Exception { - void Show (HWND parent) const { Error ("INVALID_TOKEN_KEYFILE_PATH", parent); } + void Show(HWND parent) const { Error("INVALID_TOKEN_KEYFILE_PATH", parent); } }; - struct SecurityTokenKeyfileAlreadyExists : public Exception + struct SecurityTokenKeyfileAlreadyExists: public Exception { - void Show (HWND parent) const { Error ("TOKEN_KEYFILE_ALREADY_EXISTS", parent); } + void Show(HWND parent) const { Error("TOKEN_KEYFILE_ALREADY_EXISTS", parent); } }; - struct SecurityTokenKeyfileNotFound : public Exception + struct SecurityTokenKeyfileNotFound: public Exception { - void Show (HWND parent) const { Error ("TOKEN_KEYFILE_NOT_FOUND", parent); } + void Show(HWND parent) const { Error("TOKEN_KEYFILE_NOT_FOUND", parent); } }; #endif // !TC_HEADER_Platform_Exception @@ -160,7 +153,7 @@ namespace VeraCrypt struct Pkcs11Session { - Pkcs11Session () : Handle (CK_UNAVAILABLE_INFORMATION), UserLoggedIn (false) { } + Pkcs11Session(): Handle(CK_UNAVAILABLE_INFORMATION), UserLoggedIn(false) { } CK_SESSION_HANDLE Handle; bool UserLoggedIn; @@ -168,47 +161,46 @@ namespace VeraCrypt struct GetPinFunctor { - virtual ~GetPinFunctor () { } - virtual void operator() (string &str) = 0; - virtual void notifyIncorrectPin () = 0; + virtual ~GetPinFunctor() { } + virtual void operator() (string& str) = 0; + virtual void notifyIncorrectPin() = 0; }; struct SendExceptionFunctor { - virtual ~SendExceptionFunctor () { } - virtual void operator() (const Exception &e) = 0; + virtual ~SendExceptionFunctor() { } + virtual void operator() (const Exception& e) = 0; }; class SecurityToken { public: - static void CloseAllSessions () throw (); - static void CloseLibrary (); - static void CreateKeyfile (CK_SLOT_ID slotId, vector <byte> &keyfileData, const string &name); - static void DeleteKeyfile (const SecurityTokenKeyfile &keyfile); - static vector <SecurityTokenKeyfile> GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); - static void GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector <byte> &keyfileData); - static list <SecurityTokenInfo> GetAvailableTokens (); - static SecurityTokenInfo GetTokenInfo (CK_SLOT_ID slotId); + static void CloseAllSessions() throw (); + static void CloseLibrary(); + static void CreateKeyfile(CK_SLOT_ID slotId, vector <byte>& keyfileData, const string& name); + static void DeleteKeyfile(const SecurityTokenKeyfile& keyfile); + static vector <SecurityTokenKeyfile> GetAvailableKeyfiles(CK_SLOT_ID* slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); + static list <SecurityTokenInfo> GetAvailableTokens(); + static SecurityTokenInfo GetTokenInfo(CK_SLOT_ID slotId); #ifdef TC_WINDOWS - static void InitLibrary (const wstring &pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback); + static void InitLibrary(const wstring& pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback); #else - static void InitLibrary (const string &pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback); + static void InitLibrary(const string& pkcs11LibraryPath, unique_ptr <GetPinFunctor> pinCallback, unique_ptr <SendExceptionFunctor> warningCallback); #endif - static bool IsInitialized () { return Initialized; } - static bool IsKeyfilePathValid (const wstring &securityTokenKeyfilePath); + static bool IsInitialized() { return Initialized; } + static bool IsKeyfilePathValid(const wstring& securityTokenKeyfilePath); static const size_t MaxPasswordLength = 128; protected: - static void CloseSession (CK_SLOT_ID slotId); - static vector <CK_OBJECT_HANDLE> GetObjects (CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass); - static void GetObjectAttribute (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector <byte> &attributeValue); - static list <CK_SLOT_ID> GetTokenSlots (); - static void Login (CK_SLOT_ID slotId, const char* pin); - static void LoginUserIfRequired (CK_SLOT_ID slotId); - static void OpenSession (CK_SLOT_ID slotId); - static void CheckLibraryStatus (); + static void CloseSession(CK_SLOT_ID slotId); + static vector <CK_OBJECT_HANDLE> GetObjects(CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass); + static void GetObjectAttribute(CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector <byte>& attributeValue); + static list <CK_SLOT_ID> GetTokenSlots(); + static void Login(CK_SLOT_ID slotId, const char* pin); + static void LoginUserIfRequired(CK_SLOT_ID slotId); + static void OpenSession(CK_SLOT_ID slotId); + static void CheckLibraryStatus(); static bool Initialized; static unique_ptr <GetPinFunctor> PinCallback; @@ -216,10 +208,12 @@ namespace VeraCrypt #ifdef TC_WINDOWS static HMODULE Pkcs11LibraryHandle; #else - static void *Pkcs11LibraryHandle; + static void* Pkcs11LibraryHandle; #endif static map <CK_SLOT_ID, Pkcs11Session> Sessions; static unique_ptr <SendExceptionFunctor> WarningCallback; + + friend void SecurityTokenKeyfile::GetKeyfileData(vector <byte>& keyfileData) const; }; } diff --git a/src/Common/TLVParser.cpp b/src/Common/TLVParser.cpp new file mode 100644 index 00000000..bda9dec0 --- /dev/null +++ b/src/Common/TLVParser.cpp @@ -0,0 +1,179 @@ +#include "TLVParser.h" +#include <string.h> + +using namespace std; + +/* TLV node structure creation */ +shared_ptr<TLVNode> TLVParser::TLV_CreateNode() +{ + shared_ptr<TLVNode> node= shared_ptr<TLVNode>(new TLVNode); + memset(node.get(),0,sizeof(*node)); + return node; +} + +/* Check if the bit is correct */ +uint16_t TLVParser::CheckBit(unsigned char value, int bit){ + unsigned char bitvalue[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; + + if((bit >= 1)&&(bit <= 8)){ + if(value & bitvalue[bit-1]) { + return (1); + } + else { + return (0); + } + } + else{ + throw TLVException("FILE:"+string(__FILE__)+"LINE: "+to_string(static_cast<long long>((__LINE__)))+" fonction parameter incorrect! bit=["+to_string(static_cast<long long>(bit))); + return(2); + } +} + +/* Parsing one TLV node */ +shared_ptr<TLVNode> TLVParser::TLV_Parse_One(unsigned char* buf,int size){ + int index = 0; + int i; + unsigned char tag1,tag2,tagsize; + unsigned char len,lensize; + unsigned char* value; + shared_ptr<TLVNode> node = TLV_CreateNode(); + + tag1 = tag2 = 0; + tagsize = 1; + tag1 = buf[index++]; + if((tag1 & 0x1f) == 0x1f){ + tagsize++; + tag2 = buf[index++]; + //tag2 b8 must be 0! + } + if(tagsize == 1) { + node->Tag = tag1; + } + else { + node->Tag = (tag1 << 8) + tag2; + } + node->TagSize = tagsize; + + //SubFlag + node->SubFlag = CheckBit(tag1,6); + + //L zone + len = 0; + lensize = 1; + len = buf[index++]; + if(CheckBit(len,8) == 0){ + node->Length = len; + } + else{ + lensize = len & 0x7f; + len = 0; + for(i=0;i<lensize;i++){ + len += (uint16_t)buf[index++] << (i*8); + } + lensize++; + } + node->Length = len; + node->LengthSize = lensize; + + //V zone + value = new unsigned char[len]; + std::copy(buf+index,buf+index+len,value); + node->Value = value; + index += len; + + if(index < size){ + node->MoreFlag = 1; + } + else if(index == size){ + node->MoreFlag = 0; + } + else{ + throw TLVException("Parse Error! index="+to_string(static_cast<long long>(index))+"size="+to_string(static_cast<long long>(size))); + } + + return node; +} + +/* Parsing all sub-nodes (in width not in depth) of a given parent node */ +int TLVParser::TLV_Parse_SubNodes(shared_ptr<TLVNode> parent){ + int sublen = 0; + int i; + + //No sub-nodes + if(parent->SubFlag == 0) + return 0; + + for(i=0;i<parent->SubCount;i++) + { + sublen += (parent->Sub[i]->TagSize + parent->Sub[i]->Length + parent->Sub[i]->LengthSize); + } + + if(sublen < parent->Length) + { + shared_ptr<TLVNode> subnode = TLV_Parse_One(parent->Value+sublen,parent->Length-sublen); + parent->Sub[parent->SubCount++] = subnode; + return subnode->MoreFlag; + } + else + { + return 0; + } +} + +/* Recursive function to parse all nodes starting from a root parent node */ +void TLVParser::TLV_Parse_Sub(shared_ptr<TLVNode> parent) +{ + int i; + if(parent->SubFlag != 0) + { + //Parse all sub nodes. + while(TLV_Parse_SubNodes(parent) != 0); + + for(i=0;i<parent->SubCount;i++) + { + if(parent->Sub[i]->SubFlag != 0) + { + TLV_Parse_Sub(parent->Sub[i]); + } + } + } + return; +} + +/* Parsing TLV from a buffer and constructing TLV structure */ +shared_ptr<TLVNode> TLVParser::TLV_Parse(unsigned char* buf,int size) +{ + shared_ptr<TLVNode> node = TLV_Parse_One(buf,size); + TLV_Parse_Sub(node); + + return node; +} + +/* Finding a TLV node with a particular tag */ +shared_ptr<TLVNode> TLVParser::TLV_Find(shared_ptr<TLVNode> node,uint16_t tag){ + int i; + shared_ptr<TLVNode> tmpnode; + if(node->Tag == tag) + { + return node; + } + for(i=0;i<node->SubCount;i++) + { + tmpnode = NULL; + tmpnode = TLV_Find(node->Sub[i],tag); + if(tmpnode != NULL){ + return tmpnode; + } + } + if(node->Next) + { + tmpnode = NULL; + tmpnode = TLV_Find(node->Next,tag); + if(tmpnode != NULL){ + return tmpnode; + } + } + + return nullptr; +} + diff --git a/src/Common/TLVParser.h b/src/Common/TLVParser.h new file mode 100644 index 00000000..e25e429f --- /dev/null +++ b/src/Common/TLVParser.h @@ -0,0 +1,80 @@ +// +// Created by bshp on 1/20/23. +// + +#ifndef ICC_EXTRACTOR_TLVPARSER_H +#define ICC_EXTRACTOR_TLVPARSER_H +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <algorithm> +#include <string> +#include <memory> +#include "iostream" +#include "Tcdefs.h" +using namespace std; +struct TLVNode{ + uint16_t Tag; /* T */ + uint16_t Length; /* L */ + unsigned char* Value; /* V */ + unsigned char TagSize; + unsigned char LengthSize; + uint16_t MoreFlag; /* Used In Sub */ + uint16_t SubFlag; /* Does it have sub-nodes? */ + uint16_t SubCount; + shared_ptr<TLVNode> Sub[256]; + shared_ptr<TLVNode> Next; + + ~TLVNode() { + burn(Value, Length); + delete Value; + } +}; + +class TLVParser{ +private : + + /* TLV node structure creation */ + static shared_ptr<TLVNode> TLV_CreateNode(); + + /* Check if the bit is correct */ + static uint16_t CheckBit(unsigned char value, int bit); + + /* Parsing one TLV node */ + static shared_ptr<TLVNode> TLV_Parse_One(unsigned char* buf,int size); + + /* Parsing all TLV nodes */ + static int TLV_Parse_SubNodes(shared_ptr<TLVNode> parent); + + /* Parsing all sub-nodes (in width not in depth) of a given parent node */ + static int TLV_Parse_All(shared_ptr<TLVNode> parent); + + /* Recursive function to parse all nodes starting from a root parent node */ + static void TLV_Parse_Sub(shared_ptr<TLVNode> parent); + +public: + + /* Parsing TLV from a buffer and constructing TLV structure */ + static shared_ptr<TLVNode> TLV_Parse(unsigned char* buf,int size); + + /* Finding a TLV node with a particular tag */ + static shared_ptr<TLVNode> TLV_Find(shared_ptr<TLVNode> node,uint16_t tag); +}; + +/* The definition of the exception class related to the TLV parsing */ +class TLVException +{ +public: + TLVException(std::string errormessage): m_errormessage(errormessage){} + + /* Get the error message */ + inline std::string ErrorMessage() const + { + return m_errormessage; + } + +protected: + std::string m_errormessage; +}; + +#endif //ICC_EXTRACTOR_TLVPARSER_H diff --git a/src/Common/Token.cpp b/src/Common/Token.cpp new file mode 100644 index 00000000..5da677de --- /dev/null +++ b/src/Common/Token.cpp @@ -0,0 +1,82 @@ +#include "Token.h" +#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 + +#include <vector> +#include <algorithm> +#include <memory> + +#include "SecurityToken.h" +#include "EMVToken.h" +#include "iostream" + +using namespace std; + +namespace VeraCrypt +{ + vector<shared_ptr<TokenKeyfile>> Token::GetAvailableKeyfiles(bool EMVOption) { + vector<shared_ptr<TokenKeyfile>> availableKeyfiles; + bool securityTokenLibraryInitialized = true; + + try{ + foreach (SecurityTokenKeyfile k, SecurityToken::GetAvailableKeyfiles()) { + availableKeyfiles.push_back(shared_ptr<TokenKeyfile>(new SecurityTokenKeyfile(k))); + } + } catch (SecurityTokenLibraryNotInitialized){ + securityTokenLibraryInitialized = false; + } + + if(EMVOption){ + foreach (EMVTokenKeyfile k, EMVToken::GetAvailableKeyfiles()) { + availableKeyfiles.push_back(shared_ptr<TokenKeyfile>(new EMVTokenKeyfile(k))); + } + } + + if(availableKeyfiles.size() == 0 && ! securityTokenLibraryInitialized){ + throw SecurityTokenLibraryNotInitialized(); + } + + return availableKeyfiles; + } + + bool Token::IsKeyfilePathValid(const wstring& tokenKeyfilePath, bool EMVOption) + { + if(EMVOption){ + return SecurityToken::IsKeyfilePathValid(tokenKeyfilePath) || EMVToken::IsKeyfilePathValid(tokenKeyfilePath); + } + return SecurityToken::IsKeyfilePathValid(tokenKeyfilePath); + } + + list <shared_ptr<TokenInfo>> Token::GetAvailableTokens() + { + list <shared_ptr<TokenInfo>> availableTokens; + foreach(SecurityTokenInfo securityToken, SecurityToken::GetAvailableTokens()){ + availableTokens.push_back(shared_ptr<TokenInfo>(new SecurityTokenInfo(std::move(securityToken)))); + } + + return availableTokens ; + } + + shared_ptr<TokenKeyfile> Token::getTokenKeyfile(const TokenKeyfilePath path){ + shared_ptr<TokenKeyfile> tokenKeyfile; + + if(SecurityToken::IsKeyfilePathValid(path)){ + tokenKeyfile = shared_ptr<TokenKeyfile>(new SecurityTokenKeyfile(path)); + } else { + if(EMVToken::IsKeyfilePathValid(path)){ + tokenKeyfile = shared_ptr<TokenKeyfile>(new EMVTokenKeyfile(path)); + } + } + + return tokenKeyfile; + } +}
\ No newline at end of file diff --git a/src/Common/Token.h b/src/Common/Token.h new file mode 100644 index 00000000..28c6a489 --- /dev/null +++ b/src/Common/Token.h @@ -0,0 +1,57 @@ +#ifndef TC_HEADER_Common_Token +#define TC_HEADER_Common_Token + +#include "Platform/PlatformBase.h" + +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) +# include "Exception.h" +#else + +# include "Platform/Exception.h" + +#endif + +#include <string> + +#define UNAVAILABLE_SLOT ~0UL + +namespace VeraCrypt { + + struct TokenKeyfilePath { + TokenKeyfilePath(const wstring& path): Path(path) { } + operator wstring () const { return Path; } + + wstring Path; //Complete path + + }; + struct TokenInfo { + TokenInfo() {} + virtual ~TokenInfo() {} + + virtual BOOL isEditable() const=0; + + unsigned long int SlotId; + wstring Label; //Card name + }; + + struct TokenKeyfile { + virtual operator TokenKeyfilePath () const = 0; + virtual void GetKeyfileData(vector <byte>& keyfileData) const = 0; + + string IdUtf8; // Was used in SecurityToken to compare with the file name from a PKCS11 card, remove from token ? + shared_ptr<TokenInfo> Token; + wstring Id; + }; + + class Token { + public: + static vector<shared_ptr<TokenKeyfile>> GetAvailableKeyfiles(bool EMVOption); + static bool IsKeyfilePathValid(const wstring& tokenKeyfilePath, bool EMVOption); + static list <shared_ptr<TokenInfo>> GetAvailableTokens(); // List available token to write + static shared_ptr<TokenKeyfile> getTokenKeyfile(const TokenKeyfilePath path); + }; + +}; + + +#endif //TC_HEADER_Common_Token |