1+ use der:: {
2+ asn1:: { AnyRef , BitStringRef , UintRef } ,
3+ oid:: ObjectIdentifier ,
4+ Decode , Sequence ,
5+ } ;
16use std:: {
27 fs,
38 io:: { Cursor , Read } ,
@@ -7,7 +12,10 @@ use std::{
712
813use async_trait:: async_trait;
914use prost:: Message as ProstMessage ;
10- use secp256k1:: { Message , PublicKey , Secp256k1 , SecretKey } ;
15+ use secp256k1:: {
16+ ecdsa:: { RecoverableSignature , RecoveryId } ,
17+ Message , PublicKey , Secp256k1 , SecretKey ,
18+ } ;
1119use sequoia_openpgp:: armor:: { Kind , Reader , ReaderMode } ;
1220use sha3:: { Digest , Keccak256 } ;
1321
@@ -109,15 +117,53 @@ impl Signer for FileSigner {
109117pub struct KMSSigner {
110118 client : aws_sdk_kms:: Client ,
111119 arn : aws_arn:: ResourceName ,
120+ public_key : Option < ( PublicKey , [ u8 ; 20 ] ) > ,
112121}
113122
114123impl KMSSigner {
115124 pub async fn try_new ( arn_string : String ) -> anyhow:: Result < Self > {
116125 let config = aws_config:: load_from_env ( ) . await ;
117126 let client = aws_sdk_kms:: Client :: new ( & config) ;
118127 let arn = aws_arn:: ResourceName :: from_str ( & arn_string) ?;
119- Ok ( KMSSigner { client, arn } )
128+ Ok ( KMSSigner {
129+ client,
130+ arn,
131+ public_key : None ,
132+ } )
120133 }
134+
135+ pub async fn get_and_cache_public_key ( & mut self ) -> anyhow:: Result < ( ) > {
136+ let ( public_key, pubkey_evm) = self . get_public_key ( ) . await ?;
137+ self . public_key = Some ( ( public_key, pubkey_evm) ) ;
138+ Ok ( ( ) )
139+ }
140+ }
141+
142+ /// X.509 `AlgorithmIdentifier` (same as above)
143+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , Sequence ) ] // NOTE: added `Sequence`
144+ pub struct AlgorithmIdentifier < ' a > {
145+ /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID.
146+ pub algorithm : ObjectIdentifier ,
147+
148+ /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which
149+ /// in this example allows arbitrary algorithm-defined parameters.
150+ pub parameters : Option < AnyRef < ' a > > ,
151+ }
152+
153+ /// X.509 `SubjectPublicKeyInfo` (SPKI)
154+ #[ derive( Copy , Clone , Debug , Eq , PartialEq , Sequence ) ]
155+ pub struct SubjectPublicKeyInfo < ' a > {
156+ /// X.509 `AlgorithmIdentifier`
157+ pub algorithm : AlgorithmIdentifier < ' a > ,
158+
159+ /// Public key data
160+ pub subject_public_key : BitStringRef < ' a > ,
161+ }
162+
163+ #[ derive( Sequence ) ]
164+ struct EcdsaSignature < ' a > {
165+ r : UintRef < ' a > ,
166+ s : UintRef < ' a > ,
121167}
122168
123169#[ async_trait]
@@ -128,23 +174,50 @@ impl Signer for KMSSigner {
128174 . sign ( )
129175 . key_id ( self . arn . to_string ( ) )
130176 . message ( data. to_vec ( ) . into ( ) )
177+ . message_type ( aws_sdk_kms:: types:: MessageType :: Digest )
131178 . signing_algorithm ( aws_sdk_kms:: types:: SigningAlgorithmSpec :: EcdsaSha256 )
132179 . send ( )
133180 . await
134181 . map_err ( |e| anyhow:: anyhow!( "Failed to sign data with KMS: {}" , e) ) ?;
135- result
182+ let kms_signature = result
136183 . signature
137- . ok_or_else ( || anyhow:: anyhow!( "KMS did not return a signature" ) )
138- . and_then ( |sig| {
139- let sig = sig. into_inner ( ) ;
140- let signature: [ u8 ; 65 ] = sig
141- . try_into ( )
142- . map_err ( |e| anyhow:: anyhow!( "Failed to convert KMS signature: {:?}" , e) ) ?;
143- Ok ( signature)
144- } )
184+ . ok_or_else ( || anyhow:: anyhow!( "KMS did not return a signature" ) ) ?;
185+
186+ let decoded_signature = EcdsaSignature :: from_der ( kms_signature. as_ref ( ) )
187+ . map_err ( |e| anyhow:: anyhow!( "Failed to decode SubjectPublicKeyInfo: {}" , e) ) ?;
188+
189+ let r_bytes = decoded_signature. r . as_bytes ( ) ;
190+ let s_bytes = decoded_signature. s . as_bytes ( ) ;
191+ let mut signature = [ 0u8 ; 65 ] ;
192+ signature[ ( 32 - r_bytes. len ( ) ) ..32 ] . copy_from_slice ( r_bytes) ;
193+ signature[ ( 64 - s_bytes. len ( ) ) ..64 ] . copy_from_slice ( decoded_signature. s . as_bytes ( ) ) ;
194+
195+ let public_key = self . get_public_key ( ) . await ?;
196+ for raw_id in 0 ..4 {
197+ let secp = Secp256k1 :: new ( ) ;
198+ let recid = RecoveryId :: try_from ( raw_id)
199+ . map_err ( |e| anyhow:: anyhow!( "Failed to create RecoveryId: {}" , e) ) ?;
200+ if let Ok ( recovered_public_key) = secp. recover_ecdsa (
201+ & Message :: from_digest ( data) ,
202+ & RecoverableSignature :: from_compact ( & signature[ ..64 ] , recid)
203+ . map_err ( |e| anyhow:: anyhow!( "Failed to create RecoverableSignature: {}" , e) ) ?,
204+ ) {
205+ if recovered_public_key == public_key. 0 {
206+ signature[ 64 ] = raw_id as u8 ;
207+ return Ok ( signature) ;
208+ }
209+ }
210+ }
211+ Err ( anyhow:: anyhow!(
212+ "Failed to recover public key from signature"
213+ ) )
145214 }
146215
147216 async fn get_public_key ( & self ) -> anyhow:: Result < ( PublicKey , [ u8 ; 20 ] ) > {
217+ if let Some ( ( public_key, pubkey_evm) ) = & self . public_key {
218+ return Ok ( ( * public_key, * pubkey_evm) ) ;
219+ }
220+
148221 let result = self
149222 . client
150223 . get_public_key ( )
@@ -155,9 +228,15 @@ impl Signer for KMSSigner {
155228 let public_key = result
156229 . public_key
157230 . ok_or ( anyhow:: anyhow!( "KMS did not return a public key" ) ) ?;
158- let public_key = PublicKey :: from_slice ( public_key. as_ref ( ) )
159- . map_err ( |e| anyhow:: anyhow!( "Failed to create PublicKey from KMS: {}" , e) ) ?;
231+ let decoded_algorithm_identifier = SubjectPublicKeyInfo :: from_der ( public_key. as_ref ( ) )
232+ . map_err ( |e| {
233+ anyhow:: anyhow!( "Failed to decode SubjectPublicKeyInfo from KMS: {}" , e)
234+ } ) ?;
235+ let public_key =
236+ PublicKey :: from_slice ( decoded_algorithm_identifier. subject_public_key . raw_bytes ( ) )
237+ . map_err ( |e| anyhow:: anyhow!( "Failed to create PublicKey from KMS: {}" , e) ) ?;
160238 let pubkey_evm = get_evm_public_key ( & public_key) ?;
239+
161240 Ok ( ( public_key, pubkey_evm) )
162241 }
163242}
0 commit comments