25
25
#include " crypto/Digest.h"
26
26
#include " crypto/X509Cert.h"
27
27
#include " crypto/X509Crypto.h"
28
+ #include " util/algorithm.h"
28
29
#include " util/log.h"
29
30
#include " util/File.h"
30
31
31
32
#include < openssl/evp.h>
32
33
33
- #include < algorithm>
34
34
#ifdef _WIN32
35
35
#include < Windows.h>
36
36
#else
@@ -43,9 +43,6 @@ using namespace std;
43
43
class PKCS11Signer ::Private
44
44
{
45
45
public:
46
- vector<CK_BYTE> attribute (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const ;
47
- vector<CK_OBJECT_HANDLE> findObject (CK_SESSION_HANDLE session, CK_OBJECT_CLASS cls, const vector<CK_BYTE> &id = {}) const ;
48
-
49
46
#ifdef _WIN32
50
47
bool load (const string &driver)
51
48
{
@@ -80,25 +77,74 @@ class PKCS11Signer::Private
80
77
struct SignSlot
81
78
{
82
79
X509Cert certificate;
83
- CK_SLOT_ID slot;
80
+ CK_SLOT_ID slot{} ;
84
81
vector<CK_BYTE> id;
85
- } sign { X509Cert (), 0 , {} } ;
82
+ } sign;
86
83
string pin;
87
84
};
88
85
89
- vector<CK_BYTE> PKCS11Signer::Private::attribute (CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const
86
+ template <typename > struct function_traits ;
87
+ template <typename R, typename C, typename ... Ps>
88
+ struct function_traits <R (*C::*)(Ps...)>
89
+ {
90
+ using return_type = R;
91
+ using arg_types = std::tuple<Ps...>;
92
+ static constexpr std::size_t nargs = sizeof ...(Ps);
93
+ };
94
+
95
+ template <auto Getter, typename ... Args>
96
+ static auto PKCS11List (CK_FUNCTION_LIST *f, Args&&... args)
97
+ {
98
+ using Traits = function_traits<decltype (Getter)>;
99
+ using T = std::remove_pointer_t <std::tuple_element_t <Traits::nargs - 2 , typename Traits::arg_types>>;
100
+ std::vector<T> result;
101
+ CK_ULONG count = 0 ;
102
+ if ((f->*Getter)(std::forward<Args>(args)..., static_cast <T*>(nullptr ), &count) != CKR_OK || count == 0 )
103
+ return result;
104
+ result.resize (size_t (count));
105
+ if ((f->*Getter)(std::forward<Args>(args)..., result.data (), &count) != CKR_OK)
106
+ result.clear ();
107
+ return result;
108
+ }
109
+
110
+ struct PKCS11Session
90
111
{
112
+ PKCS11Session (CK_FUNCTION_LIST *_f, CK_SLOT_ID slot)
113
+ : f(_f)
114
+ {
115
+ f->C_OpenSession (slot, CKF_SERIAL_SESSION, nullptr , nullptr , &handle);
116
+ }
117
+
118
+ DISABLE_COPY (PKCS11Session);
119
+
120
+ ~PKCS11Session ()
121
+ {
122
+ if (handle)
123
+ f->C_CloseSession (handle);
124
+ }
125
+
126
+ vector<CK_BYTE> attribute (CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const ;
127
+ vector<CK_OBJECT_HANDLE> findObject (CK_OBJECT_CLASS cls, const vector<CK_BYTE> &id = {}) const ;
128
+ operator bool () const { return handle != CK_INVALID_HANDLE; }
129
+
130
+ CK_FUNCTION_LIST *f;
131
+ CK_SESSION_HANDLE handle = CK_INVALID_HANDLE;
132
+ };
133
+
134
+ vector<CK_BYTE> PKCS11Session::attribute (CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_TYPE type) const
135
+ {
136
+ vector<CK_BYTE> value;
91
137
CK_ATTRIBUTE attr { type, nullptr , 0 };
92
- if (f->C_GetAttributeValue (session , obj, &attr, 1 ) != CKR_OK)
93
- return {} ;
94
- vector<CK_BYTE> value (size_t (attr.ulValueLen ));
138
+ if (f->C_GetAttributeValue (handle , obj, &attr, 1 ) != CKR_OK)
139
+ return value ;
140
+ value. resize (size_t (attr.ulValueLen ));
95
141
attr.pValue = value.data ();
96
- if (f->C_GetAttributeValue (session , obj, &attr, 1 ) != CKR_OK)
97
- return {} ;
142
+ if (f->C_GetAttributeValue (handle , obj, &attr, 1 ) != CKR_OK)
143
+ value. clear () ;
98
144
return value;
99
145
}
100
146
101
- vector<CK_OBJECT_HANDLE> PKCS11Signer::Private:: findObject (CK_SESSION_HANDLE session, CK_OBJECT_CLASS cls, const vector<CK_BYTE> &id) const
147
+ vector<CK_OBJECT_HANDLE> PKCS11Session:: findObject (CK_OBJECT_CLASS cls, const vector<CK_BYTE> &id) const
102
148
{
103
149
CK_BBOOL _true = CK_TRUE;
104
150
vector<CK_ATTRIBUTE> attrs {
@@ -107,14 +153,14 @@ vector<CK_OBJECT_HANDLE> PKCS11Signer::Private::findObject(CK_SESSION_HANDLE ses
107
153
};
108
154
if (!id.empty ())
109
155
attrs.push_back ({ CKA_ID, CK_VOID_PTR (id.data ()), CK_ULONG (id.size ()) });
110
- if (f->C_FindObjectsInit (session , attrs.data (), CK_ULONG (attrs.size ())) != CKR_OK)
156
+ if (f->C_FindObjectsInit (handle , attrs.data (), CK_ULONG (attrs.size ())) != CKR_OK)
111
157
return {};
112
158
113
159
CK_ULONG count = 32 ;
114
160
vector<CK_OBJECT_HANDLE> result (count);
115
- CK_RV err = f->C_FindObjects (session , result.data (), CK_ULONG (result.size ()), &count);
161
+ CK_RV err = f->C_FindObjects (handle , result.data (), CK_ULONG (result.size ()), &count);
116
162
result.resize (err == CKR_OK ? count : 0 );
117
- f->C_FindObjectsFinal (session );
163
+ f->C_FindObjectsFinal (handle );
118
164
return result;
119
165
}
120
166
@@ -195,38 +241,29 @@ X509Cert PKCS11Signer::cert() const
195
241
return d->sign .certificate ;
196
242
197
243
// Load all slots.
198
- CK_ULONG size = 0 ;
199
- if (d->f ->C_GetSlotList (true , nullptr , &size) != CKR_OK)
200
- THROW (" Could not find any ID-Cards in any readers" );
201
- vector<CK_SLOT_ID> slots (size);
202
- if (size && d->f ->C_GetSlotList (true , slots.data (), &size) != CKR_OK)
244
+ auto slots = PKCS11List<&CK_FUNCTION_LIST::C_GetSlotList>(d->f , CK_TRUE);
245
+ if (slots.empty ())
203
246
THROW (" Could not find any ID-Cards in any readers" );
204
247
205
248
// Iterate over all found slots, if the slot has a token, check if the token has any certificates.
206
- CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
207
249
vector<X509Cert> certificates;
208
250
vector<Private::SignSlot> certSlotMapping;
209
251
for (const CK_SLOT_ID &slot: slots)
210
252
{
211
- if (session)
212
- d->f ->C_CloseSession (session);
213
- if (d->f ->C_OpenSession (slot, CKF_SERIAL_SESSION, nullptr , nullptr , &session) != CKR_OK)
214
- continue ;
215
- for (CK_OBJECT_HANDLE obj: d->findObject (session, CKO_CERTIFICATE))
253
+ for (PKCS11Session session (d->f , slot);
254
+ CK_OBJECT_HANDLE obj: session.findObject (CKO_CERTIFICATE))
216
255
{
217
- X509Cert x509 (d-> attribute (session, obj, CKA_VALUE));
256
+ X509Cert x509 (session. attribute (obj, CKA_VALUE));
218
257
vector<X509Cert::KeyUsage> usage = x509.keyUsage ();
219
- if (!x509.isValid () || find (usage. cbegin (), usage. cend (), X509Cert::NonRepudiation) == usage. cend ( ) || x509.isCA ())
258
+ if (!x509.isValid () || ! contains (usage, X509Cert::NonRepudiation) || x509.isCA ())
220
259
continue ;
221
- vector<CK_BYTE> id = d-> attribute (session, obj, CKA_ID);
222
- if (d-> findObject (session, CKO_PUBLIC_KEY, id).empty ())
260
+ vector<CK_BYTE> id = session. attribute (obj, CKA_ID);
261
+ if (session. findObject (CKO_PUBLIC_KEY, id).empty ())
223
262
continue ;
224
263
certSlotMapping.push_back ({x509, slot, std::move (id)});
225
264
certificates.push_back (std::move (x509));
226
265
}
227
266
}
228
- if (session)
229
- d->f ->C_CloseSession (session);
230
267
231
268
if (certificates.empty ())
232
269
THROW (" No certificates found." );
@@ -237,10 +274,10 @@ X509Cert PKCS11Signer::cert() const
237
274
THROW (" No certificate selected." );
238
275
239
276
// Find the corresponding slot and PKCS11 certificate struct.
240
- for (const Private::SignSlot &slot: certSlotMapping)
277
+ for (Private::SignSlot &slot: certSlotMapping)
241
278
{
242
279
if (slot.certificate == selectedCert)
243
- d->sign = slot;
280
+ d->sign = std::move ( slot) ;
244
281
}
245
282
246
283
if (!d->sign .certificate )
@@ -255,13 +292,8 @@ string PKCS11Signer::method() const
255
292
if (!d->sign .certificate || !X509Crypto (d->sign .certificate ).isRSAKey () ||
256
293
parent != CONF (signatureDigestUri))
257
294
return parent;
258
- CK_ULONG count = 0 ;
259
- CK_RV rv = d->f ->C_GetMechanismList (d->sign .slot , nullptr , &count);
260
- if (rv != CKR_OK)
261
- return parent;
262
- vector<CK_MECHANISM_TYPE> mech (count);
263
- rv = d->f ->C_GetMechanismList (d->sign .slot , mech.data (), &count);
264
- if (find (mech.cbegin (), mech.cend (), CKM_RSA_PKCS_PSS) != mech.cend ())
295
+ if (auto mech = PKCS11List<&CK_FUNCTION_LIST::C_GetMechanismList>(d->f , d->sign .slot );
296
+ contains (mech, CKM_RSA_PKCS_PSS))
265
297
return Digest::toRsaPssUri (std::move (parent));
266
298
return parent;
267
299
}
@@ -323,26 +355,33 @@ vector<unsigned char> PKCS11Signer::sign(const string &method, const vector<unsi
323
355
{
324
356
DEBUG (" sign(mehthod = %s, digest = length=%zu)" , method.c_str (), digest.size ());
325
357
326
- // Check that sign slot and certificate are selected.
327
358
if (!d->sign .certificate )
328
- THROW (" Signing slot or certificate are not selected." );
359
+ THROW (" Signing certificate is not selected." );
329
360
330
- // Login if required.
331
361
CK_TOKEN_INFO token{};
332
- CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
333
- if (d->f ->C_GetTokenInfo (d->sign .slot , &token) != CKR_OK ||
334
- d->f ->C_OpenSession (d->sign .slot , CKF_SERIAL_SESSION, nullptr , nullptr , &session) != CKR_OK)
335
- THROW (" Signing slot or certificate are not selected." );
362
+ if (d->f ->C_GetTokenInfo (d->sign .slot , &token) != CKR_OK)
363
+ THROW (" Failed to get token info." );
364
+
365
+ if (token.flags & CKF_USER_PIN_LOCKED)
366
+ {
367
+ Exception e (EXCEPTION_PARAMS (" PIN Locked" ));
368
+ e.setCode (Exception::PINLocked);
369
+ throw e;
370
+ }
371
+
372
+ PKCS11Session session (d->f , d->sign .slot );
373
+ if (!session)
374
+ THROW (" Failed to open session." );
336
375
337
376
CK_RV rv = CKR_OK;
338
377
if (token.flags & CKF_LOGIN_REQUIRED)
339
378
{
340
379
if (token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
341
- rv = d->f ->C_Login (session, CKU_USER, nullptr , 0 );
380
+ rv = d->f ->C_Login (session. handle , CKU_USER, nullptr , 0 );
342
381
else
343
382
{
344
383
string _pin = pin (d->sign .certificate );
345
- rv = d->f ->C_Login (session, CKU_USER, CK_BYTE_PTR (_pin.c_str ()), CK_ULONG (_pin.size ()));
384
+ rv = d->f ->C_Login (session. handle , CKU_USER, CK_BYTE_PTR (_pin.c_str ()), CK_ULONG (_pin.size ()));
346
385
}
347
386
switch (rv)
348
387
{
@@ -374,14 +413,14 @@ vector<unsigned char> PKCS11Signer::sign(const string &method, const vector<unsi
374
413
}
375
414
}
376
415
377
- vector<CK_OBJECT_HANDLE> key = d-> findObject (session, CKO_PRIVATE_KEY, d->sign .id );
416
+ vector<CK_OBJECT_HANDLE> key = session. findObject (CKO_PRIVATE_KEY, d->sign .id );
378
417
if (key.size () != 1 )
379
418
THROW (" Could not get key that matches selected certificate." );
380
419
381
420
// Sign the digest.
382
421
CK_KEY_TYPE keyType = CKK_RSA;
383
422
CK_ATTRIBUTE attribute { CKA_KEY_TYPE, &keyType, sizeof (keyType) };
384
- d->f ->C_GetAttributeValue (session, key.front (), &attribute, 1 );
423
+ d->f ->C_GetAttributeValue (session. handle , key.front (), &attribute, 1 );
385
424
386
425
CK_RSA_PKCS_PSS_PARAMS pssParams { CKM_SHA_1, CKG_MGF1_SHA1, 0 };
387
426
CK_MECHANISM mech { keyType == CKK_ECDSA ? CKM_ECDSA : CKM_RSA_PKCS, nullptr , 0 };
@@ -409,16 +448,12 @@ vector<unsigned char> PKCS11Signer::sign(const string &method, const vector<unsi
409
448
}
410
449
else if (keyType == CKK_RSA)
411
450
data = Digest::addDigestInfo (std::move (data), method);
412
- if (d->f ->C_SignInit (session, &mech, key.front ()) != CKR_OK)
413
- THROW (" Failed to sign digest" );
414
-
415
- CK_ULONG size = 0 ;
416
- if (d->f ->C_Sign (session, data.data (), CK_ULONG (data.size ()), nullptr , &size) != CKR_OK)
451
+ if (d->f ->C_SignInit (session.handle , &mech, key.front ()) != CKR_OK)
417
452
THROW (" Failed to sign digest" );
418
453
419
- vector< unsigned char > signature ( size);
420
- rv = d->f ->C_Sign (session, data. data (), CK_ULONG (data. size ()), signature. data (), CK_ULONG_PTR (&size) );
421
- if (rv != CKR_OK )
454
+ auto signature = PKCS11List<&CK_FUNCTION_LIST::C_Sign>(d-> f , session. handle , data. data (), CK_ULONG (data. size ()) );
455
+ d->f ->C_Logout (session. handle );
456
+ if (signature. empty () )
422
457
THROW (" Failed to sign digest" );
423
458
return signature;
424
459
}
0 commit comments