Skip to content

Commit 6f7730e

Browse files
authored
Add Idemia V2 ATR (#127)
IB-8370 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent 0328016 commit 6f7730e

File tree

4 files changed

+41
-36
lines changed

4 files changed

+41
-36
lines changed

.github/workflows/cmake-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
with:
2020
vcpkgArguments: gtest:x64-windows openssl:x64-windows
2121
vcpkgTriplet: x64-windows
22-
vcpkgGitCommitId: 1f619be01b436b796dab797dd1e1721c5676f8ac
22+
vcpkgGitCommitId: 0d5cae153065957df7f382de7c1549ccc88027e5
2323

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

src/electronic-id.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ const std::map<byte_vector, ElectronicIDConstructor> SUPPORTED_ATRS {
5858
{{0x3b, 0xdb, 0x96, 0x00, 0x80, 0xb1, 0xfe, 0x45, 0x1f, 0x83, 0x00,
5959
0x12, 0x23, 0x3f, 0x53, 0x65, 0x49, 0x44, 0x0f, 0x90, 0x00, 0xf1},
6060
constructor<EstEIDIDEMIAV1>},
61+
// EstEID Idemia v2.0
62+
{{0x3b, 0xdc, 0x96, 0x00, 0x80, 0xb1, 0xfe, 0x45, 0x1f, 0x83, 0x00, 0x12,
63+
0x23, 0x3f, 0x54, 0x65, 0x49, 0x44, 0x32, 0x0f, 0x90, 0x00, 0xc3},
64+
constructor<EstEIDIDEMIAV1>},
6165
// FinEID v3.0
6266
{{0x3B, 0x7F, 0x96, 0x00, 0x00, 0x80, 0x31, 0xB8, 0x65, 0xB0,
6367
0x85, 0x03, 0x00, 0xEF, 0x12, 0x00, 0xF6, 0x82, 0x90, 0x00},

src/electronic-ids/TLV.hpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ namespace electronic_id
3838
struct TLV
3939
{
4040
using byte_vector = pcsc_cpp::byte_vector;
41-
uint16_t tag {};
41+
uint32_t tag {};
4242
uint32_t length {};
4343
byte_vector::const_iterator begin;
4444
byte_vector::const_iterator end;
@@ -57,10 +57,19 @@ struct TLV
5757

5858
tag = *begin++;
5959
if ((tag & 0x1F) == 0x1F) { // Multi-byte tag
60-
if (!*this) {
61-
THROW(std::invalid_argument, "Invalid TLV: Unexpected end of tag");
62-
}
63-
tag = (tag << 8) | (*begin++);
60+
constexpr uint8_t MAX_TAG_BYTES = sizeof(tag);
61+
uint8_t tagBytes = 1;
62+
do {
63+
if (tagBytes >= MAX_TAG_BYTES) {
64+
THROW(std::invalid_argument,
65+
"Invalid TLV: Tag too long or too large for uint32_t");
66+
}
67+
if (!*this) {
68+
THROW(std::invalid_argument, "Invalid TLV: Unexpected end of tag");
69+
}
70+
tag = (tag << 8) | (*begin++);
71+
++tagBytes;
72+
} while ((tag & 0x80) != 0x00);
6473
}
6574

6675
if (!*this) {
@@ -87,28 +96,34 @@ struct TLV
8796

8897
PCSC_CPP_CONSTEXPR_VECTOR TLV child() const { return {begin, begin + length}; }
8998

99+
PCSC_CPP_CONSTEXPR_VECTOR TLV operator[](uint32_t find) const
100+
{
101+
TLV tlv = child();
102+
for (; tlv && tlv.tag != find; ++tlv);
103+
return tlv;
104+
}
90105
PCSC_CPP_CONSTEXPR_VECTOR TLV& operator++() { return *this = {begin + length, end}; }
91106

92107
template <typename... Tags>
93-
static PCSC_CPP_CONSTEXPR_VECTOR TLV path(TLV tlv, uint16_t tag, Tags... tags)
108+
static PCSC_CPP_CONSTEXPR_VECTOR TLV path(TLV tlv, uint32_t tag, Tags... tags)
94109
{
95110
for (; tlv; ++tlv) {
96111
if (tlv.tag == tag) {
97112
if constexpr (sizeof...(tags) > 0) {
98-
return path(tlv.child(), uint16_t(tags)...);
113+
return path(tlv.child(), uint32_t(tags)...);
99114
}
100115
return tlv;
101116
}
102117
}
103118
return TLV({});
104119
}
105120
template <typename... Tags>
106-
static PCSC_CPP_CONSTEXPR_VECTOR TLV path(const byte_vector& data, uint16_t tag, Tags... tags)
121+
static PCSC_CPP_CONSTEXPR_VECTOR TLV path(const byte_vector& data, uint32_t tag, Tags... tags)
107122
{
108123
return path(TLV(data), tag, tags...);
109124
}
110125

111-
constexpr operator bool() const noexcept { return begin != end; }
126+
constexpr operator bool() const noexcept { return begin < end; }
112127
};
113128

114129
} // namespace electronic_id

src/electronic-ids/pcsc/EIDIDEMIA.cpp

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
#include "pcsc-common.hpp"
2626

27+
#include "../TLV.hpp"
28+
2729
using namespace pcsc_cpp;
2830
using namespace electronic_id;
2931

@@ -108,23 +110,11 @@ ElectronicID::Signature EIDIDEMIA::signWithSigningKeyImpl(byte_vector&& pin,
108110
{
109111
selectADF2();
110112
auto [keyRef, isECC] = signKeyRef();
111-
selectSecurityEnv(*card, 0xB6, isECC ? 0x54 : 0x42, keyRef, name());
112-
auto tmp = hash;
113-
if (isECC) {
114-
constexpr size_t ECDSA384_INPUT_LENGTH = 384 / 8;
115-
if (tmp.size() < ECDSA384_INPUT_LENGTH) {
116-
// Zero-pad hashes that are shorter than SHA-384.
117-
tmp.insert(tmp.cbegin(), ECDSA384_INPUT_LENGTH - tmp.size(), 0x00);
118-
} else if (tmp.size() > ECDSA384_INPUT_LENGTH) {
119-
// Truncate hashes that are longer than SHA-384.
120-
tmp.resize(ECDSA384_INPUT_LENGTH);
121-
}
122-
}
123-
113+
selectSecurityEnv(*card, 0xB6, isECC ? 0x24 + uint8_t(hashAlgo.hashByteLength()) : 0x42, keyRef, name());
124114
verifyPin(*card, SIGN_PIN_REFERENCE, std::move(pin), signingPinMinMaxLength().first,
125115
signingPinMinMaxLength().second, PIN_PADDING_CHAR);
126116

127-
return {computeSignature(*card, tmp, name()),
117+
return {computeSignature(*card, hash, name()),
128118
{isECC ? SignatureAlgorithm::ES : SignatureAlgorithm::RS, hashAlgo}};
129119
}
130120

@@ -136,22 +126,18 @@ ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::signingPinRetriesLeftImpl() c
136126

137127
ElectronicID::PinRetriesRemainingAndMax EIDIDEMIA::pinRetriesLeft(byte_type pinReference) const
138128
{
129+
auto ref = byte_type(pinReference & 0x0F);
139130
const pcsc_cpp::CommandApdu GET_DATA_ODD {
140-
0x00,
141-
0xCB,
142-
0x3F,
143-
0xFF,
144-
{0x4D, 0x08, 0x70, 0x06, 0xBF, 0x81, byte_type(pinReference & 0x0F), 0x02, 0xA0, 0x80},
145-
0x00};
131+
0x00, 0xCB, 0x3F, 0xFF, {0x4D, 0x08, 0x70, 0x06, 0xBF, 0x81, ref, 0x02, 0xA0, 0x80}, 0x00};
146132
const auto response = card->transmit(GET_DATA_ODD);
147133
if (!response.isOK()) {
148134
THROW(SmartCardError, "Command GET DATA ODD failed with error " + response);
149135
}
150-
if (response.data.size() < 14) {
151-
THROW(SmartCardError,
152-
"Command GET DATA ODD failed: received data size "
153-
+ std::to_string(response.data.size())
154-
+ " is less than the expected size of the PIN remaining retries offset 14");
136+
TLV info = TLV::path(response.data, 0x70, 0xBF8100 | ref, 0xA0);
137+
TLV max = info[0x9A];
138+
TLV tries = info[0x9B];
139+
if (max && tries) {
140+
return {*tries.begin, *max.begin};
155141
}
156-
return {uint8_t(response.data[13]), uint8_t(response.data[10])};
142+
THROW(SmartCardError, "Command GET DATA ODD failed: missing expected info");
157143
}

0 commit comments

Comments
 (0)