From 5b2979874bc0b80e652b3f6502eceeb9da211184 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Thu, 17 Feb 2022 14:37:49 +0100 Subject: [PATCH] Implement methods on the CardClient trait rather than on `dyn CardClient`. This patch is largely based on input and an MR by @nwalfield. --- openpgp-card/src/apdu.rs | 18 ++- openpgp-card/src/keys.rs | 36 +++-- openpgp-card/src/lib.rs | 294 +++++++++++++++++---------------------- 3 files changed, 165 insertions(+), 183 deletions(-) diff --git a/openpgp-card/src/apdu.rs b/openpgp-card/src/apdu.rs index a0bd794..d4a9cda 100644 --- a/openpgp-card/src/apdu.rs +++ b/openpgp-card/src/apdu.rs @@ -22,11 +22,14 @@ const MAX_BUFFER_SIZE: usize = 264; /// /// If the reply is truncated, this fn assembles all the parts and returns /// them as one aggregated Response. -pub(crate) fn send_command( - card_client: &mut dyn CardClient, +pub(crate) fn send_command( + card_client: &mut C, cmd: Command, expect_reply: bool, -) -> Result { +) -> Result +where + C: CardClient, +{ let mut resp = RawResponse::try_from(send_command_low_level( card_client, cmd.clone(), @@ -81,11 +84,14 @@ pub(crate) fn send_command( /// /// If the response is chained, this fn only returns one chunk, the caller /// needs to re-assemble the chained response-parts. -fn send_command_low_level( - card_client: &mut dyn CardClient, +fn send_command_low_level( + card_client: &mut C, cmd: Command, expect_response: Expect, -) -> Result, Error> { +) -> Result, Error> +where + C: CardClient, +{ let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) = if let Some(caps) = card_client.card_caps() { log::debug!("found card caps data!"); diff --git a/openpgp-card/src/keys.rs b/openpgp-card/src/keys.rs index 3f75f07..366be75 100644 --- a/openpgp-card/src/keys.rs +++ b/openpgp-card/src/keys.rs @@ -29,8 +29,8 @@ use crate::{CardClient, Error}; /// /// `fp_from_pub` calculates the fingerprint for a public key data object and /// creation timestamp -pub(crate) fn gen_key_with_metadata( - card_client: &mut dyn CardClient, +pub(crate) fn gen_key_with_metadata( + card_client: &mut C, fp_from_pub: fn( &PublicKeyMaterial, KeyGenerationTime, @@ -38,7 +38,10 @@ pub(crate) fn gen_key_with_metadata( ) -> Result, key_type: KeyType, algo: Option<&Algo>, -) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> { +) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> +where + C: CardClient, +{ // Set algo on card if it's Some if let Some(target_algo) = algo { // FIXME: caching @@ -126,10 +129,13 @@ fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result { /// /// This runs the low level key generation primitive on the card. /// (This does not set algorithm attributes, creation time or fingerprint) -pub(crate) fn generate_asymmetric_key_pair( - card_client: &mut dyn CardClient, +pub(crate) fn generate_asymmetric_key_pair( + card_client: &mut C, key_type: KeyType, -) -> Result { +) -> Result +where + C: CardClient, +{ // generate key let crt = control_reference_template(key_type)?; let gen_key_cmd = commands::gen_key(crt.serialize().to_vec()); @@ -148,10 +154,13 @@ pub(crate) fn generate_asymmetric_key_pair( /// in the card or imported") /// /// (See 7.2.14 GENERATE ASYMMETRIC KEY PAIR) -pub(crate) fn public_key( - card_client: &mut dyn CardClient, +pub(crate) fn public_key( + card_client: &mut C, key_type: KeyType, -) -> Result { +) -> Result +where + C: CardClient, +{ // get current algo let ard = card_client.application_related_data()?; // FIXME: caching let algo = ard.algorithm_attributes(key_type)?; @@ -174,12 +183,15 @@ pub(crate) fn public_key( /// If the key is suitable for `key_type`, an Error is returned (either /// caused by checks before attempting to upload the key to the card, or by /// an error that the card reports during an attempt to upload the key). -pub(crate) fn key_import( - card_client: &mut dyn CardClient, +pub(crate) fn key_import( + card_client: &mut C, key: Box, key_type: KeyType, algo_info: Option, -) -> Result<(), Error> { +) -> Result<(), Error> +where + C: CardClient, +{ // FIXME: caching? let ard = card_client.application_related_data()?; diff --git a/openpgp-card/src/lib.rs b/openpgp-card/src/lib.rs index 737b06c..4ed44d5 100644 --- a/openpgp-card/src/lib.rs +++ b/openpgp-card/src/lib.rs @@ -103,24 +103,9 @@ pub trait CardClient { /// Modify the PIN `id` via the reader pinpad fn pinpad_modify(&mut self, id: u8) -> Result>; -} -impl<'a> Deref for dyn CardClient + Send + Sync + 'a { - type Target = dyn CardClient + 'a; - - fn deref(&self) -> &Self::Target { - self - } -} -impl<'a> DerefMut for dyn CardClient + Send + Sync + 'a { - fn deref_mut(&mut self) -> &mut Self::Target { - self - } -} - -impl<'a> dyn CardClient + 'a { /// Select the OpenPGP card application - pub fn select(&mut self) -> Result { + fn select(&mut self) -> Result { let select_openpgp = commands::select_openpgp(); apdu::send_command(self, select_openpgp, false)?.try_into() } @@ -133,21 +118,12 @@ impl<'a> dyn CardClient + 'a { /// This fn initializes the CardCaps by requesting /// application_related_data from the card, and setting the /// capabilities accordingly. - pub fn initialize(&mut self) -> Result<()> { + fn initialize(&mut self) -> Result<()> { let ard = self.application_related_data()?; - self.init_caps(&ard)?; - Ok(()) - } - - /// Initialize the CardCaps settings from the data in `ard`. - /// - /// This should be done at an early point, soon after opening the card. - fn init_caps(&mut self, ard: &ApplicationRelatedData) -> Result<()> { // Determine chaining/extended length support from card - // metadata and cache this information in CardApp (as a - // CardCaps) - + // metadata and cache this information in the CardClient + // implementation (as a CardCaps) let mut ext_support = false; let mut chaining_support = false; @@ -202,9 +178,7 @@ impl<'a> dyn CardClient + 'a { /// (This data should probably be cached in a higher layer. Some parts of /// it are needed regularly, and it does not usually change during /// normal use of a card.) - pub fn application_related_data( - &mut self, - ) -> Result { + fn application_related_data(&mut self) -> Result { let ad = commands::application_related_data(); let resp = apdu::send_command(self, ad, true)?; let value = Value::from(resp.data()?, true)?; @@ -214,49 +188,47 @@ impl<'a> dyn CardClient + 'a { Ok(ApplicationRelatedData(Tlv::new(Tag::from([0x6E]), value))) } - #[allow(dead_code)] - fn ca_fingerprints() { - unimplemented!() - } - - #[allow(dead_code)] - fn key_information() { - unimplemented!() - } - - #[allow(dead_code)] - fn uif_pso_cds() { - unimplemented!() - } - - #[allow(dead_code)] - fn uif_pso_dec() { - unimplemented!() - } - - #[allow(dead_code)] - fn uif_pso_aut() { - unimplemented!() - } - - #[allow(dead_code)] - fn uif_attestation() { - unimplemented!() - } + // #[allow(dead_code)] + // fn ca_fingerprints() { + // unimplemented!() + // } + // + // #[allow(dead_code)] + // fn key_information() { + // unimplemented!() + // } + // + // #[allow(dead_code)] + // fn uif_pso_cds() { + // unimplemented!() + // } + // + // #[allow(dead_code)] + // fn uif_pso_dec() { + // unimplemented!() + // } + // + // #[allow(dead_code)] + // fn uif_pso_aut() { + // unimplemented!() + // } + // + // #[allow(dead_code)] + // fn uif_attestation() { + // unimplemented!() + // } // --- login data (5e) --- /// Get URL (5f50) - pub fn url(&mut self) -> Result> { + fn url(&mut self) -> Result> { let resp = apdu::send_command(self, commands::url(), true)?; Ok(resp.data()?.to_vec()) } /// Get cardholder related data (65) - pub fn cardholder_related_data( - &mut self, - ) -> Result { + fn cardholder_related_data(&mut self) -> Result { let crd = commands::cardholder_related_data(); let resp = apdu::send_command(self, crd, true)?; resp.check_ok()?; @@ -265,7 +237,7 @@ impl<'a> dyn CardClient + 'a { } /// Get security support template (7a) - pub fn security_support_template( + fn security_support_template( &mut self, ) -> Result { let sst = commands::security_support_template(); @@ -302,7 +274,7 @@ impl<'a> dyn CardClient + 'a { } /// Get "Algorithm Information" - pub fn algorithm_information(&mut self) -> Result> { + fn algorithm_information(&mut self) -> Result> { let resp = apdu::send_command(self, commands::algo_info(), true)?; resp.check_ok()?; @@ -311,7 +283,7 @@ impl<'a> dyn CardClient + 'a { } /// Firmware Version (YubiKey specific (?)) - pub fn firmware_version(&mut self) -> Result> { + fn firmware_version(&mut self) -> Result> { let resp = apdu::send_command(self, commands::firmware_version(), true)?; @@ -322,7 +294,7 @@ impl<'a> dyn CardClient + 'a { /// [see: /// /// ] - pub fn set_identity(&mut self, id: u8) -> Result> { + fn set_identity(&mut self, id: u8) -> Result> { let resp = apdu::send_command(self, commands::set_identity(id), false); // Apparently it's normal to get "NotTransacted" from pcsclite when @@ -336,11 +308,7 @@ impl<'a> dyn CardClient + 'a { /// SELECT DATA ("select a DO in the current template", /// e.g. for cardholder certificate) - pub fn select_data( - &mut self, - num: u8, - tag: &[u8], - ) -> Result { + fn select_data(&mut self, num: u8, tag: &[u8]) -> Result { let tlv = Tlv::new( [0x60], Value::C(vec![Tlv::new([0x5c], Value::S(tag.to_vec()))]), @@ -357,7 +325,7 @@ impl<'a> dyn CardClient + 'a { /// Get data from "private use" DO. /// /// `num` must be between 1 and 4. - pub fn private_use_do(&mut self, num: u8) -> Result> { + fn private_use_do(&mut self, num: u8) -> Result> { assert!((1..=4).contains(&num)); let cmd = commands::private_use_do(num); @@ -373,7 +341,7 @@ impl<'a> dyn CardClient + 'a { /// Access condition: /// - 1/3 need PW1 (82) /// - 2/4 need PW3 - pub fn set_private_use_do( + fn set_private_use_do( &mut self, num: u8, data: Vec, @@ -403,7 +371,7 @@ impl<'a> dyn CardClient + 'a { /// (However, e.g. vanilla Gnuk doesn't support this functionality. /// Gnuk needs to be built with the `--enable-factory-reset` /// option to the `configure` script to enable this functionality). - pub fn factory_reset(&mut self) -> Result<()> { + fn factory_reset(&mut self) -> Result<()> { // send 4 bad requests to verify pw1 // [apdu 00 20 00 81 08 40 40 40 40 40 40 40 40] for _ in 0..4 { @@ -446,22 +414,12 @@ impl<'a> dyn CardClient + 'a { // --- verify/modify --- - /// Does the cardreader support direct pinpad verify? - pub fn feature_pinpad_verify(card_client: &mut dyn CardClient) -> bool { - card_client.feature_pinpad_verify() - } - - /// Does the cardreader support direct pinpad modify? - pub fn feature_pinpad_modify(card_client: &mut dyn CardClient) -> bool { - card_client.feature_pinpad_modify() - } - /// Verify pw1 (user) for signing operation (mode 81). /// /// Depending on the PW1 status byte (see Extended Capabilities) this /// access condition is only valid for one PSO:CDS command or remains /// valid for several attempts. - pub fn verify_pw1_for_signing( + fn verify_pw1_for_signing( &mut self, pin: &str, ) -> Result { @@ -476,9 +434,7 @@ impl<'a> dyn CardClient + 'a { /// Depending on the PW1 status byte (see Extended Capabilities) this /// access condition is only valid for one PSO:CDS command or remains /// valid for several attempts. - pub fn verify_pw1_for_signing_pinpad( - &mut self, - ) -> Result { + fn verify_pw1_for_signing_pinpad(&mut self) -> Result { let res = self.pinpad_verify(0x81)?; RawResponse::try_from(res)?.try_into() } @@ -489,14 +445,14 @@ impl<'a> dyn CardClient + 'a { /// /// (Note: some cards don't correctly implement this feature, /// e.g. YubiKey 5) - pub fn check_pw1_for_signing(&mut self) -> Result { + fn check_pw1_for_signing(&mut self) -> Result { let verify = commands::verify_pw1_81(vec![]); apdu::send_command(self, verify, false)?.try_into() } /// Verify PW1 (user). /// (For operations except signing, mode 82). - pub fn verify_pw1(&mut self, pin: &str) -> Result { + fn verify_pw1(&mut self, pin: &str) -> Result { let verify = commands::verify_pw1_82(pin.as_bytes().to_vec()); apdu::send_command(self, verify, false)?.try_into() } @@ -505,7 +461,7 @@ impl<'a> dyn CardClient + 'a { /// using a pinpad on the card reader. If no usable pinpad is found, /// an error is returned. - pub fn verify_pw1_pinpad(&mut self) -> Result { + fn verify_pw1_pinpad(&mut self) -> Result { let res = self.pinpad_verify(0x82)?; RawResponse::try_from(res)?.try_into() } @@ -517,20 +473,20 @@ impl<'a> dyn CardClient + 'a { /// /// (Note: some cards don't correctly implement this feature, /// e.g. YubiKey 5) - pub fn check_pw1(&mut self) -> Result { + fn check_pw1(&mut self) -> Result { let verify = commands::verify_pw1_82(vec![]); apdu::send_command(self, verify, false)?.try_into() } /// Verify PW3 (admin). - pub fn verify_pw3(&mut self, pin: &str) -> Result { + fn verify_pw3(&mut self, pin: &str) -> Result { let verify = commands::verify_pw3(pin.as_bytes().to_vec()); apdu::send_command(self, verify, false)?.try_into() } /// Verify PW3 (admin) using a pinpad on the card reader. If no usable /// pinpad is found, an error is returned. - pub fn verify_pw3_pinpad(&mut self) -> Result { + fn verify_pw3_pinpad(&mut self) -> Result { let res = self.pinpad_verify(0x83)?; RawResponse::try_from(res)?.try_into() } @@ -541,7 +497,7 @@ impl<'a> dyn CardClient + 'a { /// /// (Note: some cards don't correctly implement this feature, /// e.g. YubiKey 5) - pub fn check_pw3(&mut self) -> Result { + fn check_pw3(&mut self) -> Result { let verify = commands::verify_pw3(vec![]); apdu::send_command(self, verify, false)?.try_into() } @@ -549,11 +505,7 @@ impl<'a> dyn CardClient + 'a { /// Change the value of PW1 (user password). /// /// The current value of PW1 must be presented in `old` for authorization. - pub fn change_pw1( - &mut self, - old: &str, - new: &str, - ) -> Result { + fn change_pw1(&mut self, old: &str, new: &str) -> Result { let mut data = vec![]; data.extend(old.as_bytes()); data.extend(new.as_bytes()); @@ -564,7 +516,7 @@ impl<'a> dyn CardClient + 'a { /// Change the value of PW1 (user password) using a pinpad on the /// card reader. If no usable pinpad is found, an error is returned. - pub fn change_pw1_pinpad(&mut self) -> Result { + fn change_pw1_pinpad(&mut self) -> Result { let res = self.pinpad_modify(0x81)?; RawResponse::try_from(res)?.try_into() } @@ -572,11 +524,7 @@ impl<'a> dyn CardClient + 'a { /// Change the value of PW3 (admin password). /// /// The current value of PW3 must be presented in `old` for authorization. - pub fn change_pw3( - &mut self, - old: &str, - new: &str, - ) -> Result { + fn change_pw3(&mut self, old: &str, new: &str) -> Result { let mut data = vec![]; data.extend(old.as_bytes()); data.extend(new.as_bytes()); @@ -587,7 +535,7 @@ impl<'a> dyn CardClient + 'a { /// Change the value of PW3 (admin password) using a pinpad on the /// card reader. If no usable pinpad is found, an error is returned. - pub fn change_pw3_pinpad(&mut self) -> Result { + fn change_pw3_pinpad(&mut self) -> Result { let res = self.pinpad_modify(0x83)?; RawResponse::try_from(res)?.try_into() } @@ -599,7 +547,7 @@ impl<'a> dyn CardClient + 'a { /// - PW3 must have been verified previously, /// - secure messaging must be currently used, /// - the resetting_code must be presented. - pub fn reset_retry_counter_pw1( + fn reset_retry_counter_pw1( &mut self, new_pw1: Vec, resetting_code: Option>, @@ -614,7 +562,7 @@ impl<'a> dyn CardClient + 'a { /// /// (This is a wrapper around the low-level pso_decipher /// operation, it builds the required `data` field from `dm`) - pub fn decipher(&mut self, dm: Cryptogram) -> Result, Error> { + fn decipher(&mut self, dm: Cryptogram) -> Result, Error> { match dm { Cryptogram::RSA(message) => { // "Padding indicator byte (00) for RSA" (pg. 69) @@ -647,6 +595,9 @@ impl<'a> dyn CardClient + 'a { /// Run decryption operation on the smartcard (low level operation) /// (7.2.11 PSO: DECIPHER) + /// + /// (consider using the `decipher()` method if you don't want to create + /// the data field manually) fn pso_decipher(&mut self, data: Vec) -> Result, Error> { // The OpenPGP card is already connected and PW1 82 has been verified let dec_cmd = commands::decryption(data); @@ -658,34 +609,6 @@ impl<'a> dyn CardClient + 'a { // --- sign --- - fn digestinfo(hash: Hash) -> Vec { - match hash { - Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => { - let tlv = Tlv::new( - [0x30], - Value::C(vec![ - Tlv::new( - [0x30], - Value::C(vec![ - Tlv::new( - [0x06], - // unwrapping is ok, for SHA* - Value::S(hash.oid().unwrap().to_vec()), - ), - Tlv::new([0x05], Value::S(vec![])), - ]), - ), - Tlv::new([0x04], Value::S(hash.digest().to_vec())), - ]), - ); - - tlv.serialize() - } - Hash::EdDSA(d) => d.to_vec(), - Hash::ECDSA(d) => d.to_vec(), - } - } - /// Sign `hash`, on the card. /// /// This is a wrapper around the low-level @@ -697,16 +620,16 @@ impl<'a> dyn CardClient + 'a { /// /// With ECC the hash data is processed as is, using /// pso_compute_digital_signature. - pub fn signature_for_hash( - &mut self, - hash: Hash, - ) -> Result, Error> { - self.pso_compute_digital_signature(Self::digestinfo(hash)) + fn signature_for_hash(&mut self, hash: Hash) -> Result, Error> { + self.pso_compute_digital_signature(digestinfo(hash)) } /// Run signing operation on the smartcard (low level operation) /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) - pub fn pso_compute_digital_signature( + /// + /// (consider using the `signature_for_hash()` method if you don't + /// want to create the data field manually) + fn pso_compute_digital_signature( &mut self, data: Vec, ) -> Result, Error> { @@ -729,16 +652,16 @@ impl<'a> dyn CardClient + 'a { /// (see 7.2.10.2 DigestInfo for RSA). /// /// With ECC the hash data is processed as is. - pub fn authenticate_for_hash( - &mut self, - hash: Hash, - ) -> Result, Error> { - self.internal_authenticate(Self::digestinfo(hash)) + fn authenticate_for_hash(&mut self, hash: Hash) -> Result, Error> { + self.internal_authenticate(digestinfo(hash)) } /// Run signing operation on the smartcard (low level operation) /// (7.2.13 INTERNAL AUTHENTICATE) - pub fn internal_authenticate( + /// + /// (consider using the `authenticate_for_hash()` method if you don't + /// want to create the data field manually) + fn internal_authenticate( &mut self, data: Vec, ) -> Result, Error> { @@ -750,12 +673,12 @@ impl<'a> dyn CardClient + 'a { // --- admin --- - pub fn set_name(&mut self, name: &[u8]) -> Result { + fn set_name(&mut self, name: &[u8]) -> Result { let put_name = commands::put_name(name.to_vec()); apdu::send_command(self, put_name, false)?.try_into() } - pub fn set_lang(&mut self, lang: &[Lang]) -> Result { + fn set_lang(&mut self, lang: &[Lang]) -> Result { let bytes: Vec = lang .iter() .map(|&l| Into::>::into(l)) @@ -766,17 +689,17 @@ impl<'a> dyn CardClient + 'a { apdu::send_command(self, put_lang, false)?.try_into() } - pub fn set_sex(&mut self, sex: Sex) -> Result { + fn set_sex(&mut self, sex: Sex) -> Result { let put_sex = commands::put_sex((&sex).into()); apdu::send_command(self, put_sex, false)?.try_into() } - pub fn set_url(&mut self, url: &[u8]) -> Result { + fn set_url(&mut self, url: &[u8]) -> Result { let put_url = commands::put_url(url.to_vec()); apdu::send_command(self, put_url, false)?.try_into() } - pub fn set_creation_time( + fn set_creation_time( &mut self, time: KeyGenerationTime, key_type: KeyType, @@ -796,7 +719,7 @@ impl<'a> dyn CardClient + 'a { apdu::send_command(self, time_cmd, false)?.try_into() } - pub fn set_fingerprint( + fn set_fingerprint( &mut self, fp: Fingerprint, key_type: KeyType, @@ -820,7 +743,7 @@ impl<'a> dyn CardClient + 'a { /// can also be changed. /// /// (See OpenPGP card spec, pg. 28) - pub fn set_pw_status_bytes( + fn set_pw_status_bytes( &mut self, pw_status: &PWStatusBytes, long: bool, @@ -835,7 +758,7 @@ impl<'a> dyn CardClient + 'a { /// /// Call select_data() before calling this fn, to select a particular /// certificate (if the card supports multiple certificates). - pub fn set_cardholder_certificate( + fn set_cardholder_certificate( &mut self, data: Vec, ) -> Result { @@ -845,7 +768,7 @@ impl<'a> dyn CardClient + 'a { /// Set algorithm attributes /// (4.4.3.9 Algorithm Attributes) - pub fn set_algorithm_attributes( + fn set_algorithm_attributes( &mut self, key_type: KeyType, algo: &Algo, @@ -861,7 +784,7 @@ impl<'a> dyn CardClient + 'a { /// Set resetting code /// (4.3.4 Resetting Code) - pub fn set_resetting_code( + fn set_resetting_code( &mut self, resetting_code: Vec, ) -> Result { @@ -871,7 +794,7 @@ impl<'a> dyn CardClient + 'a { /// Import an existing private key to the card. /// (This implicitly sets the algorithm info, fingerprint and timestamp) - pub fn key_import( + fn key_import( &mut self, key: Box, key_type: KeyType, @@ -894,7 +817,7 @@ impl<'a> dyn CardClient + 'a { /// Note: `algo` needs to precisely specify the RSA bitsize of e (if /// applicable), and import format, with values that the current card /// supports. - pub fn generate_key( + fn generate_key( &mut self, fp_from_pub: fn( &PublicKeyMaterial, @@ -916,7 +839,7 @@ impl<'a> dyn CardClient + 'a { /// Note: AlgoSimple doesn't specify card specific details (such as /// bitsize of e for RSA, and import format). This function determines /// these values based on information from the card. - pub fn generate_key_simple( + fn generate_key_simple( &mut self, fp_from_pub: fn( &PublicKeyMaterial, @@ -946,7 +869,7 @@ impl<'a> dyn CardClient + 'a { /// Note also that the information from the card is insufficient to /// reconstruct a pre-existing OpenPGP public key that corresponds to /// the private key on the card. - pub fn public_key( + fn public_key( &mut self, key_type: KeyType, ) -> Result { @@ -954,6 +877,47 @@ impl<'a> dyn CardClient + 'a { } } +impl<'a> Deref for dyn CardClient + Send + Sync + 'a { + type Target = dyn CardClient + 'a; + + fn deref(&self) -> &Self::Target { + self + } +} +impl<'a> DerefMut for dyn CardClient + Send + Sync + 'a { + fn deref_mut(&mut self) -> &mut Self::Target { + self + } +} + +fn digestinfo(hash: Hash) -> Vec { + match hash { + Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => { + let tlv = Tlv::new( + [0x30], + Value::C(vec![ + Tlv::new( + [0x30], + Value::C(vec![ + Tlv::new( + [0x06], + // unwrapping is ok, for SHA* + Value::S(hash.oid().unwrap().to_vec()), + ), + Tlv::new([0x05], Value::S(vec![])), + ]), + ), + Tlv::new([0x04], Value::S(hash.digest().to_vec())), + ]), + ); + + tlv.serialize() + } + Hash::EdDSA(d) => d.to_vec(), + Hash::ECDSA(d) => d.to_vec(), + } +} + /// Configuration of the capabilities of a card. /// /// This configuration is used to determine e.g. if chaining or extended