feat: ssh agent, not works yet

This commit is contained in:
2025-05-25 22:39:02 +08:00
parent ecf034376d
commit f870c07387
3 changed files with 235 additions and 88 deletions

View File

@@ -1,91 +1,57 @@
use std::error::Error;
use std::fs::remove_file;
use std::path::PathBuf;
use clap::{App, Arg, ArgMatches, SubCommand};
use rust_util::util_clap::{Command, CommandError};
use rust_util::util_msg::when_debug;
use rust_util::XResult;
use ssh_agent::proto::message::{self, Message};
use ssh_agent::proto::public_key::PublicKey;
use ssh_agent::proto::{from_bytes, to_bytes, EcDsaPublicKey};
use ssh_agent::Agent;
use crate::ecdsautil::{generate_ecdsa_keypair, EcdsaAlgorithm};
use rust_util::util_clap::{Command, CommandError};
use rust_util::XResult;
use ssh_agent_lib::agent::{listen, Session};
use ssh_agent_lib::error::AgentError;
use ssh_agent_lib::proto::{Identity, SignRequest};
use ssh_agent_lib::ssh_key::public::KeyData;
use ssh_agent_lib::ssh_key::{Algorithm, Signature};
use tokio::net::UnixListener as Listener;
use crate::ecdsautil;
struct SshAgent {
#[derive(Default, Clone)]
struct MySshAgent {
private_key_pem: String,
comment: String,
}
impl SshAgent {
impl MySshAgent {
fn new() -> XResult<Self> {
let (_, private_key_pem, _, _, _) = generate_ecdsa_keypair(EcdsaAlgorithm::P256)?;
Ok(SshAgent {
Ok(MySshAgent {
private_key_pem,
comment: "test".to_string(),
})
}
fn handle_message(&self, request: Message) -> Result<Message, Box<dyn Error>> {
debugging!("Request: {:?}", request);
let response = match request {
Message::RequestIdentities => {
let p256_private_key_d =
ecdsautil::parse_p256_private_key(&self.private_key_pem).unwrap();
let ec_dsa_public_key = EcDsaPublicKey {
identifier: "nistp256".to_string(),
q: p256_private_key_d,
};
let public_key = PublicKey::EcDsa(ec_dsa_public_key);
let identities = vec![message::Identity {
pubkey_blob: to_bytes(&public_key)?,
comment: self.comment.clone(),
}];
when_debug(|| {
debugging!("Return {} identities", identities.len());
for (i, identity) in identities.iter().enumerate() {
debugging!("#{} - {:?}", i, identity)
}
});
Ok(Message::IdentitiesAnswer(identities))
}
Message::RemoveIdentity(ref _identity) => {
Err(From::from(format!("Not supported message: {:?}", request)))
}
Message::AddIdentity(ref _identity) => {
Err(From::from(format!("Not supported message: {:?}", request)))
}
Message::SignRequest(sign_request) => {
let pubkey: PublicKey = from_bytes(&sign_request.pubkey_blob)?;
println!("{:?}", pubkey);
Err(From::from(format!(
"Not supported message: {:?}",
sign_request
)))
}
_ => Err(From::from(format!("Unknown message: {:?}", request))),
};
debugging!("Response {:?}", response);
response
}
}
impl Agent for SshAgent {
type Error = ();
#[ssh_agent_lib::async_trait]
impl Session for MySshAgent {
async fn request_identities(&mut self) -> Result<Vec<Identity>, AgentError> {
debugging!("request_identities");
// let p256_private_key_d = ecdsautil::parse_p256_private_key(&self.private_key_pem).unwrap();
let public_key_point = hex::decode("0474b7b8dcac7587afc8c461e96d713d05a4caae9dc4188924697fcb8dec2b8001d337e9ff4da1fb30042fef53375bde0cbe4964c71298b9d56bd9131c347119f3").unwrap();
Ok(vec![Identity {
pubkey: KeyData::Ecdsa(
ssh_key::public::EcdsaPublicKey::from_sec1_bytes(&public_key_point).unwrap(),
),
comment: "".to_string(),
}])
}
fn handle(&self, message: Message) -> Result<Message, ()> {
debugging!("Message: {:?}", message);
self.handle_message(message).or_else(|error| {
warning!("Error handling message - {:?}", error);
Ok(Message::Failure)
})
async fn sign(&mut self, request: SignRequest) -> Result<Signature, AgentError> {
debugging!("sign, request: {:?}", request);
// get the signature by signing `request.data`
let signature = vec![];
Ok(Signature::new(
Algorithm::new("algorithm").map_err(AgentError::other)?,
signature,
)
.map_err(AgentError::other)?)
}
}
@@ -108,7 +74,7 @@ impl Command for CommandImpl {
}
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
failure!("Not works!");
warning!("Not works yet.");
debugging!("Sub args: {:?}", sub_arg_matches);
@@ -125,17 +91,32 @@ impl Command for CommandImpl {
Err(e) => warning!("Get canonicalized sock file path failed: {}", e),
}
let ssh_agent = SshAgent::new()?;
// TODO information!("{}", &ssh_agent.ssh_string);
// let ssh_agent = SshAgent::new()?;
// // TODO information!("{}", &ssh_agent.ssh_string);
let _ = remove_file(sock_file);
information!("Start unix socket: {}", sock_file);
opt_result!(
ssh_agent.run_unix(sock_file),
"Run unix socket: {}, failed: {}",
sock_file
);
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(async move {
listen(
Listener::bind(sock_file).unwrap(),
MySshAgent::new().unwrap(),
)
.await
.unwrap();
});
// opt_result!(
// ssh_agent.run_unix(sock_file),
// "Run unix socket: {}, failed: {}",
// sock_file
// );
Ok(None)
}