From 04247bb846404a4a15cfcb5fbd71ddf686ebb503 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 22 Mar 2025 09:33:07 +0800 Subject: [PATCH] feat: fix sign jwt --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/cmd_signjwt.rs | 8 +++++++- src/ecdsautil.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9646581..fb782f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -487,7 +487,7 @@ dependencies = [ [[package]] name = "card-cli" -version = "1.10.16" +version = "1.10.17" dependencies = [ "authenticator 0.3.1", "base64 0.21.7", diff --git a/Cargo.toml b/Cargo.toml index 198a50c..0d0dd3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "card-cli" -version = "1.10.16" +version = "1.10.17" authors = ["Hatter Jiang "] edition = "2018" diff --git a/src/cmd_signjwt.rs b/src/cmd_signjwt.rs index a654677..0ca4fd4 100644 --- a/src/cmd_signjwt.rs +++ b/src/cmd_signjwt.rs @@ -11,6 +11,7 @@ use yubikey::{Certificate, YubiKey}; use yubikey::piv::{AlgorithmId, sign_data, SlotId}; use crate::{digest, pivutil, rsautil, util}; +use crate::ecdsautil::parse_ecdsa_to_rs; const SEPARATOR: &str = "."; @@ -153,8 +154,13 @@ fn sign_jwt(yk: &mut YubiKey, slot_id: SlotId, pin_opt: &Option, mut hea let signed_data = opt_result!( sign_data(yk, &raw_in, yk_algorithm, slot_id), "Sign YubiKey failed: {}"); + let signed_data = match jwt_algorithm { + AlgorithmType::Rs256 => signed_data.to_vec(), + AlgorithmType::Es256 | AlgorithmType::Es384 => parse_ecdsa_to_rs(signed_data.as_slice())?, + _ => return simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm), + }; - let signature = util::base64_encode_url_safe_no_pad(signed_data); + let signature = util::base64_encode_url_safe_no_pad(&signed_data); Ok([&*header, &*claims, &signature].join(SEPARATOR)) } diff --git a/src/ecdsautil.rs b/src/ecdsautil.rs index 778e982..a5ac615 100644 --- a/src/ecdsautil.rs +++ b/src/ecdsautil.rs @@ -1,3 +1,4 @@ +use der_parser::ber::BerObjectContent; use ecdsa::VerifyingKey; use p256::NistP256; use p256::ecdsa::signature::hazmat::PrehashVerifier; @@ -11,6 +12,46 @@ pub enum EcdsaAlgorithm { P384, } +pub fn parse_ecdsa_to_rs(signature_der: &[u8]) -> XResult> { + let (mut r, s)= parse_ecdsa_r_and_s(signature_der)?; + r.extend_from_slice(&s); + Ok(r) +} + +pub fn parse_ecdsa_r_and_s(signature_der: &[u8]) -> XResult<(Vec, Vec)> { + let mut vec_r: Vec = Vec::new(); + let mut vec_s: Vec = Vec::new(); + let (_, parsed_signature) = opt_result!(der_parser::parse_der(signature_der), "Parse signature failed: {}"); + match parsed_signature.content { + BerObjectContent::Sequence(seq) => { + match &seq[0].content { + BerObjectContent::Integer(r) => { + debugging!("Signature r: {}", hex::encode(r)); + if r.len() == ((256 / 8) + 1) || r.len() == ((384 / 8) + 1) { + vec_r = r[1..].to_vec(); + } else { + vec_r = r.to_vec(); + } + } + _ => return simple_error!("Parse signature failed: [0]not integer"), + } + match &seq[1].content { + BerObjectContent::Integer(s) => { + debugging!("Signature s: {}", hex::encode(s)); + if s.len() == ((256 / 8) + 1) || s.len() == ((384 / 8) + 1) { + vec_s = s[1..].to_vec(); + } else { + vec_s = s.to_vec(); + } + } + _ => return simple_error!("Parse signature failed: [1]not integer"), + } + } + _ => return simple_error!("Parse signature failed: not sequence"), + } + Ok((vec_r, vec_s)) +} + macro_rules! ecdsa_verify_signature { ($algo: tt, $pk_point: tt, $prehash: tt, $signature: tt) => ({ let verifying_key: VerifyingKey<$algo> = opt_result!(VerifyingKey::<$algo>::from_sec1_bytes($pk_point), "Parse public key failed: {}");