2009-06-17 12:30:45 +00:00
|
|
|
/*! @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
|
|
|
|
|
2009-09-21 07:43:32 +00:00
|
|
|
#include <cryptaux.hxx>
|
|
|
|
|
2009-07-16 07:23:46 +00:00
|
|
|
#include <string>
|
|
|
|
|
2014-04-28 09:07:38 +00:00
|
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
|
2009-10-21 08:52:04 +00:00
|
|
|
#undef UNICODE
|
2011-11-10 13:28:18 +00:00
|
|
|
#undef DATADIR
|
2014-04-28 09:12:40 +00:00
|
|
|
#include <winscard.h>
|
2009-10-21 08:52:04 +00:00
|
|
|
#undef ERROR
|
2009-07-10 10:02:33 +00:00
|
|
|
#ifndef MAX_ATR_SIZE
|
|
|
|
#define MAX_ATR_SIZE 33
|
|
|
|
#endif
|
2009-08-19 13:42:45 +00:00
|
|
|
namespace pcsc {
|
2010-08-03 13:48:47 +00:00
|
|
|
|
2009-10-21 08:52:04 +00:00
|
|
|
#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
|
2009-07-10 10:02:33 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
#include <PCSC/pcsclite.h>
|
|
|
|
#include <PCSC/wintypes.h>
|
2009-08-19 13:42:45 +00:00
|
|
|
#include <PCSC/winscard.h>
|
|
|
|
namespace pcsc {
|
2009-10-07 07:22:20 +00:00
|
|
|
inline const std::string& strconv(const std::string& s) {
|
2009-08-19 13:42:45 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
typedef char char_t;
|
|
|
|
typedef std::string string;
|
2009-07-10 10:02:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
2009-06-17 12:30:45 +00:00
|
|
|
|
2013-06-13 12:38:15 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
2014-04-03 11:21:18 +00:00
|
|
|
#include <mrw/checkcxx11.hxx>
|
2013-06-13 12:38:15 +00:00
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
#include <iomanip>
|
|
|
|
|
2009-09-18 11:41:30 +00:00
|
|
|
/*! @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
|
2009-06-17 12:30:45 +00:00
|
|
|
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);
|
|
|
|
- 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. */
|
2009-09-18 11:41:30 +00:00
|
|
|
//@{
|
|
|
|
/*! @defgroup pcsclib PCSC C++ Library */
|
|
|
|
/*! @defgroup pcscexceptions PCSC Exceptions */
|
|
|
|
|
2014-01-31 13:32:31 +00:00
|
|
|
//! @ref gpcsc @copydoc gpcsc
|
2009-06-17 12:30:45 +00:00
|
|
|
namespace pcsc {
|
|
|
|
|
|
|
|
//============================================================================
|
2009-09-29 07:24:04 +00:00
|
|
|
//! @addtogroup pcscexceptions
|
2009-09-18 11:41:30 +00:00
|
|
|
//@{
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
2009-06-17 12:30:45 +00:00
|
|
|
class exception: public std::exception {
|
|
|
|
public:
|
2013-11-06 12:24:52 +00:00
|
|
|
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {
|
|
|
|
CRYPTOLOG("ERROR: "<<what());
|
|
|
|
}
|
2009-06-17 12:30:45 +00:00
|
|
|
~exception() throw() {}
|
|
|
|
const char* what() const throw() {
|
|
|
|
return _what.c_str();
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::string _what;
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-07-09 12:28:10 +00:00
|
|
|
class not_implemented: public exception {
|
2009-06-17 12:30:45 +00:00
|
|
|
public:
|
|
|
|
not_implemented(const std::string& reason) throw():
|
2013-11-06 12:24:52 +00:00
|
|
|
exception("feature is not implemented: "+reason) {
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
2009-07-09 12:28:10 +00:00
|
|
|
class access_error: public exception {
|
2009-06-17 12:30:45 +00:00
|
|
|
public:
|
|
|
|
access_error(const std::string& reason) throw():
|
2013-11-06 12:24:52 +00:00
|
|
|
exception("smardcard access error: "+reason) {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class wrong_pin: public access_error {
|
|
|
|
public:
|
|
|
|
wrong_pin(const std::string& reason) throw():
|
|
|
|
access_error("wrong pin: "+reason) {
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
};
|
2009-10-07 07:22:20 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class runtime_error: public exception {
|
|
|
|
public:
|
|
|
|
runtime_error(const std::string& reason, const std::string& data) throw():
|
2013-11-06 12:24:52 +00:00
|
|
|
exception("runtime error, "+reason+": "+crypto::hex(data)) {}
|
2009-10-07 07:22:20 +00:00
|
|
|
};
|
2010-09-27 06:53:25 +00:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
class neesting_error: public exception {
|
|
|
|
public:
|
|
|
|
neesting_error() throw():
|
|
|
|
exception("neesting error: more endTransaction than beginTransaction")
|
|
|
|
{}
|
|
|
|
};
|
2009-09-18 11:41:30 +00:00
|
|
|
//@}
|
2009-06-17 12:30:45 +00:00
|
|
|
|
2009-09-18 11:41:30 +00:00
|
|
|
//! @addtogroup pcsclib
|
|
|
|
//@{
|
2014-11-11 13:56:21 +00:00
|
|
|
|
2009-06-17 12:30:45 +00:00
|
|
|
//============================================================================
|
|
|
|
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
|
2010-09-27 06:53:25 +00:00
|
|
|
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.
|
2009-06-17 12:30:45 +00:00
|
|
|
|
|
|
|
@code
|
|
|
|
pcsc::Connection c;
|
|
|
|
{
|
|
|
|
Transaction t(c.reader("name"));
|
|
|
|
[...] // do some stuff, possible exceptions thrown
|
2010-09-27 06:53:25 +00:00
|
|
|
if (problem) return; // automatically ended
|
2009-06-17 12:30:45 +00:00
|
|
|
[...]
|
2010-09-27 06:53:25 +00:00
|
|
|
t.end(); // ended if we reach this line
|
|
|
|
[...]
|
|
|
|
} // also ended, unless commit reaced
|
|
|
|
@endcode */
|
2009-06-17 12:30:45 +00:00
|
|
|
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. */
|
2014-04-03 11:21:18 +00:00
|
|
|
Transaction(std::shared_ptr<Reader> r):
|
2014-03-26 15:07:54 +00:00
|
|
|
_reader(r), _running(true) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2013-10-15 11:57:29 +00:00
|
|
|
_reader->beginTransaction();
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
//! Cancels the transaction if not yet finished.
|
|
|
|
~Transaction() try {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("log");
|
2010-09-27 06:53:25 +00:00
|
|
|
end();
|
2009-06-17 12:30:45 +00:00
|
|
|
} catch (...) {
|
|
|
|
if (!std::uncaught_exception()) throw;
|
|
|
|
}
|
2010-09-27 06:53:25 +00:00
|
|
|
//! Ends the running transaction.
|
|
|
|
void end() {
|
2013-10-15 11:57:29 +00:00
|
|
|
if (_running) _reader->endTransaction();
|
2009-06-17 12:30:45 +00:00
|
|
|
_running = false;
|
|
|
|
}
|
|
|
|
private:
|
2014-04-03 11:21:18 +00:00
|
|
|
std::shared_ptr<Reader> _reader;
|
2009-06-17 12:30:45 +00:00
|
|
|
bool _running;
|
|
|
|
};
|
|
|
|
|
|
|
|
//! State and attribute list of a reader.
|
|
|
|
class Status {
|
|
|
|
public:
|
2014-09-16 08:01:29 +00:00
|
|
|
Status(DWORD s, const std::string& a):
|
2014-09-16 07:47:26 +00:00
|
|
|
state(s), atr(a) {}
|
2014-09-16 08:01:29 +00:00
|
|
|
const DWORD state;
|
2009-10-07 07:22:20 +00:00
|
|
|
const std::string atr;
|
2009-06-17 12:30:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//.............................................................methods
|
|
|
|
public:
|
|
|
|
|
|
|
|
//! Disconnects connection.
|
|
|
|
~Reader() {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("Disconnect Reader");
|
2009-07-16 07:23:46 +00:00
|
|
|
_state = SCardDisconnect(_id, SCARD_RESET_CARD);
|
2009-07-14 09:16:59 +00:00
|
|
|
if (!std::uncaught_exception())
|
2014-03-21 12:09:50 +00:00
|
|
|
_connection->check(_state, "disconnect smartcard");
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Get reader status.
|
|
|
|
Status status() {
|
2009-07-10 10:02:33 +00:00
|
|
|
DWORD dummy(0);
|
|
|
|
DWORD s;
|
2011-03-29 12:54:00 +00:00
|
|
|
DWORD len(MAX_ATR_SIZE);
|
2014-04-01 13:10:51 +00:00
|
|
|
unsigned char a[MAX_ATR_SIZE];
|
2009-07-14 09:16:59 +00:00
|
|
|
check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len),
|
|
|
|
"query smartcard status");
|
2009-06-17 12:30:45 +00:00
|
|
|
return Status(s, std::string((char*)a, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Transmit data to reader.
|
2009-10-07 07:22:20 +00:00
|
|
|
/*! @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);
|
|
|
|
}
|
2009-10-14 13:31:27 +00:00
|
|
|
|
|
|
|
//! 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);
|
|
|
|
}
|
2009-10-07 07:22:20 +00:00
|
|
|
|
|
|
|
//! 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.*/
|
2009-06-17 12:30:45 +00:00
|
|
|
std::string transmit(std::string in) {
|
2014-04-01 13:10:51 +00:00
|
|
|
const DWORD bufflen(1024);
|
|
|
|
DWORD len(bufflen); // arbitrary
|
|
|
|
unsigned char buff[bufflen];
|
2009-06-17 12:30:45 +00:00
|
|
|
SCARD_IO_REQUEST rPci;
|
2009-07-16 07:23:46 +00:00
|
|
|
rPci.dwProtocol = pci()->dwProtocol;
|
|
|
|
rPci.cbPciLength = sizeof(rPci);
|
2013-11-06 12:24:52 +00:00
|
|
|
// log only in verbose debuggung; could log pins
|
|
|
|
CRYPTOLOG_VERBOSE("SCardTransmit: "<<crypto::hex(in));
|
2014-11-11 13:56:21 +00:00
|
|
|
try {
|
|
|
|
check(SCardTransmit(_id, &rPci,
|
|
|
|
(LPCBYTE)in.c_str(),
|
|
|
|
in.size(),
|
|
|
|
0, buff, &len),
|
|
|
|
"smartcard transmit message "+crypto::hex(in));
|
2014-12-01 10:08:38 +00:00
|
|
|
} catch (std::exception& x) {
|
|
|
|
CRYPTOLOG("failed with "<<x.what());
|
2014-11-11 13:56:21 +00:00
|
|
|
// try to fix Apple's Mac OS X 10.10 implementation bug
|
|
|
|
# ifdef __APPLE__
|
|
|
|
/*! @bug Work around Mac OSX 10.10 bug. On Mac OSX
|
|
|
|
10.10 there is a bug in PCSC: After a
|
|
|
|
reconnect, first transaction (SCardTransmit)
|
|
|
|
fails with SCARD_W_RESET_CARD
|
|
|
|
(0x80100068). */
|
2014-12-01 10:08:38 +00:00
|
|
|
for (int cnt(0); cnt<10 && _state==SCARD_W_RESET_CARD; ++cnt) {
|
|
|
|
// just try to resend
|
2014-11-12 07:54:40 +00:00
|
|
|
CRYPTOLOG("Mac OS X 10.10 implementation bug: "
|
|
|
|
"On Mac OSX 10.10 there is a bug in "
|
|
|
|
"PCSC: After a reconnect, first "
|
|
|
|
"transaction (SCardTransmit) fails "
|
|
|
|
"with SCARD_W_RESET_CARD (0x80100068). "
|
2014-12-01 10:08:38 +00:00
|
|
|
"Retry Nr. "<<cnt);
|
2014-12-01 09:08:42 +00:00
|
|
|
try {
|
2014-12-01 10:08:38 +00:00
|
|
|
reconnect();
|
2014-12-01 10:27:23 +00:00
|
|
|
if (check(SCardTransmit(_id, &rPci,
|
|
|
|
(LPCBYTE)in.c_str(),
|
|
|
|
in.size(),
|
|
|
|
0, buff, &len),
|
|
|
|
"smartcard transmit resend message "
|
|
|
|
+crypto::hex(in))) {
|
|
|
|
CRYPTOLOG("successful after retry nr. "<<cnt);
|
|
|
|
return std::string((char*)buff, len);
|
|
|
|
}
|
2014-12-01 10:08:38 +00:00
|
|
|
} catch (std::exception& x) {
|
2014-12-01 10:27:23 +00:00
|
|
|
CRYPTOLOG("failed again with "<<x.what());
|
2014-12-01 09:08:42 +00:00
|
|
|
}
|
2014-11-11 13:56:21 +00:00
|
|
|
}
|
|
|
|
# endif
|
2014-12-01 10:27:23 +00:00
|
|
|
CRYPTOLOG("definitely failed with "<<x.what());
|
2014-12-01 09:08:42 +00:00
|
|
|
throw; // just rethrow otherwise
|
2014-11-11 13:56:21 +00:00
|
|
|
}
|
2013-11-06 12:24:52 +00:00
|
|
|
//CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len)));
|
2009-06-17 12:30:45 +00:00
|
|
|
return std::string((char*)buff, len);
|
|
|
|
}
|
|
|
|
|
2012-03-14 09:54:25 +00:00
|
|
|
//! Transmit control command and data to the reader.
|
|
|
|
/*!
|
|
|
|
* @note Take care: Strings may contain embedded @c 0.
|
|
|
|
*/
|
2014-09-16 08:01:29 +00:00
|
|
|
std::string control(DWORD controlCode,
|
2012-03-14 09:54:25 +00:00
|
|
|
std::string in) {
|
|
|
|
DWORD len(256); // arbitrary
|
|
|
|
UCHAR dataBuffer[256];
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("SCardControl: "<<"Command: "<<controlCode);
|
|
|
|
CRYPTOLOG(" -> "<<crypto::hex(in));
|
2012-03-14 09:54:25 +00:00
|
|
|
check(SCardControl(_id, controlCode,
|
2014-04-01 13:10:51 +00:00
|
|
|
(LPCBYTE)in.c_str(), in.size(),
|
2012-03-14 09:54:25 +00:00
|
|
|
dataBuffer, sizeof(dataBuffer), &len),
|
|
|
|
"smartcard control message sent");
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len)));
|
2012-03-14 09:54:25 +00:00
|
|
|
return std::string((char*)dataBuffer, len);
|
|
|
|
}
|
|
|
|
|
2009-06-17 12:30:45 +00:00
|
|
|
//! @c false if last operation was not successful
|
|
|
|
operator bool() const {
|
2009-07-14 11:48:27 +00:00
|
|
|
// 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
|
2009-07-16 07:23:46 +00:00
|
|
|
//return (_state>>30&3)==0;
|
|
|
|
return _state==SCARD_S_SUCCESS;
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//...........................................................variables
|
|
|
|
public:
|
|
|
|
|
|
|
|
const std::string name;
|
|
|
|
|
|
|
|
//.............................................................methods
|
|
|
|
private:
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
2010-09-27 06:53:25 +00:00
|
|
|
/*! Calls @c SCardBeginTransaction unless it's already inside
|
|
|
|
a transaction. */
|
2009-06-17 12:30:45 +00:00
|
|
|
void beginTransaction() {
|
2013-11-06 12:24:52 +00:00
|
|
|
if (++_neesting==1) {
|
|
|
|
CRYPTOLOG("open transaction");
|
2010-09-27 06:53:25 +00:00
|
|
|
check(SCardBeginTransaction(_id), "smartcard begin transaction");
|
2013-11-06 12:24:52 +00:00
|
|
|
}
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
2010-09-27 06:53:25 +00:00
|
|
|
/*! 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() {
|
2013-11-06 12:24:52 +00:00
|
|
|
if (--_neesting==0) {
|
|
|
|
CRYPTOLOG("close transaction");
|
2010-09-27 06:53:25 +00:00
|
|
|
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD),
|
|
|
|
"smartcard end transaction");
|
2013-11-06 12:24:52 +00:00
|
|
|
} else if (_neesting<0) {
|
2010-09-27 06:53:25 +00:00
|
|
|
_neesting = 0;
|
|
|
|
throw neesting_error();
|
|
|
|
}
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*! @throw not_implemented if _protocol is unknown. */
|
2009-07-10 10:02:33 +00:00
|
|
|
const SCARD_IO_REQUEST* pci() {
|
2009-06-17 12:30:45 +00:00
|
|
|
switch(_protocol) {
|
|
|
|
case SCARD_PROTOCOL_T0: return SCARD_PCI_T0;
|
|
|
|
case SCARD_PROTOCOL_T1: return SCARD_PCI_T1;
|
|
|
|
}
|
2013-10-15 11:57:29 +00:00
|
|
|
if (_connection->exc()) throw not_implemented("unknown protocol");
|
2009-06-17 12:30:45 +00:00
|
|
|
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. */
|
2014-09-16 07:47:26 +00:00
|
|
|
bool check(DWORD state, const std::string context="") {
|
2009-06-17 12:30:45 +00:00
|
|
|
_state = state;
|
2013-10-15 11:57:29 +00:00
|
|
|
return _connection->check(state, context);
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
2014-12-01 10:08:38 +00:00
|
|
|
//! Reconnect SmartCard After Reset
|
|
|
|
/*! @param mode one of
|
|
|
|
- @c SCARD_LEAVE_CARD
|
|
|
|
Do not do anything special on reconnect.
|
|
|
|
- @c SCARD_RESET_CARD
|
|
|
|
Reset the card (Warm Reset).
|
|
|
|
- @c SCARD_UNPOWER_CARD
|
|
|
|
Power down the card and reset it (Cold Reset). */
|
|
|
|
void reconnect(DWORD mode=SCARD_LEAVE_CARD) {
|
|
|
|
check(SCardReconnect(_id, _mode, _protocol, mode, &_protocol));
|
|
|
|
}
|
|
|
|
|
2009-06-17 12:30:45 +00:00
|
|
|
//! Only Connection is allowed to instanciate.
|
|
|
|
friend class Connection;
|
|
|
|
|
|
|
|
//! Establishes a connection to the given named cardreader
|
2014-04-03 11:21:18 +00:00
|
|
|
Reader(const std::string& nm, std::shared_ptr<Connection> c,
|
2009-07-16 07:23:46 +00:00
|
|
|
DWORD mode=SCARD_SHARE_SHARED,
|
|
|
|
DWORD protocol=SCARD_PROTOCOL_T1):
|
2014-12-01 10:08:38 +00:00
|
|
|
name(nm), _connection(c), _mode(mode) {
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("Connect Reader");
|
2013-10-15 11:57:29 +00:00
|
|
|
check(SCardConnect(_connection->id(), strconv(name).c_str(),
|
2014-12-01 10:08:38 +00:00
|
|
|
_mode, protocol,
|
2009-07-14 09:16:59 +00:00
|
|
|
&_id, &_protocol),
|
2013-10-21 07:10:46 +00:00
|
|
|
"connect smartcard \""+name+"\"");
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//! forbidden
|
|
|
|
Reader();
|
|
|
|
|
|
|
|
//...........................................................variables
|
|
|
|
private:
|
|
|
|
|
2014-04-03 11:21:18 +00:00
|
|
|
std::shared_ptr<Connection> _connection;
|
2009-07-10 10:02:33 +00:00
|
|
|
SCARDHANDLE _id;
|
2009-07-14 09:16:59 +00:00
|
|
|
DWORD _state;
|
2014-12-01 10:08:38 +00:00
|
|
|
DWORD _mode;
|
2009-07-10 10:02:33 +00:00
|
|
|
DWORD _protocol;
|
2010-09-27 06:53:25 +00:00
|
|
|
static int _neesting;
|
2009-06-17 12:30:45 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
//------------------------------------------------------------------Reader
|
|
|
|
|
|
|
|
enum Scope {
|
|
|
|
USER = SCARD_SCOPE_USER,
|
|
|
|
TERMINAL = SCARD_SCOPE_TERMINAL,
|
|
|
|
SYSTEM = SCARD_SCOPE_SYSTEM
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::vector<std::string> Strings;
|
|
|
|
|
|
|
|
//................................................................methods
|
|
|
|
public:
|
|
|
|
|
|
|
|
//! Closes the connection (releases the smartcard context)
|
|
|
|
~Connection() {
|
2014-03-26 15:07:54 +00:00
|
|
|
CRYPTOLOG("Close Connection id="<<_id);
|
|
|
|
_state = SCardReleaseContext(_id);
|
|
|
|
if (!std::uncaught_exception()) check("smartcard release context");
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Scans for available readers from a specified list of groups.
|
|
|
|
/*! Defaults to all groups. */
|
2014-03-26 15:07:54 +00:00
|
|
|
static Strings scan(const Strings& groups = Strings(),
|
|
|
|
Scope s=USER, bool exceptions=true) {
|
|
|
|
Connection c(s, exceptions);
|
2009-06-17 12:30:45 +00:00
|
|
|
Strings res;
|
2014-03-26 15:07:54 +00:00
|
|
|
std::string grp(c.join(groups));
|
2009-07-10 10:02:33 +00:00
|
|
|
DWORD num(0);
|
2014-03-26 15:07:54 +00:00
|
|
|
if (!c.check(SCardListReaders(c._id,
|
|
|
|
groups.size()?strconv(grp).data():0, 0,
|
|
|
|
&num),
|
|
|
|
"smartcard get size of readers of groups "+grp))
|
2009-06-17 12:30:45 +00:00
|
|
|
return res;
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("size of readers: "<<num);
|
2011-04-15 09:42:11 +00:00
|
|
|
if (!num) return res;
|
2009-07-10 10:02:33 +00:00
|
|
|
std::auto_ptr<char_t> nm(new char_t[num]);
|
2014-03-26 15:07:54 +00:00
|
|
|
if (!c.check(SCardListReaders(c._id,
|
|
|
|
groups.size()?strconv(grp).data():0,
|
|
|
|
nm.get(), &num),
|
|
|
|
"smartcard list reader names of groups "+grp))
|
2009-06-17 12:30:45 +00:00
|
|
|
return res;
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("got all readers, size is "<<num);
|
2011-04-15 09:42:11 +00:00
|
|
|
if (!num) return res;
|
2013-11-06 12:24:52 +00:00
|
|
|
CRYPTOLOG("list of readers: "
|
2014-03-26 15:07:54 +00:00
|
|
|
<<crypto::readable(std::string(nm.get(), num-1)));
|
|
|
|
return res = c.split(strconv(string(nm.get(), num-1)));
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
2013-10-10 09:13:19 +00:00
|
|
|
//! Find all readers with a given ATR.
|
|
|
|
/*! @param atr full or partial ATR to match to the reader's ATR
|
2014-04-01 13:10:51 +00:00
|
|
|
@param s scope of scanning
|
|
|
|
@param exceptions whether exeptions should be thrown on error
|
2013-10-10 09:13:19 +00:00
|
|
|
@returns list of readers that contain @c atr in their ATR */
|
2014-03-26 15:07:54 +00:00
|
|
|
static Strings getReadersWithAtr(const std::string& atr,
|
|
|
|
Scope s=USER, bool exceptions=true) {
|
2014-05-06 16:14:54 +00:00
|
|
|
CRYPTOLOG("getting all readers with atr: "<<atr);
|
2014-03-26 15:07:54 +00:00
|
|
|
Connection c(s, exceptions);
|
2013-10-10 09:13:19 +00:00
|
|
|
Strings res;
|
2014-03-26 15:07:54 +00:00
|
|
|
pcsc::Connection::Strings readers(c.scan());
|
2013-10-10 09:13:19 +00:00
|
|
|
for (pcsc::Connection::Strings::const_iterator it(readers.begin());
|
2014-05-06 16:14:54 +00:00
|
|
|
it!=readers.end(); ++it)
|
|
|
|
try {
|
|
|
|
if (crypto::hex(c.reader(*it)->status().atr).find(atr)
|
|
|
|
!=string::npos)
|
2014-05-20 12:27:25 +00:00
|
|
|
CRYPTOLOG("found reader: "<<(*it));
|
2014-05-06 16:14:54 +00:00
|
|
|
res.push_back(*it);
|
|
|
|
} catch (std::exception& x) { // ignore unusable readers
|
|
|
|
CRYPTOLOG("ignored unusable reader: "<<x.what());
|
|
|
|
}
|
2013-10-10 09:13:19 +00:00
|
|
|
return res;
|
|
|
|
}
|
2009-06-17 12:30:45 +00:00
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
//! 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. */
|
2014-04-03 11:21:18 +00:00
|
|
|
static std::shared_ptr<Reader> reader(const std::string& name,
|
2014-03-26 15:07:54 +00:00
|
|
|
Scope s=USER, bool exceptions=true) {
|
|
|
|
CRYPTOLOG("get reader: "<<name);
|
2014-04-03 11:21:18 +00:00
|
|
|
return std::shared_ptr<Reader>
|
2014-03-26 15:07:54 +00:00
|
|
|
(new Reader(name,
|
2014-04-03 11:21:18 +00:00
|
|
|
std::shared_ptr<Connection>
|
2014-03-26 15:07:54 +00:00
|
|
|
(new Connection(s, exceptions))));
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
|
2009-06-17 12:30:45 +00:00
|
|
|
//................................................................methods
|
|
|
|
private:
|
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
//! Opens a connection (establishes a smartcard context)
|
|
|
|
/*! The errorhandling is defined with the @c exceptions flag:
|
2013-10-15 11:57:29 +00:00
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
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), _s(s),
|
|
|
|
_state(SCardEstablishContext(s, 0, 0, &_id)) {
|
|
|
|
CRYPTOLOG("Open Connection id="<<_id);
|
|
|
|
check("establish smartcard context");
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//! Splits a buffer with 0 separators into a vector of strings.
|
2014-03-26 15:07:54 +00:00
|
|
|
static Strings split(const std::string& in) {
|
2009-06-17 12:30:45 +00:00
|
|
|
Strings res;
|
2009-08-25 14:05:41 +00:00
|
|
|
for (std::string::size_type pos(0); pos<in.size() && in[pos]!=0;
|
2009-06-17 12:30:45 +00:00
|
|
|
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.
|
2014-03-26 15:07:54 +00:00
|
|
|
static std::string join(const Strings& in) {
|
2009-06-17 12:30:45 +00:00
|
|
|
std::string res;
|
2009-08-25 14:05:41 +00:00
|
|
|
if (in.size()) {
|
|
|
|
for (Strings::const_iterator it(in.begin());
|
|
|
|
it!=in.end(); ++it)
|
|
|
|
res+=*it+'\0';
|
|
|
|
res+='\0';
|
|
|
|
}
|
2009-06-17 12:30:45 +00:00
|
|
|
return res;
|
|
|
|
}
|
2013-10-15 11:57:29 +00:00
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
operator bool() const {
|
|
|
|
#ifdef WIN32
|
|
|
|
return (_state>>30&3)==0;
|
|
|
|
#else
|
|
|
|
return _state==SCARD_S_SUCCESS;
|
|
|
|
#endif
|
2013-10-15 11:57:29 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
//! Throws an exception if neccessary.
|
|
|
|
/*! @throw access_error if it is instanciated for exceptions and
|
|
|
|
an error occured in the last command. */
|
2014-09-16 07:47:26 +00:00
|
|
|
bool check(DWORD s, const std::string& context="") {
|
2014-04-01 13:10:51 +00:00
|
|
|
_state = s;
|
|
|
|
return check(context);
|
2013-10-15 11:57:29 +00:00
|
|
|
}
|
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
//! Throws an exception if neccessary.
|
|
|
|
/*! @throw access_error if it is instanciated for exceptions and
|
2013-10-15 11:57:29 +00:00
|
|
|
an error occured in the last command. */
|
2014-03-26 15:07:54 +00:00
|
|
|
bool check(const std::string& context="") {
|
|
|
|
if (_exc&&!*this) {
|
|
|
|
if (context.size()) {
|
2013-11-12 15:40:55 +00:00
|
|
|
#ifdef SCARD_W_WRONG_CHV
|
2014-03-26 15:07:54 +00:00
|
|
|
if (_state==SCARD_W_WRONG_CHV) {
|
|
|
|
throw wrong_pin(context+": "+error());
|
|
|
|
} else {
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
2014-03-26 15:07:54 +00:00
|
|
|
throw access_error(context+": "+error());
|
2013-11-12 15:40:55 +00:00
|
|
|
#ifdef SCARD_W_WRONG_CHV
|
2014-03-26 15:07:54 +00:00
|
|
|
}
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
2014-03-26 15:07:54 +00:00
|
|
|
} else {
|
2013-11-12 15:40:55 +00:00
|
|
|
#ifdef SCARD_W_WRONG_CHV
|
2014-03-26 15:07:54 +00:00
|
|
|
if (_state==SCARD_W_WRONG_CHV) {
|
|
|
|
throw wrong_pin(error());
|
|
|
|
} else {
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
2014-03-26 15:07:54 +00:00
|
|
|
throw access_error(error());
|
2013-11-12 15:40:55 +00:00
|
|
|
#ifdef SCARD_W_WRONG_CHV
|
2013-11-11 11:49:09 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
#endif
|
2013-10-15 11:57:29 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Get the describing text of the last error
|
|
|
|
std::string error() const {
|
|
|
|
std::stringstream ss;
|
|
|
|
switch (_state) {
|
2013-11-12 15:40:55 +00:00
|
|
|
#ifdef SCARD_E_CANCELLED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_CANCELLED:
|
|
|
|
ss<<"The action was canceled by an SCardCancel request.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_CANT_DISPOSE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_CANT_DISPOSE:
|
|
|
|
ss<<"The system could not dispose of the media in the requested"
|
|
|
|
<<" manner.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_CARD_UNSUPPORTED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_CARD_UNSUPPORTED:
|
|
|
|
ss<<"The smart card does not meet minimal requirements for"
|
|
|
|
<<" support.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_DUPLICATE_READER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_DUPLICATE_READER:
|
|
|
|
ss<<"The reader driver did not produce a unique reader name.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INSUFFICIENT_BUFFER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INSUFFICIENT_BUFFER:
|
|
|
|
ss<<"The data buffer for returned data is too small for the"
|
|
|
|
<<" returned data.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INVALID_ATR
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INVALID_ATR:
|
|
|
|
ss<<"An ATR string obtained from the registry is not a valid"
|
|
|
|
<<" ATR string.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INVALID_HANDLE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INVALID_HANDLE:
|
|
|
|
ss<<"The supplied handle was not valid.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INVALID_PARAMETER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INVALID_PARAMETER:
|
|
|
|
ss<<"One or more of the supplied parameters could not be properly"
|
|
|
|
<<" interpreted.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INVALID_TARGET
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INVALID_TARGET:
|
|
|
|
ss<<"Registry startup information is missing or not valid.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INVALID_VALUE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INVALID_VALUE:
|
|
|
|
ss<<"One or more of the supplied parameters values could not"
|
|
|
|
<<" be properly interpreted.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NOT_READY
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NOT_READY:
|
|
|
|
ss<<"The reader or smart card is not ready to accept commands.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NOT_TRANSACTED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NOT_TRANSACTED:
|
|
|
|
ss<<"An attempt was made to end a nonexistent transaction.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_MEMORY
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_MEMORY:
|
|
|
|
ss<<"Not enough memory available to complete this command.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_SERVICE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_SERVICE:
|
|
|
|
ss<<"The smart card resource manager is not running.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_SMARTCARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_SMARTCARD:
|
|
|
|
ss<<"The operation requires a smart card, but no smart card"
|
|
|
|
<<" is currently in the device.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_PCI_TOO_SMALL
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_PCI_TOO_SMALL:
|
|
|
|
ss<<"The PCI receive buffer was too small.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_PROTO_MISMATCH
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_PROTO_MISMATCH:
|
|
|
|
ss<<"The requested protocols are incompatible with the protocol"
|
|
|
|
<<" currently in use with the smart card.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_READER_UNAVAILABLE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_READER_UNAVAILABLE:
|
|
|
|
ss<<"The specified reader is not currently available for use.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_READER_UNSUPPORTED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_READER_UNSUPPORTED:
|
|
|
|
ss<<"The reader driver does not meet minimal requirements for"
|
|
|
|
<<" support.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_SERVICE_STOPPED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_SERVICE_STOPPED:
|
|
|
|
ss<<"The smart card resource manager has shut down.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_SHARING_VIOLATION
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_SHARING_VIOLATION:
|
|
|
|
ss<<"The smart card cannot be accessed because of other"
|
|
|
|
<<" outstanding connections.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_SYSTEM_CANCELLED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_SYSTEM_CANCELLED:
|
|
|
|
ss<<"The action was cancelled by the system, presumably to log"
|
|
|
|
<<" off or shut down.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_TIMEOUT
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_TIMEOUT:
|
|
|
|
ss<<"The user-specified time-out value has expired.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_UNKNOWN_CARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_UNKNOWN_CARD:
|
|
|
|
ss<<"The specified smart card name is not recognized.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_UNKNOWN_READER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_UNKNOWN_READER:
|
|
|
|
ss<<"The specified reader name is not recognized.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_F_COMM_ERROR
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_F_COMM_ERROR:
|
|
|
|
ss<<"An internal communications error has been detected.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_F_INTERNAL_ERROR
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_F_INTERNAL_ERROR:
|
|
|
|
ss<<"An internal consistency check failed.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_F_UNKNOWN_ERROR
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_F_UNKNOWN_ERROR:
|
|
|
|
ss<<"An internal error has been detected, but the source is"
|
|
|
|
<<" unknown.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_F_WAITED_TOO_LONG
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_F_WAITED_TOO_LONG:
|
|
|
|
ss<<"An internal consistency timer has expired.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_S_SUCCESS
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_S_SUCCESS:
|
|
|
|
ss<<"No error was encountered.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_REMOVED_CARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_REMOVED_CARD:
|
|
|
|
ss<<"The smart card has been removed, so that further"
|
|
|
|
<<" communication is not possible.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_RESET_CARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_RESET_CARD:
|
|
|
|
ss<<"The smart card was reset.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_UNPOWERED_CARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_UNPOWERED_CARD:
|
|
|
|
ss<<"Power has been removed from the smart card, so that"
|
|
|
|
<<" further communication is not possible.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_UNRESPONSIVE_CARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_UNRESPONSIVE_CARD:
|
|
|
|
ss<<"The smart card is not responding to a reset.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_UNSUPPORTED_CARD
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_UNSUPPORTED_CARD:
|
|
|
|
ss<<"The reader cannot communicate with the smart card,"
|
|
|
|
<<" due to ATR configuration conflicts.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_READERS_AVAILABLE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_READERS_AVAILABLE:
|
|
|
|
ss<<"No smart card reader is available.";
|
|
|
|
break;
|
2013-10-15 11:57:29 +00:00
|
|
|
#endif
|
2013-11-12 15:40:55 +00:00
|
|
|
#ifdef ERROR_BROKEN_PIPE
|
2014-03-26 15:07:54 +00:00
|
|
|
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;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_BAD_SEEK
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_BAD_SEEK:
|
|
|
|
ss<<"There was an error trying to set the smart card file"
|
|
|
|
<<" object pointer.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_CERTIFICATE_UNAVAILABLE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_CERTIFICATE_UNAVAILABLE:
|
|
|
|
ss<<"The requested certificate could not be obtained.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_COMM_DATA_LOST
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_COMM_DATA_LOST:
|
|
|
|
ss<<"A communications error with the smart card has been detected.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_DIR_NOT_FOUND
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_DIR_NOT_FOUND:
|
|
|
|
ss<<"The specified directory does not exist in the smart card.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_FILE_NOT_FOUND
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_FILE_NOT_FOUND:
|
|
|
|
ss<<"The specified file does not exist in the smart card.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_ICC_CREATEORDER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_ICC_CREATEORDER:
|
|
|
|
ss<<"The requested order of object creation is not supported.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_ICC_INSTALLATION
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_ICC_INSTALLATION:
|
|
|
|
ss<<"No primary provider can be found for the smart card.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_INVALID_CHV
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_INVALID_CHV:
|
|
|
|
ss<<"The supplied PIN is incorrect.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_ACCESS
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_ACCESS:
|
|
|
|
ss<<"Access is denied to this file.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_DIR
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_DIR:
|
|
|
|
ss<<"The supplied path does not represent a smart card directory.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_FILE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_FILE:
|
|
|
|
ss<<"The supplied path does not represent a smart card file.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_KEY_CONTAINER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_KEY_CONTAINER:
|
|
|
|
ss<<"The requested key container does not exist on the smart card.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_NO_SUCH_CERTIFICATE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_NO_SUCH_CERTIFICATE:
|
|
|
|
ss<<"The requested certificate does not exist.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_SERVER_TOO_BUSY
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_SERVER_TOO_BUSY:
|
|
|
|
ss<<"The Smart card resource manager is too busy to complete this"
|
|
|
|
<<" operation.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_UNSUPPORTED_FEATURE
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_UNSUPPORTED_FEATURE:
|
|
|
|
ss<<"This smart card does not support the requested feature.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#else
|
|
|
|
#ifdef SCARD_E_UNEXPECTED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_UNEXPECTED:
|
|
|
|
ss<<"An unexpected card error has occurred.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_UNKNOWN_RES_MNG
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_UNKNOWN_RES_MNG:
|
|
|
|
ss<<"An unrecognized error code was returned from a layered"
|
|
|
|
<<" component.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_E_WRITE_TOO_MANY
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_E_WRITE_TOO_MANY:
|
|
|
|
ss<<"The smartcard does not have enough memory to store the"
|
|
|
|
<<" information.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_P_SHUTDOWN
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_P_SHUTDOWN:
|
|
|
|
ss<<"The operation has been aborted to allow the server application"
|
|
|
|
<<" to exit.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_CANCELLED_BY_USER
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_CANCELLED_BY_USER:
|
|
|
|
ss<<"The action was cancelled by the user.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_CARD_NOT_AUTHENTICATED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_CARD_NOT_AUTHENTICATED:
|
|
|
|
ss<<"No PIN was presented to the smart card.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_CHV_BLOCKED
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_CHV_BLOCKED:
|
|
|
|
ss<<"The card cannot be accessed because the maximum number"
|
|
|
|
<<" of PIN entry attempts has been reached.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_EOF
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_EOF:
|
|
|
|
ss<<"The end of the smart card file has been reached.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_SECURITY_VIOLATION
|
2014-03-26 15:07:54 +00:00
|
|
|
case SCARD_W_SECURITY_VIOLATION:
|
|
|
|
ss<<"Access was denied because of a security violation.";
|
|
|
|
break;
|
2013-11-12 15:40:55 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SCARD_W_WRONG_CHV
|
2014-03-26 15:07:54 +00:00
|
|
|
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";
|
2013-10-15 11:57:29 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
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);
|
2013-11-11 11:49:09 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
return ss.str();
|
2013-11-11 11:49:09 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
//! set state
|
2014-09-16 07:47:26 +00:00
|
|
|
void state(DWORD s) {
|
2014-03-26 15:07:54 +00:00
|
|
|
_state = s;
|
|
|
|
}
|
|
|
|
//! @returns state
|
2014-09-16 07:47:26 +00:00
|
|
|
DWORD state() {
|
2014-03-26 15:07:54 +00:00
|
|
|
return _state;
|
|
|
|
}
|
|
|
|
//! @returns connection id
|
|
|
|
SCARDCONTEXT id() {
|
|
|
|
return _id;
|
2013-11-11 11:49:09 +00:00
|
|
|
}
|
2014-03-26 15:07:54 +00:00
|
|
|
bool exc() {
|
|
|
|
return _exc;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2013-11-11 11:49:09 +00:00
|
|
|
|
2014-03-26 15:07:54 +00:00
|
|
|
bool _exc;
|
|
|
|
SCARDCONTEXT _id;
|
|
|
|
Scope _s;
|
2014-09-16 07:47:26 +00:00
|
|
|
DWORD _state;
|
2009-06-17 12:30:45 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2009-09-18 11:41:30 +00:00
|
|
|
//@}
|
|
|
|
|
2009-06-17 12:30:45 +00:00
|
|
|
}
|
2009-09-18 11:41:30 +00:00
|
|
|
//@}
|
|
|
|
|
2009-06-17 12:30:45 +00:00
|
|
|
#endif
|