diff --git a/card-functionality/src/tests.rs b/card-functionality/src/tests.rs index 5f0fe12..f8304aa 100644 --- a/card-functionality/src/tests.rs +++ b/card-functionality/src/tests.rs @@ -276,6 +276,7 @@ pub fn test_keygen( Some(b"123456"), &|| {}, &|| {}, + &[], )?; let armored = String::from_utf8(cert.armored().to_vec()?)?; diff --git a/openpgp-card-sequoia/src/util.rs b/openpgp-card-sequoia/src/util.rs index 3c59e65..dc84683 100644 --- a/openpgp-card-sequoia/src/util.rs +++ b/openpgp-card-sequoia/src/util.rs @@ -45,6 +45,7 @@ use crate::PublicKey; /// `prompt` notifies the user when a pinpad needs the user pin as input. /// /// FIXME: accept optional metadata for user_id(s)? +#[allow(clippy::too_many_arguments)] pub fn make_cert<'app>( open: &mut Open<'app>, key_sig: PublicKey, @@ -53,6 +54,7 @@ pub fn make_cert<'app>( pw1: Option<&[u8]>, pinpad_prompt: &dyn Fn(), touch_prompt: &(dyn Fn() + Send + Sync), + user_ids: &[String], ) -> Result { let mut pp = vec![]; @@ -137,8 +139,12 @@ pub fn make_cert<'app>( // FIXME: accept user id/email as argument?! - if let Some(name) = cardholder.name() { - let uid: UserID = name.into(); + for uid in user_ids + .iter() + .map(|uid| uid.as_bytes()) + .chain(cardholder.name()) + { + let uid: UserID = uid.into(); pp.push(uid.clone().into()); @@ -161,7 +167,7 @@ pub fn make_cert<'app>( if let Some(mut sign) = open.signing_card() { // Card-backed signer for bindings - let mut card_signer = sign.signer_from_public(key_sig, touch_prompt); + let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt); // Temporary version of the cert let cert = Cert::try_from(pp.clone())?; diff --git a/tools/src/bin/opgpcard/cli.rs b/tools/src/bin/opgpcard/cli.rs index 116c948..5a5f3ee 100644 --- a/tools/src/bin/opgpcard/cli.rs +++ b/tools/src/bin/opgpcard/cli.rs @@ -54,6 +54,10 @@ pub enum Command { #[clap(name = "User PIN file", short = 'p', long = "user-pin")] user_pin: Option, + + /// User ID to add to the exported certificate representation + #[clap(name = "User ID", short = 'u', long = "user-id")] + user_id: Vec, }, /// Administer data on a card (including keys and metadata) @@ -175,6 +179,10 @@ pub enum AdminCommand { /// Algorithm (rsa2048|rsa3072|rsa4096|nistp256|nistp384|nistp521|25519) #[clap()] algo: Option, + + /// User ID to add to the exported certificate representation + #[clap(name = "User ID", short = 'u', long = "user-id")] + user_id: Vec, }, /// Set touch policy diff --git a/tools/src/bin/opgpcard/main.rs b/tools/src/bin/opgpcard/main.rs index ca2639e..007bc1d 100644 --- a/tools/src/bin/opgpcard/main.rs +++ b/tools/src/bin/opgpcard/main.rs @@ -56,8 +56,12 @@ fn main() -> Result<(), Box> { cli::Command::Ssh { ident } => { print_ssh(ident)?; } - cli::Command::Pubkey { ident, user_pin } => { - print_pubkey(ident, user_pin)?; + cli::Command::Pubkey { + ident, + user_pin, + user_id, + } => { + print_pubkey(ident, user_pin, user_id)?; } cli::Command::SetIdentity { ident, id } => { set_identity(&ident, id)?; @@ -300,6 +304,7 @@ fn main() -> Result<(), Box> { no_decrypt, no_auth, algo, + user_id, } => { let user_pin = util::get_pin(&mut open, user_pin, ENTER_USER_PIN); @@ -311,6 +316,7 @@ fn main() -> Result<(), Box> { !no_decrypt, !no_auth, algo, + user_id, )?; } cli::AdminCommand::Touch { key, policy } => { @@ -902,7 +908,11 @@ fn print_ssh(ident: Option) -> Result<()> { Ok(()) } -fn print_pubkey(ident: Option, user_pin: Option) -> Result<()> { +fn print_pubkey( + ident: Option, + user_pin: Option, + user_ids: Vec, +) -> Result<()> { let mut card = pick_card_for_reading(ident)?; let mut pgp = OpenPgp::new(&mut *card); @@ -956,6 +966,7 @@ fn print_pubkey(ident: Option, user_pin: Option) -> Result<()> key_dec, key_aut, user_pin.as_deref(), + &user_ids, &|| println!("Enter User PIN on card reader pinpad."), )?; @@ -1061,6 +1072,7 @@ fn get_cert( key_dec: Option, key_aut: Option, user_pin: Option<&[u8]>, + user_ids: &[String], prompt: &dyn Fn(), ) -> Result { if user_pin.is_none() && open.feature_pinpad_verify() { @@ -1070,9 +1082,16 @@ fn get_cert( ); } - make_cert(open, key_sig, key_dec, key_aut, user_pin, prompt, &|| { - println!("Touch confirmation needed for signing") - }) + make_cert( + open, + key_sig, + key_dec, + key_aut, + user_pin, + prompt, + &|| println!("Touch confirmation needed for signing"), + &user_ids, + ) } fn generate_keys( @@ -1083,6 +1102,7 @@ fn generate_keys( decrypt: bool, auth: bool, algo: Option, + user_ids: Vec, ) -> Result<()> { // 1) Interpret the user's choice of algorithm. // @@ -1124,9 +1144,15 @@ fn generate_keys( // 3) Generate a Cert from the generated keys. For this, we // need "signing" access to the card (to make binding signatures within // the Cert). - let cert = get_cert(&mut open, key_sig, key_dec, key_aut, user_pin, &|| { - println!("Enter User PIN on card reader pinpad.") - })?; + let cert = get_cert( + &mut open, + key_sig, + key_dec, + key_aut, + user_pin, + &user_ids, + &|| println!("Enter User PIN on card reader pinpad."), + )?; let armored = String::from_utf8(cert.armored().to_vec()?)?;