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
2 changes: 1 addition & 1 deletion include/electronic-id/enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class SignatureAlgorithm

constexpr bool operator==(HashAlgorithm other) const
{
return other.operator ==(operator HashAlgorithm());
return other.operator==(operator HashAlgorithm());
}
constexpr bool operator==(SignatureAlgorithmEnum other) const { return value == other; }

Expand Down
63 changes: 26 additions & 37 deletions lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ constexpr uint16_t toSW(byte_type sw1, byte_type sw2) noexcept
/** Struct that wraps response APDUs. */
struct ResponseApdu
{
enum Status: byte_type {
enum Status : byte_type {
OK = 0x90,
MORE_DATA_AVAILABLE = 0x61,
VERIFICATION_FAILED = 0x63,
Expand Down Expand Up @@ -141,52 +141,41 @@ struct ResponseApdu
/** Struct that wraps command APDUs. */
struct CommandApdu
{
byte_type cla;
byte_type ins;
byte_type p1;
byte_type p2;
unsigned short le;
// Lc is data.size()
byte_vector data;

static const size_t MAX_DATA_SIZE = 255;
static const unsigned short LE_UNUSED = std::numeric_limits<unsigned short>::max();

CommandApdu(byte_type c, byte_type i, byte_type pp1, byte_type pp2, byte_vector d = {},
unsigned short l = LE_UNUSED) :
cla(c), ins(i), p1(pp1), p2(pp2), le(l), data(std::move(d))
static constexpr size_t MAX_DATA_SIZE = 255;

// Case 1
PCSC_CPP_CONSTEXPR_VECTOR CommandApdu(byte_type cls, byte_type ins, byte_type p1,
byte_type p2) : d {cls, ins, p1, p2}
{
}

CommandApdu(const CommandApdu& other, byte_vector d) :
CommandApdu(other.cla, other.ins, other.p1, other.p2, std::move(d), other.le)
// Case 2
PCSC_CPP_CONSTEXPR_VECTOR CommandApdu(byte_type cls, byte_type ins, byte_type p1, byte_type p2,
byte_type le) : d {cls, ins, p1, p2, le}
{
}

constexpr bool isLeSet() const noexcept { return le != LE_UNUSED; }

byte_vector toBytes() const
// Case 3
PCSC_CPP_CONSTEXPR_VECTOR CommandApdu(byte_type cls, byte_type ins, byte_type p1, byte_type p2,
byte_vector data) : d {std::move(data)}
{
if (data.size() > MAX_DATA_SIZE) {
throw std::invalid_argument("Command chaining not supported");
if (d.size() > MAX_DATA_SIZE) {
throw std::invalid_argument("Command chaining and extended lenght not supported");
}
d.insert(d.begin(), {cls, ins, p1, p2, static_cast<byte_type>(d.size())});
}

auto bytes = byte_vector {cla, ins, p1, p2};

if (!data.empty()) {
bytes.push_back(static_cast<byte_type>(data.size()));
bytes.insert(bytes.end(), data.cbegin(), data.cend());
}
// Case 4
PCSC_CPP_CONSTEXPR_VECTOR CommandApdu(byte_type cls, byte_type ins, byte_type p1, byte_type p2,
byte_vector data, byte_type le) :
CommandApdu {cls, ins, p1, p2, std::move(data)}
{
d.push_back(le);
}

if (isLeSet()) {
// TODO: EstEID spec: the maximum value of Le is 0xFE
if (le > ResponseApdu::MAX_DATA_SIZE)
throw std::invalid_argument("LE larger than response size");
bytes.push_back(static_cast<byte_type>(le));
}
constexpr operator const byte_vector&() const { return d; }

return bytes;
}
byte_vector d;
};

/** Opaque class that wraps the PC/SC smart card resources like card handle and I/O protocol. */
Expand Down Expand Up @@ -291,7 +280,7 @@ void transmitApduWithExpectedResponse(const SmartCard& card, const CommandApdu&
size_t readDataLengthFromAsn1(const SmartCard& card);

/** Read lenght bytes from currently selected binary file in blockLength-sized chunks. */
byte_vector readBinary(const SmartCard& card, const size_t length, const size_t blockLength);
byte_vector readBinary(const SmartCard& card, const size_t length, byte_type blockLength);

// Errors.

Expand Down
4 changes: 2 additions & 2 deletions lib/libpcsc-cpp/src/SmartCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ ResponseApdu SmartCard::transmit(const CommandApdu& command) const
THROW(std::logic_error, "Call SmartCard::transmit() inside a transaction");
}

return card->transmitBytes(command.toBytes());
return card->transmitBytes(command);
}

ResponseApdu SmartCard::transmitCTL(const CommandApdu& command, uint16_t lang, uint8_t minlen) const
Expand All @@ -327,7 +327,7 @@ ResponseApdu SmartCard::transmitCTL(const CommandApdu& command, uint16_t lang, u
THROW(std::logic_error, "Call SmartCard::transmit() inside a transaction");
}

return card->transmitBytesCTL(command.toBytes(), lang, minlen);
return card->transmitBytesCTL(command, lang, minlen);
}

} // namespace pcsc_cpp
21 changes: 8 additions & 13 deletions lib/libpcsc-cpp/src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class UnexpectedResponseError : public Error
const char* file, const int line,
const char* callerFunctionName) :
Error("transmitApduWithExpectedResponse(): Unexpected response to command '"s
+ bytes2hexstr(command.toBytes()) + "' - expected '9000', got '"s
+ bytes2hexstr(response.toBytes()) + " in " + removeAbsolutePathPrefix(file) + ':'
+ bytes2hexstr(command) + "' - expected '9000', got '"s
+ bytes2hexstr(response.toBytes()) + "' in " + removeAbsolutePathPrefix(file) + ':'
+ std::to_string(line) + ':' + callerFunctionName)
{
}
Expand Down Expand Up @@ -95,7 +95,7 @@ size_t readDataLengthFromAsn1(const SmartCard& card)
// p1 - offset size first byte, 0
// p2 - offset size second byte, 0
// le - number of bytes to read, need 4 bytes from start for length
const auto readBinary4Bytes = CommandApdu {0x00, 0xb0, 0x00, 0x00, byte_vector(), 0x04};
const CommandApdu readBinary4Bytes {0x00, 0xb0, 0x00, 0x00, 0x04};

auto response = card.transmit(readBinary4Bytes);

Expand Down Expand Up @@ -129,24 +129,19 @@ size_t readDataLengthFromAsn1(const SmartCard& card)
return length;
}

byte_vector readBinary(const SmartCard& card, const size_t length, const size_t blockLength)
byte_vector readBinary(const SmartCard& card, const size_t length, byte_type blockLength)
{
size_t blockLengthVar = blockLength;
auto lengthCounter = length;
auto resultBytes = byte_vector {};
auto readBinary = CommandApdu {0x00, 0xb0, 0x00, 0x00};

for (size_t offset = 0; lengthCounter != 0;
offset += blockLengthVar, lengthCounter -= blockLengthVar) {
offset += blockLength, lengthCounter -= blockLength) {

if (blockLengthVar > lengthCounter) {
blockLengthVar = lengthCounter;
if (blockLength > lengthCounter) {
blockLength = byte_type(lengthCounter);
}

readBinary.p1 = HIBYTE(offset);
readBinary.p2 = LOBYTE(offset);
readBinary.le = static_cast<byte_type>(blockLengthVar);

CommandApdu readBinary {0x00, 0xb0, HIBYTE(offset), LOBYTE(offset), blockLength};
auto response = card.transmit(readBinary);

resultBytes.insert(resultBytes.end(), response.data.cbegin(), response.data.cend());
Expand Down
4 changes: 2 additions & 2 deletions src/electronic-ids/pcsc/FinEID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ byte_vector FinEIDv3::sign(const HashAlgorithm hashAlgo, const byte_vector& hash
byte_vector tlv {0x90, byte_type(hash.size())};
tlv.insert(tlv.cend(), hash.cbegin(), hash.cend());

const CommandApdu computeSignature {{0x00, 0x2A, 0x90, 0xA0}, std::move(tlv)};
const CommandApdu computeSignature {0x00, 0x2A, 0x90, 0xA0, std::move(tlv)};
const auto response = card->transmit(computeSignature);

if (response.sw1 == ResponseApdu::WRONG_LENGTH) {
Expand All @@ -156,7 +156,7 @@ byte_vector FinEIDv3::sign(const HashAlgorithm hashAlgo, const byte_vector& hash
"Command COMPUTE SIGNATURE failed with error " + bytes2hexstr(response.toBytes()));
}

const CommandApdu getSignature {0x00, 0x2A, 0x9E, 0x9A, {}, LE};
const CommandApdu getSignature {0x00, 0x2A, 0x9E, 0x9A, LE};
const auto signature = card->transmit(getSignature);

if (signature.sw1 == ResponseApdu::WRONG_LENGTH) {
Expand Down
33 changes: 8 additions & 25 deletions src/electronic-ids/pcsc/pcsc-common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace electronic_id
inline pcsc_cpp::byte_vector getCertificate(pcsc_cpp::SmartCard& card,
const pcsc_cpp::CommandApdu& selectCertFileCmd)
{
static const size_t MAX_LE_VALUE = 0xb5;
static const pcsc_cpp::byte_type MAX_LE_VALUE = 0xb5;

transmitApduWithExpectedResponse(card, selectCertFileCmd);

Expand All @@ -43,28 +43,27 @@ inline pcsc_cpp::byte_vector getCertificate(pcsc_cpp::SmartCard& card,
return readBinary(card, length, MAX_LE_VALUE);
}

inline pcsc_cpp::byte_vector addPaddingToPin(pcsc_cpp::byte_vector&& pin, size_t paddingLength,
pcsc_cpp::byte_type paddingChar)
PCSC_CPP_CONSTEXPR_VECTOR inline pcsc_cpp::byte_vector
addPaddingToPin(pcsc_cpp::byte_vector&& pin, size_t paddingLength, pcsc_cpp::byte_type paddingChar)
{
pin.resize(std::max(pin.size(), paddingLength), paddingChar);
return pin;
return std::move(pin);
}

inline void verifyPin(pcsc_cpp::SmartCard& card, pcsc_cpp::byte_type p2,
pcsc_cpp::byte_vector&& pin, uint8_t pinMinLength, size_t paddingLength,
pcsc_cpp::byte_type paddingChar)
{
const pcsc_cpp::CommandApdu VERIFY_PIN {0x00, 0x20, 0x00, p2};
pcsc_cpp::ResponseApdu response;

if (card.readerHasPinPad()) {
const pcsc_cpp::CommandApdu verifyPin {VERIFY_PIN,
const pcsc_cpp::CommandApdu verifyPin {0x00, 0x20, 0x00, p2,
addPaddingToPin({}, paddingLength, paddingChar)};
response = card.transmitCTL(verifyPin, 0, pinMinLength);

} else {
const pcsc_cpp::CommandApdu verifyPin {
VERIFY_PIN, addPaddingToPin(std::move(pin), paddingLength, paddingChar)};
0x00, 0x20, 0x00, p2, addPaddingToPin(std::move(pin), paddingLength, paddingChar)};

response = card.transmit(verifyPin);
}
Expand Down Expand Up @@ -119,15 +118,7 @@ inline pcsc_cpp::byte_vector internalAuthenticate(pcsc_cpp::SmartCard& card,
const pcsc_cpp::byte_vector& hash,
const std::string& cardType)
{
static const pcsc_cpp::CommandApdu INTERNAL_AUTHENTICATE {0x00, 0x88, 0x00, 0x00};

pcsc_cpp::CommandApdu internalAuth {INTERNAL_AUTHENTICATE, hash};
// LE is needed in case of protocol T1.
// TODO: Implement this in libpcsc-cpp.
if (card.protocol() == pcsc_cpp::SmartCard::Protocol::T1) {
internalAuth.le = 0;
}

pcsc_cpp::CommandApdu internalAuth {0x00, 0x88, 0x00, 0x00, hash, 0};
const auto response = card.transmit(internalAuth);

if (response.sw1 == pcsc_cpp::ResponseApdu::WRONG_LENGTH) {
Expand All @@ -148,15 +139,7 @@ inline pcsc_cpp::byte_vector computeSignature(pcsc_cpp::SmartCard& card,
const pcsc_cpp::byte_vector& hash,
const std::string& cardType)
{
static const pcsc_cpp::CommandApdu COMPUTE_SIGNATURE {0x00, 0x2A, 0x9E, 0x9A};

pcsc_cpp::CommandApdu computeSignature {COMPUTE_SIGNATURE, hash};
// LE is needed in case of protocol T1.
// TODO: Implement this in libpcsc-cpp.
if (card.protocol() == pcsc_cpp::SmartCard::Protocol::T1) {
computeSignature.le = 0;
}

pcsc_cpp::CommandApdu computeSignature {0x00, 0x2A, 0x9E, 0x9A, hash, 0};
const auto response = card.transmit(computeSignature);

if (response.sw1 == pcsc_cpp::ResponseApdu::WRONG_LENGTH) {
Expand Down
Loading