feat: v1.9.11, piv meta outputs ssh public key

This commit is contained in:
2024-07-04 22:20:55 +08:00
parent 7287193e49
commit f47a4fc90a
5 changed files with 37 additions and 24 deletions

2
Cargo.lock generated
View File

@@ -406,7 +406,7 @@ dependencies = [
[[package]] [[package]]
name = "card-cli" name = "card-cli"
version = "1.9.9" version = "1.9.11"
dependencies = [ dependencies = [
"authenticator", "authenticator",
"base64 0.21.7", "base64 0.21.7",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "card-cli" name = "card-cli"
version = "1.9.9" version = "1.9.11"
authors = ["Hatter Jiang <jht5945@gmail.com>"] authors = ["Hatter Jiang <jht5945@gmail.com>"]
edition = "2018" edition = "2018"

View File

@@ -12,6 +12,8 @@ use yubikey::piv::{AlgorithmId, metadata};
use crate::pivutil; use crate::pivutil;
use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr}; use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr};
use crate::pkiutil::bytes_to_pem; use crate::pkiutil::bytes_to_pem;
use crate::sshutil::SshVecWriter;
use crate::util::base64_encode;
pub struct CommandImpl; pub struct CommandImpl;
@@ -80,6 +82,7 @@ impl Command for CommandImpl {
let public_key_bit_string = &cert.subject_public_key_info.subject_public_key; let public_key_bit_string = &cert.subject_public_key_info.subject_public_key;
match algorithm_id { match algorithm_id {
AlgorithmId::EccP256 | AlgorithmId::EccP384 => { 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(); let pk_point_hex = public_key_bit_string.raw_bytes();
json.insert("pk_point_hex", hex::encode(pk_point_hex)); json.insert("pk_point_hex", hex::encode(pk_point_hex));
if pk_point_hex[0] == 0x04 { 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])), 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 x509_certificate = parse_x509_certificate(cert_der.as_slice()).unwrap().1;
let public_key_bytes = x509_certificate.public_key().raw; let public_key_bytes = x509_certificate.public_key().raw;
json.insert("subject", x509_certificate.subject.to_string()); json.insert("subject", x509_certificate.subject.to_string());
json.insert("issuer", x509_certificate.issuer.to_string()); json.insert("issuer", x509_certificate.issuer.to_string());
json.insert("public_key_hex", hex::encode(public_key_bytes)); json.insert("public_key_hex", hex::encode(public_key_bytes));

View File

@@ -7,27 +7,7 @@ use yubikey::piv::{AlgorithmId, sign_data};
use crate::{pinutil, pivutil, util}; use crate::{pinutil, pivutil, util};
use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr}; use crate::pivutil::{get_algorithm_id_by_certificate, slot_equals, ToStr};
use crate::sshutil::SshVecWriter;
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<u8> {
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);
}
}
pub struct CommandImpl; pub struct CommandImpl;

View File

@@ -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<u8>, s: &[u8]) { pub fn append_slice_with_len(v: &mut Vec<u8>, s: &[u8]) {
v.extend_from_slice(&(s.len() as u32).to_be_bytes()[..]); v.extend_from_slice(&(s.len() as u32).to_be_bytes()[..]);
v.extend_from_slice(s); v.extend_from_slice(s);
} }
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<u8> {
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);
}
}