2525#include " crypto/Digest.h"
2626#include " crypto/X509Cert.h"
2727#include " crypto/X509Crypto.h"
28+ #include " util/algorithm.h"
2829#include " util/log.h"
2930#include " util/File.h"
3031
3132#include < openssl/evp.h>
3233
33- #include < algorithm>
3434#ifdef _WIN32
3535#include < Windows.h>
3636#else
@@ -43,9 +43,6 @@ using namespace std;
4343class PKCS11Signer ::Private
4444{
4545public:
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-
4946#ifdef _WIN32
5047 bool load (const string &driver)
5148 {
@@ -80,25 +77,74 @@ class PKCS11Signer::Private
8077 struct SignSlot
8178 {
8279 X509Cert certificate;
83- CK_SLOT_ID slot;
80+ CK_SLOT_ID slot{} ;
8481 vector<CK_BYTE > id;
85- } sign { X509Cert (), 0 , {} } ;
82+ } sign;
8683 string pin;
8784};
8885
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
90111{
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;
91137 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 ));
95141 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 () ;
98144 return value;
99145}
100146
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
102148{
103149 CK_BBOOL _true = CK_TRUE ;
104150 vector<CK_ATTRIBUTE > attrs {
@@ -107,14 +153,14 @@ vector<CK_OBJECT_HANDLE> PKCS11Signer::Private::findObject(CK_SESSION_HANDLE ses
107153 };
108154 if (!id.empty ())
109155 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 )
111157 return {};
112158
113159 CK_ULONG count = 32 ;
114160 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);
116162 result.resize (err == CKR_OK ? count : 0 );
117- f->C_FindObjectsFinal (session );
163+ f->C_FindObjectsFinal (handle );
118164 return result;
119165}
120166
@@ -195,38 +241,29 @@ X509Cert PKCS11Signer::cert() const
195241 return d->sign .certificate ;
196242
197243 // 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 ())
203246 THROW (" Could not find any ID-Cards in any readers" );
204247
205248 // 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 ;
207249 vector<X509Cert> certificates;
208250 vector<Private::SignSlot> certSlotMapping;
209251 for (const CK_SLOT_ID &slot: slots)
210252 {
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 ))
216255 {
217- X509Cert x509 (d-> attribute (session, obj, CKA_VALUE ));
256+ X509Cert x509 (session. attribute (obj, CKA_VALUE ));
218257 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 ())
220259 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 ())
223262 continue ;
224263 certSlotMapping.push_back ({x509, slot, std::move (id)});
225264 certificates.push_back (std::move (x509));
226265 }
227266 }
228- if (session)
229- d->f ->C_CloseSession (session);
230267
231268 if (certificates.empty ())
232269 THROW (" No certificates found." );
@@ -237,10 +274,10 @@ X509Cert PKCS11Signer::cert() const
237274 THROW (" No certificate selected." );
238275
239276 // Find the corresponding slot and PKCS11 certificate struct.
240- for (const Private::SignSlot &slot: certSlotMapping)
277+ for (Private::SignSlot &slot: certSlotMapping)
241278 {
242279 if (slot.certificate == selectedCert)
243- d->sign = slot;
280+ d->sign = std::move ( slot) ;
244281 }
245282
246283 if (!d->sign .certificate )
@@ -255,13 +292,8 @@ string PKCS11Signer::method() const
255292 if (!d->sign .certificate || !X509Crypto (d->sign .certificate ).isRSAKey () ||
256293 parent != CONF (signatureDigestUri))
257294 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 ))
265297 return Digest::toRsaPssUri (std::move (parent));
266298 return parent;
267299}
@@ -323,26 +355,33 @@ vector<unsigned char> PKCS11Signer::sign(const string &method, const vector<unsi
323355{
324356 DEBUG (" sign(mehthod = %s, digest = length=%zu)" , method.c_str (), digest.size ());
325357
326- // Check that sign slot and certificate are selected.
327358 if (!d->sign .certificate )
328- THROW (" Signing slot or certificate are not selected." );
359+ THROW (" Signing certificate is not selected." );
329360
330- // Login if required.
331361 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." );
336375
337376 CK_RV rv = CKR_OK ;
338377 if (token.flags & CKF_LOGIN_REQUIRED )
339378 {
340379 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 );
342381 else
343382 {
344383 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 ()));
346385 }
347386 switch (rv)
348387 {
@@ -374,14 +413,14 @@ vector<unsigned char> PKCS11Signer::sign(const string &method, const vector<unsi
374413 }
375414 }
376415
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 );
378417 if (key.size () != 1 )
379418 THROW (" Could not get key that matches selected certificate." );
380419
381420 // Sign the digest.
382421 CK_KEY_TYPE keyType = CKK_RSA ;
383422 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 );
385424
386425 CK_RSA_PKCS_PSS_PARAMS pssParams { CKM_SHA_1 , CKG_MGF1_SHA1 , 0 };
387426 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
409448 }
410449 else if (keyType == CKK_RSA )
411450 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 )
417452 THROW (" Failed to sign digest" );
418453
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 () )
422457 THROW (" Failed to sign digest" );
423458 return signature;
424459}
0 commit comments