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.

974 lines
36 KiB

16 years ago
/*! @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
#include <cryptaux.hxx>
#include <mrw/shared.hxx>
#include <string>
16 years ago
#ifdef WIN32
#undef UNICODE
#undef DATADIR
#include <WinSCard.h>
#undef ERROR
16 years ago
#ifndef MAX_ATR_SIZE
#define MAX_ATR_SIZE 33
#endif
15 years ago
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
16 years ago
}
#else
#include <PCSC/pcsclite.h>
#include <PCSC/wintypes.h>
15 years ago
#include <PCSC/winscard.h>
namespace pcsc {
inline const std::string& strconv(const std::string& s) {
15 years ago
return s;
}
typedef char char_t;
typedef std::string string;
16 years ago
}
#endif
16 years ago
#include <vector>
#include <map>
#include <memory>
#include <sstream>
#include <iomanip>
#if __cplusplus > 199711L
namespace pcsc {
template<typename T> struct shared_ptr {
typedef std::shared_ptr<T> t;
};
}
#else
#warning Old compiler (pre 2011): using boost as replacement for std
#include <boost/shared_ptr.hpp>
namespace pcsc {
template<typename T> struct shared_ptr {
typedef boost::shared_ptr<T> t;
};
}
#endif
namespace pcsc {
std::string version();
}
15 years ago
/*! @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
16 years ago
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. */
15 years ago
//@{
/*! @defgroup pcsclib PCSC C++ Library */
/*! @defgroup pcscexceptions PCSC Exceptions */
//! @see gpcsc
16 years ago
namespace pcsc {
//============================================================================
15 years ago
//! @addtogroup pcscexceptions
15 years ago
//@{
//----------------------------------------------------------------------------
16 years ago
class exception: public std::exception {
public:
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {
CRYPTOLOG("ERROR: "<<what());
}
16 years ago
~exception() throw() {}
const char* what() const throw() {
return _what.c_str();
}
private:
std::string _what;
};
//----------------------------------------------------------------------------
class not_implemented: public exception {
16 years ago
public:
not_implemented(const std::string& reason) throw():
exception("feature is not implemented: "+reason) {
16 years ago
}
};
//----------------------------------------------------------------------------
class access_error: public exception {
16 years ago
public:
access_error(const std::string& reason) throw():
exception("smardcard access error: "+reason) {
}
};
//----------------------------------------------------------------------------
class wrong_pin: public access_error {
public:
wrong_pin(const std::string& reason) throw():
access_error("wrong pin: "+reason) {
16 years ago
}
};
//----------------------------------------------------------------------------
class runtime_error: public exception {
public:
runtime_error(const std::string& reason, const std::string& data) throw():
exception("runtime error, "+reason+": "+crypto::hex(data)) {}
};
//----------------------------------------------------------------------------
class neesting_error: public exception {
public:
neesting_error() throw():
exception("neesting error: more endTransaction than beginTransaction")
{}
};
15 years ago
//@}
16 years ago
15 years ago
//! @addtogroup pcsclib
//@{
16 years ago
//============================================================================
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.
16 years ago
@code
pcsc::Connection c;
{
Transaction t(c.reader("name"));
[...] // do some stuff, possible exceptions thrown
if (problem) return; // automatically ended
16 years ago
[...]
t.end(); // ended if we reach this line
[...]
} // also ended, unless commit reaced
@endcode */
16 years ago
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(mrw::Shared<Reader> r): _reader(r), _running(true) {
CRYPTOLOG("log");
_reader->beginTransaction();
16 years ago
}
//! Cancels the transaction if not yet finished.
~Transaction() try {
CRYPTOLOG("log");
end();
16 years ago
} catch (...) {
if (!std::uncaught_exception()) throw;
}
//! Ends the running transaction.
void end() {
if (_running) _reader->endTransaction();
16 years ago
_running = false;
}
private:
mrw::Shared<Reader> _reader;
16 years ago
bool _running;
};
//! State and attribute list of a reader.
class Status {
public:
Status(unsigned long s, const std::string& a): state(s), atr(a) {}
16 years ago
const unsigned long state;
const std::string atr;
16 years ago
};
//.............................................................methods
public:
//! Disconnects connection.
~Reader() {
CRYPTOLOG("Disconnect Reader");
_state = SCardDisconnect(_id, SCARD_RESET_CARD);
if (!std::uncaught_exception())
_connection->check("disconnect smartcard");
16 years ago
}
//! Get reader status.
Status status() {
16 years ago
DWORD dummy(0);
DWORD s;
DWORD len(MAX_ATR_SIZE);
16 years ago
unsigned char a[len];
check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len),
"query smartcard status");
16 years ago
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);
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);
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);
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.*/
16 years ago
std::string transmit(std::string in) {
16 years ago
DWORD len(1024); // arbitrary
16 years ago
unsigned char buff[len];
SCARD_IO_REQUEST rPci;
rPci.dwProtocol = pci()->dwProtocol;
rPci.cbPciLength = sizeof(rPci);
// log only in verbose debuggung; could log pins
CRYPTOLOG_VERBOSE("SCardTransmit: "<<crypto::hex(in));
check(SCardTransmit(_id, &rPci,
16 years ago
(unsigned char*)in.c_str(), in.size(),
0, buff, &len),
"smartcard transmit message "+crypto::hex(in));
//CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len)));
16 years ago
return std::string((char*)buff, len);
}
//! Transmit control command and data to the reader.
/*!
* @note Take care: Strings may contain embedded @c 0.
*/
std::string control(unsigned long controlCode,
std::string in) {
DWORD len(256); // arbitrary
UCHAR dataBuffer[256];
CRYPTOLOG("SCardControl: "<<"Command: "<<controlCode);
CRYPTOLOG(" -> "<<crypto::hex(in));
check(SCardControl(_id, controlCode,
(unsigned char*)in.c_str(), in.size(),
dataBuffer, sizeof(dataBuffer), &len),
"smartcard control message sent");
CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len)));
return std::string((char*)dataBuffer, len);
}
16 years ago
//! @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;
16 years ago
}
//...........................................................variables
public:
const std::string name;
//.............................................................methods
private:
//! Use scoped transactions with @ref Transaction
/*! Calls @c SCardBeginTransaction unless it's already inside
a transaction. */
16 years ago
void beginTransaction() {
if (++_neesting==1) {
CRYPTOLOG("open transaction");
check(SCardBeginTransaction(_id), "smartcard begin transaction");
}
16 years ago
}
//! 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) {
CRYPTOLOG("close transaction");
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD),
"smartcard end transaction");
} else if (_neesting<0) {
_neesting = 0;
throw neesting_error();
}
16 years ago
}
/*! @throw not_implemented if _protocol is unknown. */
16 years ago
const SCARD_IO_REQUEST* pci() {
16 years ago
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");
16 years ago
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="") {
16 years ago
_state = state;
return _connection->check(state, context);
16 years ago
}
//! Only Connection is allowed to instanciate.
friend class Connection;
//! Establishes a connection to the given named cardreader
Reader(const std::string& nm, const Connection& c,
DWORD mode=SCARD_SHARE_SHARED,
DWORD protocol=SCARD_PROTOCOL_T1):
16 years ago
name(nm), _connection(c) {
CRYPTOLOG("Connect Reader");
check(SCardConnect(_connection->id(), strconv(name).c_str(),
mode, protocol,
&_id, &_protocol),
"connect smartcard \""+name+"\"");
16 years ago
}
//! forbidden
Reader();
//...........................................................variables
private:
mrw::Shared<Connection> _connection;
16 years ago
SCARDHANDLE _id;
DWORD _state;
16 years ago
DWORD _protocol;
static int _neesting;
16 years ago
};
//------------------------------------------------------------------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):
_connectionlifetime(connectionlifetime(s, exceptions)) {
++connectionlifetimecounter();
CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter());
check("establish smartcard context");
16 years ago
}
Connection(const Connection& o) {
++connectionlifetimecounter();
*this = o;
}
16 years ago
//! Closes the connection (releases the smartcard context)
~Connection() {
// connection is closed, when _connectionlifetime is destructed
if (--connectionlifetimecounter()==0) {
CRYPTOLOG("Delete Connection");
delete connectionlifetime();
connectionlifetime()=0;
}
CRYPTOLOG("Connection Counter is now: "<<connectionlifetimecounter());
16 years ago
}
//! 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));
16 years ago
DWORD num(0);
if (!check(SCardListReaders(_connectionlifetime->id(),
groups.size()?strconv(grp).data():0, 0,
&num),
"smartcard get size of readers of groups "+grp))
16 years ago
return res;
CRYPTOLOG("size of readers: "<<num);
if (!num) return res;
16 years ago
std::auto_ptr<char_t> nm(new char_t[num]);
if (!check(SCardListReaders(_connectionlifetime->id(),
groups.size()?strconv(grp).data():0,
nm.get(), &num),
"smartcard list reader names of groups "+grp))
16 years ago
return res;
CRYPTOLOG("got all readers, size is "<<num);
if (!num) return res;
CRYPTOLOG("list of readers: "
<<crypto::readable(std::string(nm.get(), num-1)));
16 years ago
return res = split(strconv(string(nm.get(), num-1)));
16 years ago
}
//! 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. */
mrw::Shared<Reader> reader(const std::string& name) {
return _connectionlifetime->reader(name, this);
16 years ago
}
// //! 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) {
16 years ago
// }
//! Find all readers with a given ATR.
/*! @param atr full or partial ATR to match to the reader's ATR
@returns list of readers that contain @c atr in their ATR */
Strings getReadersWithAtr(const std::string& atr) {
Strings res;
pcsc::Connection::Strings readers(scan());
for (pcsc::Connection::Strings::const_iterator it(readers.begin());
11 years ago
it!=readers.end(); ++it)
if (crypto::hex(reader(*it)->status().atr).find(atr)!=string::npos)
res.push_back(*it);
return res;
}
16 years ago
//! @c false if last operation was not successful
operator bool() const {
return *_connectionlifetime;
16 years ago
}
//................................................................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="") {
_connectionlifetime->state(state);
return check(context);
16 years ago
}
16 years ago
//! 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="") {
return _connectionlifetime->check(context);
16 years ago
}
//! 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;
16 years ago
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';
}
16 years ago
return res;
}
//! Connection id
SCARDCONTEXT id() {
return _connectionlifetime->id();
}
//! @c true if exceptions are thrown
bool exc() {
return _connectionlifetime->exc();
}
16 years ago
//..............................................................variables
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)) {
CRYPTOLOG("Open Connection");
check("establish smartcard context");
}
//! Closes the connection (releases the smartcard context)
~ConnectionLifetime() {
CRYPTOLOG("Close Connection");
_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()) {
if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(context+": "+error());
} else {
throw access_error(context+": "+error());
}
} else {
if (_state==SCARD_W_WRONG_CHV) {
throw wrong_pin(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"
<<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();
}
//! set state
void state(long s) {
_state = s;
}
//! @returns state
long state() {
return _state;
}
//! @returns connection id
SCARDCONTEXT id() {
return _id;
}
bool exc() {
return _exc;
}
//! 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. */
mrw::Shared<Reader> reader(const std::string& name, Connection* c) {
CRYPTOLOG("get reader: "<<name<<" from "<<(void*)&_readers);
if (_readers.find(name)==_readers.end())
_readers.insert(std::make_pair(name, new Reader(name, *c)));
return _readers.find(name)->second;
}
private:
bool _exc;
SCARDCONTEXT _id;
long _state;
16 years ago
//! Readers are closed when the last shared object is destructed
std::map<std::string, mrw::Shared<Reader> > _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. */
static ConnectionLifetime*&
connectionlifetime(Scope s=USER, bool exc=true) {
static ConnectionLifetime* instance(0);
if (instance==0) {
CRYPTOLOG("New Connection");
instance = new ConnectionLifetime(s, exc);
}
return instance;
}
static int& connectionlifetimecounter() {
static int instance(0);
return instance;
}
ConnectionLifetime* _connectionlifetime;
16 years ago
};
15 years ago
//@}
16 years ago
}
15 years ago
//@}
16 years ago
#endif