Skip to content
Open
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
15 changes: 4 additions & 11 deletions include/electronic-id/electronic-id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@

#include "enums.hpp"

#include <functional>
#include <optional>

namespace electronic_id
{

Expand Down Expand Up @@ -99,25 +96,21 @@ class ElectronicID
* By default, this function does nothing. It serves as an extension point for
* Pkcs11ElectronicID which needs to release the PKCS#11 module before the application exits to
* prevent potential crashes. */
virtual void release() const {}
virtual void release() const { }

virtual std::string name() const = 0;
virtual Type type() const = 0;

virtual pcsc_cpp::SmartCard const& smartcard() const { return card; }

protected:
ElectronicID(pcsc_cpp::SmartCard&& _card) noexcept : card(std::move(_card)) {}
ElectronicID(pcsc_cpp::SmartCard&& _card) noexcept : card(std::move(_card)) { }

pcsc_cpp::SmartCard card;
};

using ElectronicIDConstructor = std::function<ElectronicID::ptr(const pcsc_cpp::Reader&)>;

std::optional<ElectronicIDConstructor> findMaskedATR(const pcsc_cpp::byte_vector& atr);

bool isCardSupported(const pcsc_cpp::byte_vector& atr);

/** Returns an electronic ID instance for a supported card in the reader, or nullptr if the card is
* not supported. */
ElectronicID::ptr getElectronicID(const pcsc_cpp::Reader& reader);

/** Automatic card selection that either returns a vector of electronic ID pointers with available
Expand Down
4 changes: 2 additions & 2 deletions src/availableSupportedCards.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ std::vector<ElectronicID::ptr> availableSupportedCards()
continue;
}
seenCard = true;
if (isCardSupported(reader.cardAtr)) {
cards.push_back(getElectronicID(reader));
if (auto eid = getElectronicID(reader)) {
cards.push_back(std::move(eid));
}
}

Expand Down
31 changes: 7 additions & 24 deletions src/electronic-id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include "magic_enum/magic_enum.hpp"

#include <functional>
#include <map>
#include <numeric>

Expand All @@ -39,6 +40,8 @@ using namespace std::string_literals;
namespace
{

using ElectronicIDConstructor = std::function<ElectronicID::ptr(const Reader&)>;

template <typename T>
constexpr auto constructor(const Reader& reader)
{
Expand Down Expand Up @@ -223,39 +226,19 @@ const auto SUPPORTED_ALGORITHMS = std::map<std::string, HashAlgorithm> {
namespace electronic_id
{

std::optional<ElectronicIDConstructor> findMaskedATR(const byte_vector& atr)
{
if (auto i = std::find(MASKED_ATRS.cbegin(), MASKED_ATRS.cend(), atr);
i != MASKED_ATRS.cend()) {
return i->constructor;
}
return std::nullopt;
}

bool isCardSupported(const pcsc_cpp::byte_vector& atr)
{
if (SUPPORTED_ATRS.contains(atr)) {
return true;
}

// If exact ATR match is not found, fall back to masked ATR lookup.
return findMaskedATR(atr).has_value();
}

ElectronicID::ptr getElectronicID(const pcsc_cpp::Reader& reader)
{
if (auto it = SUPPORTED_ATRS.find(reader.cardAtr); it != SUPPORTED_ATRS.end()) {
return it->second(reader);
}

// If exact ATR match is not found, fall back to masked ATR lookup.
if (auto eIDConstructor = findMaskedATR(reader.cardAtr)) {
return (*eIDConstructor)(reader);
if (auto i = std::find(MASKED_ATRS.cbegin(), MASKED_ATRS.cend(), reader.cardAtr);
i != MASKED_ATRS.cend()) {
return i->constructor(reader);
}

// It should be verified that the card is supported with isCardSupported() before
// calling getElectronicID(), so it is a programming error to reach this point.
THROW(ProgrammingError, "Card with ATR '" + reader.cardAtr + "' is not supported");
return nullptr;
}

bool ElectronicID::isSupportedSigningHashAlgorithm(const HashAlgorithm hashAlgo) const
Expand Down
28 changes: 15 additions & 13 deletions tests/mock/test-find-masked-atr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,28 @@

#include "electronic-id/electronic-id.hpp"

#include "atrs.hpp"

#include <gtest/gtest.h>

using namespace electronic_id;

const pcsc_cpp::byte_vector BEL_EID_V1_7_ATR {0x3b, 0x98, 0x13, 0x40, 0x0a, 0xa5, 0x03,
0x01, 0x01, 0x01, 0xad, 0x13, 0x11};
const pcsc_cpp::byte_vector INVALID_ATR {0xaa, 0xbb, 0xcc, 0x40, 0x0a, 0xa5, 0x03,
0x01, 0x01, 0x01, 0xad, 0x13, 0x11};

TEST(electronic_id_test, findMaskedATRSuccessWithSupportedMaskedATR)
{
EXPECT_TRUE(findMaskedATR(BEL_EID_V1_7_ATR).has_value());
}
const pcsc_cpp::Reader INVALID_ATR {
nullptr,
{},
{0xaa, 0xbb, 0xcc, 0x40, 0x0a, 0xa5, 0x03, 0x01, 0x01, 0x01, 0xad, 0x13, 0x11},
true};

TEST(electronic_id_test, findMaskedATRFailureWithUnSupportedATR)
TEST(electronic_id_test, getElectronicIDSuccessWithSupportedMaskedATR)
{
EXPECT_FALSE(findMaskedATR(INVALID_ATR).has_value());
PcscMock::setAtr(FINEID_V4_ATR);
auto result = getElectronicID(pcsc_cpp::listReaders().front());
EXPECT_TRUE(result);
EXPECT_EQ(result->name(), "FinEID v4");
PcscMock::reset();
}

TEST(electronic_id_test, isCardSupportedSuccessWithSupportedMaskedATR)
TEST(electronic_id_test, getElectronicIDFailureWithUnsupportedMaskedATR)
{
EXPECT_TRUE(isCardSupported(BEL_EID_V1_7_ATR));
EXPECT_FALSE(getElectronicID(INVALID_ATR));
}
19 changes: 7 additions & 12 deletions tests/mock/test-is-card-supported.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,13 @@

using namespace electronic_id;

const pcsc_cpp::byte_vector EstEIDIDEMIAV1_ATR {0x3b, 0xdb, 0x96, 0x00, 0x80, 0xb1, 0xfe, 0x45,
0x1f, 0x83, 0x00, 0x12, 0x23, 0x3f, 0x53, 0x65,
0x49, 0x44, 0x0f, 0x90, 0x00, 0xf1};
const pcsc_cpp::byte_vector INVALID_ATR {0xaa, 0xbb, 0xcc, 0x40, 0x0a, 0xa5, 0x03,
0x01, 0x01, 0x01, 0xad, 0x13, 0x11};
const pcsc_cpp::Reader INVALID_ATR {
nullptr,
{},
{0xaa, 0xbb, 0xcc, 0x40, 0x0a, 0xa5, 0x03, 0x01, 0x01, 0x01, 0xad, 0x13, 0x11},
true};

TEST(electronic_id_test, isCardSupportedSuccessWithSupportedATR)
TEST(electronic_id_test, getElectronicIDNullForUnsupportedATR)
{
EXPECT_TRUE(isCardSupported(EstEIDIDEMIAV1_ATR));
}

TEST(electronic_id_test, isCardSupportedFailureWithUnsupportedATR)
{
EXPECT_FALSE(isCardSupported(INVALID_ATR));
EXPECT_FALSE(getElectronicID(INVALID_ATR));
}
Loading