1- //! rustls connector for PKCS#11 tokens .
1+ //! Interfaces with the PKCS#11 dynamic module using cryptoki crate .
22//!
33//! # `p11tool` quirks
44//!
6363//! - PKCS#11: <https://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html>
6464
6565use anyhow:: Context ;
66- use asn1_rs:: BigInt ;
6766use asn1_rs:: FromDer as _;
68- use asn1_rs:: Integer ;
69- use asn1_rs:: SequenceOf ;
7067use asn1_rs:: ToDer ;
7168use camino:: Utf8Path ;
7269use camino:: Utf8PathBuf ;
7370use cryptoki:: context:: CInitializeArgs ;
7471use cryptoki:: context:: Pkcs11 ;
7572use cryptoki:: error:: Error ;
76- use cryptoki:: mechanism:: rsa:: PkcsMgfType ;
77- use cryptoki:: mechanism:: rsa:: PkcsPssParams ;
7873use cryptoki:: mechanism:: Mechanism ;
79- use cryptoki:: mechanism:: MechanismType ;
8074use cryptoki:: object:: Attribute ;
8175use cryptoki:: object:: AttributeType ;
8276use cryptoki:: object:: KeyType ;
@@ -87,10 +81,7 @@ use cryptoki::session::UserType;
8781use cryptoki:: slot:: SlotInfo ;
8882use cryptoki:: slot:: TokenInfo ;
8983use rsa:: pkcs1:: EncodeRsaPublicKey ;
90- use rustls:: sign:: Signer ;
9184use rustls:: sign:: SigningKey ;
92- use rustls:: SignatureAlgorithm ;
93- use rustls:: SignatureScheme ;
9485use serde:: Deserialize ;
9586use serde:: Serialize ;
9687use tracing:: debug;
@@ -116,6 +107,10 @@ use crate::service::SignRequestWithSigScheme;
116107use crate :: service:: SignResponse ;
117108use crate :: service:: TedgeP11Service ;
118109
110+ mod signing;
111+ pub use signing:: Pkcs11Signer ;
112+ pub use signing:: SigScheme ;
113+
119114mod uri;
120115
121116/// Parameters used when opening a session.
@@ -503,7 +498,6 @@ impl CryptokiSession<'_> {
503498 pub fn signing_key ( self ) -> anyhow:: Result < Pkcs11Signer > {
504499 // get the signing key
505500 let key = self . find_key_by_attributes ( & self . uri_attributes , ObjectClass :: PRIVATE_KEY ) ?;
506-
507501 let key_type = self
508502 . session
509503 . get_attributes ( key, & [ AttributeType :: KeyType ] ) ?
@@ -515,10 +509,6 @@ impl CryptokiSession<'_> {
515509 anyhow:: bail!( "can't get key type" ) ;
516510 } ;
517511
518- let session = Pkcs11Session {
519- session : self . session ,
520- } ;
521-
522512 // we need to select a signature scheme to use with a key - each type of key can only have one signature scheme
523513 // ideally we'd simply get a cryptoki mechanism that corresponds to this sigscheme but it's not possible;
524514 // instead we have to manually parse additional attributes to select a proper sigscheme; currently don't do it
@@ -536,18 +526,18 @@ impl CryptokiSession<'_> {
536526
537527 let key = match keytype {
538528 KeyType :: EC => {
539- let sigscheme = get_ec_mechanism ( & session . session , key )
540- . unwrap_or ( SigScheme :: EcdsaNistp256Sha256 ) ;
529+ let sigscheme =
530+ get_ec_mechanism ( & self . session , key ) . unwrap_or ( SigScheme :: EcdsaNistp256Sha256 ) ;
541531
542532 Pkcs11Signer {
543- session : Arc :: new ( Mutex :: new ( session) ) ,
533+ session : Arc :: new ( Mutex :: new ( self . session ) ) ,
544534 key,
545535 sigscheme,
546536 secondary_schemes : Vec :: new ( ) ,
547537 }
548538 }
549539 KeyType :: RSA => Pkcs11Signer {
550- session : Arc :: new ( Mutex :: new ( session) ) ,
540+ session : Arc :: new ( Mutex :: new ( self . session ) ) ,
551541 key,
552542 sigscheme : SigScheme :: RsaPssSha256 ,
553543 secondary_schemes : vec ! [ SigScheme :: RsaPkcs1Sha256 ] ,
@@ -788,221 +778,6 @@ pub enum KeyTypeParams {
788778 Ec { curve : u16 } ,
789779}
790780
791- #[ derive( Debug ) ]
792- pub struct Pkcs11Session {
793- pub session : Session ,
794- }
795-
796- #[ derive( Debug , Clone ) ]
797- pub struct Pkcs11Signer {
798- session : Arc < Mutex < Pkcs11Session > > ,
799- key : ObjectHandle ,
800- pub sigscheme : SigScheme ,
801- pub secondary_schemes : Vec < SigScheme > ,
802- }
803-
804- impl Pkcs11Signer {
805- pub fn sign (
806- & self ,
807- message : & [ u8 ] ,
808- sigscheme : Option < SigScheme > ,
809- ) -> Result < Vec < u8 > , anyhow:: Error > {
810- let guard = self . session . lock ( ) . unwrap ( ) ;
811- let session = & guard. session ;
812-
813- let sigscheme = sigscheme. unwrap_or ( self . sigscheme ) ;
814- let mechanism = sigscheme. into ( ) ;
815- let ( mechanism, digest_mechanism) = match mechanism {
816- Mechanism :: EcdsaSha256 => ( Mechanism :: Ecdsa , Some ( Mechanism :: Sha256 ) ) ,
817- Mechanism :: EcdsaSha384 => ( Mechanism :: Ecdsa , Some ( Mechanism :: Sha384 ) ) ,
818- Mechanism :: EcdsaSha512 => ( Mechanism :: Ecdsa , Some ( Mechanism :: Sha512 ) ) ,
819- Mechanism :: Sha256RsaPkcs => ( Mechanism :: Sha256RsaPkcs , None ) ,
820- Mechanism :: Sha384RsaPkcs => ( Mechanism :: Sha384RsaPkcs , None ) ,
821- Mechanism :: Sha512RsaPkcs => ( Mechanism :: Sha512RsaPkcs , None ) ,
822- Mechanism :: Sha256RsaPkcsPss ( p) => ( Mechanism :: Sha256RsaPkcsPss ( p) , None ) ,
823- Mechanism :: Sha384RsaPkcsPss ( p) => ( Mechanism :: Sha384RsaPkcsPss ( p) , None ) ,
824- Mechanism :: Sha512RsaPkcsPss ( p) => ( Mechanism :: Sha512RsaPkcsPss ( p) , None ) ,
825- _ => {
826- warn ! ( ?mechanism, "Unsupported mechanism, trying it out anyway." ) ;
827- ( Mechanism :: Ecdsa , Some ( Mechanism :: Sha256 ) )
828- }
829- } ;
830-
831- let direct_sign = digest_mechanism. is_none ( ) ;
832-
833- trace ! ( input_message = %String :: from_utf8_lossy( message) , len=message. len( ) , ?mechanism, direct_sign) ;
834-
835- let digest;
836- let to_sign = if direct_sign {
837- message
838- } else {
839- digest = session
840- . digest ( & digest_mechanism. unwrap ( ) , message)
841- . context ( "pkcs11: Failed to digest message" ) ?;
842- & digest
843- } ;
844-
845- trace ! ( ?mechanism, "Session::sign" ) ;
846- let signature_raw = session
847- . sign ( & mechanism, self . key , to_sign)
848- . context ( "pkcs11: Failed to sign message" ) ?;
849-
850- // Split raw signature into r and s values (assuming 32 bytes each)
851- trace ! ( "Signature (raw) len={:?}" , signature_raw. len( ) ) ;
852- let signature_asn1 = match mechanism {
853- Mechanism :: Ecdsa => {
854- let size = signature_raw. len ( ) / 2 ;
855- let r_bytes = & signature_raw[ 0 ..size] ;
856- let s_bytes = & signature_raw[ size..] ;
857-
858- format_asn1_ecdsa_signature ( r_bytes, s_bytes)
859- . context ( "pkcs11: Failed to format signature" ) ?
860- }
861-
862- _ => signature_raw,
863- } ;
864- trace ! (
865- "Encoded ASN.1 Signature: len={:?} {:?}" ,
866- signature_asn1. len( ) ,
867- signature_asn1
868- ) ;
869- Ok ( signature_asn1)
870- }
871- }
872-
873- /// Currently supported signature schemes.
874- #[ derive( Debug , Clone , Copy , PartialEq , Eq , Serialize , Deserialize ) ]
875- pub enum SigScheme {
876- EcdsaNistp256Sha256 ,
877- EcdsaNistp384Sha384 ,
878- EcdsaNistp521Sha512 ,
879- RsaPssSha256 ,
880- RsaPkcs1Sha256 ,
881- }
882-
883- impl From < SigScheme > for rustls:: SignatureScheme {
884- fn from ( value : SigScheme ) -> Self {
885- match value {
886- SigScheme :: EcdsaNistp256Sha256 => Self :: ECDSA_NISTP256_SHA256 ,
887- SigScheme :: EcdsaNistp384Sha384 => Self :: ECDSA_NISTP384_SHA384 ,
888- SigScheme :: EcdsaNistp521Sha512 => Self :: ECDSA_NISTP521_SHA512 ,
889- SigScheme :: RsaPssSha256 => Self :: RSA_PSS_SHA256 ,
890- SigScheme :: RsaPkcs1Sha256 => Self :: RSA_PKCS1_SHA256 ,
891- }
892- }
893- }
894-
895- impl From < SigScheme > for crate :: service:: SignatureScheme {
896- fn from ( value : SigScheme ) -> Self {
897- Self ( rustls:: SignatureScheme :: from ( value) )
898- }
899- }
900-
901- impl From < SigScheme > for rustls:: SignatureAlgorithm {
902- fn from ( value : SigScheme ) -> Self {
903- match value {
904- SigScheme :: EcdsaNistp256Sha256
905- | SigScheme :: EcdsaNistp384Sha384
906- | SigScheme :: EcdsaNistp521Sha512 => Self :: ECDSA ,
907- SigScheme :: RsaPssSha256 | SigScheme :: RsaPkcs1Sha256 => Self :: RSA ,
908- }
909- }
910- }
911-
912- impl From < SigScheme > for Mechanism < ' _ > {
913- fn from ( value : SigScheme ) -> Self {
914- match value {
915- SigScheme :: EcdsaNistp256Sha256 => Self :: EcdsaSha256 ,
916- SigScheme :: EcdsaNistp384Sha384 => Self :: EcdsaSha384 ,
917- SigScheme :: EcdsaNistp521Sha512 => Self :: EcdsaSha512 ,
918- SigScheme :: RsaPkcs1Sha256 => Self :: Sha256RsaPkcs ,
919- SigScheme :: RsaPssSha256 => Mechanism :: Sha256RsaPkcsPss ( PkcsPssParams {
920- hash_alg : MechanismType :: SHA256 ,
921- mgf : PkcsMgfType :: MGF1_SHA256 ,
922- // RFC8446 4.2.3: RSASSA-PSS PSS algorithms: [...] The length of
923- // the Salt MUST be equal to the length of the digest algorithm
924- // SHA256: 256 bits = 32 bytes
925- s_len : 32 . into ( ) ,
926- } ) ,
927- }
928- }
929- }
930-
931- impl SigningKey for Pkcs11Signer {
932- fn choose_scheme ( & self , offered : & [ SignatureScheme ] ) -> Option < Box < dyn Signer > > {
933- debug ! ( "Offered signature schemes. offered={:?}" , offered) ;
934- let key_scheme = self . sigscheme . into ( ) ;
935- if offered. contains ( & key_scheme) {
936- debug ! ( "Matching scheme: {key_scheme:?}" ) ;
937- return Some ( Box :: new ( self . clone ( ) ) ) ;
938- }
939-
940- for scheme in & self . secondary_schemes {
941- let key_scheme = ( * scheme) . into ( ) ;
942- if offered. contains ( & key_scheme) {
943- debug ! ( "Matching scheme: {key_scheme:?}" ) ;
944- let mut signer = self . clone ( ) ;
945- signer. sigscheme = * scheme;
946- return Some ( Box :: new ( signer) ) ;
947- }
948- }
949-
950- None
951- }
952-
953- fn algorithm ( & self ) -> SignatureAlgorithm {
954- self . sigscheme . into ( )
955- }
956- }
957-
958- impl Signer for Pkcs11Signer {
959- fn sign ( & self , message : & [ u8 ] ) -> Result < Vec < u8 > , rustls:: Error > {
960- Self :: sign ( self , message, Some ( self . sigscheme ) )
961- . map_err ( |e| rustls:: Error :: General ( e. to_string ( ) ) )
962- }
963-
964- fn scheme ( & self ) -> SignatureScheme {
965- self . sigscheme . into ( )
966- }
967- }
968-
969- /// Formats the output of PKCS11 EC signature as an ASN.1 Ecdsa-Sig-Value.
970- ///
971- /// This function takes the raw `r` and `s` byte slices and encodes them as ASN.1 INTEGERs,
972- /// then wraps them in an ASN.1 SEQUENCE, and finally serializes the structure to DER.
973- ///
974- /// PKCS#11 EC signature operations typically return a raw concatenation of the `r` and `s` values,
975- /// each representing a big-endian positive integer of fixed length (depending on the curve).
976- /// However, most cryptographic protocols (including TLS and X.509) expect ECDSA signatures to be
977- /// encoded as an ASN.1 DER SEQUENCE of two INTEGERs, as described in RFC 3279 section 2.2.3.
978- ///
979- /// - https://docs.oasis-open.org/pkcs11/pkcs11-curr/v3.0/os/pkcs11-curr-v3.0-os.html#_Toc30061178
980- /// - https://www.ietf.org/rfc/rfc3279#section-2.2.3
981- fn format_asn1_ecdsa_signature ( r_bytes : & [ u8 ] , s_bytes : & [ u8 ] ) -> anyhow:: Result < Vec < u8 > > {
982- let r = format_asn1_integer ( r_bytes) . to_signed_bytes_be ( ) ;
983- let r = Integer :: new ( & r) ;
984- let s = format_asn1_integer ( s_bytes) . to_signed_bytes_be ( ) ;
985- let s = Integer :: new ( & s) ;
986-
987- let seq = SequenceOf :: < Integer > :: from_iter ( [ r, s] ) ;
988- let seq_der = seq
989- . to_der_vec ( )
990- . context ( "Unexpected ASN.1 error when serializing Ecdsa-Sig-Value" ) ?;
991- Ok ( seq_der)
992- }
993-
994- fn format_asn1_integer ( b : & [ u8 ] ) -> BigInt {
995- let mut i = asn1_rs:: BigInt :: from_signed_bytes_be ( b) ;
996- if i. sign ( ) == asn1_rs:: Sign :: Minus {
997- // Prepend a most significant zero byte if value < 0
998- let mut positive = b. to_vec ( ) ;
999- positive. insert ( 0 , 0 ) ;
1000-
1001- i = asn1_rs:: BigInt :: from_signed_bytes_be ( & positive) ;
1002- }
1003- i
1004- }
1005-
1006781fn get_ec_mechanism ( session : & Session , key : ObjectHandle ) -> anyhow:: Result < SigScheme > {
1007782 let key_params = & [ AttributeType :: EcParams ] ;
1008783 let attrs = session
@@ -1060,34 +835,3 @@ fn export_session_uri(token_info: &TokenInfo) -> String {
1060835
1061836 uri
1062837}
1063-
1064- #[ cfg( test) ]
1065- mod tests {
1066- use super :: * ;
1067- use asn1_rs:: Any ;
1068- use asn1_rs:: Integer ;
1069- use asn1_rs:: SequenceOf ;
1070-
1071- #[ test]
1072- fn test_format_asn1_ecdsa_signature_invalid_asn1 ( ) {
1073- // Use 32-byte r and s (as for P-256)
1074- let r = [ 0x01u8 ; 32 ] ;
1075- let s = [ 0xffu8 ; 32 ] ;
1076-
1077- let der = format_asn1_ecdsa_signature ( & r, & s) . expect ( "Should encode" ) ;
1078-
1079- // Try to parse as ASN.1 SEQUENCE of two INTEGERs
1080- let parsed = Any :: from_der ( & der) ;
1081- assert ! ( parsed. is_ok( ) , "Should parse as ASN.1" ) ;
1082-
1083- // Now check that the sequence contains exactly two INTEGERs
1084- let seq: SequenceOf < Integer > = SequenceOf :: from_der ( & der)
1085- . expect ( "Should parse as sequence" )
1086- . 1 ;
1087- assert_eq ! ( seq. len( ) , 2 , "ASN.1 sequence should have two items" ) ;
1088-
1089- // make sure input is not misinterpreted as negative numbers
1090- assert_eq ! ( seq[ 0 ] . as_bigint( ) . to_bytes_be( ) . 1 , r) ;
1091- assert_eq ! ( seq[ 1 ] . as_bigint( ) . to_bytes_be( ) . 1 , s) ;
1092- }
1093- }
0 commit comments