From f47a4fc90a7ef1b20e3b4ee4adc74a8b060c4514 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Thu, 4 Jul 2024 22:20:55 +0800 Subject: [PATCH] feat: v1.9.11, piv meta outputs ssh public key --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/cmd_pivmeta.rs | 12 ++++++++++++ src/cmd_sshpivsign.rs | 22 +--------------------- src/sshutil.rs | 23 ++++++++++++++++++++++- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9797ce3..f288dc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -406,7 +406,7 @@ dependencies = [ [[package]] name = "card-cli" -version = "1.9.9" +version = "1.9.11" dependencies = [ "authenticator", "base64 0.21.7", diff --git a/Cargo.toml b/Cargo.toml index f9e5eeb..0d30e73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "card-cli" -version = "1.9.9" +version = "1.9.11" authors = ["Hatter Jiang "] edition = "2018" diff --git a/src/cmd_pivmeta.rs b/src/cmd_pivmeta.rs index 0684f0e..b0b671c 100644 --- a/src/cmd_pivmeta.rs +++ b/src/cmd_pivmeta.rs @@ -12,6 +12,8 @@ use yubikey::piv::{AlgorithmId, metadata}; use crate::pivutil; use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr}; use crate::pkiutil::bytes_to_pem; +use crate::sshutil::SshVecWriter; +use crate::util::base64_encode; pub struct CommandImpl; @@ -80,6 +82,7 @@ impl Command for CommandImpl { let public_key_bit_string = &cert.subject_public_key_info.subject_public_key; match algorithm_id { AlgorithmId::EccP256 | AlgorithmId::EccP384 => { + let ec_bit_len = iff!(matches!(algorithm_id, AlgorithmId::EccP256), 256, 384); let pk_point_hex = public_key_bit_string.raw_bytes(); json.insert("pk_point_hex", hex::encode(pk_point_hex)); if pk_point_hex[0] == 0x04 { @@ -88,6 +91,14 @@ impl Command for CommandImpl { format!("02{}", hex::encode(&pk_point_hex[1..(pk_point_hex.len() / 2) + 1])), ); } + + let mut ssh_public_key = vec![]; + ssh_public_key.write_string(format!("ecdsa-sha2-nistp{}", ec_bit_len).as_bytes()); + ssh_public_key.write_string(format!("nistp{}", ec_bit_len).as_bytes()); + ssh_public_key.write_string(pk_point_hex); + let ssh_public_key_str = format!( + "ecdsa-sha2-nistp{} {} PIV:{}", ec_bit_len, base64_encode(ssh_public_key), slot_id); + json.insert("ssh_public_key", ssh_public_key_str.to_string()); } _ => {} } @@ -100,6 +111,7 @@ impl Command for CommandImpl { let x509_certificate = parse_x509_certificate(cert_der.as_slice()).unwrap().1; let public_key_bytes = x509_certificate.public_key().raw; + json.insert("subject", x509_certificate.subject.to_string()); json.insert("issuer", x509_certificate.issuer.to_string()); json.insert("public_key_hex", hex::encode(public_key_bytes)); diff --git a/src/cmd_sshpivsign.rs b/src/cmd_sshpivsign.rs index adaa0af..e4903b1 100644 --- a/src/cmd_sshpivsign.rs +++ b/src/cmd_sshpivsign.rs @@ -7,27 +7,7 @@ use yubikey::piv::{AlgorithmId, sign_data}; use crate::{pinutil, pivutil, util}; use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr}; - -trait VecWriter { - fn write_bytes(&mut self, bytes: &[u8]) -> (); - fn write_u32(&mut self, num: u32) -> (); - fn write_string(&mut self, bytes: &[u8]) -> (); -} - -impl VecWriter for Vec { - fn write_bytes(&mut self, bytes: &[u8]) -> () { - self.extend_from_slice(bytes); - } - - fn write_u32(&mut self, num: u32) -> () { - self.write_bytes(&num.to_be_bytes()); - } - - fn write_string(&mut self, bytes: &[u8]) -> () { - self.write_u32(bytes.len() as u32); - self.write_bytes(bytes); - } -} +use crate::sshutil::SshVecWriter; pub struct CommandImpl; diff --git a/src/sshutil.rs b/src/sshutil.rs index a021b9c..b1cc030 100644 --- a/src/sshutil.rs +++ b/src/sshutil.rs @@ -18,4 +18,25 @@ pub fn generate_ssh_string(e: &[u8], n: &[u8], comment: &str) -> String { pub fn append_slice_with_len(v: &mut Vec, s: &[u8]) { v.extend_from_slice(&(s.len() as u32).to_be_bytes()[..]); v.extend_from_slice(s); -} \ No newline at end of file +} + +pub trait SshVecWriter { + fn write_bytes(&mut self, bytes: &[u8]) -> (); + fn write_u32(&mut self, num: u32) -> (); + fn write_string(&mut self, bytes: &[u8]) -> (); +} + +impl SshVecWriter for Vec { + fn write_bytes(&mut self, bytes: &[u8]) -> () { + self.extend_from_slice(bytes); + } + + fn write_u32(&mut self, num: u32) -> () { + self.write_bytes(&num.to_be_bytes()); + } + + fn write_string(&mut self, bytes: &[u8]) -> () { + self.write_u32(bytes.len() as u32); + self.write_bytes(bytes); + } +}