diff --git a/Cargo.lock b/Cargo.lock index c7ef8f6..0ae8788 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -593,7 +593,7 @@ dependencies = [ [[package]] name = "card-cli" -version = "1.13.18" +version = "1.13.19" dependencies = [ "aes-gcm-stream", "authenticator 0.3.1", diff --git a/Cargo.toml b/Cargo.toml index 45700e4..3fb466f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "card-cli" -version = "1.13.18" +version = "1.13.19" authors = ["Hatter Jiang "] edition = "2018" diff --git a/src/cmd_external_ecdh.rs b/src/cmd_external_ecdh.rs index 9ff07d9..c9d2f2b 100644 --- a/src/cmd_external_ecdh.rs +++ b/src/cmd_external_ecdh.rs @@ -122,7 +122,6 @@ pub fn ecdh( if let Ok(shared_secret) = ecdhutil::parse_p521_private_and_ecdh(&private_key_bytes, ephemeral_public_key_bytes) { return Ok(shared_secret.to_vec()); } - simple_error!("Invalid EC private key and/or ephemeral public key") } else if key.algorithm.is_mlkem() { let private_key = cmd_hmac_decrypt::try_decrypt(&mut None, &key.hmac_enc_private_key)?; diff --git a/src/cmd_external_public_key.rs b/src/cmd_external_public_key.rs index 05b3ce0..f3be859 100644 --- a/src/cmd_external_public_key.rs +++ b/src/cmd_external_public_key.rs @@ -2,7 +2,7 @@ use crate::keyutil::{parse_key_uri, KeyUri, KeyUsage}; use crate::util::{base64_decode, base64_encode}; use crate::yubikeyutil::find_key_or_error; use crate::{cmd_hmac_decrypt, cmdutil, ecdsautil, seutil, util, yubikeyutil}; -use clap::{App, ArgMatches, SubCommand}; +use clap::{App, Arg, ArgMatches, SubCommand}; use ecdsa::elliptic_curve::pkcs8::der::Encode; use rust_util::util_clap::{Command, CommandError}; use rust_util::XResult; @@ -11,7 +11,7 @@ use std::collections::BTreeMap; use rsa::RsaPrivateKey; use spki::EncodePublicKey; use x509_parser::parse_x509_certificate; -use crate::mlkemutil::try_parse_decapsulate_key_private_get_encapsulate; +use crate::mlkemutil::{try_parse_decapsulate_key_private_get_encapsulate, try_parse_encapsulation_key_public_then_encapsulate}; use crate::pivutil::ToStr; pub struct CommandImpl; @@ -26,14 +26,16 @@ impl Command for CommandImpl { .about("External public key subcommand") .arg(cmdutil::build_parameter_arg()) .arg(cmdutil::build_serial_arg()) + .arg(Arg::with_name("x-generate-shared-secret").long("x-generate-shared-secret").help("Generate a shared secret")) } fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError { let parameter = sub_arg_matches.value_of("parameter").unwrap(); let serial_opt = sub_arg_matches.value_of("serial"); + let generate_shared_secret = sub_arg_matches.is_present("x-generate-shared-secret"); let mut json = BTreeMap::new(); - match fetch_public_key(parameter, &serial_opt) { + match fetch_public_key(parameter, &serial_opt, generate_shared_secret, &mut json) { Ok(public_key_bytes) => { json.insert("success", Value::Bool(true)); json.insert("public_key_base64", base64_encode(&public_key_bytes).into()); @@ -49,7 +51,7 @@ impl Command for CommandImpl { } } -fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult> { +fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>, generate_shared_secret: bool, json: &mut BTreeMap<&str, Value>) -> XResult> { let key_uri = parse_key_uri(parameter)?; match key_uri { KeyUri::SecureEnclave(key) => { @@ -99,6 +101,13 @@ fn fetch_public_key(parameter: &str, serial_opt: &Option<&str>) -> XResult &str { + match self { + MlKemLen::Len512 => "mlkem512", + MlKemLen::Len768 => "mlkem768", + MlKemLen::Len1024 => "mlkem1024", + } + } +} + pub fn generate_mlkem_keypair(len: usize) -> XResult<(String, String, String, Vec, String)> { let (dk_private, ek_public) = match len { 512 => generate_ml_kem_512(), @@ -98,6 +107,19 @@ pub fn generate_ml_kem_1024() -> (Vec, Vec) { ) } +pub fn try_parse_encapsulation_key_public_then_encapsulate(bytes: &[u8]) -> XResult<(MlKemLen, Vec, Vec)> { + if let Ok((ciphertext, shared_key)) = parse_encapsulation_key_512_public_then_encapsulate(bytes) { + return Ok((MlKemLen::Len512, ciphertext, shared_key)); + } + if let Ok((ciphertext, shared_key)) = parse_encapsulation_key_768_public_then_encapsulate(bytes) { + return Ok((MlKemLen::Len768, ciphertext, shared_key)); + } + if let Ok((ciphertext, shared_key)) = parse_encapsulation_key_1024_public_then_encapsulate(bytes) { + return Ok((MlKemLen::Len1024, ciphertext, shared_key)); + } + simple_error!("Invalid encapsulation key, only allow MK-KEM-512, ML-KEM-768, ML-KEM-1024") +} + pub fn parse_encapsulation_key_512_public_then_encapsulate( bytes: &[u8], ) -> XResult<(Vec, Vec)> {