|
|
|
@ -190,7 +190,8 @@ namespace pcsc { |
|
|
|
|
//! Disconnects connection.
|
|
|
|
|
~Reader() { |
|
|
|
|
_state = SCardDisconnect(_id, SCARD_LEAVE_CARD); |
|
|
|
|
if (!std::uncaught_exception()) _connection.check(); |
|
|
|
|
if (!std::uncaught_exception()) |
|
|
|
|
_connection.check("disconnect smartcard"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Get reader status.
|
|
|
|
@ -199,7 +200,8 @@ namespace pcsc { |
|
|
|
|
DWORD s; |
|
|
|
|
DWORD len(MAX_ATR_SIZE); |
|
|
|
|
unsigned char a[len]; |
|
|
|
|
check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len)); |
|
|
|
|
check(SCardStatus(_id, 0, &dummy, &s, &_protocol, a, &len), |
|
|
|
|
"query smartcard status"); |
|
|
|
|
return Status(s, std::string((char*)a, len)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -210,7 +212,8 @@ namespace pcsc { |
|
|
|
|
SCARD_IO_REQUEST rPci; |
|
|
|
|
check(SCardTransmit(_id, pci(), |
|
|
|
|
(unsigned char*)in.c_str(), in.size(), |
|
|
|
|
&rPci, buff, &len)); |
|
|
|
|
&rPci, buff, &len), |
|
|
|
|
"smartcard transmit message "+hex(in)); |
|
|
|
|
return std::string((char*)buff, len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -229,17 +232,18 @@ namespace pcsc { |
|
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
|
|
|
|
void beginTransaction() { |
|
|
|
|
check(SCardBeginTransaction(_id)); |
|
|
|
|
check(SCardBeginTransaction(_id), "smartcard begin transaction"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
|
|
|
|
void commitTransaction() { |
|
|
|
|
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD)); |
|
|
|
|
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), |
|
|
|
|
"smartcard end transaction"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
|
|
|
|
void cancelTransaction() { |
|
|
|
|
check(SCardCancelTransaction(_id)); |
|
|
|
|
check(SCardCancelTransaction(_id), "smartcard cancel transaction"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*! @throw not_implemented if _protocol is unknown. */ |
|
|
|
@ -255,9 +259,9 @@ namespace pcsc { |
|
|
|
|
//! 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) { |
|
|
|
|
bool check(long state, const std::string context="") { |
|
|
|
|
_state = state; |
|
|
|
|
return _connection.check(state); |
|
|
|
|
return _connection.check(state, context); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Only Connection is allowed to instanciate.
|
|
|
|
@ -269,7 +273,8 @@ namespace pcsc { |
|
|
|
|
check(SCardConnect(_connection._id, strconv(name).c_str(), |
|
|
|
|
SCARD_SHARE_SHARED, |
|
|
|
|
SCARD_PROTOCOL_T0|SCARD_PROTOCOL_T1, |
|
|
|
|
&_id, &_protocol)); |
|
|
|
|
&_id, &_protocol), |
|
|
|
|
"connect smartcard \""+name+"\""); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! forbidden
|
|
|
|
@ -283,7 +288,7 @@ namespace pcsc { |
|
|
|
|
|
|
|
|
|
Connection& _connection; |
|
|
|
|
SCARDHANDLE _id; |
|
|
|
|
long _state; |
|
|
|
|
DWORD _state; |
|
|
|
|
DWORD _protocol; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
@ -331,13 +336,13 @@ namespace pcsc { |
|
|
|
|
Connection(Scope s=SYSTEM, bool exceptions=true): |
|
|
|
|
_exc(exceptions), _id(0), |
|
|
|
|
_state(SCardEstablishContext(s, 0, 0, &_id)) { |
|
|
|
|
check(); |
|
|
|
|
check("establish smartcard context"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Closes the connection (releases the smartcard context)
|
|
|
|
|
~Connection() { |
|
|
|
|
_state = SCardReleaseContext(_id); |
|
|
|
|
if (!std::uncaught_exception()) check(); |
|
|
|
|
if (!std::uncaught_exception()) check("smartcard release context"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Scans for available readers from a specified list of groups.
|
|
|
|
@ -347,11 +352,13 @@ namespace pcsc { |
|
|
|
|
std::string grp(join(groups)); |
|
|
|
|
DWORD num(0); |
|
|
|
|
if (!check(SCardListReaders(_id, grp.size()?strconv(grp).data():0, 0, |
|
|
|
|
&num))) |
|
|
|
|
&num), |
|
|
|
|
"(1) smartcard list readers of groups "+grp)) |
|
|
|
|
return res; |
|
|
|
|
std::auto_ptr<char_t> nm(new char_t[num]); |
|
|
|
|
if (!check(SCardListReaders(_id, grp.size()?strconv(grp).data():0, |
|
|
|
|
nm.get(), &num))) |
|
|
|
|
nm.get(), &num), |
|
|
|
|
"(2) smartcard list readers of groups "+grp)) |
|
|
|
|
return res; |
|
|
|
|
return res = split(strconv(string(nm.get(), num-1))); |
|
|
|
|
} |
|
|
|
@ -382,34 +389,168 @@ namespace pcsc { |
|
|
|
|
#ifdef WIN32 |
|
|
|
|
std::stringstream ss; |
|
|
|
|
switch (_state) { |
|
|
|
|
case SCARD_S_SUCCESS: |
|
|
|
|
ss<<"Success"; |
|
|
|
|
case SCARD_E_SHARING_VIOLATION: |
|
|
|
|
ss<<"The smart card cannot be accessed because of other" |
|
|
|
|
<<" connections outstanding."; |
|
|
|
|
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_UNKNOWN_CARD: |
|
|
|
|
ss<<"The specified smart card name is not recognized."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_CANT_DISPOSE: |
|
|
|
|
ss<<"The system could not dispose of the media in the" |
|
|
|
|
<<" requested manner."; |
|
|
|
|
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_NOT_READY: |
|
|
|
|
ss<<"The reader or smart card is not ready to accept commands."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_INVALID_VALUE: |
|
|
|
|
ss<<"One or more of the supplied parameters values could" |
|
|
|
|
<<" not be properly interpreted."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_SYSTEM_CANCELLED: |
|
|
|
|
ss<<"The action was cancelled by the system, presumably" |
|
|
|
|
<<" to log off or shut down."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_F_COMM_ERROR: |
|
|
|
|
ss<<"An internal communications error has been detected."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_F_UNKNOWN_ERROR: |
|
|
|
|
ss<<"An internal error has been detected, but the source" |
|
|
|
|
<<" is unknown."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_INVALID_ATR: |
|
|
|
|
ss<<"An ATR obtained from the registry is not a valid ATR string."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_NOT_TRANSACTED: |
|
|
|
|
ss<<"An attempt was made to end a non-existent transaction."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_READER_UNAVAILABLE: |
|
|
|
|
ss<<"The specified reader is not currently available for use."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_P_SHUTDOWN: |
|
|
|
|
ss<<"The operation has been aborted to allow the server" |
|
|
|
|
<<" application to exit."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_PCI_TOO_SMALL: |
|
|
|
|
ss<<"The PCI Receive buffer was too small."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_READER_UNSUPPORTED: |
|
|
|
|
ss<<"The reader driver 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_CARD_UNSUPPORTED: |
|
|
|
|
ss<<"The smart card does not meet minimal requirements" |
|
|
|
|
<<" for support."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_NO_SERVICE: |
|
|
|
|
ss<<"The Smart card resource manager is not running."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_SERVICE_STOPPED: |
|
|
|
|
ss<<"The Smart card resource manager has shut down."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_UNEXPECTED: |
|
|
|
|
ss<<"An unexpected card error has occurred."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_ICC_INSTALLATION: |
|
|
|
|
ss<<"No Primary Provider can be found for the smart card."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_ICC_CREATEORDER: |
|
|
|
|
ss<<"The requested order of object creation is not supported."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_UNSUPPORTED_FEATURE: |
|
|
|
|
ss<<"This smart card does not support the requested feature."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_DIR_NOT_FOUND: |
|
|
|
|
ss<<"The identified directory does not exist in the smart card."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_FILE_NOT_FOUND: |
|
|
|
|
ss<<"The identified file does not exist in the smart card."; |
|
|
|
|
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_ACCESS: |
|
|
|
|
ss<<"Access is denied to this file."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_WRITE_TOO_MANY: |
|
|
|
|
ss<<"The smartcard does not have enough memory to store" |
|
|
|
|
<<" the information."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_BAD_SEEK: |
|
|
|
|
ss<<"There was an error trying to set the smart card file" |
|
|
|
|
<<" object pointer."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_INVALID_CHV: |
|
|
|
|
ss<<"The supplied PIN is incorrect."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_UNKNOWN_RES_MNG: |
|
|
|
|
ss<<"An unrecognized error code was returned from a layered" |
|
|
|
|
<<" component."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_NO_SUCH_CERTIFICATE: |
|
|
|
|
ss<<"The requested certificate does not exist."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_CERTIFICATE_UNAVAILABLE: |
|
|
|
|
ss<<"The requested certificate could not be obtained."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_NO_READERS_AVAILABLE: |
|
|
|
|
ss<<"Cannot find a smart card reader."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_COMM_DATA_LOST: |
|
|
|
|
ss<<"A communications error with the smart card has been" |
|
|
|
|
<<" detected. Retry the operation."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_NO_KEY_CONTAINER: |
|
|
|
|
ss<<"The requested key container does not exist on the" |
|
|
|
|
<<" smart card."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_E_SERVER_TOO_BUSY: |
|
|
|
|
ss<<"The Smart card resource manager is too busy to complete" |
|
|
|
|
<<" this operation."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_W_UNSUPPORTED_CARD: |
|
|
|
|
ss<<"The reader cannot communicate with the smart card, due" |
|
|
|
|
<<" to ATR configuration conflicts."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_W_UNRESPONSIVE_CARD: |
|
|
|
|
ss<<"The smart card is not responding to a reset."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_W_UNPOWERED_CARD: |
|
|
|
|
ss<<"Power has been removed from the smart card, so that further" |
|
|
|
|
" communication is not possible."; |
|
|
|
|
ss<<"Power has been removed from the smart card, so that" |
|
|
|
|
<<" further communication is not possible."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_W_RESET_CARD: |
|
|
|
|
ss<<"The smart card has been reset, so any shared state" |
|
|
|
|
" information is invalid."; |
|
|
|
|
<<" information is invalid."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_W_REMOVED_CARD: |
|
|
|
|
ss<<"The smart card has been removed, so that further" |
|
|
|
|
" communication is not possible."; |
|
|
|
|
<<" communication is not possible."; |
|
|
|
|
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."; |
|
|
|
|
ss<<"The card cannot be accessed because the wrong PIN" |
|
|
|
|
<<" was presented."; |
|
|
|
|
break; |
|
|
|
|
case SCARD_W_CHV_BLOCKED: |
|
|
|
|
ss<<"The card cannot be accessed because the maximum number" |
|
|
|
|
" of PIN entry attempts has been reached."; |
|
|
|
|
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."; |
|
|
|
@ -421,7 +562,7 @@ namespace pcsc { |
|
|
|
|
ss<<"No PIN was presented to the smart card."; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
ss<<"Unknown PCSC state: "<<_state; |
|
|
|
|
ss<<"Unknown PCSC state: "<<std::hex<<_state; |
|
|
|
|
} |
|
|
|
|
return ss.str(); |
|
|
|
|
#else |
|
|
|
@ -435,16 +576,20 @@ namespace pcsc { |
|
|
|
|
//! 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) { |
|
|
|
|
bool check(long state, const std::string& context="") { |
|
|
|
|
_state = state; |
|
|
|
|
return check(); |
|
|
|
|
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() { |
|
|
|
|
if (_exc&&_state!=SCARD_S_SUCCESS) throw access_error(error()); |
|
|
|
|
bool check(const std::string& context="") { |
|
|
|
|
if (_exc&&_state!=SCARD_S_SUCCESS) |
|
|
|
|
if (context.size()) |
|
|
|
|
throw access_error(context+": "+error()); |
|
|
|
|
else |
|
|
|
|
throw access_error(error()); |
|
|
|
|
return _state==SCARD_S_SUCCESS; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|