From d7f52530dfa9feb62c08ca429e4f2487636cc844 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Fri, 2 May 2025 00:01:11 +0800 Subject: [PATCH] feat: update ecdsautil --- src/cmd_keypair_generate.rs | 15 ++++++++--- src/ecdsautil.rs | 52 +++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/cmd_keypair_generate.rs b/src/cmd_keypair_generate.rs index b154a9e..97bcba7 100644 --- a/src/cmd_keypair_generate.rs +++ b/src/cmd_keypair_generate.rs @@ -4,6 +4,7 @@ use clap::{App, Arg, ArgMatches, SubCommand}; use rust_util::util_clap::{Command, CommandError}; use std::collections::BTreeMap; use yubikey::piv::AlgorithmId; +use crate::ecdsautil::EcdsaAlgorithm; use crate::keyutil::{KeyUri, YubikeyHmacEncSoftKey}; use crate::util::base64_encode; @@ -47,13 +48,21 @@ impl Command for CommandImpl { } } - let (pkcs8_base64, secret_key_pem, public_key_pem, public_key_der, jwk_ec_key) = match key_type.as_str() { - "p256" => ecdsautil::generate_p256_keypair()?, - "p384" => ecdsautil::generate_p384_keypair()?, + let ecdsa_algorithm = match key_type.as_str() { + "p256" => EcdsaAlgorithm::P256, + "p384" => EcdsaAlgorithm::P384, _ => { return simple_error!("Key type must be p256 or p384"); } }; + + let (pkcs8_base64, + secret_key_pem, + public_key_pem, + public_key_der, + jwk_ec_key + ) = ecdsautil::generate_ecdsa_keypair(ecdsa_algorithm)?; + let (pkcs8_base64, secret_key_pem) = if with_hmac_encrypt { ( hmacutil::hmac_encrypt_from_string(&pkcs8_base64)?, diff --git a/src/ecdsautil.rs b/src/ecdsautil.rs index fe24432..e512a84 100644 --- a/src/ecdsautil.rs +++ b/src/ecdsautil.rs @@ -36,14 +36,14 @@ pub fn parse_ecdsa_r_and_s(signature_der: &[u8]) -> XResult<(Vec, Vec)> match &seq[0].content { BerObjectContent::Integer(r) => { debugging!("Signature r: {}", hex::encode(r)); - vec_r = trim_point_leading_zero(r); + vec_r = trim_ecdsa_point_coord(r); } _ => return simple_error!("Parse signature failed: [0]not integer"), } match &seq[1].content { BerObjectContent::Integer(s) => { debugging!("Signature s: {}", hex::encode(s)); - vec_s = trim_point_leading_zero(s); + vec_s = trim_ecdsa_point_coord(s); } _ => return simple_error!("Parse signature failed: [1]not integer"), } @@ -53,32 +53,47 @@ pub fn parse_ecdsa_r_and_s(signature_der: &[u8]) -> XResult<(Vec, Vec)> Ok((vec_r, vec_s)) } -fn trim_point_leading_zero(p: &[u8]) -> Vec { +fn trim_ecdsa_point_coord(p: &[u8]) -> Vec { if p.len() == ((256 / 8) + 1) || p.len() == ((384 / 8) + 1) { p[1..].to_vec() + } else if p.len() == ((256 / 8) - 1) || p.len() == ((384 / 8) - 1) { + let mut v = vec![]; + v.push(0_u8); + v.extend_from_slice(p); + v } else { p.to_vec() } } + +macro_rules! generate_inner_ecdsa_keypair { + ($algo: tt) => ({ + use $algo::SecretKey; + + let secret_key = SecretKey::random(&mut rand::thread_rng()); + let secret_key_der_base64 = base64_encode(secret_key.to_pkcs8_der()?.as_bytes()); + let secret_key_pem = secret_key.to_pkcs8_pem(LineEnding::LF)?.to_string(); + let public_key_pem = secret_key.public_key().to_public_key_pem(LineEnding::LF)?; + let public_key_der = secret_key.public_key().to_public_key_der()?.to_vec(); + let jwk_ec_key = secret_key.public_key().to_jwk(); + Ok((secret_key_der_base64, secret_key_pem, public_key_pem, public_key_der, jwk_ec_key)) + }) +} + +pub fn generate_ecdsa_keypair(algo: EcdsaAlgorithm) -> XResult<(String, String, String, Vec, JwkEcKey)> { + match algo { + EcdsaAlgorithm::P256 => generate_p256_keypair(), + EcdsaAlgorithm::P384 => generate_p384_keypair(), + } +} + pub fn generate_p256_keypair() -> XResult<(String, String, String, Vec, JwkEcKey)> { - let secret_key = p256::SecretKey::random(&mut rand::thread_rng()); - let secret_key_der_base64 = base64_encode(secret_key.to_pkcs8_der()?.as_bytes()); - let secret_key_pem = secret_key.to_pkcs8_pem(LineEnding::LF)?.to_string(); - let public_key_pem = secret_key.public_key().to_public_key_pem(LineEnding::LF)?; - let public_key_der = secret_key.public_key().to_public_key_der()?.to_vec(); - let jwk_ec_key = secret_key.public_key().to_jwk(); - Ok((secret_key_der_base64, secret_key_pem, public_key_pem, public_key_der, jwk_ec_key)) + generate_inner_ecdsa_keypair!(p256) } pub fn generate_p384_keypair() -> XResult<(String, String, String, Vec, JwkEcKey)> { - let secret_key = p384::SecretKey::random(&mut rand::thread_rng()); - let secret_key_der_base64 = base64_encode(secret_key.to_pkcs8_der()?.as_bytes()); - let secret_key_pem = secret_key.to_pkcs8_pem(LineEnding::LF)?.to_string(); - let public_key_pem = secret_key.public_key().to_public_key_pem(LineEnding::LF)?; - let public_key_der = secret_key.public_key().to_public_key_der()?.to_vec(); - let jwk_ec_key = secret_key.public_key().to_jwk(); - Ok((secret_key_der_base64, secret_key_pem, public_key_pem, public_key_der, jwk_ec_key)) + generate_inner_ecdsa_keypair!(p384) } @@ -110,6 +125,7 @@ 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) } + macro_rules! parse_ecdsa_private_key { ($algo: tt, $parse_ecdsa_private_key: tt) => ({ use $algo::pkcs8::DecodePrivateKey; @@ -137,6 +153,7 @@ pub fn parse_p384_private_key(private_key_pkcs8: &str) -> XResult> { parse_ecdsa_private_key!(p384, private_key_pkcs8) } + macro_rules! sign_ecdsa_rs_or_der { ($algo: tt, $private_key_d: tt, $pre_hash: tt, $is_rs: tt) => ({ use $algo::ecdsa::{SigningKey, Signature}; @@ -168,6 +185,7 @@ pub fn sign_p384_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) - sign_ecdsa_rs_or_der!(p384, private_key_d, pre_hash, is_rs) } + macro_rules! ecdsa_verify_signature { ($algo: tt, $pk_point: tt, $prehash: tt, $signature: tt) => ({ use ecdsa::Signature;