feat: v1.12.3
This commit is contained in:
29
Cargo.lock
generated
29
Cargo.lock
generated
@@ -508,7 +508,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.12.2"
|
version = "1.12.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm-stream",
|
"aes-gcm-stream",
|
||||||
"authenticator 0.3.1",
|
"authenticator 0.3.1",
|
||||||
@@ -551,6 +551,7 @@ dependencies = [
|
|||||||
"swift-secure-enclave-tool-rs",
|
"swift-secure-enclave-tool-rs",
|
||||||
"tabled",
|
"tabled",
|
||||||
"u2f-hatter-fork",
|
"u2f-hatter-fork",
|
||||||
|
"which 7.0.3",
|
||||||
"x509",
|
"x509",
|
||||||
"x509-parser 0.15.1",
|
"x509-parser 0.15.1",
|
||||||
"yubico_manager",
|
"yubico_manager",
|
||||||
@@ -1096,6 +1097,12 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_home"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@@ -2663,7 +2670,7 @@ dependencies = [
|
|||||||
"nom 7.1.3",
|
"nom 7.1.3",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"secrecy",
|
"secrecy",
|
||||||
"which",
|
"which 4.4.2",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4518,6 +4525,18 @@ dependencies = [
|
|||||||
"rustix 0.38.44",
|
"rustix 0.38.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "which"
|
||||||
|
version = "7.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
"env_home",
|
||||||
|
"rustix 1.0.5",
|
||||||
|
"winsafe",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@@ -4778,6 +4797,12 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winsafe"
|
||||||
|
version = "0.0.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-rt"
|
name = "wit-bindgen-rt"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.12.2"
|
version = "1.12.3"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ swift-secure-enclave-tool-rs = "0.1"
|
|||||||
u2f-hatter-fork = "0.2"
|
u2f-hatter-fork = "0.2"
|
||||||
security-framework = { version = "3.0", features = ["OSX_10_15"] }
|
security-framework = { version = "3.0", features = ["OSX_10_15"] }
|
||||||
rsa = "0.9.8"
|
rsa = "0.9.8"
|
||||||
|
which = "7.0.3"
|
||||||
#lazy_static = "1.4.0"
|
#lazy_static = "1.4.0"
|
||||||
#ssh-key = "0.4.0"
|
#ssh-key = "0.4.0"
|
||||||
#ctap-hid-fido2 = "2.1.3"
|
#ctap-hid-fido2 = "2.1.3"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ impl Command for CommandImpl {
|
|||||||
json.insert("signature_hex", hex::encode(&signature));
|
json.insert("signature_hex", hex::encode(&signature));
|
||||||
}
|
}
|
||||||
|
|
||||||
match ecdsautil::ecdsaverify(ecdsa_algorithm, &public_key, &hash_bytes, &signature) {
|
match ecdsautil::ecdsa_verify(ecdsa_algorithm, &public_key, &hash_bytes, &signature) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
success!("Verify ECDSA succeed.");
|
success!("Verify ECDSA succeed.");
|
||||||
if json_output {
|
if json_output {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ use rust_util::XResult;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use yubikey::piv::{sign_data, AlgorithmId};
|
use yubikey::piv::{sign_data, AlgorithmId};
|
||||||
use crate::cmd_sign_jwt_soft::parse_ecdsa_private_key;
|
use crate::cmd_sign_jwt_soft::{convert_jwt_algorithm_to_ecdsa_algorithm, parse_ecdsa_private_key};
|
||||||
|
use crate::ecdsautil::EcdsaSignType;
|
||||||
|
|
||||||
pub struct CommandImpl;
|
pub struct CommandImpl;
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
|||||||
let mut yk = yubikeyutil::open_yubikey_with_args(sub_arg_matches)?;
|
let mut yk = yubikeyutil::open_yubikey_with_args(sub_arg_matches)?;
|
||||||
let pin_opt = pivutil::check_read_pin(&mut yk, key.slot, sub_arg_matches);
|
let pin_opt = pivutil::check_read_pin(&mut yk, key.slot, sub_arg_matches);
|
||||||
|
|
||||||
// FIXME Check Yubikey slot algorithm
|
// FIXME Check YubiKey slot algorithm
|
||||||
let jwt_algorithm = get_jwt_algorithm(&key, alg)?;
|
let jwt_algorithm = get_jwt_algorithm(&key, alg)?;
|
||||||
|
|
||||||
if let Some(pin) = pin_opt {
|
if let Some(pin) = pin_opt {
|
||||||
@@ -90,11 +91,9 @@ fn sign(sub_arg_matches: &ArgMatches) -> XResult<Vec<u8>> {
|
|||||||
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_bytes)?;
|
||||||
let signed_data = match jwt_algorithm {
|
let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?;
|
||||||
AlgorithmType::Es256 => ecdsautil::sign_p256_der(&private_key_d, &raw_in)?,
|
let signed_data = ecdsautil::ecdsa_sign(ecdsa_algorithm, &private_key_d, &raw_in, EcdsaSignType::Der)?;
|
||||||
AlgorithmType::Es384 => ecdsautil::sign_p384_der(&private_key_d, &raw_in)?,
|
|
||||||
_ => return simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm),
|
|
||||||
};
|
|
||||||
Ok(signed_data)
|
Ok(signed_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ impl Command for CommandImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let algorithm = iff!(algorithm_id == AlgorithmId::EccP256, EcdsaAlgorithm::P256, EcdsaAlgorithm::P384);
|
let algorithm = iff!(algorithm_id == AlgorithmId::EccP256, EcdsaAlgorithm::P256, EcdsaAlgorithm::P384);
|
||||||
match ecdsautil::ecdsaverify(algorithm, pk_point, &hash_bytes, &signature) {
|
match ecdsautil::ecdsa_verify(algorithm, pk_point, &hash_bytes, &signature) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
success!("Verify ECDSA succeed.");
|
success!("Verify ECDSA succeed.");
|
||||||
if json_output {
|
if json_output {
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ 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 json_output = cmdutil::check_json_output(sub_arg_matches);
|
let json_output = cmdutil::check_json_output(sub_arg_matches);
|
||||||
|
|
||||||
|
if let Err(_) = which::which("swift-secure-enclave-tool") {
|
||||||
|
failure!("Secure Enclave tool not found.");
|
||||||
|
}
|
||||||
|
|
||||||
if json_output {
|
if json_output {
|
||||||
let mut json = BTreeMap::new();
|
let mut json = BTreeMap::new();
|
||||||
json.insert("se_supported", seutil::is_support_se());
|
json.insert("se_supported", seutil::is_support_se());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use serde_json::{Map, Value};
|
|||||||
use crate::cmd_sign_jwt::{build_jwt_parts, digest_by_jwt_algorithm, merge_header_claims, merge_payload_claims, print_jwt_token};
|
use crate::cmd_sign_jwt::{build_jwt_parts, digest_by_jwt_algorithm, merge_header_claims, merge_payload_claims, print_jwt_token};
|
||||||
use crate::keychain::{KeychainKey, KeychainKeyValue};
|
use crate::keychain::{KeychainKey, KeychainKeyValue};
|
||||||
use crate::{cmd_sign_jwt, cmdutil, ecdsautil, hmacutil, keychain, util};
|
use crate::{cmd_sign_jwt, cmdutil, ecdsautil, hmacutil, keychain, util};
|
||||||
|
use crate::ecdsautil::{EcdsaAlgorithm, EcdsaSignType};
|
||||||
|
|
||||||
const SEPARATOR: &str = ".";
|
const SEPARATOR: &str = ".";
|
||||||
|
|
||||||
@@ -76,18 +77,22 @@ fn sign_jwt(
|
|||||||
let tobe_signed = merge_header_claims(header.as_bytes(), claims.as_bytes());
|
let tobe_signed = merge_header_claims(header.as_bytes(), claims.as_bytes());
|
||||||
|
|
||||||
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &tobe_signed)?;
|
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, &tobe_signed)?;
|
||||||
|
let ecdsa_algorithm = convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm)?;
|
||||||
let signed_data = match jwt_algorithm {
|
let signed_data = ecdsautil::ecdsa_sign(ecdsa_algorithm, &private_key_d, &raw_in, EcdsaSignType::Rs)?;
|
||||||
AlgorithmType::Es256 => ecdsautil::sign_p256_rs(&private_key_d, &raw_in)?,
|
|
||||||
AlgorithmType::Es384 => ecdsautil::sign_p384_rs(&private_key_d, &raw_in)?,
|
|
||||||
_ => 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))
|
Ok([&*header, &*claims, &signature].join(SEPARATOR))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn convert_jwt_algorithm_to_ecdsa_algorithm(jwt_algorithm: AlgorithmType) -> XResult<EcdsaAlgorithm> {
|
||||||
|
match jwt_algorithm {
|
||||||
|
AlgorithmType::Es256 => Ok(EcdsaAlgorithm::P256),
|
||||||
|
AlgorithmType::Es384 => Ok(EcdsaAlgorithm::P384),
|
||||||
|
_ => simple_error!("SHOULD NOT HAPPEN: {:?}", jwt_algorithm),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_ecdsa_private_key(private_key: &str) -> XResult<(AlgorithmType, Vec<u8>)> {
|
pub fn parse_ecdsa_private_key(private_key: &str) -> XResult<(AlgorithmType, Vec<u8>)> {
|
||||||
let p256_private_key_d = ecdsautil::parse_p256_private_key(private_key).ok();
|
let p256_private_key_d = ecdsautil::parse_p256_private_key(private_key).ok();
|
||||||
let p384_private_key_d = ecdsautil::parse_p384_private_key(private_key).ok();
|
let p384_private_key_d = ecdsautil::parse_p384_private_key(private_key).ok();
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ pub enum EcdsaAlgorithm {
|
|||||||
P384,
|
P384,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum EcdsaSignType {
|
||||||
|
Der, Rs,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_ecdsa_to_rs(signature_der: &[u8]) -> XResult<Vec<u8>> {
|
pub fn parse_ecdsa_to_rs(signature_der: &[u8]) -> XResult<Vec<u8>> {
|
||||||
let (mut r, s)= parse_ecdsa_r_and_s(signature_der)?;
|
let (mut r, s)= parse_ecdsa_r_and_s(signature_der)?;
|
||||||
r.extend_from_slice(&s);
|
r.extend_from_slice(&s);
|
||||||
@@ -132,44 +137,35 @@ pub fn parse_p384_private_key(private_key_pkcs8: &str) -> XResult<Vec<u8>> {
|
|||||||
parse_ecdsa_private_key!(p384, private_key_pkcs8)
|
parse_ecdsa_private_key!(p384, private_key_pkcs8)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_p256_rs(private_key_d: &[u8], pre_hash: &[u8]) -> XResult<Vec<u8>> {
|
macro_rules! sign_ecdsa_rs_or_der {
|
||||||
use p256::ecdsa::{SigningKey, Signature};
|
($algo: tt, $private_key_d: tt, $pre_hash: tt, $is_rs: tt) => ({
|
||||||
use p256::ecdsa::signature::hazmat::PrehashSigner;
|
use $algo::ecdsa::{SigningKey, Signature};
|
||||||
|
use $algo::ecdsa::signature::hazmat::PrehashSigner;
|
||||||
|
|
||||||
let signing_key = SigningKey::from_slice(private_key_d)?;
|
let signing_key = SigningKey::from_slice($private_key_d)?;
|
||||||
let signature: Signature = signing_key.sign_prehash(pre_hash)?;
|
let signature: Signature = signing_key.sign_prehash($pre_hash)?;
|
||||||
|
|
||||||
Ok(signature.to_bytes().to_vec())
|
if $is_rs {
|
||||||
|
Ok(signature.to_bytes().to_vec())
|
||||||
|
} else {
|
||||||
|
Ok(signature.to_der().as_bytes().to_vec())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_p256_der(private_key_d: &[u8], pre_hash: &[u8]) -> XResult<Vec<u8>> {
|
pub fn ecdsa_sign(algo: EcdsaAlgorithm, private_key_d: &[u8], pre_hash: &[u8], sign_type: EcdsaSignType) -> XResult<Vec<u8>> {
|
||||||
use p256::ecdsa::{SigningKey, Signature};
|
match algo {
|
||||||
use p256::ecdsa::signature::hazmat::PrehashSigner;
|
EcdsaAlgorithm::P256 => sign_p256_rs_or_der(private_key_d, pre_hash, sign_type == EcdsaSignType::Rs),
|
||||||
|
EcdsaAlgorithm::P384 => sign_p384_rs_or_der(private_key_d, pre_hash, sign_type == EcdsaSignType::Rs),
|
||||||
let signing_key = SigningKey::from_slice(private_key_d)?;
|
}
|
||||||
let signature: Signature = signing_key.sign_prehash(pre_hash)?;
|
|
||||||
|
|
||||||
Ok(signature.to_der().as_bytes().to_vec())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_p384_rs(private_key_d: &[u8], pre_hash: &[u8]) -> XResult<Vec<u8>> {
|
pub fn sign_p256_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) -> XResult<Vec<u8>> {
|
||||||
use p384::ecdsa::{SigningKey, Signature};
|
sign_ecdsa_rs_or_der!(p256, private_key_d, pre_hash, is_rs)
|
||||||
use p384::ecdsa::signature::hazmat::PrehashSigner;
|
|
||||||
|
|
||||||
let signing_key = SigningKey::from_slice(private_key_d)?;
|
|
||||||
let signature: Signature = signing_key.sign_prehash(pre_hash)?;
|
|
||||||
|
|
||||||
Ok(signature.to_bytes().to_vec())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_p384_der(private_key_d: &[u8], pre_hash: &[u8]) -> XResult<Vec<u8>> {
|
pub fn sign_p384_rs_or_der(private_key_d: &[u8], pre_hash: &[u8], is_rs: bool) -> XResult<Vec<u8>> {
|
||||||
use p384::ecdsa::{SigningKey, Signature};
|
sign_ecdsa_rs_or_der!(p384, private_key_d, pre_hash, is_rs)
|
||||||
use p384::ecdsa::signature::hazmat::PrehashSigner;
|
|
||||||
|
|
||||||
let signing_key = SigningKey::from_slice(private_key_d)?;
|
|
||||||
let signature: Signature = signing_key.sign_prehash(pre_hash)?;
|
|
||||||
|
|
||||||
Ok(signature.to_der().as_bytes().to_vec())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! ecdsa_verify_signature {
|
macro_rules! ecdsa_verify_signature {
|
||||||
@@ -187,7 +183,7 @@ macro_rules! ecdsa_verify_signature {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ecdsaverify(algo: EcdsaAlgorithm, pk_point: &[u8], prehash: &[u8], signature: &[u8]) -> XResult<()> {
|
pub fn ecdsa_verify(algo: EcdsaAlgorithm, pk_point: &[u8], prehash: &[u8], signature: &[u8]) -> XResult<()> {
|
||||||
match algo {
|
match algo {
|
||||||
EcdsaAlgorithm::P256 => ecdsa_verify_signature!(NistP256, pk_point, prehash, signature),
|
EcdsaAlgorithm::P256 => ecdsa_verify_signature!(NistP256, pk_point, prehash, signature),
|
||||||
EcdsaAlgorithm::P384 => ecdsa_verify_signature!(NistP384, pk_point, prehash, signature),
|
EcdsaAlgorithm::P384 => ecdsa_verify_signature!(NistP384, pk_point, prehash, signature),
|
||||||
|
|||||||
Reference in New Issue
Block a user