diff --git a/openpgp-card-sequoia/src/card.rs b/openpgp-card-sequoia/src/card.rs index f9c5cae..af48f31 100644 --- a/openpgp-card-sequoia/src/card.rs +++ b/openpgp-card-sequoia/src/card.rs @@ -349,6 +349,16 @@ impl<'a> Open<'a> { self.opt.algorithm_information() } + /// "MANAGE SECURITY ENVIRONMENT" + /// Make `key_ref` usable for the operation normally done by the key designated by `for_operation` + pub fn manage_security_environment( + &mut self, + for_operation: KeyType, + key_ref: KeyType, + ) -> Result<(), Error> { + self.opt.manage_security_environment(for_operation, key_ref) + } + /// Get "Attestation Certificate (Yubico)" pub fn attestation_certificate(&mut self) -> Result, Error> { self.opt.attestation_certificate() diff --git a/openpgp-card/src/apdu/commands.rs b/openpgp-card/src/apdu/commands.rs index b50c193..fc05677 100644 --- a/openpgp-card/src/apdu/commands.rs +++ b/openpgp-card/src/apdu/commands.rs @@ -4,7 +4,7 @@ //! Pre-defined `Command` values for the OpenPGP card application use crate::apdu::command::Command; -use crate::{ShortTag, Tags}; +use crate::{KeyType, ShortTag, Tags}; /// 7.2.1 SELECT /// (select the OpenPGP application on the card) @@ -241,3 +241,19 @@ pub(crate) fn terminate_df() -> Command { pub(crate) fn activate_file() -> Command { Command::new(0x00, 0x44, 0x00, 0x00, vec![]) } + +/// 7.2.18 MANAGE SECURITY ENVIRONMENT +pub(crate) fn manage_security_environment(for_operation: KeyType, key_ref: KeyType) -> Command { + let p2 = match for_operation { + KeyType::Authentication => 0xA4, + KeyType::Decryption => 0xB8, + _ => unreachable!(), //FIXME + }; + let data = match key_ref { + KeyType::Decryption => vec![0x83, 0x01, 0x02], + KeyType::Authentication => vec![0x83, 0x01, 0x03], + _ => unreachable!(), + }; + + Command::new(0, 0x22, 0x41, p2, data) +} diff --git a/openpgp-card/src/openpgp.rs b/openpgp-card/src/openpgp.rs index f293703..d3026be 100644 --- a/openpgp-card/src/openpgp.rs +++ b/openpgp-card/src/openpgp.rs @@ -588,6 +588,40 @@ impl<'a> OpenPgpTransaction<'a> { Ok(resp.data().map(|d| d.to_vec())?) } + /// Set the key to be used for the pso_decipher and the internal_authenticate commands. + /// + /// Valid until next reset of of the card or the next call to `select` + /// The only keys that can be configured by this command are the `Decryption` and `Authentication` keys. + /// + /// The following first sets the *Authentication* key to be used for [pso_decipher](OpenPgpTransaction::pso_decipher) + /// and then sets the *Decryption* key to be used for [internal_authenticate](OpenPgpTransaction::internal_authenticate). + /// + /// ```no_run + /// # use openpgp_card::{KeyType, OpenPgpTransaction}; + /// # let mut tx: OpenPgpTransaction<'static> = panic!(); + /// tx.manage_security_environment(KeyType::Decryption, KeyType::Authentication)?; + /// tx.manage_security_environment(KeyType::Authentication, KeyType::Decryption)?; + /// # Result::<(), openpgp_card::Error>::Ok(()) + /// ``` + pub fn manage_security_environment( + &mut self, + for_operation: KeyType, + key_ref: KeyType, + ) -> Result<(), Error> { + log::info!("OpenPgpTransaction: manage_security_environment"); + + if !matches!(for_operation, KeyType::Authentication | KeyType::Decryption) + || !matches!(key_ref, KeyType::Authentication | KeyType::Decryption) + { + return Err(Error::UnsupportedAlgo("Only Decryption and Authentication keys can be manipulated by manage_security_environment".to_string())); + } + + let cmd = commands::manage_security_environment(for_operation, key_ref); + let resp = apdu::send_command(self.tx(), cmd, false)?; + resp.check_ok()?; + Ok(()) + } + // --- sign --- /// Sign `hash`, on the card.