diff --git a/configure.in b/configure.in index 293b293..2ea7d8b 100644 --- a/configure.in +++ b/configure.in @@ -21,7 +21,7 @@ TST_DIR= DOC_DIR=doc m4_define(x_packagename, libpcscxx) -m4_define(x_major, 1) +m4_define(x_major, 2) m4_define(x_minor, 0) PACKAGENAME=x_packagename MAJOR=x_major diff --git a/doc/examples/cryptoki-demo.cxx b/doc/examples/cryptoki-demo.cxx index 15e65ff..d090011 100644 --- a/doc/examples/cryptoki-demo.cxx +++ b/doc/examples/cryptoki-demo.cxx @@ -12,8 +12,8 @@ int main(int argc, char const*const*const argv) try { // //std::vector v(toVector<4>((int[]){1,2,3,4})); // std::vector v(VECTOR(((int[]){1,2,3,4}))); // print(v); - cryptoki::Init init(argc==2?argv[1]:"onepin-opensc-pkcs11.so"); - cryptoki::Info inf(init.info()); + cryptoki::Library cryptoki(argc==2?argv[1]:"onepin-opensc-pkcs11.so"); + cryptoki::Info inf(cryptoki.info()); std::cout<<"Library-Version: "<slotinfo()); diff --git a/doc/examples/cryptoki-sign-demo.cxx b/doc/examples/cryptoki-sign-demo.cxx index 659827a..47c6014 100644 --- a/doc/examples/cryptoki-sign-demo.cxx +++ b/doc/examples/cryptoki-sign-demo.cxx @@ -58,7 +58,7 @@ int main(int argc, char** argv) try { <<"-----------------------------------------------------"<slotinfo()); diff --git a/doc/examples/pcsc-demo.cxx b/doc/examples/pcsc-demo.cxx index a293b32..a75af7a 100644 --- a/doc/examples/pcsc-demo.cxx +++ b/doc/examples/pcsc-demo.cxx @@ -11,7 +11,7 @@ int main(int, char const*const*const argv) try { for (pcsc::Connection::Strings::const_iterator it(reader.begin()); it!=reader.end(); ++it) { std::cout<<"Reader: "<<*it<status()); std::cout<<"Status = "< > Cards; + + Cards scan() { + Cards res; + // By now, scan only for PostSuisseID; in future use factory pattern + pcsc::Connection::Strings readers + (_pcsc.getReadersWithAtr("4b53776973735369676e")); + for (pcsc::Connection::Strings::iterator reader(readers.begin()); + reader!=readers.end(); ++reader) { + cryptoki::SlotList slots(_cryptoki.slotList(true, *reader)); + if (slots.size()==1) + res.push_back(dynamic_cast + (new PostSuisseID(_pcsc.reader(*reader), slots[0]))); + } + return res; + } + + private: + + pcsc::Connection _pcsc; + cryptoki::Library _cryptoki; + + }; + +} + int main(int argc, char** argv) try { std::string lib("libcvP11.so"); @@ -28,20 +105,11 @@ int main(int argc, char** argv) try { mrw::args::decl::param_list() <name()<C_Initialize(0), //! @todo add optional argument - CRYPTOKI_FN_LOG("C_Initialize")); - } catch (...) { + Library::Init::Init(const std::string& library, bool exc) try: + _exc(exc), _res(CKR_OK), _fn(0) { + CRYPTOKI_LOG("library: "<C_Initialize(0), //! @todo add optional argument + CRYPTOKI_FN_LOG("C_Initialize")); + } catch (...) { throw access_error(CRYPTOKI_FN_LOG("C_Initialize") +": Error in initialization of library "+library); } - Init::operator bool() { + Library::Init::~Init() { + CRYPTOKI_LOG("log"); + try { + //! calls @c C_Finalize + check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize")); +#ifndef WIN32 + if (_lib) dlclose(_lib); + _lib = 0; +#else + FreeLibrary(_lib); + _lib = 0; +#endif + _fn = 0; + } catch (...) { + if (!std::uncaught_exception()) throw; + } + } + + Library::Init::operator bool() { CRYPTOKI_LOG("log "<<(_res==CKR_OK?"success":"failed")); return _res==CKR_OK; } - std::string Init::error() { + std::string Library::Init::error() { CRYPTOKI_LOG("log"); return error(_res); } - /*! @todo Not implemented: - @code - bool Init::getinfo() { - //! calls @c C_GetInfo - return check(_init._fn->C_GetInfo(CK_INFO_PTR), - CRYPTOKI_FN_LOG("C_GetInfo")); - } - @endcode */ + /*! @todo Not implemented: + @code + bool Library::Init::getinfo() { + //! calls @c C_GetInfo + return check(_init._fn->C_GetInfo(CK_INFO_PTR), + CRYPTOKI_FN_LOG("C_GetInfo")); + } + @endcode */ - SlotList Init::slotList(bool tokenPresent, std::string name) { + SlotList Library::slotList(bool tokenPresent, std::string name) { CRYPTOKI_LOG("log"); SlotList res; CK_ULONG count(0); //! calls @c C_GetSlotList - check(_fn->C_GetSlotList(tokenPresent?TRUE:FALSE, 0, &count), - CRYPTOKI_FN_LOG("C_GetSlotList")); + _init->check(_init->_fn->C_GetSlotList(tokenPresent?TRUE:FALSE, 0, &count), + CRYPTOKI_FN_LOG("C_GetSlotList")); if (!count || !*this) return res; CK_SLOT_ID* slots = 0; try { + CK_RV r(0); do { delete[] slots; slots = new CK_SLOT_ID[count]; - _res = _fn->C_GetSlotList(tokenPresent?TRUE:FALSE, slots, &count); - } while (_res==CKR_BUFFER_TOO_SMALL); - check(_res, CRYPTOKI_FN_LOG("C_GetSlotList")); + r = _init->_fn->C_GetSlotList(tokenPresent?TRUE:FALSE, slots, &count); + } while (r==CKR_BUFFER_TOO_SMALL); + _init->check(r, CRYPTOKI_FN_LOG("C_GetSlotList")); if (!*this) return res; for (CK_ULONG i(0); i_fn->C_FindObjectsInit + if (check(_slot->_library->C_FindObjectsInit (_session, a, attrs.size()), CRYPTOKI_FN_LOG("C_FindObjectsInit"))) { CK_OBJECT_HANDLE obj; //! calls @c C_FindObjects for (CK_ULONG objs(0); - check(_slot._init->_fn->C_FindObjects + check(_slot->_library->C_FindObjects (_session, &obj, 1, &objs), CRYPTOKI_FN_LOG("C_FindObjects")) && objs; res.push_back(Object(*this, obj))); } //! calls @c C_FindObjectsFinal - check(_slot._init->_fn->C_FindObjectsFinal(_session), + check(_slot->_library->C_FindObjectsFinal(_session), CRYPTOKI_FN_LOG("C_FindObjectsFinal")); delete[] a; return res; @@ -362,7 +381,7 @@ namespace cryptoki { }; CK_OBJECT_HANDLE object; //! calls @c C_CreateObject - check(_slot._init->_fn->C_CreateObject + check(_slot->_library->C_CreateObject (_session, a, attrs.size(), &object), CRYPTOKI_FN_LOG("C_CreateObject")); delete[] a; diff --git a/src/cryptoki.hxx b/src/cryptoki.hxx index d2cd354..89f6e10 100644 --- a/src/cryptoki.hxx +++ b/src/cryptoki.hxx @@ -18,15 +18,16 @@ #include #include #include +#include // for inline implementations only +#include #include #include // malloc/free #include // memset #include // assert #include #include -#include /*! @defgroup gcryptoki C++ Wrapper around Cryptoki API */ //@{ @@ -624,77 +625,127 @@ namespace cryptoki { //@{ //! to be instanciated before first use - class Init { - - private: - - friend class Slot; - friend class Session; - friend class Object; - - bool _exc; - CK_RV _res; - CK_FUNCTION_LIST* _fn; - - Init(const Init&); // forbidden - Init& operator=(const Init&); // forbidden + class Library { - //! Initialize Funcion List for this Instance - bool functionList(const std::string& library); - - bool check(CK_RV result, const std::string& context=""); - - /*! @return error text of last cryptoki call */ - std::string error(CK_RV res); - public: //! Initialize for a given library (default cryptoki) /*! Please notem, that you must not instanciate more than one Init per unique function list! - + @param library name of the shared library that supports pkcs#11 @param exc wether exceptions should be thrown */ - Init(const std::string& library="opensc-pkcs11.so", bool exc=true); - - ~Init() { - CRYPTOKI_LOG("log"); - try { - //! calls @c C_Finalize - check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize")); - } catch (...) { - if (!std::uncaught_exception()) throw; - } + Library(const std::string& library="opensc-pkcs11.so", bool exc=true): + _init(library, exc) { } + + public: + + class Init { - Init& reset() { - check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize")); - check(_fn->C_Initialize(0), CRYPTOKI_FN_LOG("C_Initialize")); - return *this; - } + private: - /*! @name C Like Error Handling + friend class Library; + + bool _exc; + CK_RV _res; + CK_FUNCTION_LIST* _fn; +#ifndef WIN32 + void* _lib; +#else + HINSTANCE _lib; +#endif + + //! Initialize Funcion List for this Instance + bool functionList(const std::string& library); + + bool check(CK_RV result, const std::string& context=""); + + /*! @return error text of last cryptoki call */ + std::string error(CK_RV res); + + public: + + //! Initialize for a given library (default cryptoki) + /*! Please notem, that you must not instanciate more than one + Init per unique function list! + + @param library name of the shared library that supports pkcs#11 + @param exc wether exceptions should be thrown */ + Init(const std::string& library="opensc-pkcs11.so", bool exc=true); + + ~Init(); + + Init& reset() { + check(_fn->C_Finalize(0), CRYPTOKI_FN_LOG("C_Finalize")); + check(_fn->C_Initialize(0), CRYPTOKI_FN_LOG("C_Initialize")); + return *this; + } + + CK_FUNCTION_LIST* fn() { + return _fn; + } + + /*! @name C Like Error Handling + + You are strongly recommended not to disable exception + handling. If you disable it, you must check after every + operation whether it was successful or not. These methods + provide all you need for that. */ + //@{ + + /*! @return @c true if last cryptoki on this object call was + successful */ + operator bool(); + + /*! @return error text of last cryptoki call */ + std::string error(); + + //@} + + }; + public: + + CK_FUNCTION_LIST* operator->() { + return _init->fn(); + } + + bool exc() { + return _init->_exc; + } + + /*! @name C Like Error Handling + You are strongly recommended not to disable exception handling. If you disable it, you must check after every operation whether it was successful or not. These methods provide all you need for that. */ //@{ - + /*! @return @c true if last cryptoki on this object call was successful */ - operator bool(); - + operator bool() { + return *_init; + } + /*! @return error text of last cryptoki call */ - std::string error(); + std::string error() { + return _init->error(); + } + + std::string error(CK_RV res) { + return _init->error(res); + } //@} - + Info info() { CRYPTOKI_LOG("log"); Info inf; CK_INFO cInf; //! calls @c C_GetInfo - if (!check(_fn->C_GetInfo(&cInf), CRYPTOKI_FN_LOG("C_GetInfo"))) + if (!_init->check(_init->fn() + ->C_GetInfo(&cInf), CRYPTOKI_FN_LOG("C_GetInfo"))) return inf; inf.cryptokiVersion = cInf.cryptokiVersion; inf.manufacturerID = cInf.manufacturerID; @@ -703,36 +754,42 @@ namespace cryptoki { inf.libraryVersion = cInf.libraryVersion; return inf; } - + //! Get a list of available slots - /*! @param tokenPresent whether a token must be inserted into the reader + /*! @param tokenPresent whether a token must be inserted into the + reader @param name if given, only return slots with a given name @return list of matching slots */ - SlotList slotList(bool tokenPresent=true, std::string name=std::string()); + SlotList slotList(bool tokenPresent=true, + std::string name=std::string()); - }; + private: + mrw::Shared _init; + + }; + //! Slot and Token Management class Slot { private: - friend class Init; + friend class Library; friend class Session; friend class Object; - Init* _init; + Library _library; CK_SLOT_ID _slot; CK_RV _res; - Slot(Init& init, CK_SLOT_ID slot): - _init(&init), _slot(slot), _res(CKR_OK) { + Slot(const Library& lib, CK_SLOT_ID slot): + _library(lib), _slot(slot), _res(CKR_OK) { CRYPTOKI_LOG("log"); } bool check(CK_RV result, const std::string& context="") { CRYPTOKI_LOG("log"); _res = result; - if (_init->_exc && !*this) + if (_library.exc() && !*this) if (!context.empty()) throw access_error(context+": "+error()); else @@ -743,13 +800,13 @@ namespace cryptoki { public: //! Don't use without assignment! For standard containers only! - Slot(): _init(0) { + Slot() { CRYPTOKI_LOG("log"); } Slot& operator=(const Slot& o) { CRYPTOKI_LOG("log"); - _init = o._init; + _library = o._library; _slot = o._slot; _res = o._res; return *this; @@ -772,7 +829,7 @@ namespace cryptoki { /*! @return error text of last cryptoki call */ std::string error() { CRYPTOKI_LOG("log"); - return _init->error(_res); + return _library.error(_res); } //@} @@ -782,7 +839,7 @@ namespace cryptoki { MechanismInfo info(mechanism); CK_MECHANISM_INFO cInfo; //! calls @c C_GetMechanismInfo - check(_init->_fn->C_GetMechanismInfo(_slot, mechanism, &cInfo), + check(_library->C_GetMechanismInfo(_slot, mechanism, &cInfo), CRYPTOKI_FN_LOG("C_GetMechanismInfo")); info.minKeySize = cInfo.ulMinKeySize; info.maxKeySize = cInfo.ulMaxKeySize; @@ -795,12 +852,12 @@ namespace cryptoki { MechanismList res; CK_ULONG count(0); //! calls @c C_GetMechanismList - if (!check(_init->_fn->C_GetMechanismList(_slot, 0, &count), + if (!check(_library->C_GetMechanismList(_slot, 0, &count), CRYPTOKI_FN_LOG("C_GetMechanismList")) || !count) return res; CK_MECHANISM_TYPE* mechanisms = 0; try { mechanisms = new CK_MECHANISM_TYPE[count]; - if (!check(_init->_fn->C_GetMechanismList(_slot, mechanisms, &count), + if (!check(_library->C_GetMechanismList(_slot, mechanisms, &count), CRYPTOKI_FN_LOG("C_GetMechanismList"))) { delete[] mechanisms; return res; @@ -820,7 +877,7 @@ namespace cryptoki { SlotInfo info; CK_SLOT_INFO cInfo; //! calls @c C_GetSlotInfo - if (!check(_init->_fn->C_GetSlotInfo(_slot, &cInfo), + if (!check(_library->C_GetSlotInfo(_slot, &cInfo), CRYPTOKI_FN_LOG("C_GetSlotInfo"))) return info; info.slotDescription = cInfo.slotDescription; info.manufacturerID = cInfo.manufacturerID; @@ -835,7 +892,7 @@ namespace cryptoki { TokenInfo info; //! calls @c C_GetTokenInfo CK_TOKEN_INFO cInfo; - if (!check(_init->_fn->C_GetTokenInfo(_slot, &cInfo), + if (!check(_library->C_GetTokenInfo(_slot, &cInfo), CRYPTOKI_FN_LOG("C_GetTokenInfo"))) return info; info.label = cInfo.label; info.manufacturerID = cInfo.manufacturerID; @@ -863,7 +920,7 @@ namespace cryptoki { bool inittoken(std::string pin, FixString<32> label) { CRYPTOKI_LOG("log"); //! calls @c C_InitToken - return check(_init->_fn->C_InitToken + return check(_library->C_InitToken (_slot, (unsigned char*)&pin[0], pin.size(), (unsigned char*)label.&fix()[0]) @@ -880,7 +937,7 @@ namespace cryptoki { bool registerforslotevent(SlotEventListener&) { CRYPTOKI_LOG("log"); //! calls @c C_WaitForSlotEvent - return check(_init->_fn->C_WaitForSlotEvent(CK_FLAGS, &_slot, CK_VOID_PTR), + return check(_library->C_WaitForSlotEvent(CK_FLAGS, &_slot, CK_VOID_PTR), CRYPTOKI_FN_LOG("C_WaitForSlotEvent")); } @endcode */ @@ -894,23 +951,16 @@ namespace cryptoki { friend class Login; friend class Object; - CK_FUNCTION_LIST* fn() { - return _slot._init->_fn; - } - - Slot& _slot; + mrw::Shared _slot; CK_SESSION_HANDLE _session; CK_RV _res; Session(); // forbidden - Session(const Session& o); // no-copy - Session& operator=(const Session& o); // no-copy - bool check(CK_RV result, const std::string& context="") { CRYPTOKI_LOG("log"); _res = result; - if (_slot._init->_exc && !*this) + if (_slot->_library.exc() && !*this) if (!context.empty()) throw access_error(context+": "+error()); else @@ -926,13 +976,13 @@ namespace cryptoki { } catch (...) { // still try to close session //! calls @c C_CloseSession try { - check(_slot._init->_fn->C_CloseSession(_session), + check(_slot->_library->C_CloseSession(_session), CRYPTOKI_FN_LOG("C_CloseSession")); } catch (...) {} // only report first problem throw; } //! calls @c C_CloseSession - check(_slot._init->_fn->C_CloseSession(_session), + check(_slot->_library->C_CloseSession(_session), CRYPTOKI_FN_LOG("C_CloseSession")); } @@ -940,12 +990,12 @@ namespace cryptoki { //! Opens a new session. /*! @param slot slot to open a session on */ - Session(Slot& slot, bool rw=false): - _slot(slot), _session(0), _res(CKR_OK), _login(0) { + Session(mrw::Shared slot, bool rw=false): + _slot(slot), _session(0), _res(CKR_OK) { CRYPTOKI_LOG("log"); //! calls @c C_OpenSession - check(_slot._init->_fn->C_OpenSession - (_slot._slot, CKF_SERIAL_SESSION|(rw?CKF_RW_SESSION:0), + check(_slot->_library->C_OpenSession + (_slot->_slot, CKF_SERIAL_SESSION|(rw?CKF_RW_SESSION:0), 0, 0, &_session), CRYPTOKI_FN_LOG("C_OpenSession")); //! @todo pass parameter @@ -997,7 +1047,7 @@ namespace cryptoki { /*! @return error text of last cryptoki call */ std::string error() { CRYPTOKI_LOG("log"); - return _slot._init->error(_res); + return _slot->_library.error(_res); } //@} @@ -1011,7 +1061,7 @@ namespace cryptoki { bool cancel() { CRYPTOKI_LOG("log"); //! calls @c C_CancelFunction - return check(_slot._init->_fn->C_CancelFunction(_session), + return check(_slot->_library->C_CancelFunction(_session), CRYPTOKI_FN_LOG("C_CancelFunction")); } @@ -1024,7 +1074,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_Digest - check(_slot._init->_fn->C_Digest + check(_slot->_library->C_Digest (_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1039,7 +1089,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_DigestEncryptUpdate - check(_slot._init->_fn->C_DigestEncryptUpdate + check(_slot->_library->C_DigestEncryptUpdate (_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1053,7 +1103,7 @@ namespace cryptoki { bool digestfinal() { CRYPTOKI_LOG("log"); //! calls @c C_DigestFinal - return check(_slot._init->_fn->C_DigestFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR), + return check(_slot->_library->C_DigestFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_DigestFinal")); } @endcode */ @@ -1063,7 +1113,7 @@ namespace cryptoki { bool digestinit() { CRYPTOKI_LOG("log"); //! calls @c C_DigestInit - return check(_slot._init->_fn->C_DigestInit(_session, CK_MECHANISM_PTR), + return check(_slot->_library->C_DigestInit(_session, CK_MECHANISM_PTR), CRYPTOKI_FN_LOG("C_DigestInit")); } @endcode */ @@ -1073,7 +1123,7 @@ namespace cryptoki { bool digestupdate() { CRYPTOKI_LOG("log"); //! calls @c C_DigestUpdate - return check(_slot._init->_fn->C_DigestUpdate(_session, CK_BYTE_PTR, CK_ULONG), + return check(_slot->_library->C_DigestUpdate(_session, CK_BYTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_DigestUpdate")); } @endcode */ @@ -1083,7 +1133,7 @@ namespace cryptoki { bool findobjectsfinal() { CRYPTOKI_LOG("log"); //! calls @c C_FindObjectsFinal - return check(_slot._init->_fn->C_FindObjectsFinal(_session), + return check(_slot->_library->C_FindObjectsFinal(_session), CRYPTOKI_FN_LOG("C_FindObjectsFinal")); } @endcode */ @@ -1093,7 +1143,7 @@ namespace cryptoki { bool findobjectsinit() { CRYPTOKI_LOG("log"); //! calls @c C_FindObjectsInit - return check(_slot._init->_fn->C_FindObjectsInit(_session, CK_ATTRIBUTE_PTR, CK_ULONG), + return check(_slot->_library->C_FindObjectsInit(_session, CK_ATTRIBUTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_FindObjectsInit")); } @endcode */ @@ -1103,7 +1153,7 @@ namespace cryptoki { bool findobjects() { CRYPTOKI_LOG("log"); //! calls @c C_FindObjects - return check(_session._slot._init->_fn->C_FindObjects(_session, CK_OBJECT_HANDLE_PTR, CK_ULONG, + return check(_session->_slot->_library->C_FindObjects(_session, CK_OBJECT_HANDLE_PTR, CK_ULONG, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_FindObjects")); } @@ -1114,7 +1164,7 @@ namespace cryptoki { bool generaterandom() { CRYPTOKI_LOG("log"); //! calls @c C_GenerateRandom - return check(_slot._init->_fn->C_GenerateRandom(_session, CK_BYTE_PTR, CK_ULONG), + return check(_slot->_library->C_GenerateRandom(_session, CK_BYTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_GenerateRandom")); } @endcode */ @@ -1124,7 +1174,7 @@ namespace cryptoki { bool getfunctionstatus() { CRYPTOKI_LOG("log"); //! calls @c C_GetFunctionStatus - return check(_slot._init->_fn->C_GetFunctionStatus(_session), + return check(_slot->_library->C_GetFunctionStatus(_session), CRYPTOKI_FN_LOG("C_GetFunctionStatus")); } @endcode */ @@ -1134,7 +1184,7 @@ namespace cryptoki { bool getoperationstate() { CRYPTOKI_LOG("log"); //! calls @c C_GetOperationState - return check(_slot._init->_fn->C_GetOperationState(_session, CK_BYTE_PTR, CK_ULONG_PTR), + return check(_slot->_library->C_GetOperationState(_session, CK_BYTE_PTR, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_GetOperationState")); } @endcode */ @@ -1144,7 +1194,7 @@ namespace cryptoki { bool getsessioninfo() { CRYPTOKI_LOG("log"); //! calls @c C_GetSessionInfo - return check(_slot._init->_fn->C_GetSessionInfo(_session, CK_SESSION_INFO_PTR), + return check(_slot->_library->C_GetSessionInfo(_session, CK_SESSION_INFO_PTR), CRYPTOKI_FN_LOG("C_GetSessionInfo")); } @endcode */ @@ -1154,7 +1204,7 @@ namespace cryptoki { bool initpin() { CRYPTOKI_LOG("log"); //! calls @c C_InitPIN - return check(_slot._init->_fn->C_InitPIN(_session, CK_CHAR_PTR, CK_ULONG), + return check(_slot->_library->C_InitPIN(_session, CK_CHAR_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_InitPIN")); } @endcode */ @@ -1163,13 +1213,13 @@ namespace cryptoki { public: - Login(Session& session, + Login(mrw::Shared session, const std::string& pin, CK_USER_TYPE userType=CKU_USER): _session(session) { CRYPTOKI_LOG("log"); //! calls @c C_Login - _session.check(_session.fn()->C_Login - (_session._session, userType, + _session->check(_session->_slot->_library->C_Login + (_session->_session, userType, (CK_CHAR*)pin.c_str(), pin.size()), CRYPTOKI_FN_LOG("C_Login")); @@ -1178,8 +1228,8 @@ namespace cryptoki { ~Login() { try { //! calls @c C_Logout - _session.check(_session.fn()->C_Logout - (_session._session), + _session->check(_session->_slot->_library->C_Logout + (_session->_session), CRYPTOKI_FN_LOG("C_Logout")); } catch (...) { if (!std::uncaught_exception()) throw; @@ -1188,35 +1238,33 @@ namespace cryptoki { private: - Session& _session; + mrw::Shared _session; }; void login(const std::string& pin, CK_USER_TYPE userType=CKU_USER) { CRYPTOKI_LOG("log"); - delete _login; _login = new Login(*this, pin, userType); } void logout() { CRYPTOKI_LOG("log"); try { - delete _login; - _login = 0; + _login.reset(); } catch (...) { - _login = 0; + _login.reset(); throw; } } - Login* _login; + mrw::Shared _login; /*! @todo Not implemented: @code bool seedrandom() { CRYPTOKI_LOG("log"); //! calls @c C_SeedRandom - return check(_slot._init->_fn->C_SeedRandom(_session, CK_BYTE_PTR, CK_ULONG), + return check(_slot->_library->C_SeedRandom(_session, CK_BYTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_SeedRandom")); } @endcode */ @@ -1226,7 +1274,7 @@ namespace cryptoki { bool setpin() { CRYPTOKI_LOG("log"); //! calls @c C_SetPIN - return check(_slot._init->_fn->C_SetPIN(_session, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG), + return check(_slot->_library->C_SetPIN(_session, CK_CHAR_PTR, CK_ULONG, CK_CHAR_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_SetPIN")); } @endcode */ @@ -1239,13 +1287,13 @@ namespace cryptoki { friend class Session; CK_OBJECT_HANDLE _object; - Session* _session; + mrw::Shared _session; CK_RV _res; bool check(CK_RV result, const std::string& context="") { CRYPTOKI_LOG("log"); _res = result; - if (_session->_slot._init->_exc && !*this) + if (_session->_slot->_library.exc() && !*this) if (!context.empty()) throw access_error(context+": "+error()); else @@ -1255,8 +1303,8 @@ namespace cryptoki { Object(); // forbidden - Object(Session& session, CK_OBJECT_HANDLE obj): - _object(obj), _session(&session), _res(CKR_OK) { + Object(mrw::Shared session, CK_OBJECT_HANDLE obj): + _object(obj), _session(session), _res(CKR_OK) { CRYPTOKI_LOG("log"); } @@ -1328,7 +1376,7 @@ namespace cryptoki { /*! @return error text of last cryptoki call */ std::string error() { CRYPTOKI_LOG("log"); - return _session->_slot._init->error(_res); + return _session->_slot->_library.error(_res); } //@} @@ -1344,7 +1392,7 @@ namespace cryptoki { bool copyobject() { CRYPTOKI_LOG("log"); //! calls @c C_CopyObject - return check(_session->_slot._init->_fn->C_CopyObject(_session->_session, CK_OBJECT_HANDLE, + return check(_session->_slot->_library->C_CopyObject(_session->_session, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_CopyObject")); } @@ -1358,7 +1406,7 @@ namespace cryptoki { CRYPTOKI_LOG("decryptinit: type="<_slot._init->_fn->C_DecryptInit + return check(_session->_slot->_library->C_DecryptInit (_session->_session, &mech, _object), CRYPTOKI_FN_LOG("C_DecryptInit")); } @@ -1370,13 +1418,13 @@ namespace cryptoki { CK_ULONG size(0); // two calls, first to get minimum buffer length CRYPTOKI_LOG("get size"); //! calls @c C_Decrypt - check(_session->_slot._init->_fn->C_Decrypt + check(_session->_slot->_library->C_Decrypt (_session->_session, (unsigned char*)&in[0], in.size(), 0, &size), CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_LOG("maximum size is "<_slot._init->_fn->C_Decrypt + check(_session->_slot->_library->C_Decrypt (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1392,7 +1440,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_DecryptDigestUpdate - check(_session->_slot._init->_fn->C_DecryptDigestUpdate + check(_session->_slot->_library->C_DecryptDigestUpdate (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1404,7 +1452,7 @@ namespace cryptoki { bool decryptfinal() { CRYPTOKI_LOG("log"); //! calls @c C_DecryptFinal - return check(_session->_slot._init->_fn->C_DecryptFinal + return check(_session->_slot->_library->C_DecryptFinal (_session->_session, 0, 0), CRYPTOKI_FN_LOG("C_DecryptFinal")); //! @todo does this work? @@ -1416,7 +1464,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_DecryptUpdate - check(_session->_slot._init->_fn->C_DecryptUpdate + check(_session->_slot->_library->C_DecryptUpdate (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1431,7 +1479,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_DecryptVerifyUpdate - check(_session->_slot._init->_fn->C_DecryptVerifyUpdate + check(_session->_slot->_library->C_DecryptVerifyUpdate (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1445,14 +1493,14 @@ namespace cryptoki { CRYPTOKI_LOG("log"); std::string res; CK_ULONG size(0); - check(_session->_slot._init->_fn->C_Sign + check(_session->_slot->_library->C_Sign (_session->_session, (unsigned char*)&in[0], in.size(),0, &size), CRYPTOKI_FN_LOG("C_Sign")); CRYPTOKI_LOG("maximum size is "<_slot._init->_fn->C_Sign + check(_session->_slot->_library->C_Sign (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1468,7 +1516,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_SignEncryptUpdate - check(_session->_slot._init->_fn->C_SignEncryptUpdate + check(_session->_slot->_library->C_SignEncryptUpdate (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1482,7 +1530,7 @@ namespace cryptoki { bool signfinal() { CRYPTOKI_LOG("log"); //! calls @c C_SignFinal - return check(_slot._init->_fn->C_SignFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR), + return check(_slot->_library->C_SignFinal(_session, CK_BYTE_PTR, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_SignFinal")); } @endcode */ @@ -1493,7 +1541,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_SignRecover - check(_session->_slot._init->_fn->C_SignRecover + check(_session->_slot->_library->C_SignRecover (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1507,7 +1555,7 @@ namespace cryptoki { bool signupdate() { CRYPTOKI_LOG("log"); //! calls @c C_SignUpdate - return check(_session->_slot._init->_fn->C_SignUpdate(_session->_session, CK_BYTE_PTR, CK_ULONG), + return check(_session->_slot->_library->C_SignUpdate(_session->_session, CK_BYTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_SignUpdate")); } @endcode */ @@ -1515,7 +1563,7 @@ namespace cryptoki { bool verify(std::string data, std::string signature) { CRYPTOKI_LOG("log"); //! calls @c C_Verify - return check(_session->_slot._init->_fn->C_Verify + return check(_session->_slot->_library->C_Verify (_session->_session, (unsigned char*)&data[0], data.size(), (unsigned char*)&signature[0], signature.size()), @@ -1527,7 +1575,7 @@ namespace cryptoki { bool verifyfinal() { CRYPTOKI_LOG("log"); //! calls @c C_VerifyFinal - return check(_session->_slot._init->_fn->C_VerifyFinal(_session->_session, CK_BYTE_PTR, CK_ULONG), + return check(_session->_slot->_library->C_VerifyFinal(_session->_session, CK_BYTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_VerifyFinal")); } @endcode */ @@ -1538,7 +1586,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_VerifyRecover - check(_session->_slot._init->_fn->C_VerifyRecover + check(_session->_slot->_library->C_VerifyRecover (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1552,7 +1600,7 @@ namespace cryptoki { bool verifyupdate() { CRYPTOKI_LOG("log"); //! calls @c C_VerifyUpdate - return check(_session->_slot._init->_fn->C_VerifyUpdate(_session->_session, CK_BYTE_PTR, CK_ULONG), + return check(_session->_slot->_library->C_VerifyUpdate(_session->_session, CK_BYTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_VerifyUpdate")); } @endcode */ @@ -1563,7 +1611,7 @@ namespace cryptoki { bool derivekey() { CRYPTOKI_LOG("log"); //! calls @c C_DeriveKey - return check(_session->_slot._init->_fn->C_DeriveKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + return check(_session->_slot->_library->C_DeriveKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_DeriveKey")); } @@ -1572,7 +1620,7 @@ namespace cryptoki { bool destroy() { CRYPTOKI_LOG("log"); //! calls @c C_DestroyObject - return check(_session->_slot._init->_fn->C_DestroyObject + return check(_session->_slot->_library->C_DestroyObject (_session->_session, _object), CRYPTOKI_FN_LOG("C_DestroyObject")); } @@ -1583,7 +1631,7 @@ namespace cryptoki { bool digestkey() { CRYPTOKI_LOG("log"); //! calls @c C_DigestKey - return check(_session->_slot._init->_fn->C_DigestKey(_session->_session, CK_OBJECT_HANDLE), + return check(_session->_slot->_library->C_DigestKey(_session->_session, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_DigestKey")); } @endcode */ @@ -1596,7 +1644,7 @@ namespace cryptoki { CRYPTOKI_LOG("encryptinit: type="<_slot._init->_fn->C_EncryptInit + return check(_session->_slot->_library->C_EncryptInit (_session->_session, &mech, _object), CRYPTOKI_FN_LOG("C_EncryptInit")); } @@ -1607,13 +1655,13 @@ namespace cryptoki { CK_ULONG size(0); // two calls, first to get minimum buffer length CRYPTOKI_LOG("get size"); //! calls @c C_Encrypt - check(_session->_slot._init->_fn->C_Encrypt + check(_session->_slot->_library->C_Encrypt (_session->_session, (unsigned char*)&in[0], in.size(), 0, &size), CRYPTOKI_FN_LOG("C_Decrypt")); CRYPTOKI_LOG("maximum size is "<_slot._init->_fn->C_Encrypt + check(_session->_slot->_library->C_Encrypt (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1627,7 +1675,7 @@ namespace cryptoki { bool encryptfinal() { CRYPTOKI_LOG("log"); //! calls @c C_EncryptFinal - return check(_session->_slot._init->_fn->C_EncryptFinal(_session->_session, CK_BYTE_PTR, CK_ULONG_PTR), + return check(_session->_slot->_library->C_EncryptFinal(_session->_session, CK_BYTE_PTR, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_EncryptFinal")); } @endcode */ @@ -1638,7 +1686,7 @@ namespace cryptoki { res.resize(in.size()); CK_ULONG size(res.size()); //! @todo check if size is ok //! calls @c C_EncryptUpdate - check(_session->_slot._init->_fn->C_EncryptUpdate + check(_session->_slot->_library->C_EncryptUpdate (_session->_session, (unsigned char*)&in[0], in.size(), (unsigned char*)&res[0], &size), @@ -1652,7 +1700,7 @@ namespace cryptoki { bool generatekey() { CRYPTOKI_LOG("log"); //! calls @c C_GenerateKey - return check(_session->_slot._init->_fn->C_GenerateKey(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, + return check(_session->_slot->_library->C_GenerateKey(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_GenerateKey")); } @@ -1664,7 +1712,7 @@ namespace cryptoki { bool generatekeypair() { CRYPTOKI_LOG("log"); //! calls @c C_GenerateKeyPair - return check(_session->_slot._init->_fn->C_GenerateKeyPair(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, + return check(_session->_slot->_library->C_GenerateKeyPair(_session->_session, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_GenerateKeyPair")); @@ -1684,7 +1732,7 @@ namespace cryptoki { Attribute res; CK_ATTRIBUTE attr((CK_ATTRIBUTE){a, 0, 0}); //! calls @c C_GetAttributeValue - if (!check(_session->_slot._init->_fn->C_GetAttributeValue + if (!check(_session->_slot->_library->C_GetAttributeValue (_session->_session, _object, &attr, 1), CRYPTOKI_FN_LOG("C_GetAttributeValue")) || !(long)attr.ulValueLen>0l) @@ -1693,7 +1741,7 @@ namespace cryptoki { try { attr.pValue = malloc(attr.ulValueLen); attr.pValue = memset(attr.pValue, 0, attr.ulValueLen); - if (check(_session->_slot._init->_fn->C_GetAttributeValue + if (check(_session->_slot->_library->C_GetAttributeValue (_session->_session, _object, &attr, 1), CRYPTOKI_FN_LOG("C_GetAttributeValue"))) /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open @@ -1809,7 +1857,7 @@ namespace cryptoki { attr = (CK_ATTRIBUTE){*it, 0, 0}; try { //! calls @c C_GetAttributeValue - if (_session->_slot._init->_fn->C_GetAttributeValue + if (_session->_slot->_library->C_GetAttributeValue (_session->_session, _object, &attr, 1) == CKR_ATTRIBUTE_TYPE_INVALID || _res == CKR_ATTRIBUTE_SENSITIVE) { @@ -1819,7 +1867,7 @@ namespace cryptoki { if ((long)attr.ulValueLen>0l) { attr.pValue = malloc(attr.ulValueLen); attr.pValue = memset(attr.pValue, 0, attr.ulValueLen); - if (check(_session->_slot._init->_fn->C_GetAttributeValue + if (check(_session->_slot->_library->C_GetAttributeValue (_session->_session, _object, &attr, 1), CRYPTOKI_FN_LOG("C_GetAttributeValue"))) /*! @todo There's no @c CKA_WRAP_TEMPLATE in Open @@ -1881,7 +1929,7 @@ namespace cryptoki { bool getobjectsize() { CRYPTOKI_LOG("log"); //! calls @c C_GetObjectSize - return check(_session->_slot._init->_fn->C_GetObjectSize(_session->_session, CK_OBJECT_HANDLE, CK_ULONG_PTR), + return check(_session->_slot->_library->C_GetObjectSize(_session->_session, CK_OBJECT_HANDLE, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_GetObjectSize")); } @endcode */ @@ -1892,7 +1940,7 @@ namespace cryptoki { bool setattributevalue() { CRYPTOKI_LOG("log"); //! calls @c C_SetAttributeValue - return check(_session->_slot._init->_fn->C_SetAttributeValue(_session->_session, CK_OBJECT_HANDLE, + return check(_session->_slot->_library->C_SetAttributeValue(_session->_session, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG), CRYPTOKI_FN_LOG("C_SetAttributeValue")); } @@ -1903,7 +1951,7 @@ namespace cryptoki { bool setoperationstate() { CRYPTOKI_LOG("log"); //! calls @c C_SetOperationState - return check(_session->_slot._init->_fn->C_SetOperationState(_session->_session, CK_BYTE_PTR, CK_ULONG, + return check(_session->_slot->_library->C_SetOperationState(_session->_session, CK_BYTE_PTR, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_SetOperationState")); } @@ -1917,7 +1965,7 @@ namespace cryptoki { CRYPTOKI_LOG("signinit: type="<_slot._init->_fn->C_SignInit + return check(_session->_slot->_library->C_SignInit (_session->_session, &mech, _object), CRYPTOKI_FN_LOG("C_SignInit")); } @@ -1927,7 +1975,7 @@ namespace cryptoki { bool signrecoverinit() { CRYPTOKI_LOG("log"); //! calls @c C_SignRecoverInit - return check(_session->_slot._init->_fn->C_SignRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session->_slot->_library->C_SignRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_SignRecoverInit")); } @endcode */ @@ -1937,7 +1985,7 @@ namespace cryptoki { bool unwrapkey() { CRYPTOKI_LOG("log"); //! calls @c C_UnwrapKey - return check(_session->_slot._init->_fn->C_UnwrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + return check(_session->_slot->_library->C_UnwrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR), CRYPTOKI_FN_LOG("C_UnwrapKey")); @@ -1952,7 +2000,7 @@ namespace cryptoki { CRYPTOKI_LOG("verifyinit: type="<_slot._init->_fn->C_VerifyInit + return check(_session->_slot->_library->C_VerifyInit (_session->_session, &mech, _object), CRYPTOKI_FN_LOG("C_VerifyInit")); } @@ -1962,7 +2010,7 @@ namespace cryptoki { bool verifyrecoverinit() { CRYPTOKI_LOG("log"); //! calls @c C_VerifyRecoverInit - return check(_session->_slot._init->_fn->C_VerifyRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), + return check(_session->_slot->_library->C_VerifyRecoverInit(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE), CRYPTOKI_FN_LOG("C_VerifyRecoverInit")); } @endcode */ @@ -1973,7 +2021,7 @@ namespace cryptoki { bool wrapkey() { CRYPTOKI_LOG("log"); //! calls @c C_WrapKey - return check(_session->_slot._init->_fn->C_WrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, + return check(_session->_slot->_library->C_WrapKey(_session->_session, CK_MECHANISM_PTR, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR), CRYPTOKI_FN_LOG("C_WrapKey")); } diff --git a/src/pcsc.hxx b/src/pcsc.hxx index 6a26dfb..3ae8c10 100644 --- a/src/pcsc.hxx +++ b/src/pcsc.hxx @@ -11,7 +11,7 @@ #define PCSC_HXX #ifndef PCSC_LOG -//! Declare PCSC_LOG before #include in your code, if you want logging. +//! Declare PCSC_LOG before #include in your de, if you want logging. /*! PCSC_LOG passes its argument to a stream, so your definition must behave so that the argument can be streamed. @@ -31,6 +31,7 @@ #include +#include #include #ifdef WIN32 @@ -214,8 +215,8 @@ namespace pcsc { /*! @note Please note that the Reader is required in the destructor und must therefore live longer than the Transaction instance. */ - Transaction(Reader& r): _reader(r), _running(true) { - _reader.beginTransaction(); + Transaction(mrw::Shared r): _reader(r), _running(true) { + _reader->beginTransaction(); } //! Cancels the transaction if not yet finished. ~Transaction() try { @@ -225,11 +226,11 @@ namespace pcsc { } //! Ends the running transaction. void end() { - if (_running) _reader.endTransaction(); + if (_running) _reader->endTransaction(); _running = false; } private: - Reader& _reader; + mrw::Shared _reader; bool _running; }; @@ -248,7 +249,7 @@ namespace pcsc { ~Reader() { _state = SCardDisconnect(_id, SCARD_RESET_CARD); if (!std::uncaught_exception()) - _connection.check("disconnect smartcard"); + _connection->check("disconnect smartcard"); } //! Get reader status. @@ -411,7 +412,7 @@ namespace pcsc { case SCARD_PROTOCOL_T0: return SCARD_PCI_T0; case SCARD_PROTOCOL_T1: return SCARD_PCI_T1; } - if (_connection._exc) throw not_implemented("unknown protocol"); + if (_connection->exc()) throw not_implemented("unknown protocol"); return 0; } @@ -420,18 +421,18 @@ namespace pcsc { an error occured in the last command. */ bool check(long state, const std::string context="") { _state = state; - return _connection.check(state, context); + return _connection->check(state, context); } //! Only Connection is allowed to instanciate. friend class Connection; //! Establishes a connection to the given named cardreader - Reader(const std::string& nm, Connection& c, + Reader(const std::string& nm, const Connection& c, DWORD mode=SCARD_SHARE_SHARED, DWORD protocol=SCARD_PROTOCOL_T1): name(nm), _connection(c) { - check(SCardConnect(_connection._id, strconv(name).c_str(), + check(SCardConnect(_connection->id(), strconv(name).c_str(), mode, protocol, &_id, &_protocol), "connect smartcard \""+name); @@ -440,13 +441,10 @@ namespace pcsc { //! forbidden Reader(); - //! forbidden - Reader(const Reader&); - //...........................................................variables private: - Connection& _connection; + mrw::Shared _connection; SCARDHANDLE _id; DWORD _state; DWORD _protocol; @@ -495,15 +493,13 @@ namespace pcsc { - @c false: no exceptions, check your instance after each operation */ Connection(Scope s=USER, bool exceptions=true): - _exc(exceptions), _id(0), - _state(SCardEstablishContext(s, 0, 0, &_id)) { + _connectionlifetime(new ConnectionLifetime(s, exceptions)) { check("establish smartcard context"); } //! Closes the connection (releases the smartcard context) ~Connection() { - _state = SCardReleaseContext(_id); - if (!std::uncaught_exception()) check("smartcard release context"); + // connection is closed, when last _connectionlifetime is destructed } //! Scans for available readers from a specified list of groups. @@ -512,14 +508,16 @@ namespace pcsc { Strings res; std::string grp(join(groups)); DWORD num(0); - if (!check(SCardListReaders(_id, groups.size()?strconv(grp).data():0, 0, + if (!check(SCardListReaders(_connectionlifetime->id(), + groups.size()?strconv(grp).data():0, 0, &num), "smartcard get size of readers of groups "+grp)) return res; PCSC_LOG("size of readers: "< nm(new char_t[num]); - if (!check(SCardListReaders(_id, groups.size()?strconv(grp).data():0, + if (!check(SCardListReaders(_connectionlifetime->id(), + groups.size()?strconv(grp).data():0, nm.get(), &num), "smartcard list reader names of groups "+grp)) return res; @@ -533,12 +531,10 @@ namespace pcsc { //! Get a reader, open a connection if not already open. /*! First use scan() to get a list of readers, then open a connection to the reader, then access it. */ - Reader& reader(const std::string& name) { - if (_reader.find(name)==_reader.end()) - _reader.insert - (std::make_pair - (name, shared_ptr::t(new Reader(name, *this)))); - return *_reader.find(name)->second; + mrw::Shared reader(const std::string& name) { + if (_readers.find(name)==_readers.end()) + _readers.insert(std::make_pair(name, new Reader(name, *this))); + return _readers.find(name)->second; } //! Close connection of a named reader. @@ -556,257 +552,14 @@ namespace pcsc { pcsc::Connection::Strings readers(scan()); for (pcsc::Connection::Strings::const_iterator it(readers.begin()); it!=readers.end(); ++it) - if (crypto::hex(reader(*it).status().atr).find(atr)!=string::npos) + if (crypto::hex(reader(*it)->status().atr).find(atr)!=string::npos) res.push_back(*it); return res; } //! @c false if last operation was not successful operator bool() const { -#ifdef WIN32 - return (_state>>30&3)==0; -#else - return _state==SCARD_S_SUCCESS; -#endif - } - - //! Get the describing text of the last error - std::string error() const { - std::stringstream ss; - switch (_state) { - case SCARD_E_CANCELLED: - ss<<"The action was canceled by an SCardCancel request."; - break; - case SCARD_E_CANT_DISPOSE: - ss<<"The system could not dispose of the media in the requested" - <<" manner."; - break; - case SCARD_E_CARD_UNSUPPORTED: - ss<<"The smart card does not meet minimal requirements for" - <<" support."; - break; - case SCARD_E_DUPLICATE_READER: - ss<<"The reader driver did not produce a unique reader name."; - break; - case SCARD_E_INSUFFICIENT_BUFFER: - ss<<"The data buffer for returned data is too small for the" - <<" returned data."; - break; - case SCARD_E_INVALID_ATR: - ss<<"An ATR string obtained from the registry is not a valid" - <<" ATR string."; - break; - case SCARD_E_INVALID_HANDLE: - ss<<"The supplied handle was not valid."; - break; - case SCARD_E_INVALID_PARAMETER: - ss<<"One or more of the supplied parameters could not be properly" - <<" interpreted."; - break; - case SCARD_E_INVALID_TARGET: - ss<<"Registry startup information is missing or not valid."; - break; - case SCARD_E_INVALID_VALUE: - ss<<"One or more of the supplied parameters values could not" - <<" be properly interpreted."; - break; - case SCARD_E_NOT_READY: - ss<<"The reader or smart card is not ready to accept commands."; - break; - case SCARD_E_NOT_TRANSACTED: - ss<<"An attempt was made to end a nonexistent transaction."; - break; - case SCARD_E_NO_MEMORY: - ss<<"Not enough memory available to complete this command."; - break; - case SCARD_E_NO_SERVICE: - ss<<"The smart card resource manager is not running."; - break; - case SCARD_E_NO_SMARTCARD: - ss<<"The operation requires a smart card, but no smart card" - <<" is currently in the device."; - break; - case SCARD_E_PCI_TOO_SMALL: - ss<<"The PCI receive buffer was too small."; - break; - case SCARD_E_PROTO_MISMATCH: - ss<<"The requested protocols are incompatible with the protocol" - <<" currently in use with the smart card."; - break; - case SCARD_E_READER_UNAVAILABLE: - ss<<"The specified reader is not currently available for use."; - break; - case SCARD_E_READER_UNSUPPORTED: - ss<<"The reader driver does not meet minimal requirements for" - <<" support."; - break; - case SCARD_E_SERVICE_STOPPED: - ss<<"The smart card resource manager has shut down."; - break; - case SCARD_E_SHARING_VIOLATION: - ss<<"The smart card cannot be accessed because of other outstanding" - <<" connections."; - break; - case SCARD_E_SYSTEM_CANCELLED: - ss<<"The action was cancelled by the system, presumably to log" - <<" off or shut down."; - break; - case SCARD_E_TIMEOUT: - ss<<"The user-specified time-out value has expired."; - break; - case SCARD_E_UNKNOWN_CARD: - ss<<"The specified smart card name is not recognized."; - break; - case SCARD_E_UNKNOWN_READER: - ss<<"The specified reader name is not recognized."; - break; - case SCARD_E_UNSUPPORTED_FEATURE: - ss<<"This smart card does not support the requested feature."; - break; - case SCARD_F_COMM_ERROR: - ss<<"An internal communications error has been detected."; - break; - case SCARD_F_INTERNAL_ERROR: - ss<<"An internal consistency check failed."; - break; - case SCARD_F_UNKNOWN_ERROR: - ss<<"An internal error has been detected, but the source is" - <<" unknown."; - break; - case SCARD_F_WAITED_TOO_LONG: - ss<<"An internal consistency timer has expired."; - break; - case SCARD_S_SUCCESS: - ss<<"No error was encountered."; - break; - case SCARD_W_REMOVED_CARD: - ss<<"The smart card has been removed, so that further communication" - <<" is not possible."; - break; - case SCARD_W_RESET_CARD: - ss<<"The smart card was reset."; - break; - case SCARD_W_UNPOWERED_CARD: - ss<<"Power has been removed from the smart card, so that" - <<" further communication is not possible."; - break; - case SCARD_W_UNRESPONSIVE_CARD: - ss<<"The smart card is not responding to a reset."; - break; - case SCARD_W_UNSUPPORTED_CARD: - ss<<"The reader cannot communicate with the smart card," - <<" due to ATR configuration conflicts."; - break; -#ifndef __APPLE__ - case SCARD_E_NO_READERS_AVAILABLE: - ss<<"No smart card reader is available."; - break; -#endif -#ifdef WIN32 - case ERROR_BROKEN_PIPE: - ss<<"The client attempted a smart card operation in a" - <<" remote session, such as a client session running" - <<" on a terminal server, and the operating system in" - <<" use does not support smart card redirection."; - break; - case SCARD_E_BAD_SEEK: - ss<<"There was an error trying to set the smart card file" - <<" object pointer."; - break; - case SCARD_E_CERTIFICATE_UNAVAILABLE: - ss<<"The requested certificate could not be obtained."; - break; - case SCARD_E_COMM_DATA_LOST: - ss<<"A communications error with the smart card has been detected."; - break; - case SCARD_E_DIR_NOT_FOUND: - ss<<"The specified directory does not exist in the smart card."; - break; - case SCARD_E_FILE_NOT_FOUND: - ss<<"The specified file does not exist in the smart card."; - break; - case SCARD_E_ICC_CREATEORDER: - ss<<"The requested order of object creation is not supported."; - break; - case SCARD_E_ICC_INSTALLATION: - ss<<"No primary provider can be found for the smart card."; - break; - case SCARD_E_INVALID_CHV: - ss<<"The supplied PIN is incorrect."; - break; - case SCARD_E_NO_ACCESS: - ss<<"Access is denied to this file."; - break; - case SCARD_E_NO_DIR: - ss<<"The supplied path does not represent a smart card directory."; - break; - case SCARD_E_NO_FILE: - ss<<"The supplied path does not represent a smart card file."; - break; - case SCARD_E_NO_KEY_CONTAINER: - ss<<"The requested key container does not exist on the smart card."; - break; - case SCARD_E_NO_SUCH_CERTIFICATE: - ss<<"The requested certificate does not exist."; - break; - case SCARD_E_SERVER_TOO_BUSY: - ss<<"The Smart card resource manager is too busy to complete this" - <<" operation."; - break; - case SCARD_E_UNEXPECTED: - ss<<"An unexpected card error has occurred."; - break; - case SCARD_E_UNKNOWN_RES_MNG: - ss<<"An unrecognized error code was returned from a layered" - <<" component."; - break; - case SCARD_E_WRITE_TOO_MANY: - ss<<"The smartcard does not have enough memory to store the" - <<" information."; - break; - case SCARD_P_SHUTDOWN: - ss<<"The operation has been aborted to allow the server application" - <<" to exit."; - break; - case SCARD_W_CANCELLED_BY_USER: - ss<<"The action was cancelled by the user."; - break; - case SCARD_W_CARD_NOT_AUTHENTICATED: - ss<<"No PIN was presented to the smart card."; - break; - case SCARD_W_CHV_BLOCKED: - ss<<"The card cannot be accessed because the maximum number" - <<" of PIN entry attempts has been reached."; - break; - case SCARD_W_EOF: - ss<<"The end of the smart card file has been reached."; - break; - case SCARD_W_SECURITY_VIOLATION: - ss<<"Access was denied because of a security violation."; - break; - case SCARD_W_WRONG_CHV: - ss<<"The card cannot be accessed because the wrong PIN was" - <<" presented."; - break; -#endif - default: - ss<<"unknown PCSC state=0x" - <>30) { - case 0: ss<<" means SUCCESS"; break; - case 1: ss<<" means INFORMATIONAL"; break; - case 2: ss<<" means WARNING"; break; - case 3: ss<<" means ERROR"; break; - default: ss<<" illegal value"; - } - ss<<" C="<<(_state>>29&1); - ss<<" R="<<(_state>>28&1); - ss<<" Facility=0x"<>16&0xfff); - ss<<" Code=0x"<state(state); return check(context); } - + //! Throws an exception if neccessary. /*! @throw access_error if it is instanciated for exceptions and an error occured in the last command. */ bool check(const std::string& context="") { - if (_exc&&!*this) - if (context.size()) - throw access_error(context+": "+error()); - else - throw access_error(error()); - return *this; + return _connectionlifetime->check(context); } //! Splits a buffer with 0 separators into a vector of strings. @@ -852,14 +600,324 @@ namespace pcsc { } return res; } - + + //! Connection id + SCARDCONTEXT id() { + return _connectionlifetime->id(); + } + + //! @c true if exceptions are thrown + bool exc() { + return _connectionlifetime->exc(); + } + //..............................................................variables - private: + private: + + class ConnectionLifetime { + public: + //! opens connection that is closed on destruction + ConnectionLifetime(Scope s, bool exc): + _exc(exc), _id(0), + _state(SCardEstablishContext(s, 0, 0, &_id)) { + check("establish smartcard context"); + } + //! Closes the connection (releases the smartcard context) + ~ConnectionLifetime() { + _state = SCardReleaseContext(_id); + if (!std::uncaught_exception()) check("smartcard release context"); + } + //! @c false if last operation was not successful + operator bool() const { +#ifdef WIN32 + return (_state>>30&3)==0; +#else + return _state==SCARD_S_SUCCESS; +#endif + } + //! Throws an exception if neccessary. + /*! @throw access_error if it is instanciated for exceptions and + an error occured in the last command. */ + bool check(const std::string& context="") { + if (_exc&&!*this) + if (context.size()) + throw access_error(context+": "+error()); + else + throw access_error(error()); + return *this; + } + + //! Get the describing text of the last error + std::string error() const { + std::stringstream ss; + switch (_state) { + case SCARD_E_CANCELLED: + ss<<"The action was canceled by an SCardCancel request."; + break; + case SCARD_E_CANT_DISPOSE: + ss<<"The system could not dispose of the media in the requested" + <<" manner."; + break; + case SCARD_E_CARD_UNSUPPORTED: + ss<<"The smart card does not meet minimal requirements for" + <<" support."; + break; + case SCARD_E_DUPLICATE_READER: + ss<<"The reader driver did not produce a unique reader name."; + break; + case SCARD_E_INSUFFICIENT_BUFFER: + ss<<"The data buffer for returned data is too small for the" + <<" returned data."; + break; + case SCARD_E_INVALID_ATR: + ss<<"An ATR string obtained from the registry is not a valid" + <<" ATR string."; + break; + case SCARD_E_INVALID_HANDLE: + ss<<"The supplied handle was not valid."; + break; + case SCARD_E_INVALID_PARAMETER: + ss<<"One or more of the supplied parameters could not be properly" + <<" interpreted."; + break; + case SCARD_E_INVALID_TARGET: + ss<<"Registry startup information is missing or not valid."; + break; + case SCARD_E_INVALID_VALUE: + ss<<"One or more of the supplied parameters values could not" + <<" be properly interpreted."; + break; + case SCARD_E_NOT_READY: + ss<<"The reader or smart card is not ready to accept commands."; + break; + case SCARD_E_NOT_TRANSACTED: + ss<<"An attempt was made to end a nonexistent transaction."; + break; + case SCARD_E_NO_MEMORY: + ss<<"Not enough memory available to complete this command."; + break; + case SCARD_E_NO_SERVICE: + ss<<"The smart card resource manager is not running."; + break; + case SCARD_E_NO_SMARTCARD: + ss<<"The operation requires a smart card, but no smart card" + <<" is currently in the device."; + break; + case SCARD_E_PCI_TOO_SMALL: + ss<<"The PCI receive buffer was too small."; + break; + case SCARD_E_PROTO_MISMATCH: + ss<<"The requested protocols are incompatible with the protocol" + <<" currently in use with the smart card."; + break; + case SCARD_E_READER_UNAVAILABLE: + ss<<"The specified reader is not currently available for use."; + break; + case SCARD_E_READER_UNSUPPORTED: + ss<<"The reader driver does not meet minimal requirements for" + <<" support."; + break; + case SCARD_E_SERVICE_STOPPED: + ss<<"The smart card resource manager has shut down."; + break; + case SCARD_E_SHARING_VIOLATION: + ss<<"The smart card cannot be accessed because of other outstanding" + <<" connections."; + break; + case SCARD_E_SYSTEM_CANCELLED: + ss<<"The action was cancelled by the system, presumably to log" + <<" off or shut down."; + break; + case SCARD_E_TIMEOUT: + ss<<"The user-specified time-out value has expired."; + break; + case SCARD_E_UNKNOWN_CARD: + ss<<"The specified smart card name is not recognized."; + break; + case SCARD_E_UNKNOWN_READER: + ss<<"The specified reader name is not recognized."; + break; + case SCARD_E_UNSUPPORTED_FEATURE: + ss<<"This smart card does not support the requested feature."; + break; + case SCARD_F_COMM_ERROR: + ss<<"An internal communications error has been detected."; + break; + case SCARD_F_INTERNAL_ERROR: + ss<<"An internal consistency check failed."; + break; + case SCARD_F_UNKNOWN_ERROR: + ss<<"An internal error has been detected, but the source is" + <<" unknown."; + break; + case SCARD_F_WAITED_TOO_LONG: + ss<<"An internal consistency timer has expired."; + break; + case SCARD_S_SUCCESS: + ss<<"No error was encountered."; + break; + case SCARD_W_REMOVED_CARD: + ss<<"The smart card has been removed, so that further communication" + <<" is not possible."; + break; + case SCARD_W_RESET_CARD: + ss<<"The smart card was reset."; + break; + case SCARD_W_UNPOWERED_CARD: + ss<<"Power has been removed from the smart card, so that" + <<" further communication is not possible."; + break; + case SCARD_W_UNRESPONSIVE_CARD: + ss<<"The smart card is not responding to a reset."; + break; + case SCARD_W_UNSUPPORTED_CARD: + ss<<"The reader cannot communicate with the smart card," + <<" due to ATR configuration conflicts."; + break; +#ifndef __APPLE__ + case SCARD_E_NO_READERS_AVAILABLE: + ss<<"No smart card reader is available."; + break; +#endif +#ifdef WIN32 + case ERROR_BROKEN_PIPE: + ss<<"The client attempted a smart card operation in a" + <<" remote session, such as a client session running" + <<" on a terminal server, and the operating system in" + <<" use does not support smart card redirection."; + break; + case SCARD_E_BAD_SEEK: + ss<<"There was an error trying to set the smart card file" + <<" object pointer."; + break; + case SCARD_E_CERTIFICATE_UNAVAILABLE: + ss<<"The requested certificate could not be obtained."; + break; + case SCARD_E_COMM_DATA_LOST: + ss<<"A communications error with the smart card has been detected."; + break; + case SCARD_E_DIR_NOT_FOUND: + ss<<"The specified directory does not exist in the smart card."; + break; + case SCARD_E_FILE_NOT_FOUND: + ss<<"The specified file does not exist in the smart card."; + break; + case SCARD_E_ICC_CREATEORDER: + ss<<"The requested order of object creation is not supported."; + break; + case SCARD_E_ICC_INSTALLATION: + ss<<"No primary provider can be found for the smart card."; + break; + case SCARD_E_INVALID_CHV: + ss<<"The supplied PIN is incorrect."; + break; + case SCARD_E_NO_ACCESS: + ss<<"Access is denied to this file."; + break; + case SCARD_E_NO_DIR: + ss<<"The supplied path does not represent a smart card directory."; + break; + case SCARD_E_NO_FILE: + ss<<"The supplied path does not represent a smart card file."; + break; + case SCARD_E_NO_KEY_CONTAINER: + ss<<"The requested key container does not exist on the smart card."; + break; + case SCARD_E_NO_SUCH_CERTIFICATE: + ss<<"The requested certificate does not exist."; + break; + case SCARD_E_SERVER_TOO_BUSY: + ss<<"The Smart card resource manager is too busy to complete this" + <<" operation."; + break; + case SCARD_E_UNEXPECTED: + ss<<"An unexpected card error has occurred."; + break; + case SCARD_E_UNKNOWN_RES_MNG: + ss<<"An unrecognized error code was returned from a layered" + <<" component."; + break; + case SCARD_E_WRITE_TOO_MANY: + ss<<"The smartcard does not have enough memory to store the" + <<" information."; + break; + case SCARD_P_SHUTDOWN: + ss<<"The operation has been aborted to allow the server application" + <<" to exit."; + break; + case SCARD_W_CANCELLED_BY_USER: + ss<<"The action was cancelled by the user."; + break; + case SCARD_W_CARD_NOT_AUTHENTICATED: + ss<<"No PIN was presented to the smart card."; + break; + case SCARD_W_CHV_BLOCKED: + ss<<"The card cannot be accessed because the maximum number" + <<" of PIN entry attempts has been reached."; + break; + case SCARD_W_EOF: + ss<<"The end of the smart card file has been reached."; + break; + case SCARD_W_SECURITY_VIOLATION: + ss<<"Access was denied because of a security violation."; + break; + case SCARD_W_WRONG_CHV: + ss<<"The card cannot be accessed because the wrong PIN was" + <<" presented."; + break; +#endif + default: + ss<<"unknown PCSC state=0x" + <>30) { + case 0: ss<<" means SUCCESS"; break; + case 1: ss<<" means INFORMATIONAL"; break; + case 2: ss<<" means WARNING"; break; + case 3: ss<<" means ERROR"; break; + default: ss<<" illegal value"; + } + ss<<" C="<<(_state>>29&1); + ss<<" R="<<(_state>>28&1); + ss<<" Facility=0x"<>16&0xfff); + ss<<" Code=0x"<::t > _reader; + + //! Readers are closed when the last shared object is destructed + std::map > _readers; + + //! Connection is closed when the last shared object is destructed + /*! Handling the connection lifetime in a separate shared object + allows to copy connections and still make sure, that the + lifetime of the connection is as long as all copied opbjects + live. */ + mrw::Shared _connectionlifetime; };