Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ add_library(${PROJECT_NAME}
src/electronic-ids/x509.hpp
src/electronic-ids/pcsc/EIDIDEMIA.cpp
src/electronic-ids/pcsc/EIDIDEMIA.hpp
src/electronic-ids/pcsc/EIDThales.cpp
src/electronic-ids/pcsc/EIDThales.hpp
src/electronic-ids/pcsc/EstEIDIDEMIA.hpp
src/electronic-ids/pcsc/FinEID.cpp
src/electronic-ids/pcsc/EstEIDThales.hpp
src/electronic-ids/pcsc/FinEID.hpp
src/electronic-ids/pcsc/LatEIDIDEMIAv2.cpp
src/electronic-ids/pcsc/LatEIDIDEMIAv2.hpp
Expand Down
1 change: 0 additions & 1 deletion lib/libpcsc-cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ add_library(${PROJECT_NAME}
src/SCardCall.hpp
src/SmartCard.cpp
src/listReaders.cpp
src/utils.cpp
)

target_include_directories(${PROJECT_NAME}
Expand Down
9 changes: 9 additions & 0 deletions lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp-utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
namespace pcsc_cpp
{

/** Convert bytes to hex string. */
inline std::ostream& operator<<(std::ostream& os, const byte_vector& data)
{
os << std::setfill('0') << std::hex;
for (const auto byte : data)
os << std::setw(2) << short(byte);
return os << std::setfill(' ') << std::dec;
}

/** Convert the given integer to a hex string. */
template <typename T>
inline std::string int2hexstr(const T value)
Expand Down
29 changes: 0 additions & 29 deletions lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ constexpr uint16_t toSW(byte_type sw1, byte_type sw2) noexcept
}

/** Convert bytes to hex string. */
std::ostream& operator<<(std::ostream& os, const pcsc_cpp::byte_vector& data);

std::string operator+(std::string lhs, const byte_vector& rhs);

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

PCSC_CPP_CONSTEXPR_VECTOR static ResponseApdu fromBytes(byte_vector data)
{
if (data.size() < 2) {
throw std::invalid_argument("Need at least 2 bytes for creating ResponseApdu");
}

PCSC_CPP_WARNING_PUSH
PCSC_CPP_WARNING_DISABLE_GCC("-Warray-bounds") // avoid GCC 13 false positive warning
byte_type sw1 = data[data.size() - 2];
byte_type sw2 = data[data.size() - 1];
data.resize(data.size() - 2);
PCSC_CPP_WARNING_POP

// SW1 and SW2 are in the end
return {sw1, sw2, std::move(data)};
}

constexpr uint16_t toSW() const noexcept { return pcsc_cpp::toSW(sw1, sw2); }

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

// Utility functions.

/** Transmit APDU command and verify that expected response is received. */
void transmitApduWithExpectedResponse(const SmartCard::Session& session,
const CommandApdu& command);

/** Read lenght bytes from currently selected binary file in blockLength-sized chunks. */
byte_vector readBinary(const SmartCard::Session& session, const uint16_t length,
byte_type blockLength = 0x00);

// Errors.

/** Base class for all pcsc-cpp errors. */
Expand Down
57 changes: 40 additions & 17 deletions lib/libpcsc-cpp/src/SmartCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ constexpr uint32_t OMNIKEY_6121 = 0x6632;
namespace pcsc_cpp
{

std::string operator+(std::string lhs, const byte_vector& rhs)
{
lhs.reserve(lhs.size() + rhs.size() * 2);
std::ostringstream hexStringBuilder(std::move(lhs), std::ios::ate);
hexStringBuilder << rhs;
return hexStringBuilder.str();
}

SmartCard Reader::connectToCard() const
{
return {*this};
Expand Down Expand Up @@ -146,6 +154,9 @@ class CardImpl

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

if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
getResponseWithLE(response, commandBytes);
}
if (response.sw1 == ResponseApdu::MORE_DATA_AVAILABLE) {
getMoreResponseData(response);
}
Expand Down Expand Up @@ -222,34 +233,38 @@ class CardImpl
if (responseLength > responseBytes.size()) {
THROW(Error, "SCardTransmit: received more bytes than buffer size");
}
if (responseLength < 2) {
THROW(Error, "SCardTransmit: Need at least 2 bytes for creating ResponseApdu");
}
responseBytes.resize(responseLength);

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

auto response = ResponseApdu::fromBytes(std::move(responseBytes));
ResponseApdu response {sw1, sw2, std::move(responseBytes)};

// Let expected errors through for handling in upper layers or in if blocks below.
switch (response.sw1) {
case ResponseApdu::OK:
case ResponseApdu::MORE_DATA_AVAILABLE: // See the if block after next.
case ResponseApdu::VERIFICATION_FAILED:
case ResponseApdu::VERIFICATION_CANCELLED:
case ResponseApdu::WRONG_LENGTH:
case ResponseApdu::COMMAND_NOT_ALLOWED:
case ResponseApdu::WRONG_PARAMETERS:
case ResponseApdu::WRONG_LE_LENGTH: // See next if block.
break;
using enum ResponseApdu::Status;
case OK:
case MORE_DATA_AVAILABLE:
case WRONG_LE_LENGTH:
case VERIFICATION_FAILED:
case VERIFICATION_CANCELLED:
case WRONG_LENGTH:
case COMMAND_NOT_ALLOWED:
case WRONG_PARAMETERS:
return response;
default:
THROW(Error,
"Error response: '" + response + "', protocol "
+ std::to_string(_protocol.dwProtocol));
}

if (response.sw1 == ResponseApdu::WRONG_LE_LENGTH) {
THROW(Error, "Wrong LE length (SW1=0x6C) in response, please set LE");
}

return response;
}

void getMoreResponseData(ResponseApdu& response) const
Expand All @@ -268,6 +283,14 @@ class CardImpl
response.sw1 = ResponseApdu::OK;
response.sw2 = 0;
}

void getResponseWithLE(ResponseApdu& response, byte_vector command) const
{
size_t pos = command.size() <= 5 ? 4 : 5 + command[4]; // Case 1/2 or 3/4
command.resize(pos + 1);
command[pos] = response.sw2;
response = transmitBytes(command);
}
};

SmartCard::Session::Session(const CardImpl& card) : card(card)
Expand Down
102 changes: 0 additions & 102 deletions lib/libpcsc-cpp/src/utils.cpp

This file was deleted.

5 changes: 5 additions & 0 deletions src/electronic-id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/

#include "electronic-ids/pcsc/EstEIDIDEMIA.hpp"
#include "electronic-ids/pcsc/EstEIDThales.hpp"
#include "electronic-ids/pcsc/FinEID.hpp"
#include "electronic-ids/pcsc/LatEIDIDEMIAv2.hpp"

Expand Down Expand Up @@ -60,6 +61,10 @@ const std::map<byte_vector, ElectronicIDConstructor, VectorComparator> SUPPORTED
{{0x3b, 0xdc, 0x96, 0x00, 0x80, 0xb1, 0xfe, 0x45, 0x1f, 0x83, 0x00, 0x12,
0x23, 0x3f, 0x54, 0x65, 0x49, 0x44, 0x32, 0x0f, 0x90, 0x00, 0xc3},
constructor<EstEIDIDEMIAV1>},
// EstEID Thales v1.0
{{0x3b, 0xff, 0x96, 0x00, 0x00, 0x80, 0x31, 0xfe, 0x43, 0x80, 0x31, 0xb8, 0x53,
0x65, 0x49, 0x44, 0x64, 0xb0, 0x85, 0x05, 0x10, 0x12, 0x23, 0x3f, 0x1d},
constructor<EstEIDThales>},
// FinEID v3.0
{{0x3B, 0x7F, 0x96, 0x00, 0x00, 0x80, 0x31, 0xB8, 0x65, 0xB0,
0x85, 0x03, 0x00, 0xEF, 0x12, 0x00, 0xF6, 0x82, 0x90, 0x00},
Expand Down
36 changes: 14 additions & 22 deletions src/electronic-ids/TLV.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,17 @@ struct TLV
tag = *begin++;
if ((tag & 0x1F) == 0x1F) { // Multi-byte tag
constexpr uint8_t MAX_TAG_BYTES = sizeof(tag);
uint8_t tagBytes = 1;
uint8_t tag_bytes = 1;
do {
if (tagBytes >= MAX_TAG_BYTES) {
if (tag_bytes >= MAX_TAG_BYTES) {
THROW(std::invalid_argument,
"Invalid TLV: Tag too long or too large for uint32_t");
}
if (!*this) {
THROW(std::invalid_argument, "Invalid TLV: Unexpected end of tag");
}
tag = (tag << 8) | (*begin++);
++tagBytes;
++tag_bytes;
} while ((tag & 0x80) != 0x00);
}

Expand All @@ -78,13 +78,15 @@ struct TLV

length = *begin++;
if (length & 0x80) { // Extended length encoding
auto num_bytes = uint8_t(length & 0x7F);
if (num_bytes == 0 || num_bytes > 4 || std::distance(begin, end) < num_bytes) {
constexpr uint8_t MAX_LEN_BYTES = sizeof(length);
auto len_bytes = uint8_t(length & 0x7F);
if (len_bytes == 0 || len_bytes > MAX_LEN_BYTES
|| std::distance(begin, end) < len_bytes) {
THROW(std::invalid_argument, "Invalid TLV: Incorrect extended length encoding");
}

length = 0;
for (uint8_t i = 0; i < num_bytes; ++i) {
for (uint8_t i = 0; i < len_bytes; ++i) {
length = (length << 8) | (*begin++);
}
}
Expand All @@ -94,28 +96,18 @@ struct TLV
}
}

PCSC_CPP_CONSTEXPR_VECTOR TLV child() const { return {begin, begin + length}; }

PCSC_CPP_CONSTEXPR_VECTOR TLV operator[](uint32_t find) const
{
TLV tlv = child();
for (; tlv && tlv.tag != find; ++tlv) {}
return tlv;
return TLV(begin, begin + length).find(find);
}
PCSC_CPP_CONSTEXPR_VECTOR TLV& operator++() { return *this = {begin + length, end}; }

template <typename... Tags>
static PCSC_CPP_CONSTEXPR_VECTOR TLV path(TLV tlv, uint32_t tag, Tags... tags)
PCSC_CPP_CONSTEXPR_VECTOR TLV find(uint32_t find) const
{
for (; tlv; ++tlv) {
if (tlv.tag == tag) {
if constexpr (sizeof...(tags) > 0) {
return path(tlv.child(), uint32_t(tags)...);
}
return tlv;
}
}
return TLV({});
TLV tlv = *this;
for (; tlv && tlv.tag != find; ++tlv) {}
// Return the found TLV or an empty one if not found
return tlv;
}

constexpr operator bool() const noexcept { return begin < end; }
Expand Down
Loading
Loading