Skip to content

Commit

Permalink
auth: Fix multiple 'sk' keys configured, fails on first
Browse files Browse the repository at this point in the history
When a user has configured two or more 'sk' keys, eg Yubikeys,
pam-ssh-agent will fail if the first configured key isn't currently
plugged in.

Standard SSH utilities gracefully try the next key in this situation, so
we should too.  This is very helpful for users attempting to dogfood
their backup key.  ;-)

We correct this failure by catching the error, and trying the next key
IFF the failed key was of the 'sk' type.

Signed-off-by: Jason Cooper <[email protected]>
  • Loading branch information
jac-cbi committed Apr 4, 2024
1 parent 9d302e0 commit 1ecef47
Showing 1 changed file with 20 additions and 2 deletions.
22 changes: 20 additions & 2 deletions src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::log::Log;
use anyhow::{Context, Result};
use getrandom::getrandom;
use signature::Verifier;
use ssh_agent_client_rs::Error as SACError;
use ssh_key::public::KeyData;
use ssh_key::{AuthorizedKeys, PublicKey};
use std::collections::HashSet;
Expand All @@ -28,13 +29,30 @@ pub fn authenticate(
"found a matching key: {}",
key.fingerprint(Default::default())
))?;
return sign_and_verify(key, agent);
// Allow sign_and_verify() to return RemoteFailure for hardware keys,
// as the hardware might not be plugged in, eg when the user
// has configured multiple hardware keys
match sign_and_verify(&key, &mut agent) {
Ok(res) => return Ok(res),
Err(e) => {
if let Some(SACError::RemoteFailure) = e.downcast_ref::<SACError>() {
let data = key.key_data();
if data.is_sk_ed25519() || data.is_sk_ecdsa_p256() {
log.info(format!(
"SSHAgent: RemoteFailure, keytype is 'sk'; trying next key"
))?;
continue;
}
}
return Err(e);
}
}
}
}
Ok(false)
}

fn sign_and_verify(key: PublicKey, mut agent: impl SSHAgent) -> Result<bool> {
fn sign_and_verify(key: &PublicKey, agent: &mut impl SSHAgent) -> Result<bool> {
let mut data: [u8; CHALLENGE_SIZE] = [0_u8; CHALLENGE_SIZE];
getrandom(data.as_mut_slice())?;
let sig = agent.sign(&key, data.as_ref())?;
Expand Down

0 comments on commit 1ecef47

Please sign in to comment.