1
+ use der:: {
2
+ asn1:: { AnyRef , BitStringRef , UintRef } ,
3
+ oid:: ObjectIdentifier ,
4
+ Decode , Sequence ,
5
+ } ;
1
6
use std:: {
2
7
fs,
3
8
io:: { Cursor , Read } ,
@@ -7,7 +12,10 @@ use std::{
7
12
8
13
use async_trait:: async_trait;
9
14
use prost:: Message as ProstMessage ;
10
- use secp256k1:: { Message , PublicKey , Secp256k1 , SecretKey } ;
15
+ use secp256k1:: {
16
+ ecdsa:: { RecoverableSignature , RecoveryId } ,
17
+ Message , PublicKey , Secp256k1 , SecretKey ,
18
+ } ;
11
19
use sequoia_openpgp:: armor:: { Kind , Reader , ReaderMode } ;
12
20
use sha3:: { Digest , Keccak256 } ;
13
21
@@ -109,15 +117,53 @@ impl Signer for FileSigner {
109
117
pub struct KMSSigner {
110
118
client : aws_sdk_kms:: Client ,
111
119
arn : aws_arn:: ResourceName ,
120
+ public_key : Option < ( PublicKey , [ u8 ; 20 ] ) > ,
112
121
}
113
122
114
123
impl KMSSigner {
115
124
pub async fn try_new ( arn_string : String ) -> anyhow:: Result < Self > {
116
125
let config = aws_config:: load_from_env ( ) . await ;
117
126
let client = aws_sdk_kms:: Client :: new ( & config) ;
118
127
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
+ } )
120
133
}
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 > ,
121
167
}
122
168
123
169
#[ async_trait]
@@ -128,23 +174,50 @@ impl Signer for KMSSigner {
128
174
. sign ( )
129
175
. key_id ( self . arn . to_string ( ) )
130
176
. message ( data. to_vec ( ) . into ( ) )
177
+ . message_type ( aws_sdk_kms:: types:: MessageType :: Digest )
131
178
. signing_algorithm ( aws_sdk_kms:: types:: SigningAlgorithmSpec :: EcdsaSha256 )
132
179
. send ( )
133
180
. await
134
181
. map_err ( |e| anyhow:: anyhow!( "Failed to sign data with KMS: {}" , e) ) ?;
135
- result
182
+ let kms_signature = result
136
183
. 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
+ ) )
145
214
}
146
215
147
216
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
+
148
221
let result = self
149
222
. client
150
223
. get_public_key ( )
@@ -155,9 +228,15 @@ impl Signer for KMSSigner {
155
228
let public_key = result
156
229
. public_key
157
230
. 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) ) ?;
160
238
let pubkey_evm = get_evm_public_key ( & public_key) ?;
239
+
161
240
Ok ( ( public_key, pubkey_evm) )
162
241
}
163
242
}
0 commit comments