From ac96eb5078f76b99466b1b61a33e41cb253a3075 Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Sat, 12 Jul 2025 20:36:23 +0100 Subject: [PATCH] Update the verify example to autodetect input format --- Cargo.toml | 1 + examples/verify.rs | 56 +++++++++++++++------------------------------- src/lib.rs | 6 +++++ 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bfd202d..7f1be5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ thiserror = "2.0.12" [dev-dependencies] rand = "0.9.1" +anyhow = "1.0.98" [target.'cfg(windows)'.dependencies] interprocess = "2.2.3" \ No newline at end of file diff --git a/examples/verify.rs b/examples/verify.rs index f82014d..1121be1 100644 --- a/examples/verify.rs +++ b/examples/verify.rs @@ -1,9 +1,8 @@ use bytes::BytesMut; use rand::{rng, RngCore}; use signature::Verifier; -use ssh_agent_client_rs::{Client, Identity, Result}; -use ssh_key::public::KeyData; -use ssh_key::{Certificate, PublicKey, Signature}; +use ssh_agent_client_rs::Client; +use ssh_key::{Certificate, PublicKey}; use std::env; use std::fs::read_to_string; use std::path::Path; @@ -11,34 +10,14 @@ use std::path::Path; /// This example tests whether the ssh-agent referenced by the path /// in the SSH_AUTH_SOCK environment variable holds a usable private /// key that corresponds to PUBLIC_KEY much like the command -/// `ssh-add -K PUBLIC_KEY` -/// It can use either a public key or a certificate as an argument. -/// If the second argument is "certificate" it will use a certificate, -fn main() -> Result<()> { - let path_or_certificate = env::args().nth(1).expect("argument PUBLIC_KEY missing"); - // Let's add a second optional argument that tells us if we want to use a certificate - // or a public key. If the argument is "certificate" it will not expect a path to a public key - // but the OpenSSH string representation of a certificate as given by ssh-add -L - // otherwise we will use a public key. - let key_type = env::args() - .nth(2) - .unwrap_or_else(|| String::from("public_key")); - - let identity: &Identity = &match key_type.as_str() { - "certificate" => { - println!("Using a certificate"); - Certificate::from_openssh(path_or_certificate.as_str()) - .expect("failed to parse certificate from argument") - .into() - } - "public_key" => { - println!("Using a public key"); - let key_bytes = read_to_string(Path::new(&path_or_certificate))?; - PublicKey::from_openssh(key_bytes.as_str())?.into() - } - _ => panic!("Unknown key type: {}", key_type), - }; +/// `ssh-add -T PUBLIC_KEY_PATH` +fn main() -> anyhow::Result<()> { + let path = env::args() + .nth(1) + .expect("argument PUBLIC_KEY_PATH missing"); + let identity = read_to_string(Path::new(&path))?; + let key_type = identity.split(" ").next().expect("Invalid key format"); let agent_path = env::var("SSH_AUTH_SOCK").expect("SSH_AUTH_SOCK is not set"); let mut client = Client::connect(Path::new(agent_path.as_str()))?; @@ -46,13 +25,14 @@ fn main() -> Result<()> { rng().fill_bytes(&mut data); let data = data.freeze(); - let sig = client.sign_with_ref(identity, &data)?; - verify_signature(identity.into(), &data, &sig)?; + if key_type.contains("-cert-") { + let cert = Certificate::from_openssh(&identity)?; + let sig = client.sign(&cert, &data)?; + cert.public_key().verify(&data, &sig)?; + } else { + let key = PublicKey::from_openssh(&identity)?; + let sig = client.sign(&key, &data)?; + key.key_data().verify(&data, &sig)?; + } Ok(()) } - -fn verify_signature(key: &KeyData, data: &[u8], sig: &Signature) -> Result<()> { - return Ok(key - .verify(data.as_ref(), &sig) - .expect("verification failed")); -} diff --git a/src/lib.rs b/src/lib.rs index 9eaeb4c..f6e8b1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,12 @@ impl<'a> From for Identity<'a> { } } +impl<'a> From<&'a Certificate> for Identity<'a> { + fn from(value: &'a Certificate) -> Self { + Identity::Certificate(Box::new(Cow::Borrowed(value))) + } +} + impl<'a> From<&'a Identity<'a>> for &'a KeyData { fn from(value: &'a Identity) -> Self { match value {