feat: fix sign jwt

This commit is contained in:
2025-03-22 09:33:07 +08:00
parent 2f3bf2eec7
commit 04247bb846
4 changed files with 50 additions and 3 deletions

2
Cargo.lock generated
View File

@@ -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",

View File

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

View File

@@ -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<String>, 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))
}

View File

@@ -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<Vec<u8>> {
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<u8>, Vec<u8>)> {
let mut vec_r: Vec<u8> = Vec::new();
let mut vec_s: Vec<u8> = 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: {}");