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
21 changes: 2 additions & 19 deletions include/electronic-id/electronic-id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,26 +114,9 @@ bool isCardSupported(const pcsc_cpp::byte_vector& atr);

ElectronicID::ptr getElectronicID(const pcsc_cpp::Reader& reader);

/** Aggregates reader and electronic ID objects for communicating with and inspecting the eID card.
*/
class CardInfo
{
public:
using ptr = std::shared_ptr<CardInfo>;

CardInfo(pcsc_cpp::Reader r, ElectronicID::ptr e) : _reader(std::move(r)), _eid(std::move(e)) {}

const pcsc_cpp::Reader& reader() const { return _reader; }
const ElectronicID& eid() const { return *_eid; }

private:
pcsc_cpp::Reader _reader;
ElectronicID::ptr _eid;
};

/** Automatic card selection that either returns a vector of card info pointers with available
/** Automatic card selection that either returns a vector of electronic ID pointers with available
* supported cards or throws AutoSelectFailed. */
std::vector<CardInfo::ptr> availableSupportedCards();
std::vector<ElectronicID::ptr> availableSupportedCards();

/** Base class for fatal errors in parameters or environment conditions that do not allow retrying.
*/
Expand Down
9 changes: 6 additions & 3 deletions lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,17 @@ class SmartCard
{
public:
TransactionGuard(const CardImpl& CardImpl, bool& inProgress);
~TransactionGuard();
~TransactionGuard() noexcept;
PCSC_CPP_DISABLE_COPY_MOVE(TransactionGuard);

private:
const CardImpl& card;
bool& inProgress;
};

SmartCard(const ContextPtr& context, const string_t& readerName, byte_vector atr);
SmartCard(ContextPtr context, string_t readerName, byte_vector atr);
SmartCard(); // Null object constructor.
~SmartCard();
~SmartCard() noexcept;
PCSC_CPP_DISABLE_COPY_MOVE(SmartCard);

TransactionGuard beginTransaction();
Expand All @@ -245,9 +245,12 @@ class SmartCard

Protocol protocol() const { return _protocol; }
const byte_vector& atr() const { return _atr; }
const string_t& readerName() const { return _readerName; }

private:
ContextPtr ctx;
CardImplPtr card;
string_t _readerName;
byte_vector _atr;
Protocol _protocol = Protocol::UNDEFINED;
bool transactionInProgress = false;
Expand Down
12 changes: 7 additions & 5 deletions lib/libpcsc-cpp/src/SmartCard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ SmartCard::TransactionGuard::TransactionGuard(const CardImpl& card, bool& inProg
inProgress = true;
}

SmartCard::TransactionGuard::~TransactionGuard()
SmartCard::TransactionGuard::~TransactionGuard() noexcept
{
inProgress = false;
try {
Expand All @@ -288,15 +288,17 @@ SmartCard::TransactionGuard::~TransactionGuard()
}
}

SmartCard::SmartCard(const ContextPtr& contex, const string_t& readerName, byte_vector atr) :
card(std::make_unique<CardImpl>(connectToCard(contex->handle(), readerName))),
_atr(std::move(atr)), _protocol(convertToSmartCardProtocol(card->protocol()))
SmartCard::SmartCard(ContextPtr context, string_t readerName, byte_vector atr) :
ctx(std::move(context)),
card(std::make_unique<CardImpl>(connectToCard(ctx->handle(), readerName))),
_readerName(std::move(readerName)), _atr(std::move(atr)),
_protocol(convertToSmartCardProtocol(card->protocol()))
{
// TODO: debug("Card ATR -> " + bytes2hexstr(atr))
}

SmartCard::SmartCard() = default;
SmartCard::~SmartCard() = default;
SmartCard::~SmartCard() noexcept = default;

SmartCard::TransactionGuard SmartCard::beginTransaction()
{
Expand Down
19 changes: 3 additions & 16 deletions src/availableSupportedCards.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,15 @@
#include "electronic-ids/ms-cryptoapi/listMsCryptoApiElectronicIDs.hpp"
#endif

namespace
{

using namespace electronic_id;

inline CardInfo::ptr connectToCard(const pcsc_cpp::Reader& reader)
{
auto eid = getElectronicID(reader);
return std::make_shared<CardInfo>(reader, eid);
}

} // namespace

namespace electronic_id
{

std::vector<CardInfo::ptr> availableSupportedCards()
std::vector<ElectronicID::ptr> availableSupportedCards()
{
std::vector<pcsc_cpp::Reader> readers;
try {
readers = pcsc_cpp::listReaders();
std::vector<CardInfo::ptr> cards;
std::vector<ElectronicID::ptr> cards;

auto seenCard = false;
// The list may be empty, but we cannot throw yet due to the listMsCryptoApiElectronicIDs()
Expand All @@ -58,7 +45,7 @@ std::vector<CardInfo::ptr> availableSupportedCards()
}
seenCard = true;
if (isCardSupported(reader.cardAtr)) {
cards.push_back(connectToCard(reader));
cards.push_back(getElectronicID(reader));
}
}

Expand Down
15 changes: 4 additions & 11 deletions src/electronic-ids/ms-cryptoapi/listMsCryptoApiElectronicIDs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace electronic_id

// Enumerates all certificates and converts the valid hardware-based ones to MsCryptoApiElectronicID
// objects.
std::vector<CardInfo::ptr> listMsCryptoApiElectronicIDs()
std::vector<ElectronicID::ptr> listMsCryptoApiElectronicIDs()
{
HCERTSTORE sys =
CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING, 0,
Expand All @@ -46,13 +46,7 @@ std::vector<CardInfo::ptr> listMsCryptoApiElectronicIDs()
}
auto closeCertStore = stdext::make_scope_exit([=]() { CertCloseStore(sys, 0); });

std::vector<CardInfo::ptr> msCryptoApiElectronicIDs;
pcsc_cpp::Reader dummyReader {
nullptr,
L"Dummy reader for MS CryptoAPI tokens"s,
{},
true,
};
std::vector<ElectronicID::ptr> msCryptoApiElectronicIDs;

PCCERT_CONTEXT cert = nullptr;
while ((cert = CertEnumCertificatesInStore(sys, cert)) != nullptr) {
Expand Down Expand Up @@ -121,8 +115,7 @@ std::vector<CardInfo::ptr> listMsCryptoApiElectronicIDs()
continue; // TODO: log.
}
algo.resize(size / 2 - 1);
// TODO: use algo.starts_with(L"EC") when migrating to C++20.
if (algo != L"RSA" && algo.rfind(L"EC", 0) != 0) {
if (algo != L"RSA" && !algo.starts_with(L"EC")) {
// We only support RSA and ECC algorithms.
continue; // TODO: log.
}
Expand All @@ -147,7 +140,7 @@ std::vector<CardInfo::ptr> listMsCryptoApiElectronicIDs()
std::move(certData), certType,
algo == L"RSA", key, freeKey);

msCryptoApiElectronicIDs.push_back(std::make_shared<CardInfo>(dummyReader, std::move(eid)));
msCryptoApiElectronicIDs.push_back(std::move(eid));
}

// CertEnumCertificatesInStore() function frees the CERT_CONTEXT referenced by non-NULL values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
namespace electronic_id
{

std::vector<CardInfo::ptr> listMsCryptoApiElectronicIDs();
std::vector<ElectronicID::ptr> listMsCryptoApiElectronicIDs();

}
2 changes: 1 addition & 1 deletion tests/common/selectcard.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include <stdexcept>

inline electronic_id::CardInfo::ptr autoSelectSupportedCard() {
inline electronic_id::ElectronicID::ptr autoSelectSupportedCard() {
using namespace electronic_id;

auto cardList = availableSupportedCards();
Expand Down
14 changes: 7 additions & 7 deletions tests/integration/test-authenticate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ TEST(electronic_id_test, authenticate)

EXPECT_TRUE(cardInfo);

std::cout << "Selected card: " << cardInfo->eid().name() << '\n';
std::cout << "Selected card: " << cardInfo->name() << '\n';

byte_vector cert = cardInfo->eid().getCertificate(CertificateType::AUTHENTICATION);
byte_vector cert = cardInfo->getCertificate(CertificateType::AUTHENTICATION);

std::cout << "Does the reader have a PIN-pad? "
<< (cardInfo->eid().smartcard().readerHasPinPad() ? "yes" : "no") << '\n';
<< (cardInfo->smartcard().readerHasPinPad() ? "yes" : "no") << '\n';

switch (cardInfo->eid().authSignatureAlgorithm()) {
switch (cardInfo->authSignatureAlgorithm()) {
case JsonWebSignatureAlgorithm::ES384:
case JsonWebSignatureAlgorithm::RS256:
case JsonWebSignatureAlgorithm::PS256:
Expand All @@ -55,7 +55,7 @@ TEST(electronic_id_test, authenticate)
"currently supported");
}

GTEST_ASSERT_GE(cardInfo->eid().authPinRetriesLeft().first, 0U);
GTEST_ASSERT_GE(cardInfo->authPinRetriesLeft().first, 0U);

byte_vector pin {'1', '2', '3', '4'};
pin.reserve(64);
Expand All @@ -64,9 +64,9 @@ TEST(electronic_id_test, authenticate)
<< std::string_view(reinterpret_cast<const char*>(pin.data()), pin.size()) << '\n';

const byte_vector dataToSign {'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'};
const JsonWebSignatureAlgorithm hashAlgo = cardInfo->eid().authSignatureAlgorithm();
const JsonWebSignatureAlgorithm hashAlgo = cardInfo->authSignatureAlgorithm();
const byte_vector hash = calculateDigest(hashAlgo.hashAlgorithm(), dataToSign);
auto signature = cardInfo->eid().signWithAuthKey(std::move(pin), hash);
auto signature = cardInfo->signWithAuthKey(std::move(pin), hash);

std::cout << "Authentication signature: " << signature << '\n';

Expand Down
6 changes: 3 additions & 3 deletions tests/integration/test-get-certificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ TEST(electronic_id_test, getCertificate)

EXPECT_TRUE(cardInfo);

std::cout << "Selected card: " << cardInfo->eid().name() << '\n';
std::cout << "Selected card: " << cardInfo->name() << '\n';

auto certificate = cardInfo->eid().getCertificate(CertificateType::AUTHENTICATION);
auto certificate = cardInfo->getCertificate(CertificateType::AUTHENTICATION);

std::cout << "Authentication certificate: " << certificate << '\n';

certificate = cardInfo->eid().getCertificate(CertificateType::SIGNING);
certificate = cardInfo->getCertificate(CertificateType::SIGNING);

std::cout << "Signing certificate: " << certificate << '\n';
}
17 changes: 8 additions & 9 deletions tests/integration/test-signing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,24 @@ static void signing(HashAlgorithm hashAlgo)

EXPECT_TRUE(cardInfo);

std::cout << "Selected card: " << cardInfo->eid().name() << '\n';
std::cout << "Selected card: " << cardInfo->name() << '\n';

if (!cardInfo->eid().isSupportedSigningHashAlgorithm(hashAlgo)) {
if (!cardInfo->isSupportedSigningHashAlgorithm(hashAlgo)) {
std::string skip = "Card does not support hashing algorithm: " + std::string(hashAlgo);
GTEST_SUCCESS_(skip.c_str());
return;
}

byte_vector cert = cardInfo->eid().getCertificate(CertificateType::SIGNING);
byte_vector cert = cardInfo->getCertificate(CertificateType::SIGNING);

GTEST_ASSERT_GE(cardInfo->eid().signingPinRetriesLeft().first, 0U);
GTEST_ASSERT_GE(cardInfo->signingPinRetriesLeft().first, 0U);

byte_vector pin;
if (cardInfo->eid().name() == "EstEID IDEMIA v1")
if (cardInfo->name() == "EstEID IDEMIA v1")
pin = {'1', '2', '3', '4', '5'}; // EstIDEMIA test card default PIN2
else if (cardInfo->eid().name() == "LatEID IDEMIA v1"
|| cardInfo->eid().name() == "LatEID IDEMIA v2")
else if (cardInfo->name() == "LatEID IDEMIA v1" || cardInfo->name() == "LatEID IDEMIA v2")
pin = {'1', '2', '3', '4', '5', '6'}; // LatIDEMIA test card default PIN2
else if (cardInfo->eid().name() == "FinEID v3" || cardInfo->eid().name() == "FinEID v4")
else if (cardInfo->name() == "FinEID v3" || cardInfo->name() == "FinEID v4")
pin = {'1', '2', '3', '4', '5', '6'}; // FinEID custom PIN
else
throw std::runtime_error("TEST signing: Unknown card");
Expand All @@ -66,7 +65,7 @@ static void signing(HashAlgorithm hashAlgo)
const byte_vector dataToSign {'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'};
const byte_vector hash = calculateDigest(hashAlgo, dataToSign);

auto signature = cardInfo->eid().signWithSigningKey(std::move(pin), hash, hashAlgo);
auto signature = cardInfo->signWithSigningKey(std::move(pin), hash, hashAlgo);

std::cout << "Signing signature: " << signature.first << '\n';

Expand Down
8 changes: 4 additions & 4 deletions tests/mock/test-autoselect-card.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ TEST(electronic_id_test, autoSelectSuccessWithSupportedCardEstIDEMIA)
PcscMock::setAtr(ESTEID_IDEMIA_V1_ATR);
auto result = autoSelectSupportedCard();
EXPECT_TRUE(result);
EXPECT_EQ(result->eid().name(), "EstEID IDEMIA v1");
EXPECT_EQ(result->name(), "EstEID IDEMIA v1");
PcscMock::reset();
}

Expand All @@ -47,7 +47,7 @@ TEST(electronic_id_test, autoSelectSuccessWithSupportedCardLatV2)
PcscMock::setAtr(LATEID_IDEMIA_V2_ATR);
auto result = autoSelectSupportedCard();
EXPECT_TRUE(result);
EXPECT_EQ(result->eid().name(), "LatEID IDEMIA v2");
EXPECT_EQ(result->name(), "LatEID IDEMIA v2");
PcscMock::reset();
}

Expand All @@ -56,7 +56,7 @@ TEST(electronic_id_test, autoSelectSuccessWithSupportedCardFinV3)
PcscMock::setAtr(FINEID_V3_ATR);
auto result = autoSelectSupportedCard();
EXPECT_TRUE(result);
EXPECT_EQ(result->eid().name(), "FinEID v3");
EXPECT_EQ(result->name(), "FinEID v3");
PcscMock::reset();
}

Expand All @@ -65,6 +65,6 @@ TEST(electronic_id_test, autoSelectSuccessWithSupportedCardFinV4)
PcscMock::setAtr(FINEID_V4_ATR);
auto result = autoSelectSupportedCard();
EXPECT_TRUE(result);
EXPECT_EQ(result->eid().name(), "FinEID v4");
EXPECT_EQ(result->name(), "FinEID v4");
PcscMock::reset();
}
Loading
Loading