Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Latvia card support #60

Merged
merged 1 commit into from
Sep 15, 2023
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: 8 additions & 13 deletions src/electronic-ids/pcsc/EIDIDEMIA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,19 @@ byte_vector EIDIDEMIA::getCertificateImpl(const CertificateType type) const
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);
return electronic_id::getCertificate(
*card,
{
type.isAuthentication() ? selectCertificate().AUTH_CERT : selectCertificate().SIGN_CERT,
});
}

byte_vector EIDIDEMIA::signWithAuthKeyImpl(const byte_vector& pin, const byte_vector& hash) const
{
// Select authentication application and authentication security environment.
transmitApduWithExpectedResponse(*card, selectApplicationID().MAIN_AID);
transmitApduWithExpectedResponse(*card, selectApplicationID().AUTH_AID);
transmitApduWithExpectedResponse(*card, selectSecurityEnv().AUTH_ENV);
selectAuthSecurityEnv();

verifyPin(*card, AUTH_PIN_REFERENCE, pin, authPinMinMaxLength().first, pinBlockLength(),
PIN_PADDING_CHAR);
Expand All @@ -76,7 +77,7 @@ ElectronicID::Signature EIDIDEMIA::signWithSigningKeyImpl(const byte_vector& pin
{
// Select signing application and signing security environment.
transmitApduWithExpectedResponse(*card, selectApplicationID().SIGN_AID);
transmitApduWithExpectedResponse(*card, selectSecurityEnv().SIGN_ENV);
selectSignSecurityEnv();

verifyPin(*card, signingPinReference(), pin, signingPinMinMaxLength().first, pinBlockLength(),
PIN_PADDING_CHAR);
Expand Down Expand Up @@ -117,13 +118,7 @@ const SelectCertificateCmds& EIDIDEMIA::selectCertificate() const
// Signing certificate.
{0x00, 0xA4, 0x02, 0x0C, 0x02, 0x34, 0x1F},
};
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;
return selectCert1Cmds;
}

ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::pinRetriesLeft(byte_type pinReference) const
Expand Down
11 changes: 2 additions & 9 deletions src/electronic-ids/pcsc/EIDIDEMIA.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,6 @@ struct SelectCertificateCmds
const pcsc_cpp::byte_vector SIGN_CERT;
};

struct ManageSecurityEnvCmds
{
const pcsc_cpp::byte_vector AUTH_ENV;
const pcsc_cpp::byte_vector SIGN_ENV;
};

class EIDIDEMIA : public PcscElectronicID
{
public:
Expand All @@ -63,7 +57,8 @@ class EIDIDEMIA : public PcscElectronicID

virtual const SelectApplicationIDCmds& selectApplicationID() const;
virtual const SelectCertificateCmds& selectCertificate() const;
virtual const ManageSecurityEnvCmds& selectSecurityEnv() const = 0;
virtual void selectAuthSecurityEnv() const = 0;
virtual void selectSignSecurityEnv() const = 0;

virtual size_t pinBlockLength() const { return authPinMinMaxLength().second; }
virtual byte_type signingPinReference() const { return 0x85; }
Expand All @@ -74,8 +69,6 @@ class EIDIDEMIA : public PcscElectronicID
{
return false;
}

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

} // namespace electronic_id
21 changes: 7 additions & 14 deletions src/electronic-ids/pcsc/EstEIDIDEMIA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,14 @@

using namespace electronic_id;

const ManageSecurityEnvCmds& EstEIDIDEMIAV1::selectSecurityEnv() const
void EstEIDIDEMIAV1::selectAuthSecurityEnv() const
{
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},
};
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;
selectSecurityEnv(*card, 0xA4, 0x04, 0x81, name());
}

void EstEIDIDEMIAV1::selectSignSecurityEnv() const
{
selectSecurityEnv(*card, 0xB6, 0x54, 0x9f, name());
}

const std::set<SignatureAlgorithm>& EstEIDIDEMIAV1::supportedSigningAlgorithms() const
Expand Down
3 changes: 2 additions & 1 deletion src/electronic-ids/pcsc/EstEIDIDEMIA.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class EstEIDIDEMIAV1 : public EIDIDEMIA
std::string name() const override { return "EstEID IDEMIA v1"; }
Type type() const override { return EstEID; }

const ManageSecurityEnvCmds& selectSecurityEnv() const override;
void selectAuthSecurityEnv() const override;
void selectSignSecurityEnv() const override;
};

} // namespace electronic_id
2 changes: 1 addition & 1 deletion src/electronic-ids/pcsc/FinEID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ byte_vector FinEIDv3::sign(const HashAlgorithm hashAlgo, const byte_vector& hash
verifyPin(*card, pinReference, pin, pinMinMaxLength.first, pinMinMaxLength.second,
PIN_PADDING_CHAR);
// Select security environment for COMPUTE SIGNATURE.
selectComputeSignatureEnv(*card, signatureAlgo, keyReference, name());
selectSecurityEnv(*card, 0xB6, signatureAlgo, keyReference, name());

byte_vector tlv {0x90, byte_type(hash.size())};
tlv.insert(tlv.cend(), hash.cbegin(), hash.cend());
Expand Down
15 changes: 7 additions & 8 deletions src/electronic-ids/pcsc/LatEIDIDEMIAv1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,14 @@ const SelectCertificateCmds& LatEIDIDEMIAV1::selectCertificate() const
return selectCertCmds;
}

const ManageSecurityEnvCmds& LatEIDIDEMIAV1::selectSecurityEnv() const
void LatEIDIDEMIAV1::selectAuthSecurityEnv() const
{
static const auto selectSecurityEnvCmds = ManageSecurityEnvCmds {
// Activate authentication environment.
{0x00, 0x22, 0x41, 0xa4, 0x06, 0x80, 0x01, 0x02, 0x84, 0x01, 0x82},
// Activate signing environment.
{0x00, 0x22, 0x41, 0xa4, 0x06, 0x80, 0x01, 0x02, 0x84, 0x01, 0x81},
};
return selectSecurityEnvCmds;
selectSecurityEnv(*card, 0xA4, 0x02, 0x82, name());
}

void LatEIDIDEMIAV1::selectSignSecurityEnv() const
{
selectSecurityEnv(*card, 0xA4, 0x02, 0x81, name());
}

} // namespace electronic_id
5 changes: 3 additions & 2 deletions src/electronic-ids/pcsc/LatEIDIDEMIAv1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ class LatEIDIDEMIAV1 : public LatEIDIDEMIACommon

const SelectApplicationIDCmds& selectApplicationID() const override;
const SelectCertificateCmds& selectCertificate() const override;
const ManageSecurityEnvCmds& selectSecurityEnv() const override;
void selectAuthSecurityEnv() const override;
void selectSignSecurityEnv() const override;

size_t pinBlockLength() const override { return 0x40; }
unsigned char signingPinReference() const override { return 0x81; }
byte_type signingPinReference() const override { return 0x81; }

bool useInternalAuthenticateAndRSAWithPKCS1PaddingDuringSigning() const override
{
Expand Down
110 changes: 87 additions & 23 deletions src/electronic-ids/pcsc/LatEIDIDEMIAv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,50 +29,114 @@
using namespace pcsc_cpp;
using namespace electronic_id;

struct KeyInfo
{
bool isECC;
byte_type id;
};

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

namespace
{
constexpr byte_type DEFAULT_AUTH_KEY_ID = 0x81;
constexpr byte_type DEFAULT_SIGN_KEY_ID = 0x9F;

inline byte_vector readEF_File(const SmartCard& card, const byte_vector& file)
{
auto response = card.transmit({0x00, 0xA4, 0x02, 0x04, file, 0x00});
if (!response.isOK()) {
THROW(SmartCardError, "Failed to read EF file");
}
static const byte_vector findLength {0x80, 0x02};
auto pos = std::search(response.data.cbegin(), response.data.cend(), findLength.cbegin(),
findLength.cend());
if (pos == response.data.cend()) {
THROW(SmartCardError, "Failed to read EF file length");
}
pos += findLength.size();
return readBinary(card, size_t(*pos << 8) + *(pos + 1), 0xFF);
}

inline byte_vector readEF_PrKD(const SmartCard& card)
{
static const byte_vector EF_OD {0x50, 0x31};
const auto info = readEF_File(card, EF_OD);
static const byte_vector file {0xA0, 0x06, 0x30, 0x04, 0x04, 0x02};
auto pos = std::search(info.cbegin(), info.cend(), file.cbegin(), file.cend());
if (pos == info.cend()) {
THROW(SmartCardError, "EF.PrKD reference not found");
}
pos += file.size();
return readEF_File(card, {*pos, *(pos + 1)});
}

inline KeyInfo readPrKDInfo(const SmartCard& card, byte_type keyID)
{
const auto data = readEF_PrKD(card);
if (data.empty()) {
return {false, keyID};
}
static const byte_vector needle {0x02, 0x02, 0x00};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needle is vague, keyIDPattern tells what we are looking for. But let's fix it in the future.

if (auto pos = std::search(data.cbegin(), data.cend(), needle.cbegin(), needle.cend());
pos != data.cend()) {
return {data[0] == 0xA0, *(pos + needle.size())};
}
return {data[0] == 0xA0, keyID};
}
} // namespace

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

LatEIDIDEMIAV2::~LatEIDIDEMIAV2() = default;

bool LatEIDIDEMIAV2::isUpdated() const
JsonWebSignatureAlgorithm LatEIDIDEMIAV2::authSignatureAlgorithm() const
{
if (data->isUpdated.has_value()) {
return data->isUpdated.value();
if (!data->authKeyInfo.has_value()) {
auto transactionGuard = card->beginTransaction();
transmitApduWithExpectedResponse(*card, selectApplicationID().MAIN_AID);
transmitApduWithExpectedResponse(*card, selectApplicationID().AUTH_AID);
data->authKeyInfo = readPrKDInfo(*card, DEFAULT_AUTH_KEY_ID);
}
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();
return data->authKeyInfo->isECC ? JsonWebSignatureAlgorithm::ES384
: JsonWebSignatureAlgorithm::RS256;
}

const std::set<SignatureAlgorithm>& LatEIDIDEMIAV2::supportedSigningAlgorithms() const
{
if (!data->signKeyInfo.has_value()) {
auto transactionGuard = card->beginTransaction();
transmitApduWithExpectedResponse(*card, selectApplicationID().MAIN_AID);
transmitApduWithExpectedResponse(*card, selectApplicationID().SIGN_AID);
data->signKeyInfo = readPrKDInfo(*card, DEFAULT_SIGN_KEY_ID);
}
const static std::set<SignatureAlgorithm> RS256_SIGNATURE_ALGO {
{SignatureAlgorithm::RS256},
};
return isUpdated() ? ELLIPTIC_CURVE_SIGNATURE_ALGOS() : RS256_SIGNATURE_ALGO;
return data->signKeyInfo->isECC ? ELLIPTIC_CURVE_SIGNATURE_ALGOS() : RS256_SIGNATURE_ALGO;
}

const ManageSecurityEnvCmds& LatEIDIDEMIAV2::selectSecurityEnv() const
void LatEIDIDEMIAV2::selectAuthSecurityEnv() const
{
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},
};
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;
if (!data->authKeyInfo.has_value()) {
data->authKeyInfo = readPrKDInfo(*card, DEFAULT_AUTH_KEY_ID);
}
selectSecurityEnv(*card, 0xA4, data->authKeyInfo->isECC ? 0x04 : 0x02, data->authKeyInfo->id,
name());
}

void LatEIDIDEMIAV2::selectSignSecurityEnv() const
{
if (!data->signKeyInfo.has_value()) {
data->signKeyInfo = readPrKDInfo(*card, DEFAULT_SIGN_KEY_ID);
}
selectSecurityEnv(*card, 0xB6, data->signKeyInfo->isECC ? 0x54 : 0x42, data->signKeyInfo->id,
name());
}
10 changes: 3 additions & 7 deletions src/electronic-ids/pcsc/LatEIDIDEMIAv2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,16 @@ class LatEIDIDEMIAV2 : public LatEIDIDEMIACommon
~LatEIDIDEMIAV2() override;
PCSC_CPP_DISABLE_COPY_MOVE(LatEIDIDEMIAV2);

bool isUpdated() const override;

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

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;
void selectAuthSecurityEnv() const override;
void selectSignSecurityEnv() const override;

struct Private;
std::unique_ptr<Private> data;
Expand Down
11 changes: 5 additions & 6 deletions src/electronic-ids/pcsc/pcsc-common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,16 @@ inline pcsc_cpp::byte_vector computeSignature(pcsc_cpp::SmartCard& card,
return response.data;
}

inline void selectComputeSignatureEnv(pcsc_cpp::SmartCard& card, pcsc_cpp::byte_type signatureAlgo,
pcsc_cpp::byte_type keyReference, const std::string& cardType)
inline void selectSecurityEnv(pcsc_cpp::SmartCard& card, pcsc_cpp::byte_type env,
pcsc_cpp::byte_type signatureAlgo, pcsc_cpp::byte_type keyReference,
const std::string& cardType)
{
static const pcsc_cpp::CommandApdu SET_COMPUTE_SIGNATURE_ENV {0x00, 0x22, 0x41, 0xB6};

const auto response = card.transmit(
{SET_COMPUTE_SIGNATURE_ENV, {0x80, 0x01, signatureAlgo, 0x84, 0x01, keyReference}});
{0x00, 0x22, 0x41, env, {0x80, 0x01, signatureAlgo, 0x84, 0x01, keyReference}});

if (!response.isOK()) {
THROW(SmartCardError,
cardType + ": Command SET ENV for COMPUTE SIGNATURE failed with error "
cardType + ": Command SET ENV failed with error "
+ pcsc_cpp::bytes2hexstr(response.toBytes()));
}
}
Expand Down
Loading
Loading