feat: v1.10.9, add se supprot
This commit is contained in:
25
src/cmd_se.rs
Normal file
25
src/cmd_se.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use crate::seutil;
|
||||
use clap::{App, ArgMatches, SubCommand};
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str {
|
||||
"se"
|
||||
}
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name()).about("Secure Enclave subcommand")
|
||||
// .arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
fn run(&self, _arg_matches: &ArgMatches, _sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
if seutil::is_support_se() {
|
||||
success!("Secure Enclave is supported.")
|
||||
} else {
|
||||
failure!("Secure Enclave is NOT supported.")
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
73
src/cmd_se_generate.rs
Normal file
73
src/cmd_se_generate.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use crate::pkiutil::bytes_to_pem;
|
||||
use crate::seutil;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
use rust_util::util_msg;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub struct CommandImpl;
|
||||
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> &str {
|
||||
"se-generate"
|
||||
}
|
||||
|
||||
fn subcommand<'a>(&self) -> App<'a, 'a> {
|
||||
SubCommand::with_name(self.name())
|
||||
.about("Secure Enclave subcommand")
|
||||
.arg(
|
||||
Arg::with_name("type")
|
||||
.long("type")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.help("Type signing or key_agreement"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("host")
|
||||
.long("host")
|
||||
.required(false)
|
||||
.takes_value(true)
|
||||
.help("Host name"),
|
||||
)
|
||||
.arg(Arg::with_name("json").long("json").help("JSON output"))
|
||||
}
|
||||
|
||||
fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError {
|
||||
if !seutil::is_support_se() {
|
||||
return simple_error!("Secure Enclave is NOT supported.");
|
||||
}
|
||||
let ty = sub_arg_matches.value_of("type").unwrap();
|
||||
let host = sub_arg_matches.value_of("host").unwrap_or("macbook");
|
||||
let json_output = sub_arg_matches.is_present("json");
|
||||
if json_output {
|
||||
util_msg::set_logger_std_out(false);
|
||||
}
|
||||
|
||||
let sign = match ty {
|
||||
"signing" | "ecsign" | "sign" => true,
|
||||
"key_agreement" | "ecdh" | "dh" => false,
|
||||
_ => return simple_error!("Invalie type: {}", ty),
|
||||
};
|
||||
|
||||
let (public_key_point, public_key_der, private_key) =
|
||||
seutil::generate_secure_enclave_p256_keypair(sign)?;
|
||||
|
||||
let public_key_point_hex = hex::encode(&public_key_point);
|
||||
let public_key_pem = bytes_to_pem("PUBLIC KEY", &*public_key_der);
|
||||
let key = format!("key://{}:se/p256:{}:{}",
|
||||
host, iff!(sign, "signing", "key_agreement"), private_key,
|
||||
);
|
||||
if json_output {
|
||||
let mut json = BTreeMap::<&'_ str, String>::new();
|
||||
json.insert("public_key_point", public_key_point_hex);
|
||||
json.insert("public_key_pem", public_key_pem);
|
||||
json.insert("key", key);
|
||||
} else {
|
||||
success!("Public key(point): {}", public_key_point_hex);
|
||||
success!("Public key PEM: {}", public_key_pem);
|
||||
success!("Key: {}", key);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
100
src/main.rs
100
src/main.rs
@@ -4,56 +4,62 @@ extern crate rust_util;
|
||||
use clap::{App, AppSettings, ArgMatches};
|
||||
use rust_util::util_clap::{Command, CommandError};
|
||||
|
||||
mod util;
|
||||
mod sshutil;
|
||||
mod fido;
|
||||
mod digest;
|
||||
mod pivutil;
|
||||
mod rsautil;
|
||||
mod pkiutil;
|
||||
mod hmacutil;
|
||||
mod ecdsautil;
|
||||
mod argsutil;
|
||||
mod pgpcardutil;
|
||||
mod cmd_list;
|
||||
mod cmd_u2fregister;
|
||||
mod cmd_u2fsign;
|
||||
mod cmd_rsaencrypt;
|
||||
mod cmd_rsadecrypt;
|
||||
mod cmd_rsaverify;
|
||||
#[cfg(feature = "with-sequoia-openpgp")]
|
||||
mod cmd_pgp;
|
||||
mod cmd_pgpcardadmin;
|
||||
mod cmd_pgpcardlist;
|
||||
mod cmd_pgpcardsign;
|
||||
mod cmd_pgpcarddecrypt;
|
||||
#[cfg(feature = "with-sequoia-openpgp")]
|
||||
mod cmd_pgpcardmake;
|
||||
mod cmd_piv;
|
||||
mod cmd_pivsummary;
|
||||
mod cmd_pivmeta;
|
||||
mod cmd_pivverify;
|
||||
mod cmd_pivrsasign;
|
||||
mod cmd_pivecdh;
|
||||
mod cmd_pivecsign;
|
||||
mod cmd_pivdecrypt;
|
||||
mod cmd_pivgenerate;
|
||||
mod cmd_hmac_sha1;
|
||||
mod cmd_chall;
|
||||
mod cmd_challconfig;
|
||||
mod cmd_sshagent;
|
||||
mod cmd_sshparsesign;
|
||||
mod cmd_sshpivsign;
|
||||
mod cmd_sshpivcert;
|
||||
mod cmd_sshpubkey;
|
||||
mod cmd_sshparse;
|
||||
mod cmd_hmac_sha1;
|
||||
mod cmd_list;
|
||||
#[cfg(feature = "with-sequoia-openpgp")]
|
||||
mod cmd_pgp;
|
||||
mod cmd_pgpageaddress;
|
||||
mod cmd_signjwt;
|
||||
mod cmd_pgpcardadmin;
|
||||
mod cmd_pgpcarddecrypt;
|
||||
mod cmd_pgpcardlist;
|
||||
#[cfg(feature = "with-sequoia-openpgp")]
|
||||
mod cmd_pgpcardmake;
|
||||
mod cmd_pgpcardsign;
|
||||
mod cmd_piv;
|
||||
mod cmd_pivdecrypt;
|
||||
mod cmd_pivecdh;
|
||||
mod cmd_pivecsign;
|
||||
mod cmd_pivgenerate;
|
||||
mod cmd_pivmeta;
|
||||
mod cmd_pivrsasign;
|
||||
mod cmd_pivsummary;
|
||||
mod cmd_pivverify;
|
||||
mod cmd_rsadecrypt;
|
||||
mod cmd_rsaencrypt;
|
||||
mod cmd_rsaverify;
|
||||
#[cfg(feature = "with-secure-enclave")]
|
||||
mod cmd_se;
|
||||
#[cfg(feature = "with-secure-enclave")]
|
||||
mod cmd_se_generate;
|
||||
mod cmd_signfile;
|
||||
mod cmd_signjwt;
|
||||
mod cmd_sshagent;
|
||||
mod cmd_sshparse;
|
||||
mod cmd_sshparsesign;
|
||||
mod cmd_sshpivcert;
|
||||
mod cmd_sshpivsign;
|
||||
mod cmd_sshpubkey;
|
||||
mod cmd_u2fregister;
|
||||
mod cmd_u2fsign;
|
||||
mod cmd_verifyfile;
|
||||
mod signfile;
|
||||
mod digest;
|
||||
mod ecdhutil;
|
||||
mod ecdsautil;
|
||||
mod fido;
|
||||
mod hmacutil;
|
||||
mod pgpcardutil;
|
||||
mod pinutil;
|
||||
mod pivutil;
|
||||
mod pkiutil;
|
||||
mod rsautil;
|
||||
#[cfg(feature = "with-secure-enclave")]
|
||||
mod seutil;
|
||||
mod signfile;
|
||||
mod sshutil;
|
||||
mod util;
|
||||
|
||||
pub struct DefaultCommandImpl;
|
||||
|
||||
@@ -117,11 +123,17 @@ fn inner_main() -> CommandError {
|
||||
Box::new(cmd_signjwt::CommandImpl),
|
||||
Box::new(cmd_signfile::CommandImpl),
|
||||
Box::new(cmd_verifyfile::CommandImpl),
|
||||
#[cfg(feature = "with-secure-enclave")]
|
||||
Box::new(cmd_se::CommandImpl),
|
||||
#[cfg(feature = "with-secure-enclave")]
|
||||
Box::new(cmd_se_generate::CommandImpl),
|
||||
];
|
||||
|
||||
let mut features: Vec<&str> = vec![];
|
||||
#[cfg(feature = "with-sequoia-openpgp")]
|
||||
features.push("with-sequoia-openpgp");
|
||||
features.push("sequoia-openpgp");
|
||||
#[cfg(feature = "with-secure-enclave")]
|
||||
features.push("secure-enclave");
|
||||
let about = format!(
|
||||
"{}, features: [{}]",
|
||||
"Card Cli is a command tool for WebAuthn, OpenPGP, YubiKey ... smart cards",
|
||||
@@ -144,4 +156,4 @@ fn inner_main() -> CommandError {
|
||||
}
|
||||
}
|
||||
DefaultCommandImpl::run(&matches)
|
||||
}
|
||||
}
|
||||
|
||||
46
src/seutil.rs
Normal file
46
src/seutil.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use crate::util::base64_decode;
|
||||
use rust_util::XResult;
|
||||
use swift_rs::swift;
|
||||
use swift_rs::{Bool, SRString};
|
||||
|
||||
swift!(fn is_support_secure_enclave() -> Bool);
|
||||
swift!(fn generate_secure_enclave_p256_ecdh_keypair() -> SRString);
|
||||
swift!(fn generate_secure_enclave_p256_ecsign_keypair() -> SRString);
|
||||
swift!(fn compute_secure_enclave_p256_ecdh(private_key_base64: SRString, ephemera_public_key_base64: SRString) -> SRString);
|
||||
|
||||
pub fn is_support_se() -> bool {
|
||||
unsafe { is_support_secure_enclave() }
|
||||
}
|
||||
|
||||
pub fn generate_secure_enclave_p256_keypair(sign: bool) -> XResult<(Vec<u8>, Vec<u8>, String)> {
|
||||
let p256_keypair_result = if sign {
|
||||
unsafe { generate_secure_enclave_p256_ecsign_keypair() }
|
||||
} else {
|
||||
unsafe { generate_secure_enclave_p256_ecdh_keypair() }
|
||||
};
|
||||
let p256_keypair_result_str = p256_keypair_result.as_str();
|
||||
if !p256_keypair_result_str.starts_with("ok:") {
|
||||
return simple_error!(
|
||||
"Generate P256 in secure enclave failed: {}",
|
||||
p256_keypair_result_str
|
||||
);
|
||||
}
|
||||
let public_key_and_private_key = p256_keypair_result_str.chars().skip(3).collect::<String>();
|
||||
let public_key_and_private_keys = public_key_and_private_key.split(',').collect::<Vec<_>>();
|
||||
if public_key_and_private_keys.len() != 3 {
|
||||
return simple_error!(
|
||||
"Generate P256 in secure enclave result is bad: {}",
|
||||
public_key_and_private_key
|
||||
);
|
||||
}
|
||||
let public_key_point = opt_result!(
|
||||
base64_decode(public_key_and_private_keys[0]),
|
||||
"Public key point is not base64 encoded: {}"
|
||||
);
|
||||
let public_key_der = opt_result!(
|
||||
base64_decode(public_key_and_private_keys[1]),
|
||||
"Public key der is not base64 encoded: {}"
|
||||
);
|
||||
let private_key = public_key_and_private_keys[2].to_string();
|
||||
Ok((public_key_point, public_key_der, private_key))
|
||||
}
|
||||
Reference in New Issue
Block a user