From 02401d12f4ed3595992bbf2ffd4886bb0a187fde Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Tue, 2 Nov 2021 21:33:16 +0100 Subject: [PATCH] Initial parts of key generation. --- openpgp-card-sequoia/src/util.rs | 5 +- tools/src/bin/opgpcard/cli.rs | 15 +++++ tools/src/bin/opgpcard/main.rs | 103 +++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) diff --git a/openpgp-card-sequoia/src/util.rs b/openpgp-card-sequoia/src/util.rs index 5f49a14..074464b 100644 --- a/openpgp-card-sequoia/src/util.rs +++ b/openpgp-card-sequoia/src/util.rs @@ -121,7 +121,10 @@ pub fn make_cert<'a, 'app>( // 6) add user id from name / email let cardholder = open.cardholder_related_data()?; - // FIXME: process name field? accept email as argument?! + // FIXME: process name field? + + // FIXME: accept email as argument?! + let uid: UserID = cardholder.name().expect("expecting name on card").into(); diff --git a/tools/src/bin/opgpcard/cli.rs b/tools/src/bin/opgpcard/cli.rs index eafc886..7ba70f2 100644 --- a/tools/src/bin/opgpcard/cli.rs +++ b/tools/src/bin/opgpcard/cli.rs @@ -116,4 +116,19 @@ pub enum AdminCommand { )] auth_fp: Option, }, + /// Generate a Key. + /// + /// A signing key is always created, decryption and authentication keys + /// are optional. + Generate { + #[structopt(long = "no-decrypt")] + no_decrypt: bool, + + #[structopt(long = "no-auth")] + no_auth: bool, + + #[structopt(about = "Algorithm \ + (rsa2048|rsa3072|rsa4096|nistp256|nistp384|nistp521|25519)")] + algo: Option, + }, } diff --git a/tools/src/bin/opgpcard/main.rs b/tools/src/bin/opgpcard/main.rs index 6b0d937..22b11a3 100644 --- a/tools/src/bin/opgpcard/main.rs +++ b/tools/src/bin/opgpcard/main.rs @@ -104,6 +104,23 @@ fn main() -> Result<(), Box> { )?; } } + cli::AdminCommand::Generate { + no_decrypt, + no_auth, + algo, + } => { + let pw3 = util::get_pin(&pin_file)?; + // FIXME: get PW1 from user + + generate_keys( + open, + &pw3, + "123456", + !no_decrypt, + !no_auth, + algo, + )?; + } } } } @@ -394,3 +411,89 @@ fn key_import_explicit( Ok(()) } + +fn generate_keys( + mut open: Open, + pw3: &str, + pw1: &str, + decrypt: bool, + auth: bool, + algo: Option, +) -> Result<()> { + // Figure out which algorithm the user wants + + // FIXME: + // (rsa2048|rsa3072|rsa4096|nistp256|nistp384|nistp521|25519) or None + // let alg = AlgoSimple::from(algo); + + let a = algo.unwrap(); + let a: &str = &a; + + // temporary approach: + let alg = AlgoSimple::from(a); + + // FIXME: if rsa, try 32 and 17 bit e + + // FIXME: handle None (leave algo as is) + + // --- + + // Then, we make the card generate keys (we need "admin" access to + // the card for that). + + open.verify_admin(pw3)?; + + let (key_sig, key_dec, key_aut) = { + if let Some(mut admin) = open.admin_card() { + println!(" Generate subkey for Signing"); + let (pkm, ts) = + admin.generate_key_simple(KeyType::Signing, alg)?; + let key_sig = + public_key_material_to_key(&pkm, KeyType::Signing, ts)?; + + let key_dec = if decrypt { + println!(" Generate subkey for Decryption"); + let (pkm, ts) = + admin.generate_key_simple(KeyType::Decryption, alg)?; + Some(public_key_material_to_key( + &pkm, + KeyType::Decryption, + ts, + )?) + } else { + None + }; + + let key_aut = if auth { + println!(" Generate subkey for Authentication"); + let (pkm, ts) = + admin.generate_key_simple(KeyType::Authentication, alg)?; + + Some(public_key_material_to_key( + &pkm, + KeyType::Authentication, + ts, + )?) + } else { + None + }; + + (key_sig, key_dec, key_aut) + } else { + // FIXME: couldn't get admin mode + unimplemented!() + } + }; + + // Then we generate a Cert for this set of generated keys. For this, we + // need "signing" access to the card, to make a number of binding + // signatures. + + // FIXME: get pw1 from user + let cert = make_cert(&mut open, key_sig, key_dec, key_aut, pw1)?; + let armored = String::from_utf8(cert.armored().to_vec()?)?; + + println!("{}", armored); + + Ok(()) +}