@@ -9,13 +9,9 @@ use std::borrow::Cow;
99use anyhow:: { Context , bail} ;
1010use camino:: Utf8PathBuf ;
1111use futures_util:: future:: { try_join, try_join_all} ;
12- use mas_jose:: jwk:: { JsonWebKey , JsonWebKeySet } ;
12+ use mas_jose:: jwk:: { JsonWebKey , JsonWebKeySet , Thumbprint } ;
1313use mas_keystore:: { Encrypter , Keystore , PrivateKey } ;
14- use rand:: {
15- Rng , SeedableRng ,
16- distributions:: { Alphanumeric , DistString , Standard } ,
17- prelude:: Distribution as _,
18- } ;
14+ use rand:: { Rng , SeedableRng , distributions:: Standard , prelude:: Distribution as _} ;
1915use schemars:: JsonSchema ;
2016use serde:: { Deserialize , Serialize } ;
2117use serde_with:: serde_as;
@@ -132,7 +128,11 @@ impl From<Key> for KeyRaw {
132128#[ serde_as]
133129#[ derive( JsonSchema , Serialize , Deserialize , Clone , Debug ) ]
134130pub struct KeyConfig {
135- kid : String ,
131+ /// The key ID `kid` of the key as used by JWKs.
132+ ///
133+ /// If not given, `kid` will be the key’s RFC 7638 JWK Thumbprint.
134+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
135+ kid : Option < String > ,
136136
137137 #[ schemars( with = "PasswordRaw" ) ]
138138 #[ serde_as( as = "serde_with::TryFromInto<PasswordRaw>" ) ]
@@ -178,8 +178,13 @@ impl KeyConfig {
178178 None => PrivateKey :: load ( & key) ?,
179179 } ;
180180
181+ let kid = match self . kid . clone ( ) {
182+ Some ( kid) => kid,
183+ None => private_key. thumbprint_sha256_base64 ( ) ,
184+ } ;
185+
181186 Ok ( JsonWebKey :: new ( private_key)
182- . with_kid ( self . kid . clone ( ) )
187+ . with_kid ( kid)
183188 . with_use ( mas_iana:: jose:: JsonWebKeyUse :: Sig ) )
184189 }
185190}
@@ -322,7 +327,7 @@ impl SecretsConfig {
322327 . await
323328 . context ( "could not join blocking task" ) ?;
324329 let rsa_key = KeyConfig {
325- kid : Alphanumeric . sample_string ( & mut rng , 10 ) ,
330+ kid : None ,
326331 password : None ,
327332 key : Key :: Value ( rsa_key. to_pem ( pem_rfc7468:: LineEnding :: LF ) ?. to_string ( ) ) ,
328333 } ;
@@ -338,7 +343,7 @@ impl SecretsConfig {
338343 . await
339344 . context ( "could not join blocking task" ) ?;
340345 let ec_p256_key = KeyConfig {
341- kid : Alphanumeric . sample_string ( & mut rng , 10 ) ,
346+ kid : None ,
342347 password : None ,
343348 key : Key :: Value ( ec_p256_key. to_pem ( pem_rfc7468:: LineEnding :: LF ) ?. to_string ( ) ) ,
344349 } ;
@@ -354,7 +359,7 @@ impl SecretsConfig {
354359 . await
355360 . context ( "could not join blocking task" ) ?;
356361 let ec_p384_key = KeyConfig {
357- kid : Alphanumeric . sample_string ( & mut rng , 10 ) ,
362+ kid : None ,
358363 password : None ,
359364 key : Key :: Value ( ec_p384_key. to_pem ( pem_rfc7468:: LineEnding :: LF ) ?. to_string ( ) ) ,
360365 } ;
@@ -370,7 +375,7 @@ impl SecretsConfig {
370375 . await
371376 . context ( "could not join blocking task" ) ?;
372377 let ec_k256_key = KeyConfig {
373- kid : Alphanumeric . sample_string ( & mut rng , 10 ) ,
378+ kid : None ,
374379 password : None ,
375380 key : Key :: Value ( ec_k256_key. to_pem ( pem_rfc7468:: LineEnding :: LF ) ?. to_string ( ) ) ,
376381 } ;
@@ -383,7 +388,7 @@ impl SecretsConfig {
383388
384389 pub ( crate ) fn test ( ) -> Self {
385390 let rsa_key = KeyConfig {
386- kid : "abcdef" . to_owned ( ) ,
391+ kid : None ,
387392 password : None ,
388393 key : Key :: Value (
389394 indoc:: indoc! { r"
@@ -402,7 +407,7 @@ impl SecretsConfig {
402407 ) ,
403408 } ;
404409 let ecdsa_key = KeyConfig {
405- kid : "ghijkl" . to_owned ( ) ,
410+ kid : None ,
406411 password : None ,
407412 key : Key :: Value (
408413 indoc:: indoc! { r"
@@ -422,3 +427,68 @@ impl SecretsConfig {
422427 }
423428 }
424429}
430+
431+ #[ cfg( test) ]
432+ mod tests {
433+ use figment:: {
434+ Figment , Jail ,
435+ providers:: { Format , Yaml } ,
436+ } ;
437+ use mas_jose:: constraints:: Constrainable ;
438+ use tokio:: { runtime:: Handle , task} ;
439+
440+ use super :: * ;
441+
442+ #[ tokio:: test]
443+ async fn load_config_inline_secrets ( ) {
444+ task:: spawn_blocking ( || {
445+ Jail :: expect_with ( |jail| {
446+ jail. create_file (
447+ "config.yaml" ,
448+ indoc:: indoc! { r"
449+ secrets:
450+ encryption: >-
451+ 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff
452+ keys:
453+ - kid: lekid0
454+ key: |
455+ -----BEGIN EC PRIVATE KEY-----
456+ MHcCAQEEIOtZfDuXZr/NC0V3sisR4Chf7RZg6a2dpZesoXMlsPeRoAoGCCqGSM49
457+ AwEHoUQDQgAECfpqx64lrR85MOhdMxNmIgmz8IfmM5VY9ICX9aoaArnD9FjgkBIl
458+ fGmQWxxXDSWH6SQln9tROVZaduenJqDtDw==
459+ -----END EC PRIVATE KEY-----
460+ - key: |
461+ -----BEGIN EC PRIVATE KEY-----
462+ MHcCAQEEIKlZz/GnH0idVH1PnAF4HQNwRafgBaE2tmyN1wjfdOQqoAoGCCqGSM49
463+ AwEHoUQDQgAEHrgPeG+Mt8eahih1h4qaPjhl7jT25cdzBkg3dbVks6gBR2Rx4ug9
464+ h27LAir5RqxByHvua2XsP46rSTChof78uw==
465+ -----END EC PRIVATE KEY-----
466+ " } ,
467+ ) ?;
468+
469+ let config = Figment :: new ( )
470+ . merge ( Yaml :: file ( "config.yaml" ) )
471+ . extract_inner :: < SecretsConfig > ( "secrets" ) ?;
472+
473+ Handle :: current ( ) . block_on ( async move {
474+ assert_eq ! (
475+ config. encryption( ) . await . unwrap( ) ,
476+ [
477+ 0 , 0 , 17 , 17 , 34 , 34 , 51 , 51 , 68 , 68 , 85 , 85 , 102 , 102 , 119 , 119 , 136 ,
478+ 136 , 153 , 153 , 170 , 170 , 187 , 187 , 204 , 204 , 221 , 221 , 238 , 238 , 255 ,
479+ 255
480+ ]
481+ ) ;
482+
483+ let key_store = config. key_store ( ) . await . unwrap ( ) ;
484+ assert ! ( key_store. iter( ) . any( |k| k. kid( ) == Some ( "lekid0" ) ) ) ;
485+ assert ! ( key_store. iter( ) . any( |k| k. kid( ) == Some ( "ONUCn80fsiISFWKrVMEiirNVr-QEvi7uQI0QH9q9q4o" ) ) ) ;
486+ } ) ;
487+
488+ Ok ( ( ) )
489+ } ) ;
490+ } )
491+ . await
492+ . unwrap ( ) ;
493+ }
494+ }
0 commit comments