feat: v1.3.0, ssh agent works
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -384,7 +384,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.2.1"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"authenticator",
|
"authenticator",
|
||||||
"base64 0.13.0",
|
"base64 0.13.0",
|
||||||
@@ -392,6 +392,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"digest 0.10.3",
|
"digest 0.10.3",
|
||||||
"hex",
|
"hex",
|
||||||
|
"lazy_static",
|
||||||
"openpgp-card",
|
"openpgp-card",
|
||||||
"openpgp-card-pcsc",
|
"openpgp-card-pcsc",
|
||||||
"openpgp-card-sequoia",
|
"openpgp-card-sequoia",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.2.1"
|
version = "1.3.0"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -31,5 +31,6 @@ yubico_manager = "0.9"
|
|||||||
x509 = "0.2"
|
x509 = "0.2"
|
||||||
x509-parser = "0.13"
|
x509-parser = "0.13"
|
||||||
ssh-agent = { version = "0.2.3", features = ["agent"] }
|
ssh-agent = { version = "0.2.3", features = ["agent"] }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
#ssh-key = "0.4.0"
|
#ssh-key = "0.4.0"
|
||||||
#ctap-hid-fido2 = "2.1.3"
|
#ctap-hid-fido2 = "2.1.3"
|
||||||
|
|||||||
@@ -1,21 +1,28 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::remove_file;
|
use std::fs::remove_file;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||||
use openpgp_card::{KeyType, OpenPgp};
|
use openpgp_card::{KeyType, OpenPgp};
|
||||||
use openpgp_card::crypto_data::PublicKeyMaterial;
|
use openpgp_card::crypto_data::{Hash, PublicKeyMaterial};
|
||||||
use openpgp_card_pcsc::PcscBackend;
|
use openpgp_card_pcsc::PcscBackend;
|
||||||
|
use openssl::hash::MessageDigest;
|
||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
use rust_util::XResult;
|
use rust_util::XResult;
|
||||||
use ssh_agent::Agent;
|
use ssh_agent::Agent;
|
||||||
use ssh_agent::proto::{RsaPublicKey, to_bytes};
|
use ssh_agent::proto::{from_bytes, RsaPublicKey, signature, Signature, to_bytes};
|
||||||
use ssh_agent::proto::message::{self, Message, SignRequest};
|
use ssh_agent::proto::message::{self, Message};
|
||||||
use ssh_agent::proto::public_key::PublicKey;
|
use ssh_agent::proto::public_key::PublicKey;
|
||||||
|
|
||||||
|
use crate::digest::{copy_sha256, copy_sha512};
|
||||||
use crate::sshutil::with_sign;
|
use crate::sshutil::with_sign;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CARD: Mutex<Option<PcscBackend>> = Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
struct SshAgent {
|
struct SshAgent {
|
||||||
card: PcscBackend,
|
|
||||||
public_key: PublicKey,
|
public_key: PublicKey,
|
||||||
comment: String,
|
comment: String,
|
||||||
ssh_string: String,
|
ssh_string: String,
|
||||||
@@ -47,8 +54,11 @@ impl SshAgent {
|
|||||||
let comment = format!("pgp-card:{}", serial);
|
let comment = format!("pgp-card:{}", serial);
|
||||||
(public_key, comment.clone(), crate::sshutil::generate_ssh_string(e, n, &comment))
|
(public_key, comment.clone(), crate::sshutil::generate_ssh_string(e, n, &comment))
|
||||||
};
|
};
|
||||||
|
{
|
||||||
|
let mut card_mutex = CARD.lock().unwrap();
|
||||||
|
*card_mutex = Some(card);
|
||||||
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
card,
|
|
||||||
public_key,
|
public_key,
|
||||||
comment,
|
comment,
|
||||||
ssh_string,
|
ssh_string,
|
||||||
@@ -72,10 +82,41 @@ impl SshAgent {
|
|||||||
Message::AddIdentity(ref _identity) => {
|
Message::AddIdentity(ref _identity) => {
|
||||||
Err(From::from(format!("Not supported message: {:?}", request)))
|
Err(From::from(format!("Not supported message: {:?}", request)))
|
||||||
}
|
}
|
||||||
// Message::SignRequest(request) => {
|
Message::SignRequest(sign_request) => {
|
||||||
// let signature = to_bytes(&self.sign(&request)?)?;
|
let pubkey: PublicKey = from_bytes(&sign_request.pubkey_blob)?;
|
||||||
// Ok(Message::SignResponse(signature))
|
if self.public_key != pubkey {
|
||||||
// }
|
return Err(From::from(format!("Unknown public key: {:?}", sign_request)));
|
||||||
|
}
|
||||||
|
debugging!("To be signed data: {:?}", &sign_request.data);
|
||||||
|
|
||||||
|
let (algorithm, hash) = if sign_request.flags & signature::RSA_SHA2_512 != 0 {
|
||||||
|
let hash = opt_result!(openssl::hash::hash(MessageDigest::sha512(), &sign_request.data), "Calc digest failed: {}");
|
||||||
|
("rsa-sha2-512", Hash::SHA512(copy_sha512(&hash).unwrap()))
|
||||||
|
} else if sign_request.flags & signature::RSA_SHA2_256 != 0 {
|
||||||
|
let hash = opt_result!(openssl::hash::hash(MessageDigest::sha256(), &sign_request.data), "Calc digest failed: {}");
|
||||||
|
("rsa-sha2-256", Hash::SHA256(copy_sha256(&hash).unwrap()))
|
||||||
|
} else {
|
||||||
|
return Err(From::from(format!("Not supported sign flags: {:?}", sign_request.flags)));
|
||||||
|
};
|
||||||
|
|
||||||
|
information!("SSH request, algorithm: {}", algorithm);
|
||||||
|
let mut card_mutex = CARD.lock().unwrap();
|
||||||
|
let card_mut = match card_mutex.as_mut() {
|
||||||
|
Some(card) => card,
|
||||||
|
None => return Err(From::from("Illegal card status: none")),
|
||||||
|
};
|
||||||
|
let mut pgp = OpenPgp::new(card_mut);
|
||||||
|
let mut trans = opt_result!(pgp.transaction(), "Open card failed: {}");
|
||||||
|
opt_result!(trans.verify_pw1_sign("123456".as_bytes()), "User sign pin verify failed: {}");
|
||||||
|
let sig = opt_result!(trans.signature_for_hash(hash), "Sign OpenPGP card failed: {}");
|
||||||
|
|
||||||
|
debugging!("Signature: {:?}", sig);
|
||||||
|
success!("SSH request sign success");
|
||||||
|
Ok(Message::SignResponse(to_bytes(&Signature {
|
||||||
|
algorithm: algorithm.to_string(),
|
||||||
|
blob: sig,
|
||||||
|
})?))
|
||||||
|
}
|
||||||
_ => Err(From::from(format!("Unknown message: {:?}", request)))
|
_ => Err(From::from(format!("Unknown message: {:?}", request)))
|
||||||
};
|
};
|
||||||
debugging!("Response {:?}", response);
|
debugging!("Response {:?}", response);
|
||||||
@@ -101,8 +142,7 @@ impl Command for CommandImpl {
|
|||||||
|
|
||||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||||
SubCommand::with_name(self.name()).about("SSH-Agent subcommand")
|
SubCommand::with_name(self.name()).about("SSH-Agent subcommand")
|
||||||
// .arg(Arg::with_name("pin").short("p").long("pin").takes_value(true).default_value("123456").help("OpenPGP card user pin"))
|
.arg(Arg::with_name("pin").short("p").long("pin").default_value("123456").help("OpenPGP card user pin"))
|
||||||
// .arg(Arg::with_name("in").short("i").long("in").takes_value(true).help("File in"))
|
|
||||||
.arg(Arg::with_name("pgp").long("pgp").help("Use PGP"))
|
.arg(Arg::with_name("pgp").long("pgp").help("Use PGP"))
|
||||||
.arg(Arg::with_name("piv").long("piv").help("Use PIV"))
|
.arg(Arg::with_name("piv").long("piv").help("Use PIV"))
|
||||||
.arg(Arg::with_name("sock-file").long("sock-file").default_value("connect.ssh").help("Sock file, usage SSH_AUTH_SOCK=sock-file ssh ..."))
|
.arg(Arg::with_name("sock-file").long("sock-file").default_value("connect.ssh").help("Sock file, usage SSH_AUTH_SOCK=sock-file ssh ..."))
|
||||||
@@ -118,6 +158,12 @@ impl Command for CommandImpl {
|
|||||||
let sock_file = sub_arg_matches.value_of("sock-file").unwrap();
|
let sock_file = sub_arg_matches.value_of("sock-file").unwrap();
|
||||||
information!("Sock file: {}", sock_file);
|
information!("Sock file: {}", sock_file);
|
||||||
|
|
||||||
|
let sock_file_path = PathBuf::from(sock_file);
|
||||||
|
match std::fs::canonicalize(sock_file_path) {
|
||||||
|
Ok(canonicalized_sock_file_path) => information!("SSH_AUTH_SOCK={}", canonicalized_sock_file_path.to_str().unwrap_or_else(|| "-")),
|
||||||
|
Err(e) => warning!("Get canonicalized sock file path failed: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
if use_pgp {
|
if use_pgp {
|
||||||
let ssh_agent = SshAgent::new()?;
|
let ssh_agent = SshAgent::new()?;
|
||||||
information!("{}", &ssh_agent.ssh_string);
|
information!("{}", &ssh_agent.ssh_string);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rust_util;
|
extern crate rust_util;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
use clap::{App, AppSettings, ArgMatches};
|
use clap::{App, AppSettings, ArgMatches};
|
||||||
use rust_util::util_clap::{Command, CommandError};
|
use rust_util::util_clap::{Command, CommandError};
|
||||||
|
|||||||
Reference in New Issue
Block a user