feat: v1.13.0
This commit is contained in:
@@ -33,8 +33,14 @@ impl Command for CommandImpl {
|
||||
}
|
||||
|
||||
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();
|
||||
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) => {
|
||||
json.insert("success", Value::Bool(true));
|
||||
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>> {
|
||||
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)?;
|
||||
pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
||||
match key_uri {
|
||||
KeyUri::SecureEnclaveKey(key) => {
|
||||
if "ES256" != alg {
|
||||
@@ -65,7 +65,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
||||
if key.usage != KeyUsage::Singing {
|
||||
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) => {
|
||||
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: {}",
|
||||
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!(
|
||||
sign_data(&mut yk, &raw_in, algorithm, key.slot),
|
||||
"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 (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 signed_data = ecdsautil::ecdsa_sign(
|
||||
ecdsa_algorithm,
|
||||
@@ -116,7 +116,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
||||
|
||||
let rsa_sign_algorithm =
|
||||
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 {
|
||||
simple_error!("Invalid algorithm: {}", key.algorithm.to_str())
|
||||
}
|
||||
|
||||
85
src/cmd_sign_jwt.rs
Normal file
85
src/cmd_sign_jwt.rs
Normal 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))
|
||||
}
|
||||
@@ -19,11 +19,11 @@ pub struct CommandImpl;
|
||||
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str {
|
||||
"sign-jwt"
|
||||
"sign-jwt-piv"
|
||||
}
|
||||
|
||||
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_pin_arg())
|
||||
.arg(cmdutil::build_no_pin_arg())
|
||||
|
||||
@@ -21,7 +21,7 @@ impl Command for CommandImpl {
|
||||
}
|
||||
|
||||
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_json_arg());
|
||||
cmd_sign_jwt_piv::fill_sign_jwt_app_args(app)
|
||||
|
||||
@@ -19,7 +19,7 @@ impl Command for CommandImpl {
|
||||
}
|
||||
|
||||
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(cmdutil::build_json_arg());
|
||||
cmd_sign_jwt_piv::fill_sign_jwt_app_args(app)
|
||||
|
||||
@@ -54,10 +54,14 @@ pub fn parse_ecdsa_r_and_s(signature_der: &[u8]) -> XResult<(Vec<u8>, Vec<u8>)>
|
||||
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> {
|
||||
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()
|
||||
} 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![];
|
||||
v.push(0_u8);
|
||||
v.extend_from_slice(p);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use jwt::AlgorithmType;
|
||||
use crate::pivutil::{FromStr, ToStr};
|
||||
use regex::Regex;
|
||||
use rust_util::XResult;
|
||||
@@ -18,6 +19,21 @@ impl KeyUri {
|
||||
_ => 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 {
|
||||
|
||||
@@ -49,6 +49,7 @@ mod cmd_se_ecdh;
|
||||
mod cmd_se_ecsign;
|
||||
mod cmd_se_generate;
|
||||
mod cmd_se_recover;
|
||||
mod cmd_sign_jwt;
|
||||
mod cmd_sign_jwt_piv;
|
||||
mod cmd_sign_jwt_se;
|
||||
mod cmd_sign_jwt_soft;
|
||||
@@ -69,6 +70,7 @@ mod fidoutil;
|
||||
mod hmacutil;
|
||||
mod keychain;
|
||||
mod keyutil;
|
||||
mod pbeutil;
|
||||
mod pgpcardutil;
|
||||
mod pinutil;
|
||||
mod pivutil;
|
||||
@@ -79,7 +81,6 @@ mod signfile;
|
||||
mod sshutil;
|
||||
mod util;
|
||||
mod yubikeyutil;
|
||||
mod pbeutil;
|
||||
|
||||
pub struct DefaultCommandImpl;
|
||||
|
||||
@@ -145,6 +146,7 @@ fn inner_main() -> CommandError {
|
||||
Box::new(cmd_sign_jwt_piv::CommandImpl),
|
||||
Box::new(cmd_sign_jwt_soft::CommandImpl),
|
||||
Box::new(cmd_sign_jwt_se::CommandImpl),
|
||||
Box::new(cmd_sign_jwt::CommandImpl),
|
||||
Box::new(cmd_file_sign::CommandImpl),
|
||||
Box::new(cmd_file_verify::CommandImpl),
|
||||
Box::new(cmd_se::CommandImpl),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use clap::ArgMatches;
|
||||
use jwt::AlgorithmType;
|
||||
use rust_util::XResult;
|
||||
use spki::{ObjectIdentifier, SubjectPublicKeyInfoOwned};
|
||||
use spki::der::{Decode, Encode};
|
||||
@@ -62,6 +63,26 @@ pub trait FromStr {
|
||||
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 {
|
||||
fn to_str(&self) -> &str {
|
||||
match self {
|
||||
|
||||
Reference in New Issue
Block a user