Skip to content

Commit

Permalink
Add support for updated Latvian eID cards
Browse files Browse the repository at this point in the history
WE2-748

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma authored and mrts committed May 5, 2023
1 parent 80d8ab6 commit 3ee8d1d
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 51 deletions.
8 changes: 1 addition & 7 deletions include/electronic-id/electronic-id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class ElectronicID
};

virtual ~ElectronicID() = default;
PCSC_CPP_DISABLE_COPY_MOVE(ElectronicID);

// Function for retrieving the authentication and signing certificates.
virtual pcsc_cpp::byte_vector getCertificate(const CertificateType type) const = 0;
Expand Down Expand Up @@ -94,13 +95,6 @@ class ElectronicID
ElectronicID(pcsc_cpp::SmartCard::ptr _card) : card(std::move(_card)) {}

pcsc_cpp::SmartCard::ptr card;

private:
// The rule of five (C++ Core guidelines C.21).
ElectronicID(const ElectronicID&) = delete;
ElectronicID& operator=(const ElectronicID&) = delete;
ElectronicID(ElectronicID&&) = delete;
ElectronicID& operator=(ElectronicID&&) = delete;
};

bool isCardSupported(const pcsc_cpp::byte_vector& atr);
Expand Down
8 changes: 2 additions & 6 deletions src/electronic-ids/ms-cryptoapi/MsCryptoApiElectronicID.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,14 @@ class MsCryptoApiElectronicID : public ElectronicID
CertFreeCertificateContext(certContext);
}

PCSC_CPP_DISABLE_COPY_MOVE(MsCryptoApiElectronicID);

// The following placeholders are not used as the external PIN dialog manages PIN length
// validation.
static const int8_t PIN_RETRY_COUNT_PLACEHOLDER = -1;
static const size_t PIN_LENGTH_PLACEHOLDER = 0;

private:
// The rule of five.
MsCryptoApiElectronicID(MsCryptoApiElectronicID const&) = delete;
MsCryptoApiElectronicID(MsCryptoApiElectronicID&&) = delete;
void operator=(MsCryptoApiElectronicID const&) = delete;
MsCryptoApiElectronicID& operator=(MsCryptoApiElectronicID&&) = delete;

// Use the external dialog provided by the CryptoAPI cryptographic service provider.
bool providesExternalPinDialog() const override { return true; }

Expand Down
26 changes: 15 additions & 11 deletions src/electronic-ids/pcsc/EIDIDEMIA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "pcsc-common.hpp"

using namespace pcsc_cpp;
using namespace electronic_id;

namespace
{
Expand All @@ -34,14 +35,13 @@ const byte_vector::value_type AUTH_PIN_REFERENCE = 0x01;

} // namespace

namespace electronic_id
{

byte_vector EIDIDEMIA::getCertificateImpl(const CertificateType type) const
{
const std::vector<byte_vector> SELECT_AID_AND_CERT_FILE = {
selectApplicationID().MAIN_AID,
type.isAuthentication() ? selectApplicationID().AUTH_AID : selectApplicationID().SIGN_AID,
transmitApduWithExpectedResponse(*card, selectApplicationID().MAIN_AID);
transmitApduWithExpectedResponse(*card,
type.isAuthentication() ? selectApplicationID().AUTH_AID
: selectApplicationID().SIGN_AID);
const std::vector<byte_vector> SELECT_AID_AND_CERT_FILE {
type.isAuthentication() ? selectCertificate().AUTH_CERT : selectCertificate().SIGN_CERT,
};
return electronic_id::getCertificate(*card, SELECT_AID_AND_CERT_FILE);
Expand Down Expand Up @@ -95,7 +95,7 @@ ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::signingPinRetriesLeftImpl() c

const SelectApplicationIDCmds& EIDIDEMIA::selectApplicationID() const
{
static const auto selectAppIDCmds = SelectApplicationIDCmds {
static const SelectApplicationIDCmds selectAppIDCmds {
// Main AID.
{0x00, 0xA4, 0x04, 0x00, 0x10, 0xA0, 0x00, 0x00, 0x00, 0x77, 0x01,
0x08, 0x00, 0x07, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x01, 0x00},
Expand All @@ -111,13 +111,19 @@ const SelectApplicationIDCmds& EIDIDEMIA::selectApplicationID() const

const SelectCertificateCmds& EIDIDEMIA::selectCertificate() const
{
static const auto selectCertCmds = SelectCertificateCmds {
static const SelectCertificateCmds selectCert1Cmds {
// Authentication certificate.
{0x00, 0xA4, 0x02, 0x0C, 0x02, 0x34, 0x01},
// Signing certificate.
{0x00, 0xA4, 0x02, 0x0C, 0x02, 0x34, 0x1F},
};
return selectCertCmds;
static const SelectCertificateCmds selectCert2Cmds {
// Authentication certificate.
{0x00, 0xA4, 0x02, 0x0C, 0x02, 0x34, 0x02},
// Signing certificate.
{0x00, 0xA4, 0x02, 0x0C, 0x02, 0x34, 0x1E},
};
return isUpdated() ? selectCert2Cmds : selectCert1Cmds;
}

ElectronicID::PinRetriesRemainingAndMax
Expand All @@ -139,5 +145,3 @@ EIDIDEMIA::pinRetriesLeft(byte_vector::value_type pinReference) const
}
return {uint8_t(response.data[13]), uint8_t(response.data[10])};
}

} // namespace electronic_id
4 changes: 3 additions & 1 deletion src/electronic-ids/pcsc/EIDIDEMIA.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct ManageSecurityEnvCmds
class EIDIDEMIA : public PcscElectronicID
{
public:
EIDIDEMIA(pcsc_cpp::SmartCard::ptr _card) : PcscElectronicID(std::move(_card)) {}
explicit EIDIDEMIA(pcsc_cpp::SmartCard::ptr _card) : PcscElectronicID(std::move(_card)) {}

protected:
pcsc_cpp::byte_vector getCertificateImpl(const CertificateType type) const override;
Expand All @@ -76,6 +76,8 @@ class EIDIDEMIA : public PcscElectronicID
{
return false;
}

virtual bool isUpdated() const { return false; }
};

} // namespace electronic_id
17 changes: 10 additions & 7 deletions src/electronic-ids/pcsc/EstEIDIDEMIA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,23 @@
// ESTEID specification:
// https://installer.id.ee/media/id2019/TD-ID1-Chip-App.pdf

namespace electronic_id
{
using namespace electronic_id;

const ManageSecurityEnvCmds& EstEIDIDEMIAV1::selectSecurityEnv() const
{
static const auto selectSecurityEnvCmds = ManageSecurityEnvCmds {
static const ManageSecurityEnvCmds selectSecurityEnv1Cmds {
// Activate authentication environment.
{0x00, 0x22, 0x41, 0xa4, 0x06, 0x80, 0x01, 0x04, 0x84, 0x01, 0x81},
// Activate signing environment.
{0x00, 0x22, 0x41, 0xb6, 0x06, 0x80, 0x01, 0x54, 0x84, 0x01, 0x9f},
};
return selectSecurityEnvCmds;
static const ManageSecurityEnvCmds selectSecurityEnv2Cmds {
// Activate authentication environment.
{0x00, 0x22, 0x41, 0xa4, 0x06, 0x80, 0x01, 0x04, 0x84, 0x01, 0x82},
// Activate signing environment.
{0x00, 0x22, 0x41, 0xb6, 0x06, 0x80, 0x01, 0x64, 0x84, 0x01, 0x9e},
};
return isUpdated() ? selectSecurityEnv2Cmds : selectSecurityEnv1Cmds;
}

const std::set<SignatureAlgorithm>& EstEIDIDEMIAV1::supportedSigningAlgorithms() const
Expand All @@ -50,7 +55,7 @@ ElectronicID::Signature EstEIDIDEMIAV1::signWithSigningKeyImpl(const pcsc_cpp::b
const pcsc_cpp::byte_vector& hash,
const HashAlgorithm hashAlgo) const
{
static const size_t ECDSA384_INPUT_LENGTH = 384 / 8;
static constexpr size_t ECDSA384_INPUT_LENGTH = 384 / 8;
auto tmp = hash;
if (tmp.size() < ECDSA384_INPUT_LENGTH) {
// Zero-pad hashes that are shorter than SHA-384.
Expand All @@ -61,5 +66,3 @@ ElectronicID::Signature EstEIDIDEMIAV1::signWithSigningKeyImpl(const pcsc_cpp::b
}
return EIDIDEMIA::signWithSigningKeyImpl(pin, tmp, hashAlgo);
}

} // namespace electronic_id
7 changes: 1 addition & 6 deletions src/electronic-ids/pcsc/LatEIDIDEMIACommon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ namespace electronic_id
class LatEIDIDEMIACommon : public EIDIDEMIA
{
protected:
LatEIDIDEMIACommon(pcsc_cpp::SmartCard::ptr _card) : EIDIDEMIA(std::move(_card)) {}

JsonWebSignatureAlgorithm authSignatureAlgorithm() const override
{
return JsonWebSignatureAlgorithm::RS256;
}
explicit LatEIDIDEMIACommon(pcsc_cpp::SmartCard::ptr _card) : EIDIDEMIA(std::move(_card)) {}

PinMinMaxLength authPinMinMaxLength() const override { return {4, 12}; }

Expand Down
9 changes: 8 additions & 1 deletion src/electronic-ids/pcsc/LatEIDIDEMIAv1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@ namespace electronic_id
class LatEIDIDEMIAV1 : public LatEIDIDEMIACommon
{
public:
LatEIDIDEMIAV1(pcsc_cpp::SmartCard::ptr _card) : LatEIDIDEMIACommon(std::move(_card)) {}
explicit LatEIDIDEMIAV1(pcsc_cpp::SmartCard::ptr _card) : LatEIDIDEMIACommon(std::move(_card))
{
}

private:
JsonWebSignatureAlgorithm authSignatureAlgorithm() const override
{
return JsonWebSignatureAlgorithm::RS256;
}

std::string name() const override { return "LatEID IDEMIA v1"; }

const std::set<SignatureAlgorithm>& supportedSigningAlgorithms() const override;
Expand Down
39 changes: 33 additions & 6 deletions src/electronic-ids/pcsc/LatEIDIDEMIAv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,55 @@

#include "pcsc-common.hpp"

#include <optional>

using namespace pcsc_cpp;
using namespace electronic_id;

struct LatEIDIDEMIAV2::Private
{
std::optional<bool> isUpdated;
};

LatEIDIDEMIAV2::LatEIDIDEMIAV2(pcsc_cpp::SmartCard::ptr _card) :
LatEIDIDEMIACommon(std::move(_card)), data(std::make_unique<Private>())
{
}

namespace electronic_id
LatEIDIDEMIAV2::~LatEIDIDEMIAV2() = default;

bool LatEIDIDEMIAV2::isUpdated() const
{
if (data->isUpdated.has_value()) {
return data->isUpdated.value();
}
static const auto command = CommandApdu::fromBytes({0x00, 0xA4, 0x02, 0x04, 0x02, 0x50, 0x40});
const auto response = card->transmit(command);
data->isUpdated = response.toSW() == 0x9000;
return data->isUpdated.value();
}

const std::set<SignatureAlgorithm>& LatEIDIDEMIAV2::supportedSigningAlgorithms() const
{
const static std::set<SignatureAlgorithm> RS256_SIGNATURE_ALGO {
{SignatureAlgorithm::RS256},
};
return RS256_SIGNATURE_ALGO;
return isUpdated() ? ELLIPTIC_CURVE_SIGNATURE_ALGOS() : RS256_SIGNATURE_ALGO;
}

const ManageSecurityEnvCmds& LatEIDIDEMIAV2::selectSecurityEnv() const
{
static const auto selectSecurityEnvCmds = ManageSecurityEnvCmds {
static const ManageSecurityEnvCmds selectSecurityEnv1Cmds {
// Activate authentication environment.
{0x00, 0x22, 0x41, 0xa4, 0x06, 0x80, 0x01, 0x02, 0x84, 0x01, 0x81},
// Activate signing environment.
{0x00, 0x22, 0x41, 0xb6, 0x06, 0x80, 0x01, 0x42, 0x84, 0x01, 0x9f},
};
return selectSecurityEnvCmds;
static const ManageSecurityEnvCmds selectSecurityEnv2Cmds {
// Activate authentication environment.
{0x00, 0x22, 0x41, 0xa4, 0x06, 0x80, 0x01, 0x04, 0x84, 0x01, 0x82},
// Activate signing environment.
{0x00, 0x22, 0x41, 0xb6, 0x06, 0x80, 0x01, 0x54, 0x84, 0x01, 0x9e},
};
return isUpdated() ? selectSecurityEnv2Cmds : selectSecurityEnv1Cmds;
}

} // namespace electronic_id
14 changes: 13 additions & 1 deletion src/electronic-ids/pcsc/LatEIDIDEMIAv2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,27 @@ namespace electronic_id
class LatEIDIDEMIAV2 : public LatEIDIDEMIACommon
{
public:
LatEIDIDEMIAV2(pcsc_cpp::SmartCard::ptr _card) : LatEIDIDEMIACommon(std::move(_card)) {}
explicit LatEIDIDEMIAV2(pcsc_cpp::SmartCard::ptr _card);
~LatEIDIDEMIAV2() override;
PCSC_CPP_DISABLE_COPY_MOVE(LatEIDIDEMIAV2);

bool isUpdated() const override;

private:
JsonWebSignatureAlgorithm authSignatureAlgorithm() const override
{
return isUpdated() ? JsonWebSignatureAlgorithm::ES384 : JsonWebSignatureAlgorithm::RS256;
}

std::string name() const override { return "LatEID IDEMIA v2"; }

const std::set<SignatureAlgorithm>& supportedSigningAlgorithms() const override;
SignatureAlgorithm signingSignatureAlgorithm() const override { return SignatureAlgorithm::RS; }

const ManageSecurityEnvCmds& selectSecurityEnv() const override;

struct Private;
std::unique_ptr<Private> data;
};

} // namespace electronic_id
2 changes: 2 additions & 0 deletions src/electronic-ids/pkcs11/PKCS11CardManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class PKCS11CardManager
#endif
}

PCSC_CPP_DISABLE_COPY_MOVE(PKCS11CardManager);

struct Token
{
std::string label;
Expand Down
8 changes: 4 additions & 4 deletions src/electronic-ids/scope.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ class scope_exit
}
}

void release() noexcept { execute_on_destruction = false; }

private:
// The Rule of Five.
// The Rule of Five (C++ Core guidelines C.21).
scope_exit(scope_exit const&) = delete;
void operator=(scope_exit const&) = delete;
scope_exit& operator=(scope_exit&&) = delete;

void release() noexcept { execute_on_destruction = false; }

private:
ExitFunction exit_function;
bool execute_on_destruction {true};
};
Expand Down
4 changes: 4 additions & 0 deletions tests/mock/select-certificate-script-LAT-V2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ const PcscMock::ApduScript LATEID_IDEMIA_V2_SELECT_AUTH_CERTIFICATE_AND_AUTHENTI
{{0x00, 0xA4, 0x04, 0x0C, 0x0D, 0xe8, 0x28, 0xbd, 0x08, 0x0f, 0xf2, 0x50, 0x4f, 0x54, 0x20,
0x41, 0x57, 0x50},
{0x90, 0x00}},

// Detect if card is updated
{{0x00, 0xA4, 0x02, 0x04, 0x02, 0x50, 0x40}, {0x6A, 0x82}},

// Select authentication certificate file.
{{0x00, 0xA4, 0x02, 0x0C, 0x02, 0x34, 0x01}, {0x90, 0x00}},

Expand Down

0 comments on commit 3ee8d1d

Please sign in to comment.