Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 105 additions & 3 deletions russh/src/client/encrypted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ impl Session {
key: key.clone(),
hash_alg,
},
None,
&mut self.common.buffer,
)?;
let len = self.common.buffer.len();
Expand Down Expand Up @@ -284,6 +285,7 @@ impl Session {
let i = enc.client_make_to_sign(
&self.common.auth_user,
&PublicKeyOrCertificate::Certificate(cert.clone()),
hash_alg,
&mut self.common.buffer,
)?;
let len = self.common.buffer.len();
Expand Down Expand Up @@ -1211,6 +1213,100 @@ mod tests {
assert_eq!(Vec::<u8>::decode(&mut mic).unwrap(), b"mic".to_vec());
ensure_end(&mic).unwrap();
}


fn rsa_user_certificate() -> ssh_key::Certificate {
let subject = ssh_key::PrivateKey::random(
&mut rand::rng(),
ssh_key::Algorithm::Rsa { hash: None },
)
.unwrap();
let ca = ssh_key::PrivateKey::random(&mut rand::rng(), ssh_key::Algorithm::Ed25519)
.unwrap();
let mut builder = ssh_key::certificate::Builder::new_with_random_nonce(
&mut rand::rng(),
subject.public_key(),
0,
u64::MAX,
)
.unwrap();
builder.key_id("rsa-user-cert").unwrap();
builder
.cert_type(ssh_key::certificate::CertType::User)
.unwrap();
builder.valid_principal("alice").unwrap();
builder.sign(&ca).unwrap()
}

fn decode_userauth_certificate_algorithm(
mut request: &[u8],
expected_has_signature: bool,
) -> String {
assert_eq!(u8::decode(&mut request).unwrap(), msg::USERAUTH_REQUEST);
assert_eq!(String::decode(&mut request).unwrap(), "alice");
assert_eq!(String::decode(&mut request).unwrap(), "ssh-connection");
assert_eq!(String::decode(&mut request).unwrap(), "publickey");
assert_eq!(
u8::decode(&mut request).unwrap(),
u8::from(expected_has_signature)
);
let algorithm = String::decode(&mut request).unwrap();
let _certificate = Vec::<u8>::decode(&mut request).unwrap();
ensure_end(&request).unwrap();
algorithm
}

#[test]
fn rsa_future_certificate_hash_is_encoded_in_probe_and_signed_requests() {
let certificate = rsa_user_certificate();
for (hash_alg, expected) in [
(
Some(ssh_key::HashAlg::Sha512),
"rsa-sha2-512-cert-v01@openssh.com",
),
(
Some(ssh_key::HashAlg::Sha256),
"rsa-sha2-256-cert-v01@openssh.com",
),
(None, "ssh-rsa-cert-v01@openssh.com"),
] {
let mut encrypted = test_encrypted();
encrypted
.write_auth_request(
"alice",
&auth::Method::FutureCertificate {
cert: certificate.clone(),
hash_alg,
},
)
.unwrap();
let probe_payloads = payloads(&encrypted.write);
assert_eq!(probe_payloads.len(), 1);
assert_eq!(
decode_userauth_certificate_algorithm(probe_payloads[0], false),
expected
);

let mut signed = Vec::new();
encrypted
.client_make_to_sign(
"alice",
&PublicKeyOrCertificate::Certificate(certificate.clone()),
hash_alg,
&mut signed,
)
.unwrap();
let mut signed_request = signed.as_slice();
assert_eq!(
Vec::<u8>::decode(&mut signed_request).unwrap(),
b"session-id"
);
assert_eq!(
decode_userauth_certificate_algorithm(signed_request, true),
expected
);
}
}
}

impl Encrypted {
Expand Down Expand Up @@ -1276,13 +1372,14 @@ impl Encrypted {
key.to_bytes()?.as_slice().encode(&mut self.write)?;
true
}
auth::Method::FutureCertificate { ref cert, .. } => {
auth::Method::FutureCertificate { ref cert, hash_alg } => {
user.as_bytes().encode(&mut self.write)?;
"ssh-connection".encode(&mut self.write)?;
"publickey".encode(&mut self.write)?;
self.write.push(0); // This is a probe

cert.algorithm()
.with_hash_alg(hash_alg)
.to_certificate_type()
.encode(&mut self.write)?;
cert.to_bytes()?.as_slice().encode(&mut self.write)?;
Expand Down Expand Up @@ -1365,6 +1462,7 @@ impl Encrypted {
&mut self,
user: &str,
key: &PublicKeyOrCertificate,
certificate_hash_alg: Option<ssh_key::HashAlg>,
buffer: &mut Vec<u8>,
) -> Result<usize, crate::Error> {
buffer.clear();
Expand All @@ -1379,7 +1477,10 @@ impl Encrypted {

match key {
PublicKeyOrCertificate::Certificate(cert) => {
cert.algorithm().to_certificate_type().encode(buffer)?;
cert.algorithm()
.with_hash_alg(certificate_hash_alg)
.to_certificate_type()
.encode(buffer)?;
cert.to_bytes()?.encode(buffer)?;
}
PublicKeyOrCertificate::PublicKey { key, hash_alg } => {
Expand All @@ -1399,7 +1500,7 @@ impl Encrypted {
match method {
auth::Method::PublicKey { key } => {
let i0 =
self.client_make_to_sign(user, &PublicKeyOrCertificate::from(key), buffer)?;
self.client_make_to_sign(user, &PublicKeyOrCertificate::from(key), None, buffer)?;

// Extend with self-signature.
sign_with_hash_alg(key, buffer)?.encode(&mut *buffer)?;
Expand All @@ -1413,6 +1514,7 @@ impl Encrypted {
let i0 = self.client_make_to_sign(
user,
&PublicKeyOrCertificate::Certificate(cert.clone()),
None,
buffer,
)?;

Expand Down
Loading