@@ -122,7 +122,7 @@ struct KmsDigest {
122122 sha256 : String ,
123123}
124124
125- #[ derive( Serialize , Debug ) ]
125+ #[ derive( Serialize , Debug , Default ) ]
126126struct KmsSignRequest {
127127 #[ serde( skip_serializing_if = "Option::is_none" ) ]
128128 digest : Option < KmsDigest > ,
@@ -131,7 +131,8 @@ struct KmsSignRequest {
131131}
132132
133133impl SpxKms {
134- const ALGORITHM : & ' static str = "PQ_SIGN_SLH_DSA_SHA2_128S" ;
134+ const PURE_ALGORITHM : & ' static str = "PQ_SIGN_SLH_DSA_SHA2_128S" ;
135+ const PREHASH_ALGORITHM : & ' static str = "PQ_SIGN_HASH_SLH_DSA_SHA2_128S_SHA256" ;
135136
136137 pub fn new ( parameters : & str ) -> Result < Box < Self > > {
137138 let output = Command :: new ( "gcloud" )
@@ -173,6 +174,21 @@ impl SpxKms {
173174 }
174175 }
175176
177+ fn kms_to_algorithm ( kms_algo : & str ) -> Result < String > {
178+ match kms_algo {
179+ Self :: PURE_ALGORITHM | Self :: PREHASH_ALGORITHM => Ok ( "SLH-DSA-SHA2-128S" . into ( ) ) ,
180+ _ => Err ( HsmError :: Unsupported ( format ! ( "algorithm {kms_algo}" ) ) . into ( ) ) ,
181+ }
182+ }
183+
184+ fn kms_to_domain ( kms_algo : & str ) -> Result < SpxDomain > {
185+ match kms_algo {
186+ Self :: PURE_ALGORITHM => Ok ( SpxDomain :: Pure ) ,
187+ Self :: PREHASH_ALGORITHM => Ok ( SpxDomain :: PreHashedSha256 ) ,
188+ _ => Err ( HsmError :: Unsupported ( format ! ( "algorithm {kms_algo}" ) ) . into ( ) ) ,
189+ }
190+ }
191+
176192 fn get < RSP : DeserializeOwned > ( & self , url : impl IntoUrl ) -> Result < RSP > {
177193 let client = Client :: new ( ) ;
178194 log:: debug!( "GET {}" , url. as_str( ) ) ;
@@ -216,7 +232,7 @@ impl SpxKms {
216232 match versions
217233 . crypto_key_versions
218234 . iter ( )
219- . filter ( |v| v. state == "ENABLED" && v . algorithm == Self :: ALGORITHM )
235+ . filter ( |v| v. state == "ENABLED" && Self :: kms_to_algorithm ( & v . algorithm ) . is_ok ( ) )
220236 . next_back ( )
221237 {
222238 Some ( key) => Ok ( key. clone ( ) ) ,
@@ -250,14 +266,15 @@ impl SpxInterface for SpxKms {
250266 . rsplit_once ( '/' )
251267 . ok_or_else ( || HsmError :: ParseError ( "could not parse key name" . into ( ) ) )
252268 . with_context ( || format ! ( "key name {:?}" , k. name) ) ?;
253- if k. version_template . algorithm != Self :: ALGORITHM {
269+ if Self :: kms_to_algorithm ( & k. version_template . algorithm ) . is_err ( ) {
254270 continue ;
255271 }
256272 let key = self . get_key_version ( name) ?;
257273 result. push ( KeyEntry {
258274 alias : name. into ( ) ,
259275 hash : None ,
260- algorithm : key. algorithm . clone ( ) ,
276+ algorithm : Self :: kms_to_algorithm ( & key. algorithm ) ?,
277+ domain : Some ( Self :: kms_to_domain ( & key. algorithm ) ?) ,
261278 ..Default :: default ( )
262279 } ) ;
263280 }
@@ -267,10 +284,6 @@ impl SpxInterface for SpxKms {
267284 /// Get the public key info.
268285 fn get_key_info ( & self , alias : & str ) -> Result < KeyInfo > {
269286 let key = self . get_public_key ( alias) ?;
270- let algorithm = key
271- . algorithm
272- . trim_start_matches ( "PQ_SIGN_" )
273- . replace ( '_' , "-" ) ;
274287 let data = if let Some ( pem) = & key. pem {
275288 pem. as_str ( )
276289 } else if let Some ( public_key) = & key. public_key {
@@ -280,8 +293,8 @@ impl SpxInterface for SpxKms {
280293 } ;
281294 Ok ( KeyInfo {
282295 hash : "" . into ( ) ,
283- algorithm,
284- domain : Some ( SpxDomain :: Pure ) ,
296+ algorithm : Self :: kms_to_algorithm ( & key . algorithm ) ? ,
297+ domain : Some ( Self :: kms_to_domain ( & key . algorithm ) ? ) ,
285298 public_key : Base64 :: decode_vec ( data) ?,
286299 private_blob : Vec :: new ( ) ,
287300 } )
@@ -292,31 +305,33 @@ impl SpxInterface for SpxKms {
292305 & self ,
293306 alias : & str ,
294307 _algorithm : & str ,
295- _domain : SpxDomain ,
308+ domain : SpxDomain ,
296309 _token : & str ,
297310 flags : GenerateFlags ,
298311 ) -> Result < KeyEntry > {
299312 if flags. contains ( GenerateFlags :: EXPORT_PRIVATE ) {
300313 return Err ( HsmError :: Unsupported ( "export of private key material" . into ( ) ) . into ( ) ) ;
301314 }
315+ let algorithm = match domain {
316+ SpxDomain :: Pure => Self :: PURE_ALGORITHM ,
317+ SpxDomain :: PreHashedSha256 => Self :: PREHASH_ALGORITHM ,
318+ _ => return Err ( HsmError :: Unsupported ( format ! ( "domain {domain}" ) ) . into ( ) ) ,
319+ } ;
302320 let url = self
303321 . keyring
304322 . join ( & format ! ( "cryptoKeys?crypto_key_id={alias}" ) ) ?;
305323 let template = KmsCreateKey {
306324 purpose : "ASYMMETRIC_SIGN" . into ( ) ,
307325 version_template : VersionTemplate {
308- algorithm : Self :: ALGORITHM . into ( ) ,
326+ algorithm : algorithm . into ( ) ,
309327 protection_level : "SOFTWARE" . into ( ) ,
310328 } ,
311329 } ;
312330 let resp = self . post :: < KmsKeyRef > ( url, & template) ?;
313331 Ok ( KeyEntry {
314332 alias : alias. into ( ) ,
315- algorithm : resp
316- . version_template
317- . algorithm
318- . trim_start_matches ( "PQ_SIGN_" )
319- . replace ( '_' , "-" ) ,
333+ algorithm : Self :: kms_to_algorithm ( & resp. version_template . algorithm ) ?,
334+ domain : Some ( Self :: kms_to_domain ( & resp. version_template . algorithm ) ?) ,
320335 ..Default :: default ( )
321336 } )
322337 }
@@ -347,28 +362,40 @@ impl SpxInterface for SpxKms {
347362 domain : SpxDomain ,
348363 message : & [ u8 ] ,
349364 ) -> Result < Vec < u8 > > {
350- match domain {
351- SpxDomain :: Pure => { }
352- _ => {
353- return Err ( HsmError :: Unsupported ( format ! (
354- "domain {domain} not supported by {}" ,
355- self . get_version( ) ?
356- ) )
357- . into ( ) ) ;
358- }
359- } ;
360365 let alias = alias. ok_or ( HsmError :: NoSearchCriteria ) ?;
361366 if key_hash. is_some ( ) {
362367 log:: warn!( "ignored key_hash {key_hash:?}" ) ;
363368 }
364369 let key = self . get_key_version ( alias) ?;
370+ let keydomain = Self :: kms_to_domain ( & key. algorithm ) ?;
371+ if domain != keydomain {
372+ return Err ( HsmError :: Unsupported ( format ! (
373+ "domain {domain} not supported by key {alias}" ,
374+ ) )
375+ . into ( ) ) ;
376+ }
377+
365378 let url = self
366379 . keyring
367380 . join ( & format ! ( "/v1/{}:asymmetricSign" , key. name) ) ?;
368- let req = KmsSignRequest {
369- digest : None ,
370- data : Some ( Base64 :: encode_string ( message) ) ,
381+
382+ // Format the signing request:
383+ // - For the "pure" domain, we place the message in the `data` field.
384+ // - For the "prehashed" domain, we place the digest into the `digest` field.
385+ let req = match keydomain {
386+ SpxDomain :: Pure => KmsSignRequest {
387+ data : Some ( Base64 :: encode_string ( message) ) ,
388+ ..Default :: default ( )
389+ } ,
390+ SpxDomain :: PreHashedSha256 => KmsSignRequest {
391+ digest : Some ( KmsDigest {
392+ sha256 : Base64 :: encode_string ( message) ,
393+ } ) ,
394+ ..Default :: default ( )
395+ } ,
396+ _ => unreachable ! ( ) ,
371397 } ;
398+
372399 let resp = self . post :: < IndexMap < String , String > > ( url, & req) ?;
373400 let signature = Base64 :: decode_vec ( & resp[ "signature" ] ) ?;
374401 Ok ( signature)
@@ -388,6 +415,13 @@ impl SpxInterface for SpxKms {
388415 log:: warn!( "ignored key_hash {key_hash:?}" ) ;
389416 }
390417 let info = self . get_key_info ( alias) ?;
418+ let keydomain = info. domain . expect ( "kms key domain" ) ;
419+ if domain != keydomain {
420+ return Err ( HsmError :: Unsupported ( format ! (
421+ "domain {domain} not supported by key {alias}" ,
422+ ) )
423+ . into ( ) ) ;
424+ }
391425 let pk =
392426 SpxPublicKey :: from_bytes ( SphincsPlus :: from_str ( & info. algorithm ) ?, & info. public_key ) ?;
393427 match pk. verify ( domain, signature, message) {
0 commit comments