@@ -255,6 +255,7 @@ impl Session {
255255 key : key. clone ( ) ,
256256 hash_alg,
257257 } ,
258+ None ,
258259 & mut self . common . buffer ,
259260 ) ?;
260261 let len = self . common . buffer . len ( ) ;
@@ -284,6 +285,7 @@ impl Session {
284285 let i = enc. client_make_to_sign (
285286 & self . common . auth_user ,
286287 & PublicKeyOrCertificate :: Certificate ( cert. clone ( ) ) ,
288+ hash_alg,
287289 & mut self . common . buffer ,
288290 ) ?;
289291 let len = self . common . buffer . len ( ) ;
@@ -1216,6 +1218,100 @@ mod tests {
12161218 assert_eq ! ( Vec :: <u8 >:: decode( & mut mic) . unwrap( ) , b"mic" . to_vec( ) ) ;
12171219 ensure_end ( & mic) . unwrap ( ) ;
12181220 }
1221+
1222+
1223+ fn rsa_user_certificate ( ) -> ssh_key:: Certificate {
1224+ let subject = ssh_key:: PrivateKey :: random (
1225+ & mut rand:: rng ( ) ,
1226+ ssh_key:: Algorithm :: Rsa { hash : None } ,
1227+ )
1228+ . unwrap ( ) ;
1229+ let ca = ssh_key:: PrivateKey :: random ( & mut rand:: rng ( ) , ssh_key:: Algorithm :: Ed25519 )
1230+ . unwrap ( ) ;
1231+ let mut builder = ssh_key:: certificate:: Builder :: new_with_random_nonce (
1232+ & mut rand:: rng ( ) ,
1233+ subject. public_key ( ) ,
1234+ 0 ,
1235+ u64:: MAX ,
1236+ )
1237+ . unwrap ( ) ;
1238+ builder. key_id ( "rsa-user-cert" ) . unwrap ( ) ;
1239+ builder
1240+ . cert_type ( ssh_key:: certificate:: CertType :: User )
1241+ . unwrap ( ) ;
1242+ builder. valid_principal ( "alice" ) . unwrap ( ) ;
1243+ builder. sign ( & ca) . unwrap ( )
1244+ }
1245+
1246+ fn decode_userauth_certificate_algorithm (
1247+ mut request : & [ u8 ] ,
1248+ expected_has_signature : bool ,
1249+ ) -> String {
1250+ assert_eq ! ( u8 :: decode( & mut request) . unwrap( ) , msg:: USERAUTH_REQUEST ) ;
1251+ assert_eq ! ( String :: decode( & mut request) . unwrap( ) , "alice" ) ;
1252+ assert_eq ! ( String :: decode( & mut request) . unwrap( ) , "ssh-connection" ) ;
1253+ assert_eq ! ( String :: decode( & mut request) . unwrap( ) , "publickey" ) ;
1254+ assert_eq ! (
1255+ u8 :: decode( & mut request) . unwrap( ) ,
1256+ u8 :: from( expected_has_signature)
1257+ ) ;
1258+ let algorithm = String :: decode ( & mut request) . unwrap ( ) ;
1259+ let _certificate = Vec :: < u8 > :: decode ( & mut request) . unwrap ( ) ;
1260+ ensure_end ( & request) . unwrap ( ) ;
1261+ algorithm
1262+ }
1263+
1264+ #[ test]
1265+ fn rsa_future_certificate_hash_is_encoded_in_probe_and_signed_requests ( ) {
1266+ let certificate = rsa_user_certificate ( ) ;
1267+ for ( hash_alg, expected) in [
1268+ (
1269+ Some ( ssh_key:: HashAlg :: Sha512 ) ,
1270+ "rsa-sha2-512-cert-v01@openssh.com" ,
1271+ ) ,
1272+ (
1273+ Some ( ssh_key:: HashAlg :: Sha256 ) ,
1274+ "rsa-sha2-256-cert-v01@openssh.com" ,
1275+ ) ,
1276+ ( None , "ssh-rsa-cert-v01@openssh.com" ) ,
1277+ ] {
1278+ let mut encrypted = test_encrypted ( ) ;
1279+ encrypted
1280+ . write_auth_request (
1281+ "alice" ,
1282+ & auth:: Method :: FutureCertificate {
1283+ cert : certificate. clone ( ) ,
1284+ hash_alg,
1285+ } ,
1286+ )
1287+ . unwrap ( ) ;
1288+ let probe_payloads = payloads ( & encrypted. write ) ;
1289+ assert_eq ! ( probe_payloads. len( ) , 1 ) ;
1290+ assert_eq ! (
1291+ decode_userauth_certificate_algorithm( probe_payloads[ 0 ] , false ) ,
1292+ expected
1293+ ) ;
1294+
1295+ let mut signed = Vec :: new ( ) ;
1296+ encrypted
1297+ . client_make_to_sign (
1298+ "alice" ,
1299+ & PublicKeyOrCertificate :: Certificate ( certificate. clone ( ) ) ,
1300+ hash_alg,
1301+ & mut signed,
1302+ )
1303+ . unwrap ( ) ;
1304+ let mut signed_request = signed. as_slice ( ) ;
1305+ assert_eq ! (
1306+ Vec :: <u8 >:: decode( & mut signed_request) . unwrap( ) ,
1307+ b"session-id"
1308+ ) ;
1309+ assert_eq ! (
1310+ decode_userauth_certificate_algorithm( signed_request, true ) ,
1311+ expected
1312+ ) ;
1313+ }
1314+ }
12191315}
12201316
12211317impl Encrypted {
@@ -1281,13 +1377,14 @@ impl Encrypted {
12811377 key. to_bytes( ) ?. as_slice( ) . encode( & mut self . write) ?;
12821378 true
12831379 }
1284- auth:: Method :: FutureCertificate { ref cert, .. } => {
1380+ auth:: Method :: FutureCertificate { ref cert, hash_alg } => {
12851381 user. as_bytes( ) . encode( & mut self . write) ?;
12861382 "ssh-connection" . encode( & mut self . write) ?;
12871383 "publickey" . encode( & mut self . write) ?;
12881384 self . write. push( 0 ) ; // This is a probe
12891385
12901386 cert. algorithm( )
1387+ . with_hash_alg( hash_alg)
12911388 . to_certificate_type( )
12921389 . encode( & mut self . write) ?;
12931390 cert. to_bytes( ) ?. as_slice( ) . encode( & mut self . write) ?;
@@ -1370,6 +1467,7 @@ impl Encrypted {
13701467 & mut self ,
13711468 user : & str ,
13721469 key : & PublicKeyOrCertificate ,
1470+ certificate_hash_alg : Option < ssh_key:: HashAlg > ,
13731471 buffer : & mut Vec < u8 > ,
13741472 ) -> Result < usize , crate :: Error > {
13751473 buffer. clear ( ) ;
@@ -1384,7 +1482,10 @@ impl Encrypted {
13841482
13851483 match key {
13861484 PublicKeyOrCertificate :: Certificate ( cert) => {
1387- cert. algorithm ( ) . to_certificate_type ( ) . encode ( buffer) ?;
1485+ cert. algorithm ( )
1486+ . with_hash_alg ( certificate_hash_alg)
1487+ . to_certificate_type ( )
1488+ . encode ( buffer) ?;
13881489 cert. to_bytes ( ) ?. encode ( buffer) ?;
13891490 }
13901491 PublicKeyOrCertificate :: PublicKey { key, hash_alg } => {
@@ -1404,7 +1505,7 @@ impl Encrypted {
14041505 match method {
14051506 auth:: Method :: PublicKey { key } => {
14061507 let i0 =
1407- self . client_make_to_sign ( user, & PublicKeyOrCertificate :: from ( key) , buffer) ?;
1508+ self . client_make_to_sign ( user, & PublicKeyOrCertificate :: from ( key) , None , buffer) ?;
14081509
14091510 // Extend with self-signature.
14101511 sign_with_hash_alg ( key, buffer) ?. encode ( & mut * buffer) ?;
@@ -1418,6 +1519,7 @@ impl Encrypted {
14181519 let i0 = self . client_make_to_sign (
14191520 user,
14201521 & PublicKeyOrCertificate :: Certificate ( cert. clone ( ) ) ,
1522+ None ,
14211523 buffer,
14221524 ) ?;
14231525
0 commit comments