This library provides a simple and nice C++ wrapper around these libraries, so that programmers can concentrate on functionality. It offers general support for PCSC-lite, OpenSSL, PKCS#11, plus specific functionality for the SuisseID.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
822 lines
30 KiB
822 lines
30 KiB
/*! @file |
|
|
|
This file offers a C++ access to the PCSC library. |
|
|
|
@id $Id$ |
|
*/ |
|
// 1 2 3 4 5 6 7 8 |
|
// 45678901234567890123456789012345678901234567890123456789012345678901234567890 |
|
|
|
#ifndef PCSC_HXX |
|
#define PCSC_HXX |
|
|
|
#ifndef PCSC_LOG |
|
//! Declare PCSC_LOG before #include in your code, if you want logging. |
|
/*! PCSC_LOG passes its argument to a stream, so your definition must |
|
behave so that the argument can be streamed. |
|
|
|
Example, use std::log: |
|
@code |
|
#define PCSC_LOG(x) std::clog<<x<<" ("<<__PRETTY_FUNCTION__<<')'<<std::endl |
|
#include <pcsc.hxx> |
|
@endcode |
|
|
|
Example, use qDebug(): |
|
@code |
|
#define PCSC_LOG(x) qDebug()<<x |
|
#include <pcsc.hxx> |
|
@endcode */ |
|
#define PCSC_LOG(x) // if unset, do nothing |
|
#endif |
|
|
|
#include <cryptaux.hxx> |
|
|
|
#include <string> |
|
|
|
#ifdef WIN32 |
|
#undef UNICODE |
|
#include <WinSCard.h> |
|
#undef ERROR |
|
#ifndef MAX_ATR_SIZE |
|
#define MAX_ATR_SIZE 33 |
|
#endif |
|
namespace pcsc { |
|
|
|
#ifdef UNICODE |
|
inline std::wstring strconv(std::string s) { |
|
return std::wstring(s.begin(), s.end()); |
|
} |
|
inline std::string strconv(std::wstring s) { |
|
return std::string(s.begin(), s.end()); |
|
} |
|
typedef wchar_t char_t; |
|
typedef std::wstring string; |
|
#else |
|
inline const std::string& strconv(const std::string& s) { |
|
return s; |
|
} |
|
typedef char char_t; |
|
typedef std::string string; |
|
#endif |
|
} |
|
#else |
|
#include <PCSC/pcsclite.h> |
|
#include <PCSC/wintypes.h> |
|
#include <PCSC/winscard.h> |
|
namespace pcsc { |
|
inline const std::string& strconv(const std::string& s) { |
|
return s; |
|
} |
|
typedef char char_t; |
|
typedef std::string string; |
|
} |
|
#endif |
|
|
|
#include <boost/shared_ptr.hpp> |
|
#include <vector> |
|
#include <map> |
|
#include <memory> |
|
|
|
namespace pcsc { |
|
std::string version(); |
|
} |
|
|
|
#include <sstream> |
|
#include <iomanip> |
|
|
|
/*! @defgroup gpcsc C++ Wrapper around pcsc-lite API |
|
|
|
This library is a C++ wrapper to the awful pcsc-lite interface. |
|
The reason for this wrapper is to get a nice object oriented |
|
interface written in C++ manner and using standard types and so to |
|
avoid the ugly M$-C-quirks. This interface is memory clean. |
|
@todo: Not implemented, not supported: |
|
- SCardGetStatusChange(hContext, 0, rgReaderStates, 1); |
|
- SCardReconnect(hCard, SCARD_SHARE_SHARED, |
|
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, |
|
SCARD_LEAVE_CARD, |
|
&dwActiveProtocol); |
|
- several other |
|
I do not need these, and I don't know the usecase where they are |
|
required. If you need something that is not yet supported, please |
|
let me know, what you need and why. Then I'll add it so that it |
|
best fits the common needs. */ |
|
//@{ |
|
/*! @defgroup pcsclib PCSC C++ Library */ |
|
/*! @defgroup pcscexceptions PCSC Exceptions */ |
|
|
|
//! @see gpcsc |
|
namespace pcsc { |
|
|
|
//============================================================================ |
|
//! @addtogroup pcscexceptions |
|
//@{ |
|
|
|
//---------------------------------------------------------------------------- |
|
class exception: public std::exception { |
|
public: |
|
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {} |
|
~exception() throw() {} |
|
const char* what() const throw() { |
|
return _what.c_str(); |
|
} |
|
private: |
|
std::string _what; |
|
}; |
|
//---------------------------------------------------------------------------- |
|
class not_implemented: public exception { |
|
public: |
|
not_implemented(const std::string& reason) throw(): |
|
exception("feature is not implemented:\n"+reason) { |
|
} |
|
}; |
|
//---------------------------------------------------------------------------- |
|
class access_error: public exception { |
|
public: |
|
access_error(const std::string& reason) throw(): |
|
exception("smardcard access error:\n"+reason) { |
|
} |
|
}; |
|
//---------------------------------------------------------------------------- |
|
class runtime_error: public exception { |
|
public: |
|
runtime_error(const std::string& reason, const std::string& data) throw(): |
|
exception("runtime error,\n"+reason+":\n"+crypto::hex(data)) {} |
|
}; |
|
//---------------------------------------------------------------------------- |
|
class neesting_error: public exception { |
|
public: |
|
neesting_error() throw(): |
|
exception("neesting error: more endTransaction than beginTransaction") |
|
{} |
|
}; |
|
//@} |
|
|
|
//! @addtogroup pcsclib |
|
//@{ |
|
|
|
//============================================================================ |
|
class Connection { |
|
|
|
//...............................................................typedefs |
|
public: |
|
|
|
|
|
//------------------------------------------------------------------Reader |
|
friend class Reader; |
|
class Reader { |
|
|
|
//............................................................typedefs |
|
public: |
|
|
|
friend class Transaction; |
|
//! Scoped transaction. |
|
/*! This is a scoped transaction. That means, the |
|
transaction is started in the constructor and ended in |
|
the destructor, unless it is already ended before. In |
|
case of an exception or leaving the block, the |
|
transaction is always cleaned up. |
|
|
|
There's a neesting counter to make sure, transaction is |
|
started only once and ended only once, even though the |
|
locking can be neested. |
|
|
|
@code |
|
pcsc::Connection c; |
|
{ |
|
Transaction t(c.reader("name")); |
|
[...] // do some stuff, possible exceptions thrown |
|
if (problem) return; // automatically ended |
|
[...] |
|
t.end(); // ended if we reach this line |
|
[...] |
|
} // also ended, unless commit reaced |
|
@endcode */ |
|
class Transaction { |
|
public: |
|
//! Begins a transaction. |
|
/*! @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(); |
|
} |
|
//! Cancels the transaction if not yet finished. |
|
~Transaction() try { |
|
end(); |
|
} catch (...) { |
|
if (!std::uncaught_exception()) throw; |
|
} |
|
//! Ends the running transaction. |
|
void end() { |
|
if (_running) _reader.endTransaction(); |
|
_running = false; |
|
} |
|
private: |
|
Reader& _reader; |
|
bool _running; |
|
}; |
|
|
|
//! State and attribute list of a reader. |
|
class Status { |
|
public: |
|
Status(unsigned long s, const std::string& a): state(s), atr(a) {} |
|
const unsigned long state; |
|
const std::string atr; |
|
}; |
|
|
|
//.............................................................methods |
|
public: |
|
|
|
//! Disconnects connection. |
|
~Reader() { |
|
_state = SCardDisconnect(_id, SCARD_RESET_CARD); |
|
if (!std::uncaught_exception()) |
|
_connection.check("disconnect smartcard"); |
|
} |
|
|
|
//! Get reader status. |
|
Status status() { |
|
DWORD dummy(0); |
|
DWORD s; |
|
DWORD len(MAX_ATR_SIZE); |
|
unsigned char a[len]; |
|
check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len), |
|
"query smartcard status"); |
|
return Status(s, std::string((char*)a, len)); |
|
} |
|
|
|
//! Transmit data to reader. |
|
/*! @note Take care: Stings may contain embedded @c 0. */ |
|
std::string transmit(char cla, char ins, char p1, char p2, |
|
const std::string& lc = std::string(), |
|
unsigned char le = 253) { |
|
std::string claInsP1P2; |
|
claInsP1P2.push_back(cla); |
|
claInsP1P2.push_back(ins); |
|
claInsP1P2.push_back(p1); |
|
claInsP1P2.push_back(p2); |
|
assert(claInsP1P2.size()==4); |
|
return transmit(claInsP1P2, lc, le); |
|
} |
|
|
|
//! Transmit data to reader. |
|
/*! @note Take care: Stings may contain embedded @c 0. */ |
|
std::string transmit(char cla, char ins, char p1, char p2, |
|
unsigned char le) { |
|
std::string claInsP1P2; |
|
claInsP1P2.push_back(cla); |
|
claInsP1P2.push_back(ins); |
|
claInsP1P2.push_back(p1); |
|
claInsP1P2.push_back(p2); |
|
assert(claInsP1P2.size()==4); |
|
return transmit(claInsP1P2, std::string(), le); |
|
} |
|
|
|
//! Transmit data to reader. |
|
/*! @note Take care: Stings may contain embedded @c 0. */ |
|
std::string transmit(char cla, char ins, char p1, char p2, |
|
const char* lc, int len, |
|
unsigned char le = 253) { |
|
std::string claInsP1P2; |
|
claInsP1P2.push_back(cla); |
|
claInsP1P2.push_back(ins); |
|
claInsP1P2.push_back(p1); |
|
claInsP1P2.push_back(p2); |
|
assert(claInsP1P2.size()==4); |
|
return transmit(claInsP1P2, std::string(lc, len), le); |
|
} |
|
|
|
//! Transmit data to reader. |
|
/*! @note Take care: Stings may contain embedded @c 0. |
|
@note Prefer the transmit methods that passes @c cla, @c |
|
ins, @c p1 and @c p2 separate.*/ |
|
std::string transmit(const std::string& claInsP1P2, |
|
const std::string& lc, |
|
unsigned char le = 253) { |
|
if (claInsP1P2.size()!=4) |
|
throw runtime_error("transmit: claInsP1P2 must be 4 byte", |
|
claInsP1P2); |
|
if (lc.size()>255) throw runtime_error("transmit: lc too long", lc); |
|
std::string msg(claInsP1P2); |
|
if (lc.size()) (msg+=(char)lc.size())+=lc; |
|
msg+=le; |
|
return transmit(msg); |
|
} |
|
|
|
//! Transmit data to reader. |
|
/*! @note Take care: Stings may contain embedded @c 0. |
|
@note Prefer the transmit methods that passes @c cla, @c |
|
ins, @c p1 and @c p2 separate.*/ |
|
std::string transmit(std::string in) { |
|
DWORD len(1024); // arbitrary |
|
unsigned char buff[len]; |
|
SCARD_IO_REQUEST rPci; |
|
rPci.dwProtocol = pci()->dwProtocol; |
|
rPci.cbPciLength = sizeof(rPci); |
|
// don't log; could log pins |
|
//PCSC_LOG("SCardTransmit: "<<crypto::hex(in)); |
|
check(SCardTransmit(_id, &rPci, |
|
(unsigned char*)in.c_str(), in.size(), |
|
0, buff, &len), |
|
"smartcard transmit message "+crypto::hex(in)); |
|
//PCSC_LOG(" -> "<<crypto::hex(std::string((char*)buff, len))); |
|
return std::string((char*)buff, len); |
|
} |
|
|
|
//! @c false if last operation was not successful |
|
operator bool() const { |
|
// Values are 32 bit values layed out as follows: |
|
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 |
|
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 |
|
// ---+-+-+-----------------------+------------------------------- |
|
// Sev|C|R| Facility | Code |
|
// ---+-+-+-----------------------+------------------------------- |
|
// where Sev - is the severity code |
|
// 00 - Success |
|
// 01 - Informational |
|
// 10 - Warning |
|
// 11 - Error |
|
// So everything with Sev=00 is successful |
|
// theoretically even with Sev=01, but that's still rejected |
|
//return (_state>>30&3)==0; |
|
return _state==SCARD_S_SUCCESS; |
|
} |
|
|
|
//...........................................................variables |
|
public: |
|
|
|
const std::string name; |
|
|
|
//.............................................................methods |
|
private: |
|
|
|
//! Use scoped transactions with @ref Transaction |
|
/*! Calls @c SCardBeginTransaction unless it's already inside |
|
a transaction. */ |
|
void beginTransaction() { |
|
if (++_neesting==1) |
|
check(SCardBeginTransaction(_id), "smartcard begin transaction"); |
|
} |
|
|
|
//! Use scoped transactions with @ref Transaction |
|
/*! Calls @c SCardEndTransaction if it's inside a transaction. |
|
|
|
@throws neesting_error if there are more calls to @c |
|
endTransaction than to @c beginTransaction. */ |
|
void endTransaction() { |
|
if (--_neesting==0) |
|
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), |
|
"smartcard end transaction"); |
|
else if (_neesting<0) { |
|
_neesting = 0; |
|
throw neesting_error(); |
|
} |
|
} |
|
|
|
/*! @throw not_implemented if _protocol is unknown. */ |
|
const SCARD_IO_REQUEST* pci() { |
|
switch(_protocol) { |
|
case SCARD_PROTOCOL_T0: return SCARD_PCI_T0; |
|
case SCARD_PROTOCOL_T1: return SCARD_PCI_T1; |
|
} |
|
if (_connection._exc) throw not_implemented("unknown protocol"); |
|
return 0; |
|
} |
|
|
|
//! Sets state and throws an exception if neccessary. |
|
/*! @throw access_error if it is instanciated for exceptions and |
|
an error occured in the last command. */ |
|
bool check(long state, const std::string context="") { |
|
_state = state; |
|
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, |
|
DWORD mode=SCARD_SHARE_SHARED, |
|
DWORD protocol=SCARD_PROTOCOL_T1): |
|
name(nm), _connection(c) { |
|
check(SCardConnect(_connection._id, strconv(name).c_str(), |
|
mode, protocol, |
|
&_id, &_protocol), |
|
"connect smartcard \""+name); |
|
} |
|
|
|
//! forbidden |
|
Reader(); |
|
|
|
//! forbidden |
|
Reader(const Reader&); |
|
|
|
//...........................................................variables |
|
private: |
|
|
|
Connection& _connection; |
|
SCARDHANDLE _id; |
|
DWORD _state; |
|
DWORD _protocol; |
|
static int _neesting; |
|
|
|
}; |
|
//------------------------------------------------------------------Reader |
|
|
|
enum Scope { |
|
USER = SCARD_SCOPE_USER, |
|
TERMINAL = SCARD_SCOPE_TERMINAL, |
|
SYSTEM = SCARD_SCOPE_SYSTEM |
|
}; |
|
|
|
typedef std::vector<std::string> Strings; |
|
|
|
//................................................................methods |
|
public: |
|
|
|
//! Opens a connection (establishes a smartcard context) |
|
/*! The errorhandling is defined with the @c exceptions flag: |
|
|
|
Using exceptions: |
|
@code |
|
try { |
|
pcsc::Connection c; // standard with exceptions |
|
pcsc::Connection::Strings r(c.scan()); |
|
} catch (std::exception& x) { |
|
std::cout<<"Error with message: "<<x.what()<<std::endl; |
|
} |
|
@endcode |
|
|
|
Without exceptions: |
|
@code |
|
pcsc::Connection c(SYSTEM, false); |
|
if (!c) std::cout<<"Error with message: "<<c.error()<<std::endl; |
|
pcsc::Connection::Strings r(c.scan()); |
|
if (!c) std::cout<<"Error with message: "<<c.error()<<std::endl; |
|
@endcode |
|
|
|
Recommendation: Use exceptions! |
|
|
|
@param s defines the scope of the connection |
|
@param exceptions |
|
- @c true: class throws exceptions in case of an error |
|
- @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)) { |
|
check("establish smartcard context"); |
|
} |
|
|
|
//! Closes the connection (releases the smartcard context) |
|
~Connection() { |
|
_state = SCardReleaseContext(_id); |
|
if (!std::uncaught_exception()) check("smartcard release context"); |
|
} |
|
|
|
//! Scans for available readers from a specified list of groups. |
|
/*! Defaults to all groups. */ |
|
Strings scan(const Strings& groups = Strings()) { |
|
Strings res; |
|
std::string grp(join(groups)); |
|
DWORD num(0); |
|
if (!check(SCardListReaders(_id, groups.size()?strconv(grp).data():0, 0, |
|
&num), |
|
"smartcard get size of readers of groups "+grp)) |
|
return res; |
|
PCSC_LOG("size of readers: "<<num); |
|
if (!num) return res; |
|
std::auto_ptr<char_t> nm(new char_t[num]); |
|
if (!check(SCardListReaders(_id, groups.size()?strconv(grp).data():0, |
|
nm.get(), &num), |
|
"smartcard list reader names of groups "+grp)) |
|
return res; |
|
PCSC_LOG("got all readers, size is "<<num); |
|
if (!num) return res; |
|
PCSC_LOG("list of readers: " |
|
<<crypto::readable(std::string(nm.get(), num-1))); |
|
return res = split(strconv(string(nm.get(), num-1))); |
|
} |
|
|
|
//! 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, new Reader(name, *this))); |
|
return *_reader.find(name)->second; |
|
} |
|
|
|
//! Close connection of a named reader. |
|
/*! If you access the same reader through raeder() later, the |
|
connection will be reestablished. */ |
|
void close(const std::string& s) { |
|
|
|
} |
|
|
|
//! @c false if last operation was not successful |
|
operator bool() const { |
|
//return (_state>>30&3)==0; |
|
return _state==SCARD_S_SUCCESS; |
|
} |
|
|
|
//! 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" |
|
<<std::hex<<std::setfill('0')<<std::setw(8)<<_state; |
|
switch (_state>>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"<<std::hex<<std::setfill('0')<<std::setw(3) |
|
<<(_state>>16&0xfff); |
|
ss<<" Code=0x"<<std::hex<<std::setfill('0')<<std::setw(4) |
|
<<(_state&0xffff); |
|
} |
|
return ss.str(); |
|
} |
|
|
|
//................................................................methods |
|
private: |
|
|
|
//! Sets state and throws an exception if neccessary. |
|
/*! @throw access_error if it is instanciated for exceptions and |
|
an error occured in the last command. */ |
|
bool check(long state, const std::string& context="") { |
|
_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; |
|
} |
|
|
|
//! Splits a buffer with 0 separators into a vector of strings. |
|
Strings split(const std::string& in) { |
|
Strings res; |
|
for (std::string::size_type pos(0); pos<in.size() && in[pos]!=0; |
|
pos+=res.rbegin()->size()+1) |
|
res.push_back(in.substr(pos).c_str()); |
|
return res; |
|
} |
|
|
|
//! Joins a vector of strings into a buffer with 0 separators. |
|
std::string join(const Strings& in) { |
|
std::string res; |
|
if (in.size()) { |
|
for (Strings::const_iterator it(in.begin()); |
|
it!=in.end(); ++it) |
|
res+=*it+'\0'; |
|
res+='\0'; |
|
} |
|
return res; |
|
} |
|
|
|
//..............................................................variables |
|
private: |
|
|
|
bool _exc; |
|
SCARDCONTEXT _id; |
|
long _state; |
|
std::map<std::string, boost::shared_ptr<Reader> > _reader; |
|
|
|
}; |
|
|
|
//@} |
|
|
|
} |
|
//@} |
|
|
|
#endif
|
|
|