feat: v1.12.5

This commit is contained in:
2025-05-02 13:13:32 +08:00
parent a3541e7b68
commit e52e42d48c
6 changed files with 48 additions and 26 deletions

17
Cargo.lock generated
View File

@@ -508,7 +508,7 @@ dependencies = [
[[package]] [[package]]
name = "card-cli" name = "card-cli"
version = "1.12.4" version = "1.12.5"
dependencies = [ dependencies = [
"aes-gcm-stream", "aes-gcm-stream",
"authenticator 0.3.1", "authenticator 0.3.1",
@@ -528,6 +528,7 @@ dependencies = [
"openssl", "openssl",
"p256 0.13.2", "p256 0.13.2",
"p384 0.13.1", "p384 0.13.1",
"p521",
"pem", "pem",
"pinentry", "pinentry",
"rand 0.8.5", "rand 0.8.5",
@@ -2482,6 +2483,20 @@ dependencies = [
"sha2 0.10.8", "sha2 0.10.8",
] ]
[[package]]
name = "p521"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2"
dependencies = [
"base16ct 0.2.0",
"ecdsa 0.16.9",
"elliptic-curve 0.13.8",
"primeorder",
"rand_core 0.6.4",
"sha2 0.10.8",
]
[[package]] [[package]]
name = "papergrid" name = "papergrid"
version = "0.10.0" version = "0.10.0"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "card-cli" name = "card-cli"
version = "1.12.4" version = "1.12.5"
authors = ["Hatter Jiang <jht5945@gmail.com>"] authors = ["Hatter Jiang <jht5945@gmail.com>"]
edition = "2018" edition = "2018"
@@ -40,6 +40,7 @@ x509-parser = { version = "0.15", features = ["verify"] }
ssh-agent = { version = "0.2", features = ["agent"] } ssh-agent = { version = "0.2", features = ["agent"] }
p256 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] } p256 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] }
p384 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] } p384 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] }
p521 = { version = "0.13", features = ["pem", "ecdh", "ecdsa", "jwk"] }
spki = { version = "0.7", features = ["pem"] } spki = { version = "0.7", features = ["pem"] }
tabled = "0.14" tabled = "0.14"
env_logger = "0.10" env_logger = "0.10"

View File

@@ -71,6 +71,7 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult<Vec<u
let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?; let private_key = hmacutil::try_hmac_decrypt_to_string(&key.hmac_enc_private_key)?;
let p256_public_key = ecdsautil::parse_p256_private_key_to_public_key(&private_key).ok(); let p256_public_key = ecdsautil::parse_p256_private_key_to_public_key(&private_key).ok();
let p384_public_key = ecdsautil::parse_p384_private_key_to_public_key(&private_key).ok(); let p384_public_key = ecdsautil::parse_p384_private_key_to_public_key(&private_key).ok();
let p521_public_key = ecdsautil::parse_p521_private_key_to_public_key(&private_key).ok();
if let Some(p256_public_key) = p256_public_key { if let Some(p256_public_key) = p256_public_key {
return Ok(p256_public_key); return Ok(p256_public_key);
@@ -78,6 +79,9 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult<Vec<u
if let Some(p384_public_key) = p384_public_key { if let Some(p384_public_key) = p384_public_key {
return Ok(p384_public_key); return Ok(p384_public_key);
} }
if let Some(p521_public_key) = p521_public_key {
return Ok(p521_public_key);
}
simple_error!("Invalid hmac enc private key") simple_error!("Invalid hmac enc private key")
} }
} }

View File

@@ -23,7 +23,7 @@ impl Command for CommandImpl {
.long("type") .long("type")
.required(true) .required(true)
.takes_value(true) .takes_value(true)
.help("Key type (e.g. p256, p384)"), .help("Key type (e.g. p256, p384, p521)"),
) )
.arg( .arg(
Arg::with_name("with-hmac-encrypt") Arg::with_name("with-hmac-encrypt")
@@ -51,6 +51,7 @@ impl Command for CommandImpl {
let ecdsa_algorithm = match key_type.as_str() { let ecdsa_algorithm = match key_type.as_str() {
"p256" => EcdsaAlgorithm::P256, "p256" => EcdsaAlgorithm::P256,
"p384" => EcdsaAlgorithm::P384, "p384" => EcdsaAlgorithm::P384,
"p521" => EcdsaAlgorithm::P521,
_ => { _ => {
return simple_error!("Key type must be p256 or p384"); return simple_error!("Key type must be p256 or p384");
} }

View File

@@ -89,6 +89,7 @@ pub fn convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm: AlgorithmType) ->
match jwt_algorithm { match jwt_algorithm {
AlgorithmType::Es256 => Ok(EcdsaAlgorithm::P256), AlgorithmType::Es256 => Ok(EcdsaAlgorithm::P256),
AlgorithmType::Es384 => Ok(EcdsaAlgorithm::P384), AlgorithmType::Es384 => Ok(EcdsaAlgorithm::P384),
AlgorithmType::Es512 => Ok(EcdsaAlgorithm::P521),
_ => simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm), _ => simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm),
} }
} }
@@ -96,10 +97,12 @@ pub fn convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm: AlgorithmType) ->
pub fn parse_ecdsa_private_key(private_key: &str) -> XResult<(AlgorithmType, Vec<u8>)> { pub fn parse_ecdsa_private_key(private_key: &str) -> XResult<(AlgorithmType, Vec<u8>)> {
let p256_private_key_d = ecdsautil::parse_p256_private_key(private_key).ok(); let p256_private_key_d = ecdsautil::parse_p256_private_key(private_key).ok();
let p384_private_key_d = ecdsautil::parse_p384_private_key(private_key).ok(); let p384_private_key_d = ecdsautil::parse_p384_private_key(private_key).ok();
let p521_private_key_d = ecdsautil::parse_p521_private_key(private_key).ok();
let (jwt_algorithm, private_key_d) = match (p256_private_key_d, p384_private_key_d) { let (jwt_algorithm, private_key_d) = match (p256_private_key_d, p384_private_key_d, p521_private_key_d) {
(Some(p256_private_key_d), None) => (AlgorithmType::Es256, p256_private_key_d), (Some(p256_private_key_d), None, None) => (AlgorithmType::Es256, p256_private_key_d),
(None, Some(p384_private_key_d)) => (AlgorithmType::Es384, p384_private_key_d), (None, Some(p384_private_key_d), None) => (AlgorithmType::Es384, p384_private_key_d),
(None, None, Some(p521_private_key_d)) => (AlgorithmType::Es512, p521_private_key_d),
_ => return simple_error!("Invalid private key: {}", private_key), _ => return simple_error!("Invalid private key: {}", private_key),
}; };
Ok((jwt_algorithm, private_key_d)) Ok((jwt_algorithm, private_key_d))

View File

@@ -6,6 +6,7 @@ use p256::ecdsa::signature::hazmat::PrehashVerifier;
use p256::elliptic_curve::JwkEcKey; use p256::elliptic_curve::JwkEcKey;
use p384::NistP384; use p384::NistP384;
use p256::pkcs8::EncodePrivateKey; use p256::pkcs8::EncodePrivateKey;
use p521::NistP521;
use rust_util::XResult; use rust_util::XResult;
use spki::EncodePublicKey; use spki::EncodePublicKey;
use crate::util::{base64_encode, try_decode}; use crate::util::{base64_encode, try_decode};
@@ -14,6 +15,7 @@ use crate::util::{base64_encode, try_decode};
pub enum EcdsaAlgorithm { pub enum EcdsaAlgorithm {
P256, P256,
P384, P384,
P521,
} }
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq)]
@@ -83,19 +85,12 @@ macro_rules! generate_inner_ecdsa_keypair {
pub fn generate_ecdsa_keypair(algo: EcdsaAlgorithm) -> XResult<(String, String, String, Vec<u8>, JwkEcKey)> { pub fn generate_ecdsa_keypair(algo: EcdsaAlgorithm) -> XResult<(String, String, String, Vec<u8>, JwkEcKey)> {
match algo { match algo {
EcdsaAlgorithm::P256 => generate_p256_keypair(), EcdsaAlgorithm::P256 => generate_inner_ecdsa_keypair!(p256),
EcdsaAlgorithm::P384 => generate_p384_keypair(), EcdsaAlgorithm::P384 => generate_inner_ecdsa_keypair!(p384),
EcdsaAlgorithm::P521 => generate_inner_ecdsa_keypair!(p521),
} }
} }
pub fn generate_p256_keypair() -> XResult<(String, String, String, Vec<u8>, JwkEcKey)> {
generate_inner_ecdsa_keypair!(p256)
}
pub fn generate_p384_keypair() -> XResult<(String, String, String, Vec<u8>, JwkEcKey)> {
generate_inner_ecdsa_keypair!(p384)
}
macro_rules! parse_ecdsa_private_key_to_public_key { macro_rules! parse_ecdsa_private_key_to_public_key {
($algo: tt, $parse_ecdsa_private_key: tt) => ({ ($algo: tt, $parse_ecdsa_private_key: tt) => ({
@@ -125,6 +120,10 @@ pub fn parse_p384_private_key_to_public_key(private_key_pkcs8: &str) -> XResult<
parse_ecdsa_private_key_to_public_key!(p384, private_key_pkcs8) parse_ecdsa_private_key_to_public_key!(p384, private_key_pkcs8)
} }
pub fn parse_p521_private_key_to_public_key(private_key_pkcs8: &str) -> XResult<Vec<u8>> {
parse_ecdsa_private_key_to_public_key!(p521, private_key_pkcs8)
}
macro_rules! parse_ecdsa_private_key { macro_rules! parse_ecdsa_private_key {
($algo: tt, $parse_ecdsa_private_key: tt) => ({ ($algo: tt, $parse_ecdsa_private_key: tt) => ({
@@ -153,6 +152,10 @@ pub fn parse_p384_private_key(private_key_pkcs8: &str) -> XResult<Vec<u8>> {
parse_ecdsa_private_key!(p384, private_key_pkcs8) parse_ecdsa_private_key!(p384, private_key_pkcs8)
} }
pub fn parse_p521_private_key(private_key_pkcs8: &str) -> XResult<Vec<u8>> {
parse_ecdsa_private_key!(p521, private_key_pkcs8)
}
macro_rules! sign_ecdsa_rs_or_der { macro_rules! sign_ecdsa_rs_or_der {
($algo: tt, $private_key_d: tt, $pre_hash: tt, $is_rs: tt) => ({ ($algo: tt, $private_key_d: tt, $pre_hash: tt, $is_rs: tt) => ({
@@ -171,20 +174,14 @@ macro_rules! sign_ecdsa_rs_or_der {
} }
pub fn ecdsa_sign(algo: EcdsaAlgorithm, private_key_d: &[u8], pre_hash: &[u8], sign_type: EcdsaSignType) -> XResult<Vec<u8>> { pub fn ecdsa_sign(algo: EcdsaAlgorithm, private_key_d: &[u8], pre_hash: &[u8], sign_type: EcdsaSignType) -> XResult<Vec<u8>> {
let is_rs = sign_type == EcdsaSignType::Rs;
match algo { match algo {
EcdsaAlgorithm::P256 => sign_p256_rs_or_der(private_key_d, pre_hash, sign_type == EcdsaSignType::Rs), EcdsaAlgorithm::P256 => sign_ecdsa_rs_or_der!(p256, private_key_d, pre_hash, is_rs),
EcdsaAlgorithm::P384 => sign_p384_rs_or_der(private_key_d, pre_hash, sign_type == EcdsaSignType::Rs), EcdsaAlgorithm::P384 => sign_ecdsa_rs_or_der!(p384, private_key_d, pre_hash, is_rs),
EcdsaAlgorithm::P521 => sign_ecdsa_rs_or_der!(p521, private_key_d, pre_hash, is_rs),
} }
} }
pub fn sign_p256_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) -> XResult<Vec<u8>> {
sign_ecdsa_rs_or_der!(p256, private_key_d, pre_hash, is_rs)
}
pub fn sign_p384_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) -> XResult<Vec<u8>> {
sign_ecdsa_rs_or_der!(p384, private_key_d, pre_hash, is_rs)
}
macro_rules! ecdsa_verify_signature { macro_rules! ecdsa_verify_signature {
($algo: tt, $pk_point: tt, $prehash: tt, $signature: tt) => ({ ($algo: tt, $pk_point: tt, $prehash: tt, $signature: tt) => ({
@@ -205,6 +202,7 @@ pub fn ecdsa_verify(algo: EcdsaAlgorithm, pk_point: &[u8], prehash: &[u8], signa
match algo { match algo {
EcdsaAlgorithm::P256 => ecdsa_verify_signature!(NistP256, pk_point, prehash, signature), EcdsaAlgorithm::P256 => ecdsa_verify_signature!(NistP256, pk_point, prehash, signature),
EcdsaAlgorithm::P384 => ecdsa_verify_signature!(NistP384, pk_point, prehash, signature), EcdsaAlgorithm::P384 => ecdsa_verify_signature!(NistP384, pk_point, prehash, signature),
EcdsaAlgorithm::P521 => ecdsa_verify_signature!(NistP521, pk_point, prehash, signature),
} }
Ok(()) Ok(())
} }