feat: v1.13.18, external_sign supports --message-type

This commit is contained in:
2025-07-19 13:58:51 +08:00
parent 33a6661c3f
commit 6f556cc2d6
8 changed files with 214 additions and 230 deletions

View File

@@ -13,6 +13,7 @@ use rust_util::util_clap::{Command, CommandError};
use rust_util::XResult;
use serde_json::Value;
use std::collections::BTreeMap;
use swift_secure_enclave_tool_rs::DigestType;
use yubikey::piv::sign_data;
pub struct CommandImpl;
@@ -28,6 +29,7 @@ impl Command for CommandImpl {
.arg(cmdutil::build_alg_arg())
.arg(cmdutil::build_parameter_arg())
.arg(cmdutil::build_message_arg())
.arg(cmdutil::build_message_type_arg())
.arg(cmdutil::build_pin_arg())
.arg(cmdutil::build_serial_arg())
}
@@ -36,11 +38,12 @@ impl Command for CommandImpl {
let alg = sub_arg_matches.value_of("alg").unwrap();
let parameter = sub_arg_matches.value_of("parameter").unwrap();
let message_base64 = sub_arg_matches.value_of("message-base64").unwrap();
let message_type = sub_arg_matches.value_of("message-type");
let message_bytes = base64_decode(message_base64)?;
let mut json = BTreeMap::new();
let key_uri = parse_key_uri(parameter)?;
match sign(alg, &message_bytes, key_uri, sub_arg_matches) {
match sign(alg, &message_bytes, message_type, key_uri, sub_arg_matches) {
Ok(signature_bytes) => {
json.insert("success", Value::Bool(true));
json.insert("signature_base64", base64_encode(&signature_bytes).into());
@@ -56,7 +59,14 @@ impl Command for CommandImpl {
}
}
pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
pub fn sign(alg: &str, message: &[u8], message_type: Option<&str>, key_uri: KeyUri, sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
let digest_type = DigestType::parse(message_type)?;
if let Some(bytes_len) = digest_type.bytes() {
if message.len() != bytes_len as usize {
return simple_error!("Invalid message length, requires: {}, actual: {}", bytes_len, message.len());
}
}
let is_raw = DigestType::Raw == digest_type;
match key_uri {
KeyUri::SecureEnclave(key) => {
if "ES256" != alg {
@@ -66,7 +76,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
return simple_error!("Not singing key");
}
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.private_key)?;
seutil::secure_enclave_p256_sign(&private_key, message)
seutil::secure_enclave_p256_sign(&private_key, message, digest_type)
}
KeyUri::YubikeyPiv(key) => {
let mut yk = yubikeyutil::open_yubikey_with_args(sub_arg_matches)?;
@@ -87,7 +97,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
"Yubikey not supported algorithm: {}",
key.algorithm.to_str()
);
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, message)?;
let raw_in = iff!(is_raw, digest_by_jwt_algorithm(jwt_algorithm, message)?, message.to_vec());
let signed_data = opt_result!(
sign_data(&mut yk, &raw_in, algorithm, key.slot),
"Sign YubiKey failed: {}"
@@ -99,7 +109,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.hmac_enc_private_key)?;
let (jwt_algorithm, private_key_d) = parse_ecdsa_private_key(&private_key)?;
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, message)?;
let raw_in = iff!(is_raw, digest_by_jwt_algorithm(jwt_algorithm, message)?, message.to_vec());
let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?;
let signed_data = ecdsautil::ecdsa_sign(
ecdsa_algorithm,
@@ -117,7 +127,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
let rsa_sign_algorithm =
opt_value_result!(RsaSignAlgorithm::from_str(alg), "Invalid --alg: {}", alg);
rsautil::sign(&rsa_private_key, rsa_sign_algorithm, message)
rsautil::sign(&rsa_private_key, rsa_sign_algorithm, message, is_raw)
} else {
simple_error!("Invalid algorithm: {}", key.algorithm.to_str())
}
@@ -125,7 +135,8 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
KeyUri::ExternalCommand(key) => {
let parameter = cmd_hmac_decrypt::try_decrypt(&mut None, &key.parameter)?;
let alg = key.algorithm.as_jwa_name();
let signature = external_command_rs::external_sign(&key.external_command, &parameter, alg, message)?;
let signature = external_command_rs::external_sign_digested(
&key.external_command, &parameter, alg, message, digest_type.to_str())?;
Ok(signature)
}
}

View File

@@ -4,6 +4,7 @@ use crate::util::{base64_decode, base64_encode};
use clap::{App, Arg, ArgMatches, SubCommand};
use rust_util::util_clap::{Command, CommandError};
use std::collections::BTreeMap;
use swift_secure_enclave_tool_rs::DigestType;
pub struct CommandImpl;
@@ -50,7 +51,7 @@ impl Command for CommandImpl {
debugging!("Secure enclave key URI: {:?}", se_key_uri);
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &se_key_uri.private_key)?;
let signature = seutil::secure_enclave_p256_sign(&private_key, &input_bytes)?;
let signature = seutil::secure_enclave_p256_sign(&private_key, &input_bytes, DigestType::Raw)?;
if json_output {
let mut json = BTreeMap::<&'_ str, String>::new();

View File

@@ -69,7 +69,7 @@ fn sign_jwt(
let claims = merge_payload_claims(payload, claims)?;
let tobe_signed = merge_header_claims(header.as_bytes(), claims.as_bytes());
let signature = cmd_external_sign::sign(jwt_algorithm.to_str(), &tobe_signed, key_uri, sub_arg_matches)?;
let signature = cmd_external_sign::sign(jwt_algorithm.to_str(), &tobe_signed, None, key_uri, sub_arg_matches)?;
let signed_data = match jwt_algorithm {
AlgorithmType::Rs256 => signature,

View File

@@ -53,6 +53,11 @@ pub fn build_message_arg() -> Arg<'static, 'static> {
Arg::with_name("message-base64").long("message-base64").takes_value(true).required(true).help("Message in base64")
}
pub fn build_message_type_arg() -> Arg<'static, 'static> {
Arg::with_name("message-type").long("message-type").takes_value(true).help("Optional, message type, raw, sha256, sha384 or sha512")
}
pub fn build_no_pin_arg() -> Arg<'static, 'static> {
Arg::with_name("no-pin").long("no-pin").help("No PIN")
}

View File

@@ -33,18 +33,18 @@ impl RsaSignAlgorithm {
}
}
pub fn sign(rsa_private_key: &RsaPrivateKey, rsa_sign_algorithm: RsaSignAlgorithm, message: &[u8]) -> XResult<Vec<u8>> {
pub fn sign(rsa_private_key: &RsaPrivateKey, rsa_sign_algorithm: RsaSignAlgorithm, message: &[u8], is_raw: bool) -> XResult<Vec<u8>> {
match rsa_sign_algorithm {
RsaSignAlgorithm::Rs256 => {
let raw_in = digestutil::sha256_bytes(message);
let raw_in = iff!(is_raw, digestutil::sha256_bytes(message), message.to_vec());
Ok(rsa_private_key.sign(Pkcs1v15Sign::new::<Sha256>(), &raw_in)?)
}
RsaSignAlgorithm::Rs384 => {
let raw_in = digestutil::sha384_bytes(message);
let raw_in = iff!(is_raw, digestutil::sha384_bytes(message), message.to_vec());
Ok(rsa_private_key.sign(Pkcs1v15Sign::new::<Sha384>(), &raw_in)?)
}
RsaSignAlgorithm::Rs512 => {
let raw_in = digestutil::sha512_bytes(message);
let raw_in = iff!(is_raw, digestutil::sha512_bytes(message), message.to_vec());
Ok(rsa_private_key.sign(Pkcs1v15Sign::new::<Sha512>(), &raw_in)?)
}
}

View File

@@ -2,7 +2,7 @@ use crate::util::{base64_decode, base64_encode};
use rust_util::XResult;
use se_tool::KeyPurpose;
use swift_secure_enclave_tool_rs as se_tool;
use swift_secure_enclave_tool_rs::ControlFlag;
use swift_secure_enclave_tool_rs::{ControlFlag, DigestType};
pub fn is_support_se() -> bool {
se_tool::is_secure_enclave_supported().unwrap_or_else(|e| {
@@ -62,8 +62,8 @@ pub fn secure_enclave_p256_dh(
Ok(shared_secret)
}
pub fn secure_enclave_p256_sign(private_key: &str, content: &[u8]) -> XResult<Vec<u8>> {
pub fn secure_enclave_p256_sign(private_key: &str, content: &[u8], digest_type: DigestType) -> XResult<Vec<u8>> {
let private_key_representation = base64_decode(private_key)?;
let signature = se_tool::private_key_sign(&private_key_representation, content)?;
let signature = se_tool::private_key_sign_digested(&private_key_representation, content, digest_type)?;
Ok(signature)
}
}