Skip to content

Commit 38f9454

Browse files
committed
Thales card support
IB-8171 Signed-off-by: Raul Metsma <[email protected]>
1 parent a229955 commit 38f9454

File tree

16 files changed

+211
-234
lines changed

16 files changed

+211
-234
lines changed

lib/libpcsc-cpp/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ add_library(${PROJECT_NAME}
1414
src/SCardCall.hpp
1515
src/SmartCard.cpp
1616
src/listReaders.cpp
17-
src/utils.cpp
1817
)
1918

2019
target_include_directories(${PROJECT_NAME}

lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp-utils.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@
2929
namespace pcsc_cpp
3030
{
3131

32+
/** Convert bytes to hex string. */
33+
inline std::ostream& operator<<(std::ostream& os, const byte_vector& data)
34+
{
35+
os << std::setfill('0') << std::hex;
36+
for (const auto byte : data)
37+
os << std::setw(2) << short(byte);
38+
return os << std::setfill(' ') << std::dec;
39+
}
40+
3241
/** Convert the given integer to a hex string. */
3342
template <typename T>
3443
inline std::string int2hexstr(const T value)

lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp.hpp

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ constexpr uint16_t toSW(byte_type sw1, byte_type sw2) noexcept
8585
}
8686

8787
/** Convert bytes to hex string. */
88-
std::ostream& operator<<(std::ostream& os, const pcsc_cpp::byte_vector& data);
89-
9088
std::string operator+(std::string lhs, const byte_vector& rhs);
9189

9290
/** Struct that wraps response APDUs. */
@@ -111,23 +109,6 @@ struct ResponseApdu
111109
static constexpr size_t MAX_DATA_SIZE = 256;
112110
static constexpr size_t MAX_SIZE = MAX_DATA_SIZE + 2; // + sw1 and sw2
113111

114-
PCSC_CPP_CONSTEXPR_VECTOR static ResponseApdu fromBytes(byte_vector data)
115-
{
116-
if (data.size() < 2) {
117-
throw std::invalid_argument("Need at least 2 bytes for creating ResponseApdu");
118-
}
119-
120-
PCSC_CPP_WARNING_PUSH
121-
PCSC_CPP_WARNING_DISABLE_GCC("-Warray-bounds") // avoid GCC 13 false positive warning
122-
byte_type sw1 = data[data.size() - 2];
123-
byte_type sw2 = data[data.size() - 1];
124-
data.resize(data.size() - 2);
125-
PCSC_CPP_WARNING_POP
126-
127-
// SW1 and SW2 are in the end
128-
return {sw1, sw2, std::move(data)};
129-
}
130-
131112
constexpr uint16_t toSW() const noexcept { return pcsc_cpp::toSW(sw1, sw2); }
132113

133114
constexpr bool isOK() const noexcept { return sw1 == OK && sw2 == 0x00; }
@@ -300,16 +281,6 @@ class SmartCard
300281
*/
301282
std::vector<Reader> listReaders();
302283

303-
// Utility functions.
304-
305-
/** Transmit APDU command and verify that expected response is received. */
306-
void transmitApduWithExpectedResponse(const SmartCard::Session& session,
307-
const CommandApdu& command);
308-
309-
/** Read lenght bytes from currently selected binary file in blockLength-sized chunks. */
310-
byte_vector readBinary(const SmartCard::Session& session, const uint16_t length,
311-
byte_type blockLength = 0x00);
312-
313284
// Errors.
314285

315286
/** Base class for all pcsc-cpp errors. */

lib/libpcsc-cpp/src/SmartCard.cpp

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ constexpr uint32_t OMNIKEY_6121 = 0x6632;
6464
namespace pcsc_cpp
6565
{
6666

67+
std::string operator+(std::string lhs, const byte_vector& rhs)
68+
{
69+
lhs.reserve(lhs.size() + rhs.size() * 2);
70+
std::ostringstream hexStringBuilder(std::move(lhs), std::ios::ate);
71+
hexStringBuilder << rhs;
72+
return hexStringBuilder.str();
73+
}
74+
6775
SmartCard Reader::connectToCard() const
6876
{
6977
return {*this};
@@ -146,6 +154,9 @@ class CardImpl
146154

147155
auto response = toResponse(std::move(responseBytes), responseLength);
148156

157+
if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
158+
getResponseWithLE(response, commandBytes);
159+
}
149160
if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
150161
getMoreResponseData(response);
151162
}
@@ -222,34 +233,38 @@ class CardImpl
222233
if (responseLength > responseBytes.size()) {
223234
THROW(Error, "SCardTransmit: received more bytes than buffer size");
224235
}
236+
if (responseLength < 2) {
237+
THROW(Error, "SCardTransmit: Need at least 2 bytes for creating ResponseApdu");
238+
}
225239
responseBytes.resize(responseLength);
226240

227-
// TODO: debug("Received: " + bytes2hexstr(responseBytes))
241+
PCSC_CPP_WARNING_PUSH
242+
PCSC_CPP_WARNING_DISABLE_GCC("-Warray-bounds") // avoid GCC 13 false positive warning
243+
// SW1 and SW2 are in the end
244+
byte_type sw1 = responseBytes[responseLength - 2];
245+
byte_type sw2 = responseBytes[responseLength - 1];
246+
responseBytes.resize(responseLength - 2);
247+
PCSC_CPP_WARNING_POP
228248

229-
auto response = ResponseApdu::fromBytes(std::move(responseBytes));
249+
ResponseApdu response {sw1, sw2, std::move(responseBytes)};
230250

231251
// Let expected errors through for handling in upper layers or in if blocks below.
232252
switch (response.sw1) {
233-
case ResponseApdu::OK:
234-
case ResponseApdu::MORE_DATA_AVAILABLE: // See the if block after next.
235-
case ResponseApdu::VERIFICATION_FAILED:
236-
case ResponseApdu::VERIFICATION_CANCELLED:
237-
case ResponseApdu::WRONG_LENGTH:
238-
case ResponseApdu::COMMAND_NOT_ALLOWED:
239-
case ResponseApdu::WRONG_PARAMETERS:
240-
case ResponseApdu::WRONG_LE_LENGTH: // See next if block.
241-
break;
253+
using enum ResponseApdu::Status;
254+
case OK:
255+
case MORE_DATA_AVAILABLE:
256+
case WRONG_LE_LENGTH:
257+
case VERIFICATION_FAILED:
258+
case VERIFICATION_CANCELLED:
259+
case WRONG_LENGTH:
260+
case COMMAND_NOT_ALLOWED:
261+
case WRONG_PARAMETERS:
262+
return response;
242263
default:
243264
THROW(Error,
244265
"Error response: '" + response + "', protocol "
245266
+ std::to_string(_protocol.dwProtocol));
246267
}
247-
248-
if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
249-
THROW(Error, "Wrong LE length (SW1=0x6C) in response, please set LE");
250-
}
251-
252-
return response;
253268
}
254269

255270
void getMoreResponseData(ResponseApdu& response) const
@@ -268,6 +283,13 @@ class CardImpl
268283
response.sw1 = ResponseApdu::OK;
269284
response.sw2 = 0;
270285
}
286+
287+
void getResponseWithLE(ResponseApdu& response, byte_vector command) const
288+
{
289+
size_t pos = command.size() <= 5 ? 4 : 5 + command[4];
290+
command[pos] = response.sw2;
291+
response = transmitBytes(command);
292+
}
271293
};
272294

273295
SmartCard::Session::Session(const CardImpl& card) : card(card)

lib/libpcsc-cpp/src/utils.cpp

Lines changed: 0 additions & 102 deletions
This file was deleted.

src/electronic-id.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ const std::map<byte_vector, ElectronicIDConstructor, VectorComparator> SUPPORTED
6060
{{0x3b, 0xdc, 0x96, 0x00, 0x80, 0xb1, 0xfe, 0x45, 0x1f, 0x83, 0x00, 0x12,
6161
0x23, 0x3f, 0x54, 0x65, 0x49, 0x44, 0x32, 0x0f, 0x90, 0x00, 0xc3},
6262
constructor<EstEIDIDEMIAV1>},
63+
// EstEID Thales v1.0
64+
{{0x3b, 0xff, 0x96, 0x00, 0x00, 0x80, 0x31, 0xfe, 0x43, 0x80, 0x31, 0xb8, 0x53,
65+
0x65, 0x49, 0x44, 0x64, 0xb0, 0x85, 0x05, 0x10, 0x12, 0x23, 0x3f, 0x1d},
66+
constructor<EstEIDTHALES>},
6367
// FinEID v3.0
6468
{{0x3B, 0x7F, 0x96, 0x00, 0x00, 0x80, 0x31, 0xB8, 0x65, 0xB0,
6569
0x85, 0x03, 0x00, 0xEF, 0x12, 0x00, 0xF6, 0x82, 0x90, 0x00},

src/electronic-ids/TLV.hpp

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,28 +94,17 @@ struct TLV
9494
}
9595
}
9696

97-
PCSC_CPP_CONSTEXPR_VECTOR TLV child() const { return {begin, begin + length}; }
98-
9997
PCSC_CPP_CONSTEXPR_VECTOR TLV operator[](uint32_t find) const
10098
{
101-
TLV tlv = child();
102-
for (; tlv && tlv.tag != find; ++tlv) {}
103-
return tlv;
99+
return TLV(begin, begin + length).find(find);
104100
}
105101
PCSC_CPP_CONSTEXPR_VECTOR TLV& operator++() { return *this = {begin + length, end}; }
106102

107-
template <typename... Tags>
108-
static PCSC_CPP_CONSTEXPR_VECTOR TLV path(TLV tlv, uint32_t tag, Tags... tags)
103+
PCSC_CPP_CONSTEXPR_VECTOR TLV find(uint32_t find) const
109104
{
110-
for (; tlv; ++tlv) {
111-
if (tlv.tag == tag) {
112-
if constexpr (sizeof...(tags) > 0) {
113-
return path(tlv.child(), uint32_t(tags)...);
114-
}
115-
return tlv;
116-
}
117-
}
118-
return TLV({});
105+
TLV tlv = *this;
106+
for (; tlv && tlv.tag != find; ++tlv) {}
107+
return tlv;
119108
}
120109

121110
constexpr operator bool() const noexcept { return begin < end; }

src/electronic-ids/pcsc/EIDIDEMIA.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ const auto SIGN_CERT = CommandApdu::selectEF(0x09, {0xAD, 0xF2, 0x34, 0x1F});
5353

5454
void EIDIDEMIA::selectMain(const SmartCard::Session& session)
5555
{
56-
transmitApduWithExpectedResponse(session, MAIN_AID);
56+
selectFile(session, MAIN_AID);
5757
}
5858

5959
void EIDIDEMIA::selectADF1(const pcsc_cpp::SmartCard::Session& session)
6060
{
61-
transmitApduWithExpectedResponse(session, ADF1_AID);
61+
selectFile(session, ADF1_AID);
6262
}
6363

6464
void EIDIDEMIA::selectADF2(const pcsc_cpp::SmartCard::Session& session)
6565
{
66-
transmitApduWithExpectedResponse(session, ADF2_AID);
66+
selectFile(session, ADF2_AID);
6767
}
6868

6969
byte_vector EIDIDEMIA::getCertificateImpl(const pcsc_cpp::SmartCard::Session& session,
@@ -86,8 +86,7 @@ byte_vector EIDIDEMIA::signWithAuthKeyImpl(const pcsc_cpp::SmartCard::Session& s
8686
auto [keyId, isECC] = authKeyRef(session);
8787
selectSecurityEnv(session, 0xA4, isECC ? 0x04 : 0x02, keyId, name());
8888

89-
verifyPin(session, AUTH_PIN_REFERENCE, std::move(pin), authPinMinMaxLength().first,
90-
authPinMinMaxLength().second, PIN_PADDING_CHAR);
89+
verifyPin(session, AUTH_PIN_REFERENCE, std::move(pin), authPinMinMaxLength(), PIN_PADDING_CHAR);
9190

9291
return internalAuthenticate(session,
9392
authSignatureAlgorithm().isRSAWithPKCS1Padding()
@@ -115,8 +114,8 @@ EIDIDEMIA::signWithSigningKeyImpl(const pcsc_cpp::SmartCard::Session& session, b
115114
selectADF2(session);
116115
auto [keyRef, isECC] = signKeyRef(session);
117116
selectSecurityEnv(session, 0xB6, isECC ? 0x54 : 0x42, keyRef, name());
118-
verifyPin(session, SIGN_PIN_REFERENCE, std::move(pin), signingPinMinMaxLength().first,
119-
signingPinMinMaxLength().second, PIN_PADDING_CHAR);
117+
verifyPin(session, SIGN_PIN_REFERENCE, std::move(pin), signingPinMinMaxLength(),
118+
PIN_PADDING_CHAR);
120119
auto tmp = hash;
121120
if (isECC) {
122121
constexpr size_t ECDSA384_INPUT_LENGTH = 384 / 8;
@@ -149,7 +148,7 @@ ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::pinRetriesLeft(const SmartCar
149148
if (!response.isOK()) {
150149
THROW(SmartCardError, "Command GET DATA ODD failed with error " + response);
151150
}
152-
TLV info = TLV::path(TLV(response.data), 0x70, 0xBF8100 | ref, 0xA0);
151+
TLV info = TLV(response.data).find(0x70)[0xBF8100 | ref][0xA0];
153152
TLV max = info[0x9A];
154153
TLV tries = info[0x9B];
155154
if (max && tries) {

0 commit comments

Comments
 (0)