feat: v1.13.2
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -508,7 +508,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.13.1"
|
version = "1.13.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm-stream",
|
"aes-gcm-stream",
|
||||||
"authenticator 0.3.1",
|
"authenticator 0.3.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "card-cli"
|
name = "card-cli"
|
||||||
version = "1.13.1"
|
version = "1.13.2"
|
||||||
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
authors = ["Hatter Jiang <jht5945@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult<Vec<u
|
|||||||
if key.usage != KeyUsage::Singing {
|
if key.usage != KeyUsage::Singing {
|
||||||
simple_error!("Not singing key")
|
simple_error!("Not singing key")
|
||||||
} else {
|
} else {
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&key.private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.private_key)?;
|
||||||
let (_, public_key_der, _) =
|
let (_, public_key_der, _) =
|
||||||
seutil::recover_secure_enclave_p256_public_key(&private_key, true)?;
|
seutil::recover_secure_enclave_p256_public_key(&private_key, true)?;
|
||||||
Ok(public_key_der)
|
Ok(public_key_der)
|
||||||
@@ -73,7 +73,7 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult<Vec<u
|
|||||||
}
|
}
|
||||||
KeyUri::YubikeyHmacEncSoftKey(key) => {
|
KeyUri::YubikeyHmacEncSoftKey(key) => {
|
||||||
if key.algorithm.is_ecc() {
|
if key.algorithm.is_ecc() {
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&key.hmac_enc_private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.hmac_enc_private_key)?;
|
||||||
let p256_public_key = ecdsautil::parse_p256_private_key_to_public_key(&private_key).ok();
|
let p256_public_key = ecdsautil::parse_p256_private_key_to_public_key(&private_key).ok();
|
||||||
let p384_public_key = ecdsautil::parse_p384_private_key_to_public_key(&private_key).ok();
|
let p384_public_key = ecdsautil::parse_p384_private_key_to_public_key(&private_key).ok();
|
||||||
let p521_public_key = ecdsautil::parse_p521_private_key_to_public_key(&private_key).ok();
|
let p521_public_key = ecdsautil::parse_p521_private_key_to_public_key(&private_key).ok();
|
||||||
@@ -90,7 +90,7 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult<Vec<u
|
|||||||
simple_error!("Invalid hmac enc private key")
|
simple_error!("Invalid hmac enc private key")
|
||||||
} else if key.algorithm.is_rsa() {
|
} else if key.algorithm.is_rsa() {
|
||||||
use rsa::pkcs8::DecodePrivateKey;
|
use rsa::pkcs8::DecodePrivateKey;
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&key.hmac_enc_private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.hmac_enc_private_key)?;
|
||||||
let private_key_der = base64_decode(&private_key)?;
|
let private_key_der = base64_decode(&private_key)?;
|
||||||
let rsa_private_key = RsaPrivateKey::from_pkcs8_der(&private_key_der)?;
|
let rsa_private_key = RsaPrivateKey::from_pkcs8_der(&private_key_der)?;
|
||||||
Ok(rsa_private_key.to_public_key().to_public_key_der()?.to_vec())
|
Ok(rsa_private_key.to_public_key().to_public_key_der()?.to_vec())
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
|
|||||||
if key.usage != KeyUsage::Singing {
|
if key.usage != KeyUsage::Singing {
|
||||||
return simple_error!("Not singing key");
|
return simple_error!("Not singing key");
|
||||||
}
|
}
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&key.private_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)
|
||||||
}
|
}
|
||||||
KeyUri::YubikeyPivKey(key) => {
|
KeyUri::YubikeyPivKey(key) => {
|
||||||
@@ -96,7 +96,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
|
|||||||
}
|
}
|
||||||
KeyUri::YubikeyHmacEncSoftKey(key) => {
|
KeyUri::YubikeyHmacEncSoftKey(key) => {
|
||||||
if key.algorithm.is_ecc() {
|
if key.algorithm.is_ecc() {
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&key.hmac_enc_private_key)?;
|
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 (jwt_algorithm, private_key_d) = parse_ecdsa_private_key(&private_key)?;
|
||||||
|
|
||||||
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, message)?;
|
let raw_in = digest_by_jwt_algorithm(jwt_algorithm, message)?;
|
||||||
@@ -111,7 +111,7 @@ pub fn sign(alg: &str, message: &[u8], key_uri: KeyUri, sub_arg_matches: &ArgMat
|
|||||||
Ok(signed_data)
|
Ok(signed_data)
|
||||||
} else if key.algorithm.is_rsa() {
|
} else if key.algorithm.is_rsa() {
|
||||||
use rsa::pkcs8::DecodePrivateKey;
|
use rsa::pkcs8::DecodePrivateKey;
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&key.hmac_enc_private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.hmac_enc_private_key)?;
|
||||||
let private_key_der = base64_decode(&private_key)?;
|
let private_key_der = base64_decode(&private_key)?;
|
||||||
let rsa_private_key = RsaPrivateKey::from_pkcs8_der(&private_key_der)?;
|
let rsa_private_key = RsaPrivateKey::from_pkcs8_der(&private_key_der)?;
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,10 @@ impl Command for CommandImpl {
|
|||||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||||
SubCommand::with_name(self.name())
|
SubCommand::with_name(self.name())
|
||||||
.about("YubiKey HMAC decrypt")
|
.about("YubiKey HMAC decrypt")
|
||||||
.arg(
|
.arg(Arg::with_name("ciphertext").long("ciphertext").takes_value(true).required(true).help("Ciphertext"), )
|
||||||
Arg::with_name("ciphertext")
|
|
||||||
.long("ciphertext")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
.help("Ciphertext"),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("auto-pbe").long("auto-pbe").help("Auto PBE decryption"))
|
.arg(Arg::with_name("auto-pbe").long("auto-pbe").help("Auto PBE decryption"))
|
||||||
|
.arg(Arg::with_name("password").long("password").takes_value(true).help("Password"))
|
||||||
|
.arg(Arg::with_name("outputs-password").long("outputs-password").help("Outputs password"))
|
||||||
.arg(cmdutil::build_json_arg())
|
.arg(cmdutil::build_json_arg())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,13 +26,18 @@ impl Command for CommandImpl {
|
|||||||
let json_output = cmdutil::check_json_output(sub_arg_matches);
|
let json_output = cmdutil::check_json_output(sub_arg_matches);
|
||||||
|
|
||||||
let ciphertext = sub_arg_matches.value_of("ciphertext").unwrap();
|
let ciphertext = sub_arg_matches.value_of("ciphertext").unwrap();
|
||||||
|
let mut pin_opt = sub_arg_matches.value_of("password").map(|p| p.to_string());
|
||||||
let auto_pbe = sub_arg_matches.is_present("auto-pbe");
|
let auto_pbe = sub_arg_matches.is_present("auto-pbe");
|
||||||
|
let outputs_password = sub_arg_matches.is_present("outputs-password");
|
||||||
|
|
||||||
let text = try_decrypt_with_pbe_option(ciphertext, auto_pbe)?;
|
let text = try_decrypt_with_pbe_option(&mut pin_opt, ciphertext, auto_pbe)?;
|
||||||
|
|
||||||
if json_output {
|
if json_output {
|
||||||
let mut json = BTreeMap::<&'_ str, String>::new();
|
let mut json = BTreeMap::<&'_ str, String>::new();
|
||||||
json.insert("plaintext", text);
|
json.insert("plaintext", text);
|
||||||
|
if let (true, Some(pin)) = (outputs_password, pin_opt.as_ref()) {
|
||||||
|
json.insert("password", pin.to_string());
|
||||||
|
}
|
||||||
util::print_pretty_json(&json);
|
util::print_pretty_json(&json);
|
||||||
} else {
|
} else {
|
||||||
success!("Plaintext: {}", text);
|
success!("Plaintext: {}", text);
|
||||||
@@ -45,24 +46,24 @@ impl Command for CommandImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_decrypt(ciphertext: &str) -> XResult<String> {
|
pub fn try_decrypt(pin_opt: &mut Option<String>,ciphertext: &str) -> XResult<String> {
|
||||||
try_decrypt_with_pbe_option(ciphertext, true)
|
try_decrypt_with_pbe_option(pin_opt, ciphertext, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_decrypt_with_pbe_option(ciphertext: &str, auto_pbe: bool) -> XResult<String> {
|
pub fn try_decrypt_with_pbe_option(pin_opt: &mut Option<String>, ciphertext: &str, auto_pbe: bool) -> XResult<String> {
|
||||||
if is_hmac_encrypted(ciphertext) {
|
if is_hmac_encrypted(ciphertext) {
|
||||||
hmac_decrypt(ciphertext, auto_pbe)
|
hmac_decrypt(pin_opt, ciphertext, auto_pbe)
|
||||||
} else if pbeutil::is_simple_pbe_encrypted(ciphertext) {
|
} else if pbeutil::is_simple_pbe_encrypted(ciphertext) {
|
||||||
pbeutil::simple_pbe_decrypt_with_prompt_to_string(&ciphertext)
|
pbeutil::simple_pbe_decrypt_with_prompt_to_string(pin_opt,&ciphertext)
|
||||||
} else {
|
} else {
|
||||||
Ok(ciphertext.to_string())
|
Ok(ciphertext.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hmac_decrypt(ciphertext: &str, auto_pbe: bool) -> XResult<String> {
|
pub fn hmac_decrypt(pin_opt: &mut Option<String>, ciphertext: &str, auto_pbe: bool) -> XResult<String> {
|
||||||
let text = hmac_decrypt_to_string(ciphertext)?;
|
let text = hmac_decrypt_to_string(ciphertext)?;
|
||||||
if auto_pbe && pbeutil::is_simple_pbe_encrypted(&text) {
|
if auto_pbe && pbeutil::is_simple_pbe_encrypted(&text) {
|
||||||
pbeutil::simple_pbe_decrypt_with_prompt_to_string(&text)
|
pbeutil::simple_pbe_decrypt_with_prompt_to_string(pin_opt, &text)
|
||||||
} else {
|
} else {
|
||||||
Ok(text)
|
Ok(text)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ impl Command for CommandImpl {
|
|||||||
opt_result!(hex::decode(epk), "Decode public key from hex failed: {}")
|
opt_result!(hex::decode(epk), "Decode public key from hex failed: {}")
|
||||||
};
|
};
|
||||||
|
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&se_key_uri.private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &se_key_uri.private_key)?;
|
||||||
let dh = seutil::secure_enclave_p256_dh(
|
let dh = seutil::secure_enclave_p256_dh(
|
||||||
&private_key,
|
&private_key,
|
||||||
&ephemeral_public_key_der_bytes,
|
&ephemeral_public_key_der_bytes,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ impl Command for CommandImpl {
|
|||||||
let se_key_uri = key_uri.as_secure_enclave_key()?;
|
let se_key_uri = key_uri.as_secure_enclave_key()?;
|
||||||
debugging!("Secure enclave key URI: {:?}", se_key_uri);
|
debugging!("Secure enclave key URI: {:?}", se_key_uri);
|
||||||
|
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&se_key_uri.private_key)?;
|
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)?;
|
||||||
|
|
||||||
if json_output {
|
if json_output {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl Command for CommandImpl {
|
|||||||
let se_key_uri = key_uri.as_secure_enclave_key()?;
|
let se_key_uri = key_uri.as_secure_enclave_key()?;
|
||||||
debugging!("Secure enclave key URI: {:?}", se_key_uri);
|
debugging!("Secure enclave key URI: {:?}", se_key_uri);
|
||||||
|
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(&se_key_uri.private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &se_key_uri.private_key)?;
|
||||||
let (public_key_point, public_key_der, _private_key) =
|
let (public_key_point, public_key_der, _private_key) =
|
||||||
seutil::recover_secure_enclave_p256_public_key(
|
seutil::recover_secure_enclave_p256_public_key(
|
||||||
&private_key,
|
&private_key,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl Command for CommandImpl {
|
|||||||
sub_arg_matches.value_of("key"),
|
sub_arg_matches.value_of("key"),
|
||||||
"Private key PKCS#8 DER base64 encoded or PEM"
|
"Private key PKCS#8 DER base64 encoded or PEM"
|
||||||
);
|
);
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, private_key)?;
|
||||||
let key_uri = parse_key_uri(&private_key)?;
|
let key_uri = parse_key_uri(&private_key)?;
|
||||||
let se_key_uri = key_uri.as_secure_enclave_key()?;
|
let se_key_uri = key_uri.as_secure_enclave_key()?;
|
||||||
debugging!("Secure enclave key URI: {:?}", se_key_uri);
|
debugging!("Secure enclave key URI: {:?}", se_key_uri);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ impl Command for CommandImpl {
|
|||||||
"Private key PKCS#8 DER base64 encoded or PEM"
|
"Private key PKCS#8 DER base64 encoded or PEM"
|
||||||
);
|
);
|
||||||
|
|
||||||
let private_key = cmd_hmac_decrypt::try_decrypt(private_key)?;
|
let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, private_key)?;
|
||||||
|
|
||||||
let private_key = if keychain::is_keychain_key_uri(&private_key) {
|
let private_key = if keychain::is_keychain_key_uri(&private_key) {
|
||||||
debugging!("Private key keychain key URI: {}", &private_key);
|
debugging!("Private key keychain key URI: {}", &private_key);
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ pub fn simple_pbe_encrypt_with_prompt_from_string(iteration: u32, plaintext: &st
|
|||||||
simple_pbe_encrypt_with_prompt(iteration, plaintext.as_bytes(), passowrd, password_double_check)
|
simple_pbe_encrypt_with_prompt(iteration, plaintext.as_bytes(), passowrd, password_double_check)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simple_pbe_decrypt_with_prompt_to_string(ciphertext: &str) -> XResult<String> {
|
pub fn simple_pbe_decrypt_with_prompt_to_string(pin_opt: &mut Option<String>, ciphertext: &str) -> XResult<String> {
|
||||||
let plaintext = simple_pbe_decrypt_with_prompt(ciphertext)?;
|
let plaintext = simple_pbe_decrypt_with_prompt(pin_opt, ciphertext)?;
|
||||||
Ok(String::from_utf8(plaintext)?)
|
Ok(String::from_utf8(plaintext)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,8 +34,9 @@ pub fn simple_pbe_encrypt_with_prompt(iteration: u32, plaintext: &[u8], password
|
|||||||
simple_pbe_encrypt(&pin, iteration, plaintext)
|
simple_pbe_encrypt(&pin, iteration, plaintext)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simple_pbe_decrypt_with_prompt(ciphertext: &str) -> XResult<Vec<u8>> {
|
pub fn simple_pbe_decrypt_with_prompt(pin_opt: &mut Option<String>, ciphertext: &str) -> XResult<Vec<u8>> {
|
||||||
let pin = opt_value_result!(pinutil::get_pin(None), "Simple PBE password required");
|
let pin = opt_value_result!(pinutil::get_pin(pin_opt.clone().as_deref()), "Simple PBE password required");
|
||||||
|
*pin_opt = Some(pin.clone());
|
||||||
simple_pbe_decrypt(&pin, ciphertext)
|
simple_pbe_decrypt(&pin, ciphertext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user