@@ -73,6 +73,16 @@ const NSS_PIN_MAX: usize = 500;
7373/// Length of the salt used for NSS password hashing (from SHA1_LENGTH).
7474const NSS_PIN_SALT_LEN : usize = 20 ;
7575
76+ /// CKA_PARAMETER_SET bug fallback guard value:
77+ /// Generally numeric identifiers for parameters set are small,
78+ /// The largest so far is SLH-DSA with a value of 0x0C, but we'll give
79+ /// a little more space to avoid having to constantly tweak this in the
80+ /// future. It is unlikely any function will ever need more than 0x8F
81+ /// identifiers unless they decide to assign non consequent identifiers
82+ /// at some point in the future. By then we can probably drop this
83+ /// fallback code entriely
84+ const CKP_MAX_IDENTIFIER : u32 = 0x8F ;
85+
7686/// Formats an internal UID string from the table name and numeric NSS object ID.
7787fn nss_id_format ( table : & str , id : u32 ) -> String {
7888 format ! ( "{}-{}-{}" , NSS_ID_PREFIX , table, id)
@@ -430,6 +440,55 @@ impl NSSStorage {
430440 Ok ( ( ) )
431441 }
432442
443+ /// NSS broke the database format by not converting CKA_PARAMETER_SET to a
444+ /// database ulong as it should have. We try to be compatible on reading
445+ /// nss databases that were malformed this way (we do not bother trying
446+ /// to write because there is no correct way to do it as what's written
447+ /// is platform's CK_ULONG and endianness dependent, so there is no stable
448+ /// "bad format". Luckily CKA_PARAMETER_SET has only a very small set of
449+ /// valid values and does not store arbitrary integers so we can also
450+ /// detect endianness violations on reading.
451+ fn cka_parameter_set_fixup ( & self , blob : & [ u8 ] ) -> Result < CK_ULONG > {
452+ match blob. len ( ) {
453+ 4 => {
454+ let bytes: [ u8 ; 4 ] = match blob. try_into ( ) {
455+ Ok ( b) => b,
456+ Err ( _) => return Err ( CKR_ATTRIBUTE_VALUE_INVALID ) ?,
457+ } ;
458+ /* assume correct format by default, try inverse endianness
459+ * later */
460+ let number = u32:: from_be_bytes ( bytes) ;
461+ if number < CKP_MAX_IDENTIFIER {
462+ return Ok ( number as CK_ULONG ) ;
463+ }
464+ /* try the other endianness */
465+ let number = u32:: from_le_bytes ( bytes) ;
466+ if number < CKP_MAX_IDENTIFIER {
467+ return Ok ( number as CK_ULONG ) ;
468+ }
469+ }
470+ 8 => {
471+ let bytes: [ u8 ; 8 ] = match blob. try_into ( ) {
472+ Ok ( b) => b,
473+ Err ( _) => return Err ( CKR_ATTRIBUTE_VALUE_INVALID ) ?,
474+ } ;
475+ /* assume little endianness by default case as LE are the
476+ * most common 64bit platforms */
477+ let number = u64:: from_le_bytes ( bytes) ;
478+ if number < CKP_MAX_IDENTIFIER as u64 {
479+ return Ok ( number as CK_ULONG ) ;
480+ }
481+ /* try the other endianness */
482+ let number = u64:: from_be_bytes ( bytes) ;
483+ if number < CKP_MAX_IDENTIFIER as u64 {
484+ return Ok ( number as CK_ULONG ) ;
485+ }
486+ }
487+ _ => ( ) ,
488+ }
489+ return Err ( CKR_ATTRIBUTE_VALUE_INVALID ) ?;
490+ }
491+
433492 /// Converts rows returned from an NSS DB query into a PKCS#11 `Object`.
434493 ///
435494 /// Maps NSS column names (e.g., "a81") to attribute types and converts
@@ -460,22 +519,29 @@ impl NSSStorage {
460519 }
461520 let bn: Option < & [ u8 ] > =
462521 row. get_ref ( i + offset) ?. as_blob_or_null ( ) ?;
463- let blob: & [ u8 ] = match bn {
522+ let mut blob: & [ u8 ] = match bn {
464523 Some ( ref b) => b,
465524 None => continue ,
466525 } ;
467526 let atype = AttrType :: attr_id_to_attrtype ( cols[ i] ) ?;
468527 let attr = match atype {
469528 AttrType :: NumType => {
470- if blob. len ( ) != 4 {
471- return Err ( CKR_ATTRIBUTE_VALUE_INVALID ) ?;
472- }
473- let bytes: [ u8 ; 4 ] = match blob. try_into ( ) {
474- Ok ( b) => b,
475- Err ( _) => return Err ( CKR_ATTRIBUTE_VALUE_INVALID ) ?,
529+ /* Handle NSS bug with CKA_PARAMETER_SET storage */
530+ let ulong = if cols[ i] == CKA_PARAMETER_SET {
531+ match self . cka_parameter_set_fixup ( blob) {
532+ Ok ( u) => u,
533+ Err ( e) => return Err ( e) ,
534+ }
535+ } else {
536+ let bytes: [ u8 ; 4 ] = match blob. try_into ( ) {
537+ Ok ( b) => b,
538+ Err ( _) => {
539+ return Err ( CKR_ATTRIBUTE_VALUE_INVALID ) ?
540+ }
541+ } ;
542+ let number = u32:: from_be_bytes ( bytes) ;
543+ number as CK_ULONG
476544 } ;
477- let number = u32:: from_be_bytes ( bytes) ;
478- let ulong = number as CK_ULONG ;
479545 Attribute :: from_attr_slice (
480546 cols[ i] ,
481547 atype,
0 commit comments