feat: v1.13.0

This commit is contained in:
2025-05-07 23:54:20 +08:00
parent 06d2da4ddf
commit a1ae0ff4dc
11 changed files with 193 additions and 65 deletions

90
Cargo.lock generated
View File

@@ -166,7 +166,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.40", "quote 1.0.40",
"syn 2.0.101", "syn 2.0.101",
"synstructure 0.13.1", "synstructure 0.13.2",
] ]
[[package]] [[package]]
@@ -242,7 +242,7 @@ dependencies = [
"serde_bytes", "serde_bytes",
"serde_cbor", "serde_cbor",
"serde_json", "serde_json",
"sha2 0.10.8", "sha2 0.10.9",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@@ -508,7 +508,7 @@ dependencies = [
[[package]] [[package]]
name = "card-cli" name = "card-cli"
version = "1.12.10" version = "1.13.0"
dependencies = [ dependencies = [
"aes-gcm-stream", "aes-gcm-stream",
"authenticator 0.3.1", "authenticator 0.3.1",
@@ -544,7 +544,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha1", "sha1",
"sha2 0.10.8", "sha2 0.10.9",
"simpledateformat", "simpledateformat",
"spki 0.7.3", "spki 0.7.3",
"ssh-agent", "ssh-agent",
@@ -561,9 +561,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.20" version = "1.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@@ -1442,7 +1442,7 @@ dependencies = [
"http", "http",
"indexmap", "indexmap",
"slab", "slab",
"tokio 1.44.2", "tokio 1.45.0",
"tokio-util", "tokio-util",
"tracing", "tracing",
] ]
@@ -1455,9 +1455,9 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.2" version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -1482,9 +1482,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.5.0" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
[[package]] [[package]]
name = "hex" name = "hex"
@@ -1593,7 +1593,7 @@ dependencies = [
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio 1.44.2", "tokio 1.45.0",
"tower-service", "tower-service",
"tracing", "tracing",
"want", "want",
@@ -1608,7 +1608,7 @@ dependencies = [
"bytes 1.10.1", "bytes 1.10.1",
"hyper", "hyper",
"native-tls", "native-tls",
"tokio 1.44.2", "tokio 1.45.0",
"tokio-native-tls", "tokio-native-tls",
] ]
@@ -1815,7 +1815,7 @@ version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [ dependencies = [
"hermit-abi 0.5.0", "hermit-abi 0.5.1",
"libc", "libc",
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@@ -1866,7 +1866,7 @@ dependencies = [
"hmac 0.12.1", "hmac 0.12.1",
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.10.8", "sha2 0.10.9",
] ]
[[package]] [[package]]
@@ -1952,9 +1952,9 @@ dependencies = [
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.13" version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]] [[package]]
name = "libredox" name = "libredox"
@@ -2427,9 +2427,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.107" version = "0.9.108"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@@ -2445,7 +2445,7 @@ checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594"
dependencies = [ dependencies = [
"ecdsa 0.14.8", "ecdsa 0.14.8",
"elliptic-curve 0.12.3", "elliptic-curve 0.12.3",
"sha2 0.10.8", "sha2 0.10.9",
] ]
[[package]] [[package]]
@@ -2457,7 +2457,7 @@ dependencies = [
"ecdsa 0.16.9", "ecdsa 0.16.9",
"elliptic-curve 0.13.8", "elliptic-curve 0.13.8",
"primeorder", "primeorder",
"sha2 0.10.8", "sha2 0.10.9",
] ]
[[package]] [[package]]
@@ -2468,7 +2468,7 @@ checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa"
dependencies = [ dependencies = [
"ecdsa 0.14.8", "ecdsa 0.14.8",
"elliptic-curve 0.12.3", "elliptic-curve 0.12.3",
"sha2 0.10.8", "sha2 0.10.9",
] ]
[[package]] [[package]]
@@ -2480,7 +2480,7 @@ dependencies = [
"ecdsa 0.16.9", "ecdsa 0.16.9",
"elliptic-curve 0.13.8", "elliptic-curve 0.13.8",
"primeorder", "primeorder",
"sha2 0.10.8", "sha2 0.10.9",
] ]
[[package]] [[package]]
@@ -2494,7 +2494,7 @@ dependencies = [
"elliptic-curve 0.13.8", "elliptic-curve 0.13.8",
"primeorder", "primeorder",
"rand_core 0.6.4", "rand_core 0.6.4",
"sha2 0.10.8", "sha2 0.10.9",
] ]
[[package]] [[package]]
@@ -2552,7 +2552,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"redox_syscall 0.5.11", "redox_syscall 0.5.12",
"smallvec 1.15.0", "smallvec 1.15.0",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
@@ -2952,9 +2952,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.11" version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
] ]
@@ -3023,7 +3023,7 @@ dependencies = [
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper", "sync_wrapper",
"system-configuration", "system-configuration",
"tokio 1.44.2", "tokio 1.45.0",
"tokio-native-tls", "tokio-native-tls",
"tower-service", "tower-service",
"url", "url",
@@ -3149,7 +3149,7 @@ dependencies = [
"pkcs1 0.7.5", "pkcs1 0.7.5",
"pkcs8 0.10.2", "pkcs8 0.10.2",
"rand_core 0.6.4", "rand_core 0.6.4",
"sha2 0.10.8", "sha2 0.10.9",
"signature 2.2.0", "signature 2.2.0",
"spki 0.7.3", "spki 0.7.3",
"subtle", "subtle",
@@ -3249,9 +3249,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "1.0.5" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [ dependencies = [
"bitflags 2.9.0", "bitflags 2.9.0",
"errno", "errno",
@@ -3545,9 +3545,9 @@ dependencies = [
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.10.8" version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
@@ -3823,9 +3823,9 @@ dependencies = [
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.13.1" version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.40", "quote 1.0.40",
@@ -3892,7 +3892,7 @@ dependencies = [
"fastrand", "fastrand",
"getrandom 0.3.2", "getrandom 0.3.2",
"once_cell", "once_cell",
"rustix 1.0.5", "rustix 1.0.7",
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
@@ -4063,9 +4063,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.44.2" version = "1.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes 1.10.1", "bytes 1.10.1",
@@ -4136,7 +4136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [ dependencies = [
"native-tls", "native-tls",
"tokio 1.44.2", "tokio 1.45.0",
] ]
[[package]] [[package]]
@@ -4254,7 +4254,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"pin-project-lite", "pin-project-lite",
"tokio 1.44.2", "tokio 1.45.0",
] ]
[[package]] [[package]]
@@ -4548,7 +4548,7 @@ checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
dependencies = [ dependencies = [
"either", "either",
"env_home", "env_home",
"rustix 1.0.5", "rustix 1.0.7",
"winsafe", "winsafe",
] ]
@@ -4951,7 +4951,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.40", "quote 1.0.40",
"syn 2.0.101", "syn 2.0.101",
"synstructure 0.13.1", "synstructure 0.13.2",
] ]
[[package]] [[package]]
@@ -4996,7 +4996,7 @@ dependencies = [
"rsa 0.7.2", "rsa 0.7.2",
"secrecy", "secrecy",
"sha1", "sha1",
"sha2 0.10.8", "sha2 0.10.9",
"subtle", "subtle",
"uuid", "uuid",
"x509", "x509",
@@ -5029,7 +5029,7 @@ dependencies = [
"rsa 0.9.8", "rsa 0.9.8",
"secrecy", "secrecy",
"sha1", "sha1",
"sha2 0.10.8", "sha2 0.10.9",
"signature 2.2.0", "signature 2.2.0",
"subtle", "subtle",
"uuid", "uuid",
@@ -5075,7 +5075,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote 1.0.40", "quote 1.0.40",
"syn 2.0.101", "syn 2.0.101",
"synstructure 0.13.1", "synstructure 0.13.2",
] ]
[[package]] [[package]]

View File

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

View File

@@ -33,8 +33,14 @@ impl Command for CommandImpl {
} }
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError { fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
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_bytes = base64_decode(message_base64)?;
let mut json = BTreeMap::new(); let mut json = BTreeMap::new();
match sign(sub_arg_matches) { let key_uri = parse_key_uri(parameter)?;
match sign(alg, &message_bytes, key_uri, sub_arg_matches) {
Ok(signature_bytes) => { Ok(signature_bytes) => {
json.insert("success", Value::Bool(true)); json.insert("success", Value::Bool(true));
json.insert("signature_base64", base64_encode(&signature_bytes).into()); json.insert("signature_base64", base64_encode(&signature_bytes).into());
@@ -50,13 +56,7 @@ impl Command for CommandImpl {
} }
} }
fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> { pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
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 key_uri = parse_key_uri(parameter)?;
let message_bytes = base64_decode(message_base64)?;
match key_uri { match key_uri {
KeyUri::SecureEnclaveKey(key) => { KeyUri::SecureEnclaveKey(key) => {
if "ES256" != alg { if "ES256" != alg {
@@ -65,7 +65,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
if key.usage != KeyUsage::Singing { if key.usage != KeyUsage::Singing {
return simple_error!("Not singing key"); return simple_error!("Not singing key");
} }
seutil::secure_enclave_p256_sign(&key.private_key, &message_bytes) seutil::secure_enclave_p256_sign(&key.private_key, message)
} }
KeyUri::YubikeyPivKey(key) => { KeyUri::YubikeyPivKey(key) => {
let mut yk = yubikeyutil::open_yubikey_with_args(sub_arg_matches)?; let mut yk = yubikeyutil::open_yubikey_with_args(sub_arg_matches)?;
@@ -86,7 +86,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
"Yubikey not supported algorithm: {}", "Yubikey not supported algorithm: {}",
key.algorithm.to_str() key.algorithm.to_str()
); );
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &message_bytes)?; let raw_in = digest_by_jwt_algorithm(jwt_algorithm, message)?;
let signed_data = opt_result!( let signed_data = opt_result!(
sign_data(&mut yk, &raw_in, algorithm, key.slot), sign_data(&mut yk, &raw_in, algorithm, key.slot),
"Sign YubiKey failed: {}" "Sign YubiKey failed: {}"
@@ -98,7 +98,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
let private_key = cmd_hmac_decrypt::try_decrypt(&key.hmac_enc_private_key)?; let private_key = cmd_hmac_decrypt::try_decrypt(&key.hmac_enc_private_key)?;
let (jwt_algorithm, private_key_d) = parse_ecdsa_private_key(&private_key)?; let (jwt_algorithm, private_key_d) = parse_ecdsa_private_key(&private_key)?;
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &message_bytes)?; let raw_in = digest_by_jwt_algorithm(jwt_algorithm, message)?;
let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?; let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?;
let signed_data = ecdsautil::ecdsa_sign( let signed_data = ecdsautil::ecdsa_sign(
ecdsa_algorithm, ecdsa_algorithm,
@@ -116,7 +116,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
let rsa_sign_algorithm = let rsa_sign_algorithm =
opt_value_result!(RsaSignAlgorithm::from_str(alg), "Invalid --alg: {}", alg); opt_value_result!(RsaSignAlgorithm::from_str(alg), "Invalid --alg: {}", alg);
rsautil::sign(&rsa_private_key, rsa_sign_algorithm, &message_bytes) rsautil::sign(&rsa_private_key, rsa_sign_algorithm, message)
} else { } else {
simple_error!("Invalid algorithm: {}", key.algorithm.to_str()) simple_error!("Invalid algorithm: {}", key.algorithm.to_str())
} }

85
src/cmd_sign_jwt.rs Normal file
View File

@@ -0,0 +1,85 @@
use crate::cmd_sign_jwt_piv::{
build_jwt_parts, fill_sign_jwt_app_args, merge_header_claims,
merge_payload_claims, print_jwt_token,
};
use crate::ecdsautil::parse_ecdsa_to_rs;
use crate::keyutil::parse_key_uri;
use crate::{cmd_external_sign, cmdutil, util};
use clap::{App, ArgMatches, SubCommand};
use jwt::ToBase64;
use jwt::{AlgorithmType, Header};
use rust_util::util_clap::{Command, CommandError};
use rust_util::XResult;
use serde_json::{Map, Value};
use crate::pivutil::ToStr;
const SEPARATOR: &str = ".";
pub struct CommandImpl;
impl Command for CommandImpl {
fn name(&self) -> &str {
"sign-jwt"
}
fn subcommand<'a>(&self) -> App<'a, 'a> {
let app = SubCommand::with_name(self.name())
.about("Sign JWT subcommand")
.arg(cmdutil::build_key_uri_arg().required(false))
.arg(cmdutil::build_parameter_arg().required(false))
.arg(cmdutil::build_pin_arg())
.arg(cmdutil::build_serial_arg())
.arg(cmdutil::build_json_arg());
fill_sign_jwt_app_args(app)
}
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
let json_output = cmdutil::check_json_output(sub_arg_matches);
let (header, payload, jwt_claims) = build_jwt_parts(sub_arg_matches)?;
let token_string = sign_jwt(header, &payload, &jwt_claims, sub_arg_matches)?;
print_jwt_token(json_output, token_string);
Ok(None)
}
}
fn sign_jwt(
mut header: Header,
payload: &Option<String>,
claims: &Map<String, Value>,
sub_arg_matches: &ArgMatches,
) -> XResult<String> {
let key = match sub_arg_matches.value_of("key") {
Some(key) => key,
None => match sub_arg_matches.value_of("parameter") {
Some(parameter) => parameter,
None => return simple_error!("Parameter --key or --parameter required"),
}
};
let key_uri = parse_key_uri(key)?;
let jwt_algorithm = key_uri.get_preferred_algorithm_type();
header.algorithm = jwt_algorithm;
debugging!("Header: {:?}", header);
debugging!("Claims: {:?}", claims);
let header = opt_result!(header.to_base64(), "Header to base64 failed: {}");
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 signed_data = match jwt_algorithm {
AlgorithmType::Rs256 => signature,
AlgorithmType::Es256 | AlgorithmType::Es384 | AlgorithmType::Es512 => {
parse_ecdsa_to_rs(signature.as_slice())?
}
_ => return simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm),
};
let signature = util::base64_encode_url_safe_no_pad(&signed_data);
Ok([&*header, &*claims, &signature].join(SEPARATOR))
}

View File

@@ -19,11 +19,11 @@ pub struct CommandImpl;
impl Command for CommandImpl { impl Command for CommandImpl {
fn name(&self) -> &str { fn name(&self) -> &str {
"sign-jwt" "sign-jwt-piv"
} }
fn subcommand<'a>(&self) -> App<'a, 'a> { fn subcommand<'a>(&self) -> App<'a, 'a> {
let app = SubCommand::with_name(self.name()).about("Sign JWT subcommand") let app = SubCommand::with_name(self.name()).about("Sign JWT(PIV) subcommand")
.arg(cmdutil::build_slot_arg()) .arg(cmdutil::build_slot_arg())
.arg(cmdutil::build_pin_arg()) .arg(cmdutil::build_pin_arg())
.arg(cmdutil::build_no_pin_arg()) .arg(cmdutil::build_no_pin_arg())

View File

@@ -21,7 +21,7 @@ impl Command for CommandImpl {
} }
fn subcommand<'a>(&self) -> App<'a, 'a> { fn subcommand<'a>(&self) -> App<'a, 'a> {
let app = SubCommand::with_name(self.name()).about("Sign JWT subcommand") let app = SubCommand::with_name(self.name()).about("Sign JWT(SE) subcommand")
.arg(cmdutil::build_key_uri_arg()) .arg(cmdutil::build_key_uri_arg())
.arg(cmdutil::build_json_arg()); .arg(cmdutil::build_json_arg());
cmd_sign_jwt_piv::fill_sign_jwt_app_args(app) cmd_sign_jwt_piv::fill_sign_jwt_app_args(app)

View File

@@ -19,7 +19,7 @@ impl Command for CommandImpl {
} }
fn subcommand<'a>(&self) -> App<'a, 'a> { fn subcommand<'a>(&self) -> App<'a, 'a> {
let app = SubCommand::with_name(self.name()).about("Sign JWT subcommand") let app = SubCommand::with_name(self.name()).about("Sign JWT(Soft EC) subcommand")
.arg(Arg::with_name("private-key").short("k").long("private-key").takes_value(true).help("Private key PKCS#8")) .arg(Arg::with_name("private-key").short("k").long("private-key").takes_value(true).help("Private key PKCS#8"))
.arg(cmdutil::build_json_arg()); .arg(cmdutil::build_json_arg());
cmd_sign_jwt_piv::fill_sign_jwt_app_args(app) cmd_sign_jwt_piv::fill_sign_jwt_app_args(app)

View File

@@ -54,10 +54,14 @@ pub fn parse_ecdsa_r_and_s(signature_der: &[u8]) -> XResult<(Vec<u8>, Vec<u8>)>
Ok((vec_r, vec_s)) Ok((vec_r, vec_s))
} }
const P256_LEN: usize = 32;
const P384_LEN: usize = 48;
const P521_LEN: usize = 66;
fn trim_ecdsa_point_coord(p: &[u8]) -> Vec<u8> { fn trim_ecdsa_point_coord(p: &[u8]) -> Vec<u8> {
if p.len() == ((256 / 8) + 1) || p.len() == ((384 / 8) + 1) { if p.len() == (P256_LEN + 1) || p.len() == (P384_LEN + 1) || p.len() == (P521_LEN + 1) {
p[1..].to_vec() p[1..].to_vec()
} else if p.len() == ((256 / 8) - 1) || p.len() == ((384 / 8) - 1) { } else if p.len() == (P256_LEN - 1) || p.len() == (P384_LEN - 1) || p.len() == (P521_LEN - 1) {
let mut v = vec![]; let mut v = vec![];
v.push(0_u8); v.push(0_u8);
v.extend_from_slice(p); v.extend_from_slice(p);

View File

@@ -1,3 +1,4 @@
use jwt::AlgorithmType;
use crate::pivutil::{FromStr, ToStr}; use crate::pivutil::{FromStr, ToStr};
use regex::Regex; use regex::Regex;
use rust_util::XResult; use rust_util::XResult;
@@ -18,6 +19,21 @@ impl KeyUri {
_ => simple_error!("Not a secure enclave key."), _ => simple_error!("Not a secure enclave key."),
} }
} }
pub fn get_preferred_algorithm_type(&self) -> AlgorithmType {
let algorithm_id = match &self {
KeyUri::SecureEnclaveKey(_) => return AlgorithmType::Es256,
KeyUri::YubikeyPivKey(key) => key.algorithm,
KeyUri::YubikeyHmacEncSoftKey(key) => key.algorithm,
};
match algorithm_id {
KeyAlgorithmId::Rsa1024 | KeyAlgorithmId::Rsa2048
| KeyAlgorithmId::Rsa3072 | KeyAlgorithmId::Rsa4096 => AlgorithmType::Rs256,
KeyAlgorithmId::EccP256 => AlgorithmType::Es256,
KeyAlgorithmId::EccP384 => AlgorithmType::Es384,
KeyAlgorithmId::EccP521 => AlgorithmType::Es512,
}
}
} }
impl ToString for KeyUri { impl ToString for KeyUri {

View File

@@ -49,6 +49,7 @@ mod cmd_se_ecdh;
mod cmd_se_ecsign; mod cmd_se_ecsign;
mod cmd_se_generate; mod cmd_se_generate;
mod cmd_se_recover; mod cmd_se_recover;
mod cmd_sign_jwt;
mod cmd_sign_jwt_piv; mod cmd_sign_jwt_piv;
mod cmd_sign_jwt_se; mod cmd_sign_jwt_se;
mod cmd_sign_jwt_soft; mod cmd_sign_jwt_soft;
@@ -69,6 +70,7 @@ mod fidoutil;
mod hmacutil; mod hmacutil;
mod keychain; mod keychain;
mod keyutil; mod keyutil;
mod pbeutil;
mod pgpcardutil; mod pgpcardutil;
mod pinutil; mod pinutil;
mod pivutil; mod pivutil;
@@ -79,7 +81,6 @@ mod signfile;
mod sshutil; mod sshutil;
mod util; mod util;
mod yubikeyutil; mod yubikeyutil;
mod pbeutil;
pub struct DefaultCommandImpl; pub struct DefaultCommandImpl;
@@ -145,6 +146,7 @@ fn inner_main() -> CommandError {
Box::new(cmd_sign_jwt_piv::CommandImpl), Box::new(cmd_sign_jwt_piv::CommandImpl),
Box::new(cmd_sign_jwt_soft::CommandImpl), Box::new(cmd_sign_jwt_soft::CommandImpl),
Box::new(cmd_sign_jwt_se::CommandImpl), Box::new(cmd_sign_jwt_se::CommandImpl),
Box::new(cmd_sign_jwt::CommandImpl),
Box::new(cmd_file_sign::CommandImpl), Box::new(cmd_file_sign::CommandImpl),
Box::new(cmd_file_verify::CommandImpl), Box::new(cmd_file_verify::CommandImpl),
Box::new(cmd_se::CommandImpl), Box::new(cmd_se::CommandImpl),

View File

@@ -1,4 +1,5 @@
use clap::ArgMatches; use clap::ArgMatches;
use jwt::AlgorithmType;
use rust_util::XResult; use rust_util::XResult;
use spki::{ObjectIdentifier, SubjectPublicKeyInfoOwned}; use spki::{ObjectIdentifier, SubjectPublicKeyInfoOwned};
use spki::der::{Decode, Encode}; use spki::der::{Decode, Encode};
@@ -62,6 +63,26 @@ pub trait FromStr {
Self: Sized; Self: Sized;
} }
impl ToStr for AlgorithmType {
fn to_str(&self) -> &str {
match self {
AlgorithmType::Hs256 => "HS256",
AlgorithmType::Hs384 => "HS384",
AlgorithmType::Hs512 => "HS512",
AlgorithmType::Rs256 => "RS256",
AlgorithmType::Rs384 => "RS384",
AlgorithmType::Rs512 => "RS512",
AlgorithmType::Es256 => "ES256",
AlgorithmType::Es384 => "ES384",
AlgorithmType::Es512 => "ES512",
AlgorithmType::Ps256 => "PS256",
AlgorithmType::Ps384 => "PS384",
AlgorithmType::Ps512 => "PS512",
AlgorithmType::None => "NONE",
}
}
}
impl ToStr for PinPolicy { impl ToStr for PinPolicy {
fn to_str(&self) -> &str { fn to_str(&self) -> &str {
match self { match self {