@@ -26,6 +26,7 @@ use cryptoki::object::ObjectClass;
26
26
use cryptoki:: object:: ObjectHandle ;
27
27
use cryptoki:: session:: Session ;
28
28
use cryptoki:: session:: UserType ;
29
+ use cryptoki:: slot:: SlotInfo ;
29
30
use cryptoki:: slot:: TokenInfo ;
30
31
use rsa:: pkcs1:: EncodeRsaPublicKey ;
31
32
use rustls:: sign:: Signer ;
@@ -35,6 +36,7 @@ use rustls::SignatureScheme;
35
36
use serde:: Deserialize ;
36
37
use serde:: Serialize ;
37
38
use tracing:: debug;
39
+ use tracing:: error;
38
40
use tracing:: trace;
39
41
use tracing:: warn;
40
42
@@ -181,8 +183,8 @@ impl Cryptoki {
181
183
self . open_session ( uri, CryptokiSessionType :: ReadOnly )
182
184
}
183
185
184
- fn open_session_rw < ' a > ( & ' a self , uri : Option < & ' a str > ) -> anyhow:: Result < CryptokiSession < ' a > > {
185
- self . open_session ( uri, CryptokiSessionType :: ReadWrite )
186
+ fn _open_session_rw < ' a > ( & ' a self , uri : Option < & ' a str > ) -> anyhow:: Result < CryptokiSession < ' a > > {
187
+ self . open_session ( uri, CryptokiSessionType :: _ReadWrite )
186
188
}
187
189
188
190
fn open_session < ' a > (
@@ -203,6 +205,9 @@ impl Cryptoki {
203
205
Err ( e) => e. into_inner ( ) ,
204
206
} ;
205
207
208
+ debug ! ( slots = ?get_all_slots_info( & context) ) ;
209
+ debug ! ( tokens = ?get_all_token_info( & context) ) ;
210
+
206
211
let slots_with_tokens = context. get_slots_with_token ( ) ?;
207
212
let tokens: Result < Vec < _ > , _ > = slots_with_tokens
208
213
. iter ( )
@@ -232,18 +237,40 @@ impl Cryptoki {
232
237
233
238
let session = match session_type {
234
239
CryptokiSessionType :: ReadOnly => context. open_ro_session ( slot) ?,
235
- CryptokiSessionType :: ReadWrite => context. open_rw_session ( slot) ?,
240
+ CryptokiSessionType :: _ReadWrite => context. open_rw_session ( slot) ?,
236
241
} ;
237
242
238
243
session. login ( UserType :: User , Some ( & self . config . pin ) ) ?;
239
244
let session_info = session. get_session_info ( ) ?;
240
245
debug ! ( ?session_info, "Opened a readonly session" ) ;
241
246
242
- Ok ( CryptokiSession {
247
+ let session = CryptokiSession {
243
248
session,
244
249
token_info,
245
250
uri_attributes,
246
- } )
251
+ } ;
252
+
253
+ let template = [ ] ;
254
+ let objects = session. session . find_objects ( & template) ;
255
+ match objects {
256
+ Err ( err) => {
257
+ error ! ( ?template, ?err, "failed to find objects" ) ;
258
+ }
259
+ Ok ( objects) => {
260
+ let objects = objects
261
+ . into_iter ( )
262
+ . flat_map ( |o| {
263
+ let uri = session. export_object_uri ( o) . inspect_err (
264
+ |err| error ! ( ?err, object = ?o, "failed to read properties of object" ) ,
265
+ ) ;
266
+ uri. map ( |u| ( o, u) ) . ok ( )
267
+ } )
268
+ . collect :: < Vec < _ > > ( ) ;
269
+ trace ! ( ?objects, "Objects found in the token" ) ;
270
+ }
271
+ }
272
+
273
+ Ok ( session)
247
274
}
248
275
249
276
fn request_uri < ' a > (
@@ -268,6 +295,45 @@ impl Cryptoki {
268
295
}
269
296
}
270
297
298
+ fn get_all_slots_info ( cryptoki : & Pkcs11 ) -> Vec < SlotInfo > {
299
+ let slots = match cryptoki. get_all_slots ( ) {
300
+ Ok ( slots) => slots,
301
+ Err ( err) => {
302
+ error ! ( ?err, "failed to get slots" ) ;
303
+ return vec ! [ ] ;
304
+ }
305
+ } ;
306
+ slots
307
+ . into_iter ( )
308
+ . flat_map ( |s| {
309
+ cryptoki
310
+ . get_slot_info ( s)
311
+ . inspect_err ( |err| error ! ( slot = ?s, ?err, "failed to read slot info from slot" ) )
312
+ . ok ( )
313
+ } )
314
+ . collect :: < Vec < _ > > ( )
315
+ }
316
+
317
+ fn get_all_token_info ( cryptoki : & Pkcs11 ) -> Vec < TokenInfo > {
318
+ let slots = match cryptoki. get_slots_with_token ( ) {
319
+ Ok ( slots) => slots,
320
+ Err ( err) => {
321
+ error ! ( ?err, "failed to get slots" ) ;
322
+ return vec ! [ ] ;
323
+ }
324
+ } ;
325
+
326
+ slots
327
+ . into_iter ( )
328
+ . flat_map ( |s| {
329
+ cryptoki
330
+ . get_token_info ( s)
331
+ . inspect_err ( |err| error ! ( slot = ?s, ?err, "failed to read token info from slot" ) )
332
+ . ok ( )
333
+ } )
334
+ . collect :: < Vec < _ > > ( )
335
+ }
336
+
271
337
/// A cryptoki session opened with a token.
272
338
struct CryptokiSession < ' a > {
273
339
session : Session ,
@@ -278,7 +344,7 @@ struct CryptokiSession<'a> {
278
344
#[ derive( Debug , Clone , Copy ) ]
279
345
enum CryptokiSessionType {
280
346
ReadOnly ,
281
- ReadWrite ,
347
+ _ReadWrite ,
282
348
}
283
349
284
350
impl CryptokiSession < ' _ > {
@@ -442,6 +508,41 @@ impl CryptokiSession<'_> {
442
508
443
509
Ok ( pubkey_pem)
444
510
}
511
+
512
+ fn export_object_uri ( & self , object : ObjectHandle ) -> anyhow:: Result < String > {
513
+ let template = & [ AttributeType :: Id , AttributeType :: Label ] ;
514
+ let attrs = self . session . get_attributes ( object, template) ?. into_iter ( ) ;
515
+
516
+ let mut key_uri = export_session_uri ( & self . token_info ) ;
517
+
518
+ for attr in attrs {
519
+ match attr {
520
+ Attribute :: Id ( id) => {
521
+ key_uri. push ( ';' ) ;
522
+ key_uri. push_str ( "id=" ) ;
523
+ // from RFC section 2.3: Note that the value of the "id" attribute SHOULD NOT be encoded as UTF-8 because it can
524
+ // contain non-textual data, instead it SHOULD be entirely percent-encoded
525
+ for byte in & id {
526
+ key_uri. push_str ( percent_encoding:: percent_encode_byte ( * byte) ) ;
527
+ }
528
+ }
529
+ Attribute :: Label ( label) => {
530
+ let label = std:: str:: from_utf8 ( & label) . context ( "label should be utf-8" ) ?;
531
+ key_uri. push ( ';' ) ;
532
+ key_uri. push_str ( "object=" ) ;
533
+ let label = uri:: percent_encode ( label) ;
534
+ key_uri. push_str ( & label) ;
535
+ }
536
+ other => warn ! ( asked = ?template, got= ?other, "Got invalid attribute" ) ,
537
+ }
538
+ }
539
+
540
+ // omit the "type" attribute since its not relevant when used as device.key_uri, which is intended use for this produced value
541
+
542
+ anyhow:: ensure!( key_uri. starts_with( "pkcs11:" ) ) ;
543
+
544
+ Ok ( key_uri)
545
+ }
445
546
}
446
547
447
548
#[ derive( Debug ) ]
@@ -687,6 +788,36 @@ fn get_ec_mechanism(session: &Session, key: ObjectHandle) -> anyhow::Result<SigS
687
788
}
688
789
}
689
790
791
+ /// Generates PKCS11 URI of the selected token.
792
+ ///
793
+ /// The generated URI attempts to be similar to URIs generated by gnutls. Notably, "slot-description", "slot-id", and
794
+ /// "slot-manufacturer" attributes are missing from gnutls URIs, perhaps for portability (URI points to the same thing
795
+ /// even if token is reinserted into a different slot).
796
+ fn export_session_uri ( token_info : & TokenInfo ) -> String {
797
+ let mut uri = String :: from ( "pkcs11:" ) ;
798
+
799
+ uri. push_str ( "model=" ) ;
800
+ let model = uri:: percent_encode ( token_info. model ( ) ) ;
801
+ uri. push_str ( & model) ;
802
+
803
+ uri. push ( ';' ) ;
804
+ uri. push_str ( "manufacturer=" ) ;
805
+ let manufacturer = uri:: percent_encode ( token_info. manufacturer_id ( ) ) ;
806
+ uri. push_str ( & manufacturer) ;
807
+
808
+ uri. push ( ';' ) ;
809
+ uri. push_str ( "serial=" ) ;
810
+ let serial = uri:: percent_encode ( token_info. serial_number ( ) ) ;
811
+ uri. push_str ( & serial) ;
812
+
813
+ uri. push ( ';' ) ;
814
+ uri. push_str ( "token=" ) ;
815
+ let token = uri:: percent_encode ( token_info. label ( ) ) ;
816
+ uri. push_str ( & token) ;
817
+
818
+ uri
819
+ }
820
+
690
821
#[ cfg( test) ]
691
822
mod tests {
692
823
use super :: * ;
0 commit comments