Skip to content

Commit

Permalink
Add lux cards support
Browse files Browse the repository at this point in the history
fix syntax

fix atr not exist in scope

Add masked cards map

Format code

enhance support mask
  • Loading branch information
alexandre-rcdevs committed Oct 8, 2024
1 parent 2f17973 commit e2d4e3d
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 9 deletions.
2 changes: 2 additions & 0 deletions include/electronic-id/electronic-id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class ElectronicID
HrvEID,
BelEID,
CzeEID,
LuxtrustV2,
LuxEID,
#ifdef _WIN32
MsCryptoApiEID,
#endif
Expand Down
150 changes: 143 additions & 7 deletions src/electronic-id.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,118 @@ const std::map<byte_vector, ElectronicIDConstructor> SUPPORTED_ATRS {
{{0x3b, 0x7e, 0x94, 0x00, 0x00, 0x80, 0x25, 0xd2, 0x03, 0x10, 0x01, 0x00, 0x56, 0x00, 0x00,
0x00, 0x02, 0x02, 0x00},
constructor<ElectronicID::Type::CzeEID>},
// LuxtrustV2
{{0x3B, 0x7D, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x83,
0x00, 0x90, 0x00},
constructor<ElectronicID::Type::LuxtrustV2>},
// LuxEID
{{0x3B, 0x7F, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xB0,
0x00, 0x03, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3B, 0xFF, 0x00, 0x00, 0x00, 0x81, 0x31, 0x00, 0x43, 0x80, 0x31, 0x80, 0x65,
0xB0, 0x00, 0x03, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3B, 0x8F, 0x00, 0x01, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00,
0x03, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3B, 0x88, 0x00, 0x01, 0xE1, 0xF3, 0x5E, 0x11, 0x00, 0x87, 0x95, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3b, 0x7f, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xb0,
0x00, 0x04, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3b, 0xff, 0x00, 0x00, 0x00, 0x81, 0x31, 0x00, 0x43, 0x80, 0x31, 0x80, 0x65,
0xb0, 0x00, 0x04, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3B, 0x8F, 0x80, 0x01, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00,
0x04, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3b, 0x88, 0x80, 0x01, 0x00, 0x88, 0x3c, 0x1f, 0x77, 0x81, 0x95, 0x00, 0xc1},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3b, 0x7f, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xb0,
0x00, 0x05, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3b, 0xff, 0x00, 0x00, 0x00, 0x81, 0x31, 0x00, 0x43, 0x80, 0x31, 0x80, 0x65,
0xb0, 0x00, 0x05, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3B, 0x8F, 0x80, 0x01, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00,
0x05, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
constructor<ElectronicID::Type::LuxEID>},
// LuxEID
{{0x3b, 0x88, 0x80, 0x01, 0xe1, 0xf3, 0x5e, 0x11, 0x77, 0xa1, 0x97, 0x00, 0x15},
constructor<ElectronicID::Type::LuxEID>},
};

// Masked cards.
const std::map<byte_vector, byte_vector> MASKED_ATRS {
// LuxtrustV2
{{0x3B, 0x7D, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x83,
0x00, 0x90, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0xFF, 0xFF}},
// LuxEID
{{0x3B, 0x7F, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xB0,
0x00, 0x03, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
// LuxEID
{{0x3B, 0xFF, 0x00, 0x00, 0x00, 0x81, 0x31, 0x00, 0x43, 0x80, 0x31, 0x80, 0x65,
0xB0, 0x00, 0x03, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3B, 0x8F, 0x00, 0x01, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00,
0x03, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3B, 0x88, 0x00, 0x01, 0xE1, 0xF3, 0x5E, 0x11, 0x00, 0x87, 0x95, 0x00, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3b, 0x7f, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xb0,
0x00, 0x04, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
// LuxEID
{{0x3b, 0xff, 0x00, 0x00, 0x00, 0x81, 0x31, 0x00, 0x43, 0x80, 0x31, 0x80, 0x65,
0xb0, 0x00, 0x04, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3B, 0x8F, 0x80, 0x01, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00,
0x04, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3b, 0x88, 0x80, 0x01, 0x00, 0x88, 0x3c, 0x1f, 0x77, 0x81, 0x95, 0x00, 0xc1},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
// LuxEID
{{0x3b, 0x7f, 0x00, 0x00, 0x00, 0x80, 0x31, 0x80, 0x65, 0xb0,
0x00, 0x05, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
// LuxEID
{{0x3b, 0xff, 0x00, 0x00, 0x00, 0x81, 0x31, 0x00, 0x43, 0x80, 0x31, 0x80, 0x65,
0xb0, 0x00, 0x05, 0x00, 0x00, 0x12, 0x0f, 0xff, 0x82, 0x90, 0x00, 0x00},
{0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3B, 0x8F, 0x80, 0x01, 0x80, 0x31, 0x80, 0x65, 0xB0, 0x00,
0x05, 0x00, 0x00, 0x12, 0x0F, 0xFF, 0x82, 0x90, 0x00, 0x00},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}},
// LuxEID
{{0x3b, 0x88, 0x80, 0x01, 0xe1, 0xf3, 0x5e, 0x11, 0x77, 0xa1, 0x97, 0x00, 0x15},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
};

inline std::string byteVectorToHexString(const byte_vector& bytes)
Expand Down Expand Up @@ -137,22 +249,46 @@ const auto SUPPORTED_ALGORITHMS = std::map<std::string, HashAlgorithm> {
namespace electronic_id
{

pcsc_cpp::byte_vector applyMask(const pcsc_cpp::byte_vector& atr, const pcsc_cpp::byte_vector& mask)
{
pcsc_cpp::byte_vector result(atr.size());
for (size_t i = 0; i < atr.size(); ++i) {
result[i] = atr[i] & mask[i];
}
return result;
}

bool isCardSupported(const pcsc_cpp::byte_vector& atr)
{
return SUPPORTED_ATRS.contains(atr);
if (SUPPORTED_ATRS.contains(atr)) {
return true;
}
for (const auto& [maskedAtr, mask] : MASKED_ATRS) {
if (applyMask(atr, mask) == maskedAtr) {
return SUPPORTED_ATRS.contains(maskedAtr);
}
}
return false;
}

ElectronicID::ptr getElectronicID(const pcsc_cpp::Reader& reader)
{
try {
if (SUPPORTED_ATRS.contains(reader.cardAtr)) {
const auto& eidConstructor = SUPPORTED_ATRS.at(reader.cardAtr);
return eidConstructor(reader);
} catch (const std::out_of_range&) {
// It should be verified that the card is supported with isCardSupported() before
// calling getElectronicID(), so it is a programming error if out_of_range occurs here.
THROW(ProgrammingError,
"Card with ATR '" + byteVectorToHexString(reader.cardAtr) + "' is not supported");
}

for (const auto& [maskedAtr, mask] : MASKED_ATRS) {
if (applyMask(reader.cardAtr, mask) == maskedAtr && SUPPORTED_ATRS.contains(maskedAtr)) {
const auto& eidConstructor = SUPPORTED_ATRS.at(maskedAtr);
return eidConstructor(reader);
}
}

// It should be verified that the card is supported with isCardSupported() before
// calling getElectronicID(), so it is a programming error if out_of_range occurs here.
THROW(ProgrammingError,
"Card with ATR '" + byteVectorToHexString(reader.cardAtr) + "' is not supported");
}

bool ElectronicID::isSupportedSigningHashAlgorithm(const HashAlgorithm hashAlgo) const
Expand Down
37 changes: 36 additions & 1 deletion src/electronic-ids/pkcs11/Pkcs11ElectronicID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ inline fs::path czechPkcs11ModulePath()
#endif
}

inline fs::path luxembourgPkcs11ModulePath()

Check notice

Code scanning / CodeQL

Unused static function Note

Static function luxembourgPkcs11ModulePath is unreachable
{
#ifdef _WIN32
return programFilesPath() / L"Gemalto/Classic Client/BIN/gclib.dll";
#elif defined __APPLE__
return "/Library/Frameworks/Pkcs11ClassicClient.framework/Versions/A/Pkcs11ClassicClient/"
"libgclib.dylib";
#else // Linux
return "/usr/lib/pkcs11/libgclib.so";
#endif
}

const std::map<ElectronicID::Type, Pkcs11ElectronicIDModule> SUPPORTED_PKCS11_MODULES {
// EstEID configuration is here only for testing,
// it is not enabled in getElectronicID().
Expand Down Expand Up @@ -156,6 +168,26 @@ const std::map<ElectronicID::Type, Pkcs11ElectronicIDModule> SUPPORTED_PKCS11_MO
true,
false,
}},
{ElectronicID::Type::LuxtrustV2,
{
"LuxtrustV2 eID (PKCS#11)"s, // name
ElectronicID::Type::LuxtrustV2, // type
luxembourgPkcs11ModulePath().make_preferred(), // path

3,
true,
false,
}},
{ElectronicID::Type::LuxEID,
{
"Luxembourg eID (PKCS#11)"s, // name
ElectronicID::Type::LuxEID, // type
luxembourgPkcs11ModulePath().make_preferred(), // path

3,
true,
true,
}},
};

const Pkcs11ElectronicIDModule& getModule(ElectronicID::Type eidType)
Expand All @@ -176,11 +208,14 @@ Pkcs11ElectronicID::Pkcs11ElectronicID(ElectronicID::Type type) :
{
REQUIRE_NON_NULL(manager)

const bool checkExtKeyUsage =
(type != ElectronicID::Type::LuxtrustV2 && type != ElectronicID::Type::LuxEID);

bool seenAuthToken = false;
bool seenSigningToken = false;

for (const auto& token : manager->tokens()) {
const auto certType = certificateType(token.cert);
const auto certType = certificateType(token.cert, checkExtKeyUsage);
if (certType.isAuthentication()) {
authToken = token;
seenAuthToken = true;
Expand Down
9 changes: 8 additions & 1 deletion src/electronic-ids/x509.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <openssl/x509v3.h>
#include <openssl/err.h>

#include <optional>

namespace electronic_id
{

Expand Down Expand Up @@ -37,7 +39,8 @@ inline bool hasClientAuthExtendedKeyUsage(EXTENDED_KEY_USAGE* usage) noexcept
return false;
}

inline CertificateType certificateType(const pcsc_cpp::byte_vector& cert)
inline CertificateType certificateType(const pcsc_cpp::byte_vector& cert,
const bool checkExtKeyUsage = true)
{
auto x509 = make_x509(cert);
auto keyUsage = extension(x509.get(), NID_key_usage, ASN1_BIT_STRING_free);
Expand All @@ -52,6 +55,10 @@ inline CertificateType certificateType(const pcsc_cpp::byte_vector& cert)

static const int KEY_USAGE_DIGITAL_SIGNATURE = 0;
if (ASN1_BIT_STRING_get_bit(keyUsage.get(), KEY_USAGE_DIGITAL_SIGNATURE)) {
if (!checkExtKeyUsage) {
return CertificateType::AUTHENTICATION;
}

if (auto extKeyUsage = extension(x509.get(), NID_ext_key_usage, EXTENDED_KEY_USAGE_free);
extKeyUsage && hasClientAuthExtendedKeyUsage(extKeyUsage.get())) {
return CertificateType::AUTHENTICATION;
Expand Down

0 comments on commit e2d4e3d

Please sign in to comment.