-
Notifications
You must be signed in to change notification settings - Fork 20
/
electronic-id.hpp
252 lines (202 loc) · 7.36 KB
/
electronic-id.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
* Copyright (c) 2020-2024 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include "enums.hpp"
#include "pcsc-cpp/pcsc-cpp.hpp"
#include <memory>
namespace electronic_id
{
/** Interface for all electronic ID cards and tokens, contains cryptographic
* operations and card information. */
class ElectronicID
{
public:
using ptr = std::shared_ptr<ElectronicID>;
using PinMinMaxLength = std::pair<size_t, size_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>;
enum Type {
EstEID,
FinEID,
LatEID,
LitEID,
HrvEID,
BelEIDV1_7,
BelEIDV1_8,
CzeEID,
#ifdef _WIN32
MsCryptoApiEID,
#endif
};
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;
// Functions related to authentication.
virtual JsonWebSignatureAlgorithm authSignatureAlgorithm() const = 0;
virtual PinMinMaxLength authPinMinMaxLength() const = 0;
virtual PinRetriesRemainingAndMax authPinRetriesLeft() const = 0;
virtual pcsc_cpp::byte_vector signWithAuthKey(const pcsc_cpp::byte_vector& cert,
const byte_vector& pin,
const byte_vector& hash) const = 0;
// Functions related to signing.
virtual const std::set<SignatureAlgorithm>& supportedSigningAlgorithms() const = 0;
bool isSupportedSigningHashAlgorithm(const HashAlgorithm hashAlgo) const;
virtual PinMinMaxLength signingPinMinMaxLength() const = 0;
virtual PinRetriesRemainingAndMax signingPinRetriesLeft() const = 0;
virtual Signature signWithSigningKey(const byte_vector& cert, const byte_vector& pin,
const byte_vector& hash,
const HashAlgorithm hashAlgo) const = 0;
// General functions.
virtual bool allowsUsingLettersAndSpecialCharactersInPin() const { return false; }
virtual bool providesExternalPinDialog() const { return false; }
virtual std::string name() const = 0;
virtual Type type() const = 0;
virtual pcsc_cpp::SmartCard const& smartcard() const { return *card; }
protected:
ElectronicID(pcsc_cpp::SmartCard::ptr _card) : card(std::move(_card)) {}
pcsc_cpp::SmartCard::ptr card;
};
bool isCardSupported(const pcsc_cpp::byte_vector& atr);
ElectronicID::ptr getElectronicID(const pcsc_cpp::Reader& reader);
/** Aggregates reader and electronic ID objects for communicating with and inspecting the eID card.
*/
class CardInfo
{
public:
using ptr = std::shared_ptr<CardInfo>;
CardInfo(pcsc_cpp::Reader r, ElectronicID::ptr e) : _reader(std::move(r)), _eid(std::move(e)) {}
const pcsc_cpp::Reader& reader() const { return _reader; }
const ElectronicID& eid() const { return *_eid; }
const ElectronicID::ptr eidPtr() const { return _eid; }
private:
pcsc_cpp::Reader _reader;
ElectronicID::ptr _eid;
};
/** Automatic card selection that either returns a vector of card info pointers with available
* supported cards or throws AutoSelectFailed. */
std::vector<CardInfo::ptr> availableSupportedCards();
/** Base class for fatal errors in parameters or environment conditions that do not allow retrying.
*/
class FatalError : public std::runtime_error
{
protected:
using std::runtime_error::runtime_error;
};
/** Fatal error caused by violating application logic pre-/post-conditions or invariants. */
class ProgrammingError : public FatalError
{
using FatalError::FatalError;
};
/** Fatal error caused by input arguments. */
class ArgumentFatalError : public FatalError
{
using FatalError::FatalError;
};
/** Base class for non-fatal errors, possibly allowing retry. */
class Error : public std::runtime_error
{
protected:
using std::runtime_error::runtime_error;
};
/** An error that can possibly be mitigated by changing the smart card in the reader. */
class SmartCardChangeRequiredError : public Error
{
using Error::Error;
};
/** Attempt to perform an operation with a wrong certificate type. */
class WrongCertificateTypeError : public Error
{
using Error::Error;
};
/** Non-fatal error caused by the smart card services layer. */
class SmartCardError : public Error
{
using Error::Error;
};
/** Non-fatal error caused by the PKCS #11 layer. */
class Pkcs11Error : public Error
{
using Error::Error;
};
/** Smart card was not present in its slot at the time that a PKCS#11 function was invoked. */
class Pkcs11TokenNotPresent : public Error
{
using Error::Error;
};
/** Smart card was removed from its slot during the execution of a PKCS#11 function. */
class Pkcs11TokenRemoved : public Error
{
using Error::Error;
};
#ifdef _WIN32
class MsCryptoApiError : public Error
{
using Error::Error;
};
#endif
/** Communicates why auto-select failed to the caller. */
class AutoSelectFailed : public Error
{
public:
enum class Reason {
SERVICE_NOT_RUNNING,
NO_READERS,
SINGLE_READER_NO_CARD,
SINGLE_READER_UNSUPPORTED_CARD,
MULTIPLE_READERS_NO_CARD,
MULTIPLE_READERS_NO_SUPPORTED_CARD
};
explicit AutoSelectFailed(Reason r);
Reason reason() const { return _reason; }
private:
Reason _reason;
};
/** Communicates why PIN verification failed to the caller. */
class VerifyPinFailed : public Error
{
public:
// Non-owning observing pointer.
template <typename T>
using observer_ptr = T*;
enum class Status {
RETRY_ALLOWED,
INVALID_PIN_LENGTH,
PIN_ENTRY_TIMEOUT,
PIN_ENTRY_CANCEL,
PIN_ENTRY_DISABLED,
// Retry not allowed starting from PIN_BLOCKED.
PIN_BLOCKED,
UNKNOWN_ERROR
};
explicit VerifyPinFailed(const Status s,
const observer_ptr<pcsc_cpp::ResponseApdu> ra = nullptr,
const int8_t retries = 0);
Status status() const { return _status; }
int8_t retries() const { return _retries; }
private:
Status _status;
int8_t _retries;
};
} // namespace electronic_id