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 lib/libelectronic-id
Submodule libelectronic-id updated 40 files
+1 −1 .github/workflows/cmake-windows.yml
+3 −1 CMakeLists.txt
+5 −22 include/electronic-id/electronic-id.hpp
+0 −1 lib/libpcsc-cpp/CMakeLists.txt
+9 −0 lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp-utils.hpp
+66 −67 lib/libpcsc-cpp/include/pcsc-cpp/pcsc-cpp.hpp
+18 −30 lib/libpcsc-cpp/src/SCardCall.hpp
+105 −86 lib/libpcsc-cpp/src/SmartCard.cpp
+0 −161 lib/libpcsc-cpp/src/utils.cpp
+5 −5 lib/libpcsc-cpp/tests/mock/test-connect-to-card-transmit-apdus.cpp
+1 −1 scripts/clang-format.sh
+3 −16 src/availableSupportedCards.cpp
+5 −0 src/electronic-id.cpp
+14 −27 src/electronic-ids/TLV.hpp
+1 −2 src/electronic-ids/ms-cryptoapi/MsCryptoApiElectronicID.hpp
+4 −11 src/electronic-ids/ms-cryptoapi/listMsCryptoApiElectronicIDs.cpp
+1 −1 src/electronic-ids/ms-cryptoapi/listMsCryptoApiElectronicIDs.hpp
+71 −43 src/electronic-ids/pcsc/EIDIDEMIA.cpp
+18 −20 src/electronic-ids/pcsc/EIDIDEMIA.hpp
+54 −83 src/electronic-ids/pcsc/EIDThales.cpp
+66 −0 src/electronic-ids/pcsc/EIDThales.hpp
+1 −2 src/electronic-ids/pcsc/EstEIDIDEMIA.hpp
+52 −0 src/electronic-ids/pcsc/EstEIDThales.hpp
+33 −40 src/electronic-ids/pcsc/FinEID.hpp
+37 −44 src/electronic-ids/pcsc/LatEIDIDEMIAv2.cpp
+11 −12 src/electronic-ids/pcsc/LatEIDIDEMIAv2.hpp
+28 −18 src/electronic-ids/pcsc/PcscElectronicID.hpp
+91 −94 src/electronic-ids/pcsc/pcsc-common.hpp
+1 −2 src/electronic-ids/pkcs11/Pkcs11ElectronicID.cpp
+17 −2 tests/common/selectcard.hpp
+20 −20 tests/common/verify.hpp
+7 −9 tests/integration/test-authenticate.cpp
+3 −5 tests/integration/test-get-certificate.cpp
+8 −10 tests/integration/test-signing.cpp
+131 −142 tests/mock/select-certificate-script-EST-IDEMIA.hpp
+24 −28 tests/mock/select-certificate-script-FIN-V3.hpp
+20 −24 tests/mock/select-certificate-script-FIN-V4.hpp
+32 −36 tests/mock/select-certificate-script-LAT-V2.hpp
+4 −4 tests/mock/test-autoselect-card.cpp
+36 −40 tests/mock/test-get-certificate.cpp
8 changes: 4 additions & 4 deletions src/controller/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,12 @@ CommandWithArgumentsPtr Application::parseArgs()
void Application::registerMetatypes()
{
qRegisterMetaType<electronic_id::AutoSelectFailed::Reason>();
qRegisterMetaType<electronic_id::CardInfo::ptr>();
qRegisterMetaType<std::vector<electronic_id::CardInfo::ptr>>();
qRegisterMetaType<electronic_id::ElectronicID::ptr>();
qRegisterMetaType<std::vector<electronic_id::ElectronicID::ptr>>();
qRegisterMetaType<electronic_id::VerifyPinFailed::Status>();

qRegisterMetaType<CardCertificateAndPinInfo>();
qRegisterMetaType<std::vector<CardCertificateAndPinInfo>>();
qRegisterMetaType<EidCertificateAndPinInfo>();
qRegisterMetaType<std::vector<EidCertificateAndPinInfo>>();

qRegisterMetaType<RetriableError>();
}
6 changes: 3 additions & 3 deletions src/controller/certandpininfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ struct PinInfo
static constexpr int PIN_PAD_PIN_ENTRY_TIMEOUT = pcsc_cpp::PIN_PAD_PIN_ENTRY_TIMEOUT;
};

struct CardCertificateAndPinInfo
struct EidCertificateAndPinInfo
{
electronic_id::CardInfo::ptr cardInfo;
electronic_id::ElectronicID::ptr eid;
QByteArray certificateBytesInDer;
QSslCertificate certificate {};
CertificateInfo certInfo;
PinInfo pinInfo;
};

Q_DECLARE_METATYPE(CardCertificateAndPinInfo)
Q_DECLARE_METATYPE(EidCertificateAndPinInfo)
12 changes: 6 additions & 6 deletions src/controller/command-handlers/authenticate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,20 @@ Authenticate::Authenticate(const CommandWithArguments& cmd) : CertificateReader(
}

QVariantMap Authenticate::onConfirm(WebEidUI* window,
const CardCertificateAndPinInfo& cardCertAndPin)
const EidCertificateAndPinInfo& certAndPinInfo)
{
try {
const auto signatureAlgorithm =
QString::fromStdString(cardCertAndPin.cardInfo->eid().authSignatureAlgorithm());
QString::fromStdString(certAndPinInfo.eid->authSignatureAlgorithm());
pcsc_cpp::byte_vector pin;
// Reserve space for APDU overhead (5 bytes) + PIN padding (16 bytes) to prevent PIN memory
// reallocation. The 16-byte limit comes from the max PIN length of 12 bytes across all card
// implementations in lib/libelectronic-id/src/electronic-ids/pcsc/.
pin.reserve(5 + 16);
getPin(pin, cardCertAndPin.cardInfo->eid(), window);
const auto signature = createSignature(origin.url(), challengeNonce,
cardCertAndPin.cardInfo->eid(), std::move(pin));
return createAuthenticationToken(signatureAlgorithm, cardCertAndPin.certificateBytesInDer,
getPin(pin, *certAndPinInfo.eid, window);
const auto signature =
createSignature(origin.url(), challengeNonce, *certAndPinInfo.eid, std::move(pin));
return createAuthenticationToken(signatureAlgorithm, certAndPinInfo.certificateBytesInDer,
signature);

} catch (const VerifyPinFailed& failure) {
Expand Down
2 changes: 1 addition & 1 deletion src/controller/command-handlers/authenticate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Authenticate : public CertificateReader

void connectSignals(const WebEidUI* window) override;
QVariantMap onConfirm(WebEidUI* window,
const CardCertificateAndPinInfo& cardCertAndPin) override;
const EidCertificateAndPinInfo& certAndPinInfo) override;

signals:
void verifyPinFailed(const electronic_id::VerifyPinFailed::Status status,
Expand Down
44 changes: 22 additions & 22 deletions src/controller/command-handlers/certificatereader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ using namespace electronic_id;
namespace
{

CardCertificateAndPinInfo getCertificateWithStatusAndInfo(const CardInfo::ptr& card,
const CertificateType certificateType)
EidCertificateAndPinInfo getCertificateWithStatusAndInfo(const ElectronicID::ptr& eid,
const CertificateType certificateType)
{
const auto certificateBytes = card->eid().getCertificate(certificateType);
const auto certificateBytes = eid->getCertificate(certificateType);

QByteArray certificateDer(reinterpret_cast<const char*>(certificateBytes.data()),
int(certificateBytes.size()));
QSslCertificate certificate(certificateDer, QSsl::Der);
if (certificate.isNull()) {
THROW(SmartCardChangeRequiredError,
"Invalid certificate returned by electronic ID " + card->eid().name());
"Invalid certificate returned by electronic ID " + eid->name());
}

auto subject = certificate.subjectInfo(QSslCertificate::CommonName).join(' ');
Expand All @@ -61,16 +61,16 @@ CardCertificateAndPinInfo getCertificateWithStatusAndInfo(const CardInfo::ptr& c
CertificateInfo certInfo {
certificateType, certificate.expiryDate() < QDateTime::currentDateTimeUtc(),
certificate.effectiveDate() > QDateTime::currentDateTimeUtc(), std::move(subject)};
PinInfo pinInfo {certificateType.isAuthentication() ? card->eid().authPinMinMaxLength()
: card->eid().signingPinMinMaxLength(),
certificateType.isAuthentication() ? card->eid().authPinRetriesLeft()
: card->eid().signingPinRetriesLeft(),
card->eid().smartcard().readerHasPinPad()};
PinInfo pinInfo {certificateType.isAuthentication() ? eid->authPinMinMaxLength()
: eid->signingPinMinMaxLength(),
certificateType.isAuthentication() ? eid->authPinRetriesLeft()
: eid->signingPinRetriesLeft(),
eid->smartcard().readerHasPinPad()};
if (pinInfo.pinRetriesCount.first == 0) {
pinInfo.pinIsBlocked = true;
}

return {card, std::move(certificateDer), certificate, std::move(certInfo), std::move(pinInfo)};
return {eid, std::move(certificateDer), certificate, std::move(certInfo), std::move(pinInfo)};
}

} // namespace
Expand All @@ -83,27 +83,27 @@ CertificateReader::CertificateReader(const CommandWithArguments& cmd) : CommandH
}
}

void CertificateReader::run(const std::vector<CardInfo::ptr>& cards)
void CertificateReader::run(const std::vector<ElectronicID::ptr>& eids)
{
REQUIRE_NOT_EMPTY_CONTAINS_NON_NULL_PTRS(cards)
REQUIRE_NOT_EMPTY_CONTAINS_NON_NULL_PTRS(eids)

certificateType = command.first == CommandType::AUTHENTICATE ? CertificateType::AUTHENTICATION
: CertificateType::SIGNING;

std::vector<CardCertificateAndPinInfo> certInfos;
certInfos.reserve(cards.size());
for (const auto& card : cards) {
std::vector<EidCertificateAndPinInfo> certAndPinInfos;
certAndPinInfos.reserve(eids.size());
for (const auto& eid : eids) {
try {
certInfos.push_back(getCertificateWithStatusAndInfo(card, certificateType));
certAndPinInfos.push_back(getCertificateWithStatusAndInfo(eid, certificateType));
} catch (const WrongCertificateTypeError&) {
// Ignore eIDs that don't support the given ceritifcate type.
}
}

if (certInfos.empty()) {
if (certAndPinInfos.empty()) {
emit retry(RetriableError::NO_VALID_CERTIFICATE_AVAILABLE);
} else {
emitCertificatesReady(certInfos);
emitCertificatesReady(certAndPinInfos);
}
}

Expand All @@ -117,12 +117,12 @@ void CertificateReader::connectSignals(const WebEidUI* window)
}

void CertificateReader::emitCertificatesReady(
const std::vector<CardCertificateAndPinInfo>& certInfos)
const std::vector<EidCertificateAndPinInfo>& certAndPinInfos)
{
if (certInfos.size() == 1) {
emit singleCertificateReady(origin, certInfos[0]);
if (certAndPinInfos.size() == 1) {
emit singleCertificateReady(origin, certAndPinInfos[0]);
} else {
emit multipleCertificatesReady(origin, certInfos);
emit multipleCertificatesReady(origin, certAndPinInfos);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/controller/command-handlers/certificatereader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ class CertificateReader : public CommandHandler
public:
explicit CertificateReader(const CommandWithArguments& cmd);

void run(const std::vector<electronic_id::CardInfo::ptr>& cards) override;
void run(const std::vector<electronic_id::ElectronicID::ptr>& eids) override;
void connectSignals(const WebEidUI* window) override;

protected:
virtual void
emitCertificatesReady(const std::vector<CardCertificateAndPinInfo>& cardCertAndPinInfos);
emitCertificatesReady(const std::vector<EidCertificateAndPinInfo>& certAndPinInfos);
void validateAndStoreOrigin(const QVariantMap& arguments);

electronic_id::CertificateType certificateType = electronic_id::CertificateType::NONE;
Expand Down
6 changes: 3 additions & 3 deletions src/controller/command-handlers/getcertificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ GetCertificate::GetCertificate(const CommandWithArguments& cmd) : CertificateRea
}

QVariantMap GetCertificate::onConfirm(WebEidUI* /* window */,
const CardCertificateAndPinInfo& cardCertAndPin)
const EidCertificateAndPinInfo& certAndPinInfo)
{
// Quoting https://tools.ietf.org/html/rfc7515#section-4.1.6:
// Each string in the array is a Base64-encoded (Section 4 of [RFC4648] -- not
// Base64url-encoded) DER [ITU.X690.2008] PKIX certificate value.
auto certPem = cardCertAndPin.certificateBytesInDer.toBase64();
auto algos = supportedSigningAlgos(cardCertAndPin.cardInfo->eid());
auto certPem = certAndPinInfo.certificateBytesInDer.toBase64();
auto algos = supportedSigningAlgos(*certAndPinInfo.eid);
return {{"certificate", QString(certPem)}, {"supportedSignatureAlgorithms", algos}};
}
2 changes: 1 addition & 1 deletion src/controller/command-handlers/getcertificate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ class GetCertificate : public CertificateReader
GetCertificate(const CommandWithArguments& cmd);

QVariantMap onConfirm(WebEidUI* window,
const CardCertificateAndPinInfo& cardCertAndPin) override;
const EidCertificateAndPinInfo& certAndPinInfo) override;
};
25 changes: 12 additions & 13 deletions src/controller/command-handlers/sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ Sign::Sign(const CommandWithArguments& cmd) : CertificateReader(cmd)
validateAndStoreOrigin(arguments);
}

void Sign::emitCertificatesReady(const std::vector<CardCertificateAndPinInfo>& cardCertAndPinInfos)
void Sign::emitCertificatesReady(const std::vector<EidCertificateAndPinInfo>& certAndPinInfos)
{
const CardCertificateAndPinInfo* cardWithCertificateFromArgs = nullptr;
const EidCertificateAndPinInfo* cardWithCertificateFromArgs = nullptr;

for (const auto& cardCertAndPin : cardCertAndPinInfos) {
for (const auto& certAndPinInfo : certAndPinInfos) {
// Check if the certificate read from the eID matches the certificate provided as argument.
if (cardCertAndPin.certificate.toDer() == userEidCertificateFromArgs) {
cardWithCertificateFromArgs = &cardCertAndPin;
if (certAndPinInfo.certificate.toDer() == userEidCertificateFromArgs) {
cardWithCertificateFromArgs = &certAndPinInfo;
}
}

Expand All @@ -86,28 +86,27 @@ void Sign::emitCertificatesReady(const std::vector<CardCertificateAndPinInfo>& c
return;
}

if (!cardWithCertificateFromArgs->cardInfo->eid().isSupportedSigningHashAlgorithm(hashAlgo)) {
if (!cardWithCertificateFromArgs->eid->isSupportedSigningHashAlgorithm(hashAlgo)) {
THROW(ArgumentFatalError,
"Electronic ID " + cardWithCertificateFromArgs->cardInfo->eid().name()
"Electronic ID " + cardWithCertificateFromArgs->eid->name()
+ " does not support hash algorithm " + std::string(hashAlgo));
}

emit singleCertificateReady(origin, *cardWithCertificateFromArgs);
}

QVariantMap Sign::onConfirm(WebEidUI* window, const CardCertificateAndPinInfo& cardCertAndPin)
QVariantMap Sign::onConfirm(WebEidUI* window, const EidCertificateAndPinInfo& certAndPinInfo)
{
try {
pcsc_cpp::byte_vector pin;
// Reserve space for APDU overhead (5 bytes) + PIN padding (16 bytes) to prevent PIN memory
// reallocation. The 16-byte limit comes from the max PIN length of 12 bytes across all card
// implementations in lib/libelectronic-id/src/electronic-ids/pcsc/.
pin.reserve(5 + 16);
getPin(pin, cardCertAndPin.cardInfo->eid(), window);
const auto signature =
signHash(cardCertAndPin.cardInfo->eid(), std::move(pin), docHash, hashAlgo);
return {{QStringLiteral("signature"), signature.first},
{QStringLiteral("signatureAlgorithm"), signature.second}};
getPin(pin, *certAndPinInfo.eid, window);
auto signature = signHash(*certAndPinInfo.eid, std::move(pin), docHash, hashAlgo);
return {{QStringLiteral("signature"), std::move(signature.first)},
{QStringLiteral("signatureAlgorithm"), std::move(signature.second)}};

} catch (const VerifyPinFailed& failure) {
switch (failure.status()) {
Expand Down
6 changes: 3 additions & 3 deletions src/controller/command-handlers/sign.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ class Sign : public CertificateReader

void connectSignals(const WebEidUI* window) override;
QVariantMap onConfirm(WebEidUI* window,
const CardCertificateAndPinInfo& cardCertAndPin) override;
const EidCertificateAndPinInfo& certAndPinInfo) override;

signals:
void signingCertificateMismatch();
void verifyPinFailed(const electronic_id::VerifyPinFailed::Status status,
const qint8 retriesLeft);

private:
void emitCertificatesReady(
const std::vector<CardCertificateAndPinInfo>& cardCertAndPinInfos) override;
void
emitCertificatesReady(const std::vector<EidCertificateAndPinInfo>& certAndPinInfos) override;
void validateAndStoreDocHashAndHashAlgo(const QVariantMap& args);

QByteArray docHash;
Expand Down
12 changes: 5 additions & 7 deletions src/controller/commandhandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,18 @@ class CommandHandler : public QObject
public:
using ptr = std::unique_ptr<CommandHandler>;

virtual void run(const std::vector<electronic_id::CardInfo::ptr>& cards) = 0;
virtual void run(const std::vector<electronic_id::ElectronicID::ptr>& eids) = 0;
virtual void connectSignals(const WebEidUI* window) = 0;
virtual QVariantMap onConfirm(WebEidUI* window,
const CardCertificateAndPinInfo& cardCertAndPin) = 0;
const EidCertificateAndPinInfo& certAndPinInfo) = 0;

CommandType commandType() const { return command.first; }

signals:
void retry(const RetriableError error);
void
multipleCertificatesReady(const QUrl& origin,
const std::vector<CardCertificateAndPinInfo>& cardCertAndPinInfos);
void singleCertificateReady(const QUrl& origin,
const CardCertificateAndPinInfo& cardCertAndPinInfo);
void multipleCertificatesReady(const QUrl& origin,
const std::vector<EidCertificateAndPinInfo>& certAndPinInfos);
void singleCertificateReady(const QUrl& origin, const EidCertificateAndPinInfo& certAndPinInfo);

protected:
CommandHandler(const CommandWithArguments& cmd) : command(cmd) {}
Expand Down
25 changes: 13 additions & 12 deletions src/controller/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,36 +163,37 @@ void Controller::connectOkCancelWaitingForPinPad()
connect(window, &WebEidUI::waitingForPinPad, this, &Controller::onConfirmCommandHandler);
}

void Controller::onCardsAvailable(const std::vector<electronic_id::CardInfo::ptr>& availableCards)
void Controller::onCardsAvailable(
const std::vector<electronic_id::ElectronicID::ptr>& availableEids)
{
try {
REQUIRE_NON_NULL(commandHandler)
REQUIRE_NON_NULL(window)
REQUIRE_NOT_EMPTY_CONTAINS_NON_NULL_PTRS(availableCards)
REQUIRE_NOT_EMPTY_CONTAINS_NON_NULL_PTRS(availableEids)

for (const auto& card : availableCards) {
for (const auto& card : availableEids) {
const auto protocol =
card->eid().smartcard().protocol() == SmartCard::Protocol::T0 ? "T=0" : "T=1";
qInfo() << "Card" << card->eid().name() << "in reader" << card->reader().name
card->smartcard().protocol() == SmartCard::Protocol::T0 ? "T=0" : "T=1";
qInfo() << "Card" << card->name() << "in reader" << card->smartcard().readerName()
<< "using protocol" << protocol;
}

window->showWaitingForCardPage(commandHandler->commandType());

commandHandler->connectSignals(window);

runCommandHandler(availableCards);
runCommandHandler(availableEids);

} catch (const std::exception& error) {
onCriticalFailure(error.what());
}
}

void Controller::runCommandHandler(const std::vector<electronic_id::CardInfo::ptr>& availableCards)
void Controller::runCommandHandler(const std::vector<ElectronicID::ptr>& availableEids)
{
try {
CommandHandlerRunThread* commandHandlerRunThread =
new CommandHandlerRunThread(this, *commandHandler, availableCards);
new CommandHandlerRunThread(this, *commandHandler, availableEids);
saveChildThreadPtrAndConnectFailureFinish(commandHandlerRunThread);
connectRetry(commandHandlerRunThread);

Expand Down Expand Up @@ -247,13 +248,13 @@ void Controller::disposeUI()
}
}

void Controller::onConfirmCommandHandler(const CardCertificateAndPinInfo& cardCertAndPinInfo)
void Controller::onConfirmCommandHandler(const EidCertificateAndPinInfo& certAndPinInfo)
{
stopCardEventMonitorThread();

try {
CommandHandlerConfirmThread* commandHandlerConfirmThread =
new CommandHandlerConfirmThread(this, *commandHandler, window, cardCertAndPinInfo);
new CommandHandlerConfirmThread(this, *commandHandler, window, certAndPinInfo);
connect(commandHandlerConfirmThread, &CommandHandlerConfirmThread::completed, this,
&Controller::onCommandHandlerConfirmCompleted);
saveChildThreadPtrAndConnectFailureFinish(commandHandlerConfirmThread);
Expand Down Expand Up @@ -317,10 +318,10 @@ void Controller::connectRetry(const ControllerChildThread* childThread)
connect(window, &WebEidUI::retry, this, &Controller::onRetry);
}

void Controller::onDialogOK(const CardCertificateAndPinInfo& cardCertAndPinInfo)
void Controller::onDialogOK(const EidCertificateAndPinInfo& certAndPinInfo)
{
if (commandHandler) {
onConfirmCommandHandler(cardCertAndPinInfo);
onConfirmCommandHandler(certAndPinInfo);
} else {
// This should not happen, and when it does, OK should be equivalent to cancel.
onPinPadCancel();
Expand Down
Loading
Loading