Added all SuisseID Functionality except certificate import from server, which shall remain closed; refs #28

This commit is contained in:
Marc Wäckerlin
2013-11-06 12:24:52 +00:00
parent 3b702012c1
commit 885cb0f0fe
17 changed files with 1157 additions and 926 deletions

View File

@@ -10,25 +10,6 @@
#ifndef PCSC_HXX
#define PCSC_HXX
#ifndef PCSC_LOG
//! Declare PCSC_LOG before #include in your de, if you want logging.
/*! PCSC_LOG passes its argument to a stream, so your definition must
behave so that the argument can be streamed.
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 <mrw/shared.hxx>
@@ -132,7 +113,9 @@ namespace pcsc {
//----------------------------------------------------------------------------
class exception: public std::exception {
public:
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {}
exception(const std::string& reason) throw(): _what("pcsc: "+reason) {
CRYPTOLOG("ERROR: "<<what());
}
~exception() throw() {}
const char* what() const throw() {
return _what.c_str();
@@ -144,21 +127,28 @@ namespace pcsc {
class not_implemented: public exception {
public:
not_implemented(const std::string& reason) throw():
exception("feature is not implemented:\n"+reason) {
exception("feature is not implemented: "+reason) {
}
};
//----------------------------------------------------------------------------
class access_error: public exception {
public:
access_error(const std::string& reason) throw():
exception("smardcard access error:\n"+reason) {
exception("smardcard access error: "+reason) {
}
};
//----------------------------------------------------------------------------
class wrong_pin: public access_error {
public:
wrong_pin(const std::string& reason) throw():
access_error("wrong pin: "+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)) {}
exception("runtime error, "+reason+": "+crypto::hex(data)) {}
};
//----------------------------------------------------------------------------
class neesting_error: public exception {
@@ -216,10 +206,12 @@ namespace pcsc {
destructor und must therefore live longer than the
Transaction instance. */
Transaction(mrw::Shared<Reader> r): _reader(r), _running(true) {
CRYPTOLOG("log");
_reader->beginTransaction();
}
//! Cancels the transaction if not yet finished.
~Transaction() try {
CRYPTOLOG("log");
end();
} catch (...) {
if (!std::uncaught_exception()) throw;
@@ -247,6 +239,7 @@ namespace pcsc {
//! Disconnects connection.
~Reader() {
CRYPTOLOG("Disconnect Reader");
_state = SCardDisconnect(_id, SCARD_RESET_CARD);
if (!std::uncaught_exception())
_connection->check("disconnect smartcard");
@@ -328,13 +321,13 @@ namespace pcsc {
SCARD_IO_REQUEST rPci;
rPci.dwProtocol = pci()->dwProtocol;
rPci.cbPciLength = sizeof(rPci);
// don't log; could log pins
//PCSC_LOG("SCardTransmit: "<<crypto::hex(in));
// log only in verbose debuggung; could log pins
CRYPTOLOG_VERBOSE("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)));
//CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)buff, len)));
return std::string((char*)buff, len);
}
@@ -346,13 +339,13 @@ namespace pcsc {
std::string in) {
DWORD len(256); // arbitrary
UCHAR dataBuffer[256];
PCSC_LOG("SCardControl: "<<"Command: "<<controlCode);
PCSC_LOG(" -> "<<crypto::hex(in));
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");
PCSC_LOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len)));
CRYPTOLOG(" -> "<<crypto::hex(std::string((char*)dataBuffer, len)));
return std::string((char*)dataBuffer, len);
}
@@ -387,8 +380,10 @@ namespace pcsc {
/*! Calls @c SCardBeginTransaction unless it's already inside
a transaction. */
void beginTransaction() {
if (++_neesting==1)
if (++_neesting==1) {
CRYPTOLOG("open transaction");
check(SCardBeginTransaction(_id), "smartcard begin transaction");
}
}
//! Use scoped transactions with @ref Transaction
@@ -397,10 +392,11 @@ namespace pcsc {
@throws neesting_error if there are more calls to @c
endTransaction than to @c beginTransaction. */
void endTransaction() {
if (--_neesting==0)
if (--_neesting==0) {
CRYPTOLOG("close transaction");
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD),
"smartcard end transaction");
else if (_neesting<0) {
} else if (_neesting<0) {
_neesting = 0;
throw neesting_error();
}
@@ -432,6 +428,7 @@ namespace pcsc {
DWORD mode=SCARD_SHARE_SHARED,
DWORD protocol=SCARD_PROTOCOL_T1):
name(nm), _connection(c) {
CRYPTOLOG("Connect Reader");
check(SCardConnect(_connection->id(), strconv(name).c_str(),
mode, protocol,
&_id, &_protocol),
@@ -513,7 +510,7 @@ namespace pcsc {
&num),
"smartcard get size of readers of groups "+grp))
return res;
PCSC_LOG("size of readers: "<<num);
CRYPTOLOG("size of readers: "<<num);
if (!num) return res;
std::auto_ptr<char_t> nm(new char_t[num]);
if (!check(SCardListReaders(_connectionlifetime->id(),
@@ -521,9 +518,9 @@ namespace pcsc {
nm.get(), &num),
"smartcard list reader names of groups "+grp))
return res;
PCSC_LOG("got all readers, size is "<<num);
CRYPTOLOG("got all readers, size is "<<num);
if (!num) return res;
PCSC_LOG("list of readers: "
CRYPTOLOG("list of readers: "
<<crypto::readable(std::string(nm.get(), num-1)));
return res = split(strconv(string(nm.get(), num-1)));
}
@@ -620,10 +617,12 @@ namespace pcsc {
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");
}
@@ -641,9 +640,15 @@ namespace pcsc {
bool check(const std::string& context="") {
if (_exc&&!*this)
if (context.size())
throw access_error(context+": "+error());
if (_state==SCARD_W_WRONG_CHV)
throw wrong_pin(context+": "+error());
else
throw access_error(context+": "+error());
else
throw access_error(error());
if (_state==SCARD_W_WRONG_CHV)
throw wrong_pin(error());
else
throw access_error(error());
return *this;
}
@@ -721,8 +726,8 @@ namespace pcsc {
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.";
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"
@@ -757,8 +762,8 @@ namespace pcsc {
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.";
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.";