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
5 changes: 5 additions & 0 deletions .github/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "web-eid-app",
"dependencies": ["openssl", "gtest"],
"builtin-baseline": "bc38a15b0bee8bc48a49ea267cc32fbb49aedfc4"
}
22 changes: 17 additions & 5 deletions .github/workflows/cmake-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on: [push, pull_request]
env:
BUILD_TYPE: RelWithDebInfo
CMAKE_BUILD_PARALLEL_LEVEL: 3
VCPKG_MANIFEST_DIR: .github
VCPKG_INSTALLED_DIR: ${{ github.workspace }}/build/vcpkg_installed

jobs:
build:
Expand All @@ -14,15 +16,25 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Cache vcpkg
uses: actions/cache@v4
with:
path: ${{ github.workspace }}/vcpkg_cache
key: vcpkg-${{ hashFiles(format('{0}/vcpkg.json', env.VCPKG_MANIFEST_DIR)) }}

- name: Prepare vcpkg and libraries
uses: lukka/run-vcpkg@v7
uses: lukka/run-vcpkg@v11
with:
vcpkgArguments: gtest:x64-windows openssl:x64-windows
vcpkgTriplet: x64-windows
vcpkgGitCommitId: 031ad89ce6c575df35a8e58707ad2c898446c63e
vcpkgJsonGlob: ${{ env.VCPKG_MANIFEST_DIR }}/vcpkg.json
runVcpkgInstall: true
env:
VCPKG_BINARY_SOURCES: clear;files,${{ github.workspace }}/vcpkg_cache,readwrite

- name: Configure CMake
run: cmake -A x64 "-DCMAKE_TOOLCHAIN_FILE=${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" "-DCMAKE_BUILD_TYPE=${env:BUILD_TYPE}" -S . -B build
run: |
cmake -A x64 -S . -B build "-DCMAKE_BUILD_TYPE=${env:BUILD_TYPE}" `
"-DCMAKE_TOOLCHAIN_FILE=${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" `
"-DVCPKG_MANIFEST_DIR=${{ env.VCPKG_MANIFEST_DIR }}"

- name: Build
run: cmake --build build --config ${env:BUILD_TYPE}
Expand Down
14 changes: 10 additions & 4 deletions include/electronic-id/electronic-id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

#include "enums.hpp"

#include <optional>
#include <functional>
#include <optional>

namespace electronic_id
{
Expand All @@ -37,11 +37,17 @@ class ElectronicID
public:
using ptr = std::shared_ptr<ElectronicID>;
using PinMinMaxLength = std::pair<uint8_t, uint8_t>;
using PinRetriesRemainingAndMax = std::pair<uint8_t, int8_t>;
using byte_vector = pcsc_cpp::byte_vector;
using byte_type = pcsc_cpp::byte_type;
using Signature = std::pair<byte_vector, SignatureAlgorithm>;

struct PinInfo
{
uint8_t retryCount;
int8_t maxRetry;
bool pinActive;
};

enum Type : uint8_t {
EstEID,
FinEID,
Expand All @@ -68,7 +74,7 @@ class ElectronicID

virtual PinMinMaxLength authPinMinMaxLength() const = 0;

virtual PinRetriesRemainingAndMax authPinRetriesLeft() const = 0;
virtual PinInfo authPinInfo() const = 0;

virtual pcsc_cpp::byte_vector signWithAuthKey(byte_vector&& pin,
const byte_vector& hash) const = 0;
Expand All @@ -80,7 +86,7 @@ class ElectronicID

virtual PinMinMaxLength signingPinMinMaxLength() const = 0;

virtual PinRetriesRemainingAndMax signingPinRetriesLeft() const = 0;
virtual PinInfo signingPinInfo() const = 0;

virtual Signature signWithSigningKey(byte_vector&& pin, const byte_vector& hash,
const HashAlgorithm hashAlgo) const = 0;
Expand Down
8 changes: 4 additions & 4 deletions src/electronic-ids/ms-cryptoapi/MsCryptoApiElectronicID.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ class MsCryptoApiElectronicID : public ElectronicID
return {PIN_LENGTH_PLACEHOLDER, PIN_LENGTH_PLACEHOLDER};
}

PinRetriesRemainingAndMax authPinRetriesLeft() const override
PinInfo authPinInfo() const override
{
return {uint8_t(PIN_RETRY_COUNT_PLACEHOLDER), PIN_RETRY_COUNT_PLACEHOLDER};
return {uint8_t(PIN_RETRY_COUNT_PLACEHOLDER), PIN_RETRY_COUNT_PLACEHOLDER, true};
}

byte_vector signWithAuthKey(byte_vector&& pin, const byte_vector& hash) const override;
Expand All @@ -92,9 +92,9 @@ class MsCryptoApiElectronicID : public ElectronicID
return {PIN_LENGTH_PLACEHOLDER, PIN_LENGTH_PLACEHOLDER};
}

PinRetriesRemainingAndMax signingPinRetriesLeft() const override
PinInfo signingPinInfo() const override
{
return {uint8_t(PIN_RETRY_COUNT_PLACEHOLDER), PIN_RETRY_COUNT_PLACEHOLDER};
return {uint8_t(PIN_RETRY_COUNT_PLACEHOLDER), PIN_RETRY_COUNT_PLACEHOLDER, true};
}

Signature signWithSigningKey(byte_vector&& pin, const byte_vector& hash,
Expand Down
12 changes: 5 additions & 7 deletions src/electronic-ids/pcsc/EIDIDEMIA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ byte_vector EIDIDEMIA::signWithAuthKeyImpl(const SmartCard::Session& session, by
return std::move(response.data);
}

ElectronicID::PinRetriesRemainingAndMax
EIDIDEMIA::authPinRetriesLeftImpl(const SmartCard::Session& session) const
ElectronicID::PinInfo EIDIDEMIA::authPinInfoImpl(const SmartCard::Session& session) const
{
selectMain(session);
return pinRetriesLeft(session, AUTH_PIN_REFERENCE);
Expand Down Expand Up @@ -154,15 +153,14 @@ ElectronicID::Signature EIDIDEMIA::signWithSigningKeyImpl(const SmartCard::Sessi
{isECC ? SignatureAlgorithm::ES : SignatureAlgorithm::RS, hashAlgo}};
}

ElectronicID::PinRetriesRemainingAndMax
EIDIDEMIA::signingPinRetriesLeftImpl(const SmartCard::Session& session) const
ElectronicID::PinInfo EIDIDEMIA::signingPinInfoImpl(const SmartCard::Session& session) const
{
selectADF2(session);
return pinRetriesLeft(session, SIGN_PIN_REFERENCE);
}

ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::pinRetriesLeft(const SmartCard::Session& session,
byte_type pinReference)
ElectronicID::PinInfo EIDIDEMIA::pinRetriesLeft(const SmartCard::Session& session,
byte_type pinReference)
{
auto ref = byte_type(pinReference & 0x0F);
const CommandApdu GET_DATA_ODD {
Expand All @@ -175,7 +173,7 @@ ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::pinRetriesLeft(const SmartCar
TLV max = info[0x9A];
TLV tries = info[0x9B];
if (max && tries) {
return {*tries.begin, *max.begin};
return {*tries.begin, int8_t(*max.begin), true};
}
THROW(SmartCardError, "Command GET DATA ODD failed: missing expected info");
}
9 changes: 3 additions & 6 deletions src/electronic-ids/pcsc/EIDIDEMIA.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,18 @@ class EIDIDEMIA : public PcscElectronicID
byte_vector getCertificateImpl(const SmartCard::Session& session,
const CertificateType type) const override;

PinRetriesRemainingAndMax
authPinRetriesLeftImpl(const SmartCard::Session& session) const override;
PinInfo authPinInfoImpl(const SmartCard::Session& session) const override;
virtual KeyInfo authKeyRef(const SmartCard::Session& session) const;
byte_vector signWithAuthKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
const byte_vector& hash) const override;

PinRetriesRemainingAndMax
signingPinRetriesLeftImpl(const SmartCard::Session& session) const override;
PinInfo signingPinInfoImpl(const SmartCard::Session& session) const override;
virtual KeyInfo signKeyRef(const SmartCard::Session& session) const;
Signature signWithSigningKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
const byte_vector& hash,
const HashAlgorithm hashAlgo) const override;

static PinRetriesRemainingAndMax pinRetriesLeft(const SmartCard::Session& session,
byte_type pinReference);
static PinInfo pinRetriesLeft(const SmartCard::Session& session, byte_type pinReference);

static void selectMain(const SmartCard::Session& session);
static void selectADF1(const SmartCard::Session& session);
Expand Down
20 changes: 9 additions & 11 deletions src/electronic-ids/pcsc/EIDThales.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,15 @@ namespace

constexpr byte_type PIN_PADDING_CHAR = 0x00;
constexpr byte_type ECDSA_ALGO = 0x04;
constexpr byte_type SIGNING_PIN_REFERENCE = 0x82;

const auto SELECT_MAIN_AID = CommandApdu::select(
0x04, {0xa0, 0x00, 0x00, 0x00, 0x63, 0x50, 0x4b, 0x43, 0x53, 0x2d, 0x31, 0x35});

} // namespace

ElectronicID::PinRetriesRemainingAndMax
EIDThales::authPinRetriesLeftImpl(const SmartCard::Session& session) const
ElectronicID::PinInfo EIDThales::authPinInfoImpl(const SmartCard::Session& session) const
{
return pinRetriesLeft(session, authPinReference());
return pinRetriesLeft(session, authPinReference(), true);
}

byte_vector EIDThales::getCertificateImpl(const SmartCard::Session& session,
Expand All @@ -68,8 +66,8 @@ byte_vector EIDThales::getCertificateImpl(const SmartCard::Session& session,
return readFile(session, type.isAuthentication() ? authCertFile() : signCertFile());
}

ElectronicID::PinRetriesRemainingAndMax EIDThales::pinRetriesLeft(const SmartCard::Session& session,
byte_type pinReference) const
ElectronicID::PinInfo EIDThales::pinRetriesLeft(const SmartCard::Session& session,
byte_type pinReference, bool pinActive) const
{
const auto GET_DATA = smartcard().protocol() == SmartCard::Protocol::T1
? CommandApdu {0x00, 0xCB, 0x00, 0xFF, {0xA0, 0x03, 0x83, 0x01, pinReference}, 0x00}
Expand All @@ -78,8 +76,9 @@ ElectronicID::PinRetriesRemainingAndMax EIDThales::pinRetriesLeft(const SmartCar
if (!response.isOK()) {
THROW(SmartCardError, "Command GET DATA failed with error " + response);
}
if (TLV info = TLV(response.data).find(0xA0)[0xdf21]) {
return {*info.begin, maximumPinRetries()};
if (TLV info = TLV(response.data).find(0xA0); TLV count = info[0xdf21]) {
TLV pinChanged = info[0xdf2f];
return {*count.begin, maximumPinRetries(), pinActive || !pinChanged || *pinChanged.begin};
}
THROW(SmartCardError,
"Command GET DATA failed: received data does not contain the PIN remaining retries info");
Expand Down Expand Up @@ -147,10 +146,9 @@ byte_vector EIDThales::sign(const SmartCard::Session& session, const HashAlgorit
return std::move(signature.data);
}

ElectronicID::PinRetriesRemainingAndMax
EIDThales::signingPinRetriesLeftImpl(const SmartCard::Session& session) const
ElectronicID::PinInfo EIDThales::signingPinInfoImpl(const SmartCard::Session& session) const
{
return pinRetriesLeft(session, SIGNING_PIN_REFERENCE);
return pinRetriesLeft(session, SIGNING_PIN_REFERENCE, true);
}

byte_vector EIDThales::signWithAuthKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
Expand Down
19 changes: 9 additions & 10 deletions src/electronic-ids/pcsc/EIDThales.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,24 @@ class EIDThales : public PcscElectronicID
virtual constexpr byte_type signingKeyReference() const = 0;

byte_vector getCertificateImpl(const SmartCard::Session& session,
const CertificateType type) const override;
PinRetriesRemainingAndMax
authPinRetriesLeftImpl(const SmartCard::Session& session) const override;
PinRetriesRemainingAndMax
signingPinRetriesLeftImpl(const SmartCard::Session& session) const override;
CertificateType type) const override;
PinInfo authPinInfoImpl(const SmartCard::Session& session) const override;
PinInfo signingPinInfoImpl(const SmartCard::Session& session) const override;
byte_vector signWithAuthKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
const byte_vector& hash) const override;
Signature signWithSigningKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
const byte_vector& hash,
const HashAlgorithm hashAlgo) const override;
HashAlgorithm hashAlgo) const override;

PinRetriesRemainingAndMax pinRetriesLeft(const SmartCard::Session& session,
byte_type pinReference) const;
byte_vector sign(const SmartCard::Session& session, const HashAlgorithm hashAlgo,
PinInfo pinRetriesLeft(const SmartCard::Session& session, byte_type pinReference,
bool pinActive) const;
byte_vector sign(const SmartCard::Session& session, HashAlgorithm hashAlgo,
const byte_vector& hash, byte_vector&& pin, byte_type pinReference,
PinMinMaxLength pinMinMaxLength, byte_type keyReference,
byte_type signatureAlgo) const;

static constexpr byte_type AUTH_KEY_REFERENCE = 0x01;
static constexpr byte_type SIGNING_PIN_REFERENCE = 0x82;
};

} // namespace electronic_id
} // namespace electronic_id
7 changes: 6 additions & 1 deletion src/electronic-ids/pcsc/EstEIDThales.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class EstEIDThales : public EIDThales
}
constexpr byte_type signingKeyReference() const override { return 0x05; }
constexpr PinMinMaxLength signingPinMinMaxLength() const override { return {5, 12}; }
PinInfo signingPinInfoImpl(const SmartCard::Session& session) const override
{
// EstEID cards must change PIN2 first to use signing key
return pinRetriesLeft(session, SIGNING_PIN_REFERENCE, false);
}
};

} // namespace electronic_id
} // namespace electronic_id
16 changes: 4 additions & 12 deletions src/electronic-ids/pcsc/PcscElectronicID.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,9 @@ class PcscElectronicID : public ElectronicID
return signWithSigningKeyImpl(card.beginSession(), std::move(pin), hash, hashAlgo);
}

PinRetriesRemainingAndMax signingPinRetriesLeft() const override
{
return signingPinRetriesLeftImpl(card.beginSession());
}
PinInfo signingPinInfo() const override { return signingPinInfoImpl(card.beginSession()); }

ElectronicID::PinRetriesRemainingAndMax authPinRetriesLeft() const override
{
return authPinRetriesLeftImpl(card.beginSession());
}
PinInfo authPinInfo() const override { return authPinInfoImpl(card.beginSession()); }

// The following pure virtual *Impl functions are the interface of all
// PC/SC electronic ID implementations,
Expand All @@ -86,15 +80,13 @@ class PcscElectronicID : public ElectronicID
virtual byte_vector signWithAuthKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
const byte_vector& hash) const = 0;

virtual PinRetriesRemainingAndMax
authPinRetriesLeftImpl(const SmartCard::Session& session) const = 0;
virtual PinInfo authPinInfoImpl(const SmartCard::Session& session) const = 0;

virtual Signature signWithSigningKeyImpl(const SmartCard::Session& session, byte_vector&& pin,
const byte_vector& hash,
const HashAlgorithm hashAlgo) const = 0;

virtual PinRetriesRemainingAndMax
signingPinRetriesLeftImpl(const SmartCard::Session& session) const = 0;
virtual PinInfo signingPinInfoImpl(const SmartCard::Session& session) const = 0;
};

} // namespace electronic_id
4 changes: 2 additions & 2 deletions src/electronic-ids/pkcs11/PKCS11CardManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class PKCS11CardManager
std::string serialNumber;
CK_SLOT_ID slotID;
std::vector<CK_BYTE> cert, certID;
int8_t retry;
uint8_t retry;
bool pinpad;
uint8_t minPinLen, maxPinLen;
};
Expand Down Expand Up @@ -362,7 +362,7 @@ class PKCS11CardManager
return objectHandle;
}

static constexpr int8_t pinRetryCount(CK_FLAGS flags) noexcept
static constexpr uint8_t pinRetryCount(CK_FLAGS flags) noexcept
{
// As PKCS#11 does not provide an API for querying remaining PIN retries, we currently
// simply assume max retry count of 3, which is quite common. We might need to revisit this
Expand Down
8 changes: 4 additions & 4 deletions src/electronic-ids/pkcs11/Pkcs11ElectronicID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,9 @@ ElectronicID::PinMinMaxLength Pkcs11ElectronicID::authPinMinMaxLength() const
return {authToken.minPinLen, authToken.maxPinLen};
}

ElectronicID::PinRetriesRemainingAndMax Pkcs11ElectronicID::authPinRetriesLeft() const
ElectronicID::PinInfo Pkcs11ElectronicID::authPinInfo() const
{
return {authToken.retry, module.retryMax};
return {authToken.retry, module.retryMax, true};
}

pcsc_cpp::byte_vector Pkcs11ElectronicID::signWithAuthKey(byte_vector&& pin,
Expand Down Expand Up @@ -295,9 +295,9 @@ ElectronicID::PinMinMaxLength Pkcs11ElectronicID::signingPinMinMaxLength() const
return {signingToken.minPinLen, signingToken.maxPinLen};
}

ElectronicID::PinRetriesRemainingAndMax Pkcs11ElectronicID::signingPinRetriesLeft() const
ElectronicID::PinInfo Pkcs11ElectronicID::signingPinInfo() const
{
return {signingToken.retry, module.retryMax};
return {signingToken.retry, module.retryMax, true};
}

ElectronicID::Signature Pkcs11ElectronicID::signWithSigningKey(byte_vector&& pin,
Expand Down
4 changes: 2 additions & 2 deletions src/electronic-ids/pkcs11/Pkcs11ElectronicID.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ class Pkcs11ElectronicID : public ElectronicID
JsonWebSignatureAlgorithm authSignatureAlgorithm() const override;
PinMinMaxLength authPinMinMaxLength() const override;

PinRetriesRemainingAndMax authPinRetriesLeft() const override;
PinInfo authPinInfo() const override;
byte_vector signWithAuthKey(byte_vector&& pin, const byte_vector& hash) const override;

const std::set<SignatureAlgorithm>& supportedSigningAlgorithms() const override;
PinMinMaxLength signingPinMinMaxLength() const override;

PinRetriesRemainingAndMax signingPinRetriesLeft() const override;
PinInfo signingPinInfo() const override;
Signature signWithSigningKey(byte_vector&& pin, const byte_vector& hash,
const HashAlgorithm hashAlgo) const override;

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test-authenticate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ TEST(electronic_id_test, authenticate)
"currently supported");
}

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

byte_vector pin {'1', '2', '3', '4'};
pin.reserve(64);
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test-signing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static void signing(HashAlgorithm hashAlgo)

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

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

byte_vector pin;
if (cardInfo->name() == "EstEID IDEMIA v1" || cardInfo->name() == "EstEIDThales")
Expand Down
Loading