From f00865ab755bc4f70040d19a8137800a9902d728 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Thu, 1 Jul 2021 23:46:12 +0200 Subject: [PATCH] rustfmt --- .rustfmt.toml | 9 + openpgp-card-sequoia/src/decryptor.rs | 81 +-- openpgp-card-sequoia/src/lib.rs | 104 +-- openpgp-card-sequoia/src/main.rs | 37 +- openpgp-card-sequoia/src/signer.rs | 86 +-- openpgp-card/src/apdu/command.rs | 19 +- openpgp-card/src/apdu/commands.rs | 8 +- openpgp-card/src/apdu/mod.rs | 97 +-- openpgp-card/src/apdu/response.rs | 7 +- openpgp-card/src/card.rs | 10 +- openpgp-card/src/errors.rs | 11 +- openpgp-card/src/key_upload.rs | 280 ++++---- openpgp-card/src/lib.rs | 259 +++++--- openpgp-card/src/parse/algo_attrs.rs | 88 ++- openpgp-card/src/parse/algo_info.rs | 605 ++++++++++++------ openpgp-card/src/parse/application_id.rs | 17 +- openpgp-card/src/parse/cardholder.rs | 19 +- openpgp-card/src/parse/extended_cap.rs | 70 +- .../src/parse/extended_length_info.rs | 13 +- openpgp-card/src/parse/fingerprint.rs | 10 +- openpgp-card/src/parse/historical.rs | 69 +- openpgp-card/src/parse/mod.rs | 6 +- openpgp-card/src/tlv/length.rs | 5 +- openpgp-card/src/tlv/mod.rs | 75 ++- openpgp-card/src/tlv/tag.rs | 34 +- 25 files changed, 1225 insertions(+), 794 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..3f6431a --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2019-2020 Heiko Schaefer +# SPDX-License-Identifier: CC0-1.0 + +# The following configuration gives warnings in stable rust versions since +# they're unstable (Jan 2020). +max_width = 79 +comment_width = 79 +#report_fixme = "Always" + diff --git a/openpgp-card-sequoia/src/decryptor.rs b/openpgp-card-sequoia/src/decryptor.rs index 544f985..bebebcf 100644 --- a/openpgp-card-sequoia/src/decryptor.rs +++ b/openpgp-card-sequoia/src/decryptor.rs @@ -3,7 +3,6 @@ use anyhow::anyhow; -use openpgp::Cert; use openpgp::crypto; use openpgp::crypto::mpi; use openpgp::crypto::SessionKey; @@ -13,10 +12,11 @@ use openpgp::parse::stream::{ }; use openpgp::policy::Policy; use openpgp::types::{Curve, SymmetricAlgorithm}; +use openpgp::Cert; use sequoia_openpgp as openpgp; -use openpgp_card::{DecryptMe, OpenPGPCardUser}; use openpgp_card::errors::OpenpgpCardError; +use openpgp_card::{DecryptMe, OpenPGPCardUser}; use crate::PublicKey; @@ -33,10 +33,11 @@ impl<'a> CardDecryptor<'a> { /// /// An Error is returned if no match between the card's decryption /// key and a (sub)key of `cert` can be made. - pub fn new(ocu: &'a OpenPGPCardUser, - cert: &Cert, - policy: &dyn Policy) -> Result, OpenpgpCardError> { - + pub fn new( + ocu: &'a OpenPGPCardUser, + cert: &Cert, + policy: &dyn Policy, + ) -> Result, OpenpgpCardError> { // Get the fingerprint for the decryption key from the card. let fps = ocu.get_fingerprints()?; let fp = fps.decryption(); @@ -46,27 +47,28 @@ impl<'a> CardDecryptor<'a> { let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes()); // Find the matching encryption-capable (sub)key in `cert` - let keys: Vec<_> = - cert.keys() - .with_policy(policy, None) - .for_storage_encryption() - .for_transport_encryption() - .filter(|ka| ka.fingerprint() == fp) - .map(|ka| ka.key()) - .collect(); + let keys: Vec<_> = cert + .keys() + .with_policy(policy, None) + .for_storage_encryption() + .for_transport_encryption() + .filter(|ka| ka.fingerprint() == fp) + .map(|ka| ka.key()) + .collect(); // Exactly one matching (sub)key should be found. If not, fail! if keys.len() == 1 { let public = keys[0].clone(); Ok(Self { ocu, public }) } else { - Err(OpenpgpCardError::InternalError( - anyhow!("Failed to find a matching (sub)key in cert"))) + Err(OpenpgpCardError::InternalError(anyhow!( + "Failed to find a matching (sub)key in cert" + ))) } } else { - Err(OpenpgpCardError::InternalError( - anyhow!("Failed to get the decryption key's Fingerprint \ - from the card"))) + Err(OpenpgpCardError::InternalError(anyhow!( + "Failed to get the decryption key's Fingerprint from the card" + ))) } } } @@ -88,10 +90,7 @@ impl<'a> crypto::Decryptor for CardDecryptor<'a> { _plaintext_len: Option, ) -> openpgp::Result { match (ciphertext, self.public.mpis()) { - ( - mpi::Ciphertext::RSA { c: ct }, - mpi::PublicKey::RSA { .. }, - ) => { + (mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => { let dm = DecryptMe::RSA(ct.value()); let dec = self.ocu.decrypt(dm)?; @@ -102,29 +101,29 @@ impl<'a> crypto::Decryptor for CardDecryptor<'a> { mpi::Ciphertext::ECDH { ref e, .. }, mpi::PublicKey::ECDH { ref curve, .. }, ) => { - let dm = - if curve == &Curve::Cv25519 { - // Ephemeral key without header byte 0x40 - DecryptMe::ECDH(&e.value()[1..]) - } else { - // NIST curves: ephemeral key with header byte - DecryptMe::ECDH(&e.value()) - }; + let dm = if curve == &Curve::Cv25519 { + // Ephemeral key without header byte 0x40 + DecryptMe::ECDH(&e.value()[1..]) + } else { + // NIST curves: ephemeral key with header byte + DecryptMe::ECDH(&e.value()) + }; // Decryption operation on the card let dec = self.ocu.decrypt(dm)?; #[allow(non_snake_case)] - let S: openpgp::crypto::mem::Protected = dec.into(); + let S: openpgp::crypto::mem::Protected = dec.into(); Ok(crypto::ecdh::decrypt_unwrap(&self.public, &S, ciphertext)?) } - (ciphertext, public) => - Err(anyhow!( - "Unsupported combination of ciphertext {:?} \ - and public key {:?} ", ciphertext, public - )), + (ciphertext, public) => Err(anyhow!( + "Unsupported combination of ciphertext {:?} \ + and public key {:?} ", + ciphertext, + public + )), } } } @@ -137,7 +136,8 @@ impl<'a> DecryptionHelper for CardDecryptor<'a> { sym_algo: Option, mut dec_fn: D, ) -> openpgp::Result> - where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool, + where + D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool, { // Try to decrypt each PKESK, see: // https://docs.sequoia-pgp.org/src/sequoia_openpgp/packet/pkesk.rs.html#125 @@ -160,7 +160,10 @@ impl<'a> DecryptionHelper for CardDecryptor<'a> { } impl<'a> VerificationHelper for CardDecryptor<'a> { - fn get_certs(&mut self, _ids: &[openpgp::KeyHandle]) -> openpgp::Result> { + fn get_certs( + &mut self, + _ids: &[openpgp::KeyHandle], + ) -> openpgp::Result> { Ok(vec![]) } fn check(&mut self, _structure: MessageStructure) -> openpgp::Result<()> { diff --git a/openpgp-card-sequoia/src/lib.rs b/openpgp-card-sequoia/src/lib.rs index e4c5aea..1f43204 100644 --- a/openpgp-card-sequoia/src/lib.rs +++ b/openpgp-card-sequoia/src/lib.rs @@ -12,17 +12,18 @@ use chrono::prelude::*; use openpgp::armor; use openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation; use openpgp::crypto::mpi; -use openpgp::crypto::mpi::{MPI, ProtectedMPI}; -use openpgp::packet::{Key, key}; +use openpgp::crypto::mpi::{ProtectedMPI, MPI}; use openpgp::packet::key::{SecretParts, UnspecifiedRole}; -use openpgp::parse::{Parse, stream::DecryptorBuilder}; +use openpgp::packet::{key, Key}; +use openpgp::parse::{stream::DecryptorBuilder, Parse}; use openpgp::policy::StandardPolicy; use openpgp::serialize::stream::{Message, Signer}; use sequoia_openpgp as openpgp; -use openpgp_card::{CardUploadableKey, EccKey, EccType, errors::OpenpgpCardError, - KeyType, OpenPGPCardAdmin, OpenPGPCardUser, PrivateKeyMaterial, - RSAKey}; +use openpgp_card::{ + errors::OpenpgpCardError, CardUploadableKey, EccKey, EccType, KeyType, + OpenPGPCardAdmin, OpenPGPCardUser, PrivateKeyMaterial, RSAKey, +}; mod decryptor; mod signer; @@ -30,7 +31,6 @@ mod signer; /// Shorthand for public key data pub(crate) type PublicKey = Key; - /// A SequoiaKey represents the private cryptographic key material of an /// OpenPGP (sub)key to be uploaded to an OpenPGP card. struct SequoiaKey { @@ -43,8 +43,10 @@ impl SequoiaKey { /// A `SequoiaKey` wraps a Sequoia PGP private (sub)key data /// (i.e. a ValidErasedKeyAmalgamation) in a form that can be uploaded /// by the openpgp-card crate. - fn new(vka: ValidErasedKeyAmalgamation, - password: Option) -> Self { + fn new( + vka: ValidErasedKeyAmalgamation, + password: Option, + ) -> Self { let public = vka.parts_as_public().mpis().clone(); Self { @@ -62,51 +64,72 @@ impl CardUploadableKey for SequoiaKey { // Decrypt key with password, if set let key = match &self.password { None => self.key.clone(), - Some(pw) => self.key.clone() - .decrypt_secret(&openpgp::crypto::Password::from(pw.as_str()))? + Some(pw) => self.key.clone().decrypt_secret( + &openpgp::crypto::Password::from(pw.as_str()), + )?, }; // Get private cryptographic material - let unenc = - if let Some(openpgp::packet::key::SecretKeyMaterial::Unencrypted(ref u)) = key.optional_secret() { - u - } else { - panic!("can't get private key material"); - }; + let unenc = if let Some( + openpgp::packet::key::SecretKeyMaterial::Unencrypted(ref u), + ) = key.optional_secret() + { + u + } else { + panic!("can't get private key material"); + }; let secret_key_material = unenc.map(|mpis| mpis.clone()); match (&self.public, secret_key_material) { - (mpi::PublicKey::RSA { e, n }, - mpi::SecretKeyMaterial::RSA { d: _, p, q, u: _ }) => { + ( + mpi::PublicKey::RSA { e, n }, + mpi::SecretKeyMaterial::RSA { d: _, p, q, u: _ }, + ) => { let sq_rsa = SqRSA::new(e.clone(), n.clone(), p, q); Ok(PrivateKeyMaterial::R(Box::new(sq_rsa))) } - (mpi::PublicKey::ECDH { curve, .. }, - mpi::SecretKeyMaterial::ECDH { scalar }) => { - let sq_ecc = SqEccKey::new(curve.oid().to_vec(), - scalar, EccType::ECDH); + ( + mpi::PublicKey::ECDH { curve, .. }, + mpi::SecretKeyMaterial::ECDH { scalar }, + ) => { + let sq_ecc = + SqEccKey::new(curve.oid().to_vec(), scalar, EccType::ECDH); Ok(PrivateKeyMaterial::E(Box::new(sq_ecc))) } - (mpi::PublicKey::ECDSA { curve, .. }, - mpi::SecretKeyMaterial::ECDSA { scalar }) => { - let sq_ecc = SqEccKey::new(curve.oid().to_vec(), - scalar, EccType::ECDSA); + ( + mpi::PublicKey::ECDSA { curve, .. }, + mpi::SecretKeyMaterial::ECDSA { scalar }, + ) => { + let sq_ecc = SqEccKey::new( + curve.oid().to_vec(), + scalar, + EccType::ECDSA, + ); Ok(PrivateKeyMaterial::E(Box::new(sq_ecc))) } - (mpi::PublicKey::EdDSA { curve, .. }, - mpi::SecretKeyMaterial::EdDSA { scalar }) => { - let sq_ecc = SqEccKey::new(curve.oid().to_vec(), - scalar, EccType::EdDSA); + ( + mpi::PublicKey::EdDSA { curve, .. }, + mpi::SecretKeyMaterial::EdDSA { scalar }, + ) => { + let sq_ecc = SqEccKey::new( + curve.oid().to_vec(), + scalar, + EccType::EdDSA, + ); Ok(PrivateKeyMaterial::E(Box::new(sq_ecc))) } (p, s) => { - unimplemented!("Unexpected algorithms: public {:?}, \ - secret {:?}", p, s); + unimplemented!( + "Unexpected algorithms: public {:?}, \ + secret {:?}", + p, + s + ); } } } @@ -121,7 +144,6 @@ impl CardUploadableKey for SequoiaKey { } } - /// RSA-specific data-structure to hold private (sub)key material for upload /// with the `openpgp-card` crate. struct SqRSA { @@ -165,7 +187,11 @@ struct SqEccKey { impl SqEccKey { fn new(oid: Vec, scalar: ProtectedMPI, ecc_type: EccType) -> Self { - SqEccKey { oid, scalar, ecc_type } + SqEccKey { + oid, + scalar, + ecc_type, + } } } @@ -183,7 +209,6 @@ impl EccKey for SqEccKey { } } - /// Convenience fn to select and upload a (sub)key from a Cert, as a given /// KeyType. If multiple suitable (sub)keys are found, the first one is /// used. @@ -267,9 +292,7 @@ pub fn sign( let s = signer::CardSigner::new(ocu, cert, &p)?; let message = Message::new(&mut armorer); - let mut message = Signer::new(message, s) - .detached() - .build()?; + let mut message = Signer::new(message, s).detached().build()?; // Process input data, via message io::copy(input, &mut message)?; @@ -279,6 +302,5 @@ pub fn sign( let buffer = armorer.finalize()?; - String::from_utf8(buffer) - .context("Failed to convert signature to utf8") + String::from_utf8(buffer).context("Failed to convert signature to utf8") } diff --git a/openpgp-card-sequoia/src/main.rs b/openpgp-card-sequoia/src/main.rs index e601066..a5d3ee6 100644 --- a/openpgp-card-sequoia/src/main.rs +++ b/openpgp-card-sequoia/src/main.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use std::error::Error; use std::env; +use std::error::Error; use anyhow::Result; -use sequoia_openpgp::Cert; use sequoia_openpgp::parse::Parse; +use sequoia_openpgp::Cert; use openpgp_card::{KeyType, OpenPGPCard}; @@ -21,7 +21,6 @@ use openpgp_card::{KeyType, OpenPGPCard}; const TEST_KEY_PATH: &str = "example/test25519.sec"; const TEST_ENC_MSG: &str = "example/encrypted_to_25519.asc"; - fn main() -> Result<(), Box> { env_logger::init(); @@ -72,14 +71,12 @@ fn main() -> Result<(), Box> { let algo = oc.get_algorithm_attributes(KeyType::Authentication)?; println!("algo aut {:?}", algo); - // --------------------------------------------- // CAUTION: Write commands ahead! // Try not to overwrite your production cards. // --------------------------------------------- assert_eq!(app_id.serial(), test_card_serial); - oc.factory_reset()?; match oc.verify_pw3("12345678") { @@ -89,7 +86,8 @@ fn main() -> Result<(), Box> { let res = oc_admin.set_name("Bar< Result<(), Box> { let res = oc_admin.set_url("https://keys.openpgp.org")?; println!("set url {:x?}", res); - let cert = Cert::from_file(TEST_KEY_PATH)?; openpgp_card_sequoia::upload_from_cert_yolo( @@ -123,7 +120,7 @@ fn main() -> Result<(), Box> { // None, // )?; } - _ => panic!() + _ => panic!(), } // ----------------------------- @@ -141,21 +138,23 @@ fn main() -> Result<(), Box> { println!("pw1 82 verify ok"); let cert = Cert::from_file(TEST_KEY_PATH)?; - let msg = std::fs::read_to_string - (TEST_ENC_MSG) + let msg = std::fs::read_to_string(TEST_ENC_MSG) .expect("Unable to read file"); println!("{:?}", msg); - let res = openpgp_card_sequoia::decrypt - (&oc_user, &cert, msg.into_bytes())?; + let res = openpgp_card_sequoia::decrypt( + &oc_user, + &cert, + msg.into_bytes(), + )?; let plain = String::from_utf8_lossy(&res); println!("decrypted plaintext: {}", plain); assert_eq!(plain, "Hello world!\n"); } - _ => panic!("verify pw1 failed") + _ => panic!("verify pw1 failed"), } // ----------------------------- @@ -171,8 +170,11 @@ fn main() -> Result<(), Box> { let cert = Cert::from_file(TEST_KEY_PATH)?; let text = "Hello world, I am signed."; - let res = openpgp_card_sequoia::sign(&oc_user, &cert, - &mut text.as_bytes()); + let res = openpgp_card_sequoia::sign( + &oc_user, + &cert, + &mut text.as_bytes(), + ); println!("res sign {:?}", res); @@ -180,7 +182,7 @@ fn main() -> Result<(), Box> { // FIXME: validate sig } - _ => panic!("verify pw1 failed") + _ => panic!("verify pw1 failed"), } } else { println!("Please set environment variable TEST_CARD_SERIAL."); @@ -190,8 +192,7 @@ fn main() -> Result<(), Box> { println!("So do NOT use your production card for testing."); println!(); - println!("The following OpenPGP cards are currently connected to \ - your system:"); + println!("The following OpenPGP cards are connected to your system:"); let cards = openpgp_card::OpenPGPCard::list_cards()?; for c in cards { diff --git a/openpgp-card-sequoia/src/signer.rs b/openpgp-card-sequoia/src/signer.rs index 8fa74fc..071e520 100644 --- a/openpgp-card-sequoia/src/signer.rs +++ b/openpgp-card-sequoia/src/signer.rs @@ -10,13 +10,12 @@ use openpgp::policy::Policy; use openpgp::types::PublicKeyAlgorithm; use sequoia_openpgp as openpgp; +use openpgp_card::errors::OpenpgpCardError; use openpgp_card::Hash; use openpgp_card::OpenPGPCardUser; -use openpgp_card::errors::OpenpgpCardError; use crate::PublicKey; - pub(crate) struct CardSigner<'a> { /// The OpenPGP card (authenticated to allow signing operations) ocu: &'a OpenPGPCardUser, @@ -30,11 +29,11 @@ impl<'a> CardSigner<'a> { /// /// An Error is returned if no match between the card's signing /// key and a (sub)key of `cert` can be made. - pub fn new(ocu: &'a OpenPGPCardUser, - cert: &openpgp::Cert, - policy: &dyn Policy) - -> Result, OpenpgpCardError> { - + pub fn new( + ocu: &'a OpenPGPCardUser, + cert: &openpgp::Cert, + policy: &dyn Policy, + ) -> Result, OpenpgpCardError> { // Get the fingerprint for the signing key from the card. let fps = ocu.get_fingerprints()?; let fp = fps.signature(); @@ -44,16 +43,15 @@ impl<'a> CardSigner<'a> { let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes()); // Find the matching signing-capable (sub)key in `cert` - let keys: Vec<_> = - cert - .keys() - .with_policy(policy, None) - .alive() - .revoked(false) - .for_signing() - .filter(|ka| ka.fingerprint() == fp) - .map(|ka| ka.key()) - .collect(); + let keys: Vec<_> = cert + .keys() + .with_policy(policy, None) + .alive() + .revoked(false) + .for_signing() + .filter(|ka| ka.fingerprint() == fp) + .map(|ka| ka.key()) + .collect(); // Exactly one matching (sub)key should be found. If not, fail! if keys.len() == 1 { @@ -64,13 +62,15 @@ impl<'a> CardSigner<'a> { public: public.role_as_unspecified().clone(), }) } else { - Err(OpenpgpCardError::InternalError( - anyhow!("Failed to find a matching (sub)key in cert"))) + Err(OpenpgpCardError::InternalError(anyhow!( + "Failed to find a matching (sub)key in cert" + ))) } } else { - Err(OpenpgpCardError::InternalError( - anyhow!("Failed to get the signing key's Fingerprint \ - from the card"))) + Err(OpenpgpCardError::InternalError(anyhow!( + "Failed to get the signing key's Fingerprint \ + from the card" + ))) } } } @@ -86,34 +86,45 @@ impl<'a> crypto::Signer for CardSigner<'a> { /// perform the signing operation. /// /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) - fn sign(&mut self, - hash_algo: openpgp::types::HashAlgorithm, - digest: &[u8], + fn sign( + &mut self, + hash_algo: openpgp::types::HashAlgorithm, + digest: &[u8], ) -> openpgp::Result { match (self.public.pk_algo(), self.public.mpis()) { #[allow(deprecated)] - (PublicKeyAlgorithm::RSASign, mpi::PublicKey::RSA { .. }) | - (PublicKeyAlgorithm::RSAEncryptSign, mpi::PublicKey::RSA { .. }) => { + (PublicKeyAlgorithm::RSASign, mpi::PublicKey::RSA { .. }) + | ( + PublicKeyAlgorithm::RSAEncryptSign, + mpi::PublicKey::RSA { .. }, + ) => { let sig = match hash_algo { openpgp::types::HashAlgorithm::SHA256 => { - let hash = Hash::SHA256(digest.try_into() - .map_err(|_| anyhow!("invalid slice length"))?); + let hash = + Hash::SHA256(digest.try_into().map_err(|_| { + anyhow!("invalid slice length") + })?); self.ocu.signature_for_hash(hash)? } openpgp::types::HashAlgorithm::SHA384 => { - let hash = Hash::SHA384(digest.try_into() - .map_err(|_| anyhow!("invalid slice length"))?); + let hash = + Hash::SHA384(digest.try_into().map_err(|_| { + anyhow!("invalid slice length") + })?); self.ocu.signature_for_hash(hash)? } openpgp::types::HashAlgorithm::SHA512 => { - let hash = Hash::SHA512(digest.try_into() - .map_err(|_| anyhow!("invalid slice length"))?); + let hash = + Hash::SHA512(digest.try_into().map_err(|_| { + anyhow!("invalid slice length") + })?); self.ocu.signature_for_hash(hash)? } _ => { - return Err( - anyhow!("Unsupported hash algorithm for RSA {:?}", - hash_algo)); + return Err(anyhow!( + "Unsupported hash algorithm for RSA {:?}", + hash_algo + )); } }; @@ -133,7 +144,8 @@ impl<'a> crypto::Signer for CardSigner<'a> { // FIXME: implement NIST etc (pk_algo, _) => Err(anyhow!( "Unsupported combination of algorithm {:?} and pubkey {:?}", - pk_algo, self.public + pk_algo, + self.public )), } } diff --git a/openpgp-card/src/apdu/command.rs b/openpgp-card/src/apdu/command.rs index 36d8262..723c468 100644 --- a/openpgp-card/src/apdu/command.rs +++ b/openpgp-card/src/apdu/command.rs @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use anyhow::Result; use crate::apdu::Le; +use anyhow::Result; #[allow(clippy::upper_case_acronyms)] #[derive(Clone, Debug)] @@ -22,7 +22,13 @@ pub struct Command { impl Command { pub fn new(cla: u8, ins: u8, p1: u8, p2: u8, data: Vec) -> Self { - Command { cla, ins, p1, p2, data } + Command { + cla, + ins, + p1, + p2, + data, + } } pub(crate) fn serialize(&self, ext: Le) -> Result> { @@ -34,9 +40,11 @@ impl Command { // (must be the same) let data_len = if self.data.len() as u16 > 0xff || ext == Le::Long { - vec![0, - (self.data.len() as u16 >> 8) as u8, - (self.data.len() as u16 & 255) as u8] + vec![ + 0, + (self.data.len() as u16 >> 8) as u8, + (self.data.len() as u16 & 255) as u8, + ] } else { vec![self.data.len() as u8] }; @@ -56,7 +64,6 @@ impl Command { // thus disable Le in this case. */ // if (reader_table[slot].is_t0) // le = -1; - Le::None => (), Le::Short => buf.push(0), diff --git a/openpgp-card/src/apdu/commands.rs b/openpgp-card/src/apdu/commands.rs index c8cbbec..050e651 100644 --- a/openpgp-card/src/apdu/commands.rs +++ b/openpgp-card/src/apdu/commands.rs @@ -2,13 +2,15 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 /// APDU Commands for OpenPGP card operations - use crate::apdu::command::Command; /// Select the OpenPGP applet pub fn select_openpgp() -> Command { Command::new( - 0x00, 0xA4, 0x04, 0x00, + 0x00, + 0xA4, + 0x04, + 0x00, vec![0xD2, 0x76, 0x00, 0x01, 0x24, 0x01], ) } @@ -68,7 +70,6 @@ pub fn activate_file() -> Command { Command::new(0x00, 0x44, 0x00, 0x00, vec![]) } - /// 7.2.8 PUT DATA, /// ('tag' must consist of either one or two bytes) pub fn put_data(tag: &[u8], data: Vec) -> Command { @@ -82,7 +83,6 @@ pub fn put_data(tag: &[u8], data: Vec) -> Command { Command::new(0x00, 0xda, p1, p2, data) } - /// PUT DO Name pub fn put_name(name: Vec) -> Command { put_data(&[0x5b], name) diff --git a/openpgp-card/src/apdu/mod.rs b/openpgp-card/src/apdu/mod.rs index 002d9ad..fd19942 100644 --- a/openpgp-card/src/apdu/mod.rs +++ b/openpgp-card/src/apdu/mod.rs @@ -5,26 +5,33 @@ pub mod command; pub mod commands; pub mod response; -use std::convert::TryFrom; use pcsc::Card; +use std::convert::TryFrom; -use crate::OpenPGPCard; use crate::apdu::command::Command; -use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError}; use crate::apdu::response::Response; +use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError}; +use crate::OpenPGPCard; #[derive(Clone, Copy, PartialEq)] -pub(crate) enum Le { None, Short, Long } +pub(crate) enum Le { + None, + Short, + Long, +} /// Send a Command and return the result as a Response. /// /// If the reply is truncated, this fn assembles all the parts and returns /// them as one aggregated Response. -pub(crate) fn send_command(card: &Card, cmd: Command, ext: Le, - oc: Option<&OpenPGPCard>) - -> Result { - let mut resp = Response::try_from( - send_command_low_level(&card, cmd, ext, oc)?)?; +pub(crate) fn send_command( + card: &Card, + cmd: Command, + ext: Le, + oc: Option<&OpenPGPCard>, +) -> Result { + let mut resp = + Response::try_from(send_command_low_level(&card, cmd, ext, oc)?)?; while resp.status()[0] == 0x61 { // More data is available for this command from the card @@ -32,9 +39,12 @@ pub(crate) fn send_command(card: &Card, cmd: Command, ext: Le, log::trace!(" response was truncated, getting more data"); // Get additional data - let next = Response::try_from - (send_command_low_level(&card, - commands::get_response(), ext, oc)?)?; + let next = Response::try_from(send_command_low_level( + &card, + commands::get_response(), + ext, + oc, + )?)?; // FIXME: first check for 0x61xx or 0x9000? log::trace!(" appending {} bytes to response", next.raw_data().len()); @@ -54,11 +64,12 @@ pub(crate) fn send_command(card: &Card, cmd: Command, ext: Le, /// /// If the response is chained, this fn only returns one chunk, the caller /// needs take care of chained responses -fn send_command_low_level(card: &Card, - cmd: Command, - ext: Le, - oc: Option<&OpenPGPCard>) - -> Result, OpenpgpCardError> { +fn send_command_low_level( + card: &Card, + cmd: Command, + ext: Le, + oc: Option<&OpenPGPCard>, +) -> Result, OpenpgpCardError> { log::trace!(" -> full APDU command: {:x?}", cmd); log::trace!(" serialized: {:x?}", cmd.serialize(ext)); @@ -81,14 +92,18 @@ fn send_command_low_level(card: &Card, } } - log::trace!("ext le/lc {}, chaining {}, command chunk size {}", - ext_support, chaining_support, chunk_size); + log::trace!( + "ext le/lc {}, chaining {}, command chunk size {}", + ext_support, + chaining_support, + chunk_size + ); // update Le setting to 'long', if we're using a larger chunk size let ext = match (ext, chunk_size > 0xff) { (Le::None, _) => Le::None, (_, true) => Le::Long, - _ => ext + _ => ext, }; let buf_size = if !ext_support { @@ -109,21 +124,23 @@ fn send_command_low_level(card: &Card, for (i, d) in chunks.iter().enumerate() { let last = i == chunks.len() - 1; - let partial = - Command { - cla: if last { 0x00 } else { 0x10 }, - data: d.to_vec(), - ..cmd - }; + let partial = Command { + cla: if last { 0x00 } else { 0x10 }, + data: d.to_vec(), + ..cmd + }; - let serialized = partial.serialize(ext). - map_err(OpenpgpCardError::InternalError)?; + let serialized = partial + .serialize(ext) + .map_err(OpenpgpCardError::InternalError)?; log::trace!(" -> chunked APDU command: {:x?}", &serialized); - let resp = card - .transmit(&serialized, &mut resp_buffer) - .map_err(|e| OpenpgpCardError::Smartcard(SmartcardError::Error( - format!("Transmit failed: {:?}", e))))?; + let resp = + card.transmit(&serialized, &mut resp_buffer).map_err(|e| { + OpenpgpCardError::Smartcard(SmartcardError::Error( + format!("Transmit failed: {:?}", e), + )) + })?; log::trace!(" <- APDU chunk response: {:x?}", &resp); @@ -139,8 +156,8 @@ fn send_command_low_level(card: &Card, // ISO: "If SW1-SW2 is set to '6883', then the last // command of the chain is expected." if !((sw1 == 0x90 && sw2 == 0x00) - || (sw1 == 0x68 && sw2 == 0x83)) { - + || (sw1 == 0x68 && sw2 == 0x83)) + { // Unexpected status for a non-final chunked response return Err(OcErrorStatus::from((sw1, sw2)).into()); } @@ -156,11 +173,13 @@ fn send_command_low_level(card: &Card, } else { let serialized = cmd.serialize(ext)?; - let resp = card - .transmit(&serialized, &mut resp_buffer) - .map_err(|e| OpenpgpCardError::Smartcard(SmartcardError::Error( - format!("Transmit failed: {:?}", e))))?; - + let resp = + card.transmit(&serialized, &mut resp_buffer).map_err(|e| { + OpenpgpCardError::Smartcard(SmartcardError::Error(format!( + "Transmit failed: {:?}", + e + ))) + })?; log::trace!(" <- APDU response: {:x?}", resp); diff --git a/openpgp-card/src/apdu/response.rs b/openpgp-card/src/apdu/response.rs index b8e6a9e..dcdde71 100644 --- a/openpgp-card/src/apdu/response.rs +++ b/openpgp-card/src/apdu/response.rs @@ -66,16 +66,17 @@ impl TryFrom> for Response { type Error = OcErrorStatus; fn try_from(mut data: Vec) -> Result { - let sw2 = data.pop() + let sw2 = data + .pop() .ok_or_else(|| OcErrorStatus::ResponseLength(data.len()))?; - let sw1 = data.pop() + let sw1 = data + .pop() .ok_or_else(|| OcErrorStatus::ResponseLength(data.len()))?; Ok(Response { data, sw1, sw2 }) } } - impl Response { /// Is the response (0x90 0x00)? pub fn is_ok(&self) -> bool { diff --git a/openpgp-card/src/card.rs b/openpgp-card/src/card.rs index 2fe2ad3..f0877fe 100644 --- a/openpgp-card/src/card.rs +++ b/openpgp-card/src/card.rs @@ -2,15 +2,16 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use anyhow::Result; -use pcsc::{Card, Context, Scope, ShareMode, Protocols, Error}; +use pcsc::{Card, Context, Error, Protocols, Scope, ShareMode}; use crate::errors; - pub fn get_cards() -> Result, errors::SmartcardError> { let ctx = match Context::establish(Scope::User) { Ok(ctx) => ctx, - Err(err) => return Err(errors::SmartcardError::ContextError(err.to_string())), + Err(err) => { + return Err(errors::SmartcardError::ContextError(err.to_string())) + } }; // List available readers. @@ -32,7 +33,8 @@ pub fn get_cards() -> Result, errors::SmartcardError> { found_reader = true; // Try connecting to card in this reader - let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) { + let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) + { Ok(card) => card, Err(Error::NoSmartcard) => { continue; // try next reader diff --git a/openpgp-card/src/errors.rs b/openpgp-card/src/errors.rs index aeeab60..7fbf720 100644 --- a/openpgp-card/src/errors.rs +++ b/openpgp-card/src/errors.rs @@ -100,17 +100,16 @@ pub enum OcErrorStatus { #[error("Unexpected response length: {0}")] ResponseLength(usize), - } impl From<(u8, u8)> for OcErrorStatus { fn from(status: (u8, u8)) -> Self { match (status.0, status.1) { (0x62, 0x85) => OcErrorStatus::TerminationState, - (0x63, 0xC0..=0xCF) => - OcErrorStatus::PasswordNotChecked(status.1 & 0xf), - (0x64, 0x02..=0x80) => - OcErrorStatus::TriggeringByCard(status.1), + (0x63, 0xC0..=0xCF) => { + OcErrorStatus::PasswordNotChecked(status.1 & 0xf) + } + (0x64, 0x02..=0x80) => OcErrorStatus::TriggeringByCard(status.1), (0x65, 0x01) => OcErrorStatus::MemoryFailure, (0x66, 0x00) => OcErrorStatus::SecurityRelatedIssues, (0x67, 0x00) => OcErrorStatus::WrongLength, @@ -130,7 +129,7 @@ impl From<(u8, u8)> for OcErrorStatus { (0x6D, 0x00) => OcErrorStatus::INSNotSupported, (0x6E, 0x00) => OcErrorStatus::CLANotSupported, (0x6F, 0x00) => OcErrorStatus::NoPreciseDiagnosis, - _ => OcErrorStatus::UnknownStatus(status.0, status.1) + _ => OcErrorStatus::UnknownStatus(status.0, status.1), } } } diff --git a/openpgp-card/src/key_upload.rs b/openpgp-card/src/key_upload.rs index 8e90aa9..3987fdf 100644 --- a/openpgp-card/src/key_upload.rs +++ b/openpgp-card/src/key_upload.rs @@ -3,17 +3,18 @@ use anyhow::{anyhow, Result}; -use crate::{KeyType, OpenPGPCardAdmin, tlv, - CardUploadableKey, EccKey, RSAKey, EccType, PrivateKeyMaterial}; use crate::apdu; -use crate::apdu::commands; use crate::apdu::command::Command; +use crate::apdu::commands; use crate::apdu::Le; +use crate::errors::OpenpgpCardError; use crate::parse::algo_attrs::{Algo, RsaAttrs}; use crate::parse::algo_info::AlgoInfo; -use crate::tlv::{Tlv, TlvEntry, tag::Tag}; -use crate::errors::OpenpgpCardError; - +use crate::tlv::{tag::Tag, Tlv, TlvEntry}; +use crate::{ + tlv, CardUploadableKey, EccKey, EccType, KeyType, OpenPGPCardAdmin, + PrivateKeyMaterial, RSAKey, +}; /// Upload an explicitly selected Key to the card as a specific KeyType. /// @@ -27,56 +28,66 @@ pub(crate) fn upload_key( // be cached let algo_list = oca.list_supported_algo()?; - let (algo_cmd, key_cmd) = - match key.get_key()? { - PrivateKeyMaterial::R(rsa_key) => { - // RSA bitsize - // (round up to 4-bytes, in case the key has 8+ leading zeros) - let rsa_bits = - (((rsa_key.get_n().len() * 8 + 31) / 32) * 32) as u16; + let (algo_cmd, key_cmd) = match key.get_key()? { + PrivateKeyMaterial::R(rsa_key) => { + // RSA bitsize + // (round up to 4-bytes, in case the key has 8+ leading zeros) + let rsa_bits = + (((rsa_key.get_n().len() * 8 + 31) / 32) * 32) as u16; - // FIXME: deal with absence of algo list (unwrap!) - // Get suitable algorithm from card's list - let algo = get_card_algo_rsa(algo_list.unwrap(), key_type, rsa_bits); + // FIXME: deal with absence of algo list (unwrap!) + // Get suitable algorithm from card's list + let algo = + get_card_algo_rsa(algo_list.unwrap(), key_type, rsa_bits); - let algo_cmd = rsa_algo_attrs_cmd(key_type, rsa_bits, &algo)?; - let key_cmd = rsa_key_cmd(key_type, rsa_key, &algo)?; + let algo_cmd = rsa_algo_attrs_cmd(key_type, rsa_bits, &algo)?; + let key_cmd = rsa_key_cmd(key_type, rsa_key, &algo)?; - // Return commands - (algo_cmd, key_cmd) - } - PrivateKeyMaterial::E(ecc_key) => { - // Initially there were checks of the following form, here. - // However, some cards seem to report erroneous - // information about supported algorithms. - // (e.g. Yk5 reports support of EdDSA over Cv25519/Ed25519, - // but not ECDH). + // Return commands + (algo_cmd, key_cmd) + } + PrivateKeyMaterial::E(ecc_key) => { + // Initially there were checks of the following form, here. + // However, some cards seem to report erroneous + // information about supported algorithms. + // (e.g. Yk5 reports support of EdDSA over Cv25519/Ed25519, + // but not ECDH). - // if !check_card_algo_*(algo_list.unwrap(), - // key_type, ecc_key.get_oid()) { - // // Error - // } + // if !check_card_algo_*(algo_list.unwrap(), + // key_type, ecc_key.get_oid()) { + // // Error + // } - let algo_cmd = ecc_algo_attrs_cmd(key_type, - ecc_key.get_oid(), - ecc_key.get_type()); + let algo_cmd = ecc_algo_attrs_cmd( + key_type, + ecc_key.get_oid(), + ecc_key.get_type(), + ); - let key_cmd = ecc_key_cmd(ecc_key, key_type)?; + let key_cmd = ecc_key_cmd(ecc_key, key_type)?; - (algo_cmd, key_cmd) - } - }; + (algo_cmd, key_cmd) + } + }; - copy_key_to_card(oca, key_type, key.get_ts(), key.get_fp(), algo_cmd, - key_cmd)?; + copy_key_to_card( + oca, + key_type, + key.get_ts(), + key.get_fp(), + algo_cmd, + key_cmd, + )?; Ok(()) } // FIXME: refactor, these checks currently pointlessly duplicate code -fn get_card_algo_rsa(algo_list: AlgoInfo, key_type: KeyType, rsa_bits: u16) - -> RsaAttrs { - +fn get_card_algo_rsa( + algo_list: AlgoInfo, + key_type: KeyType, + rsa_bits: u16, +) -> RsaAttrs { // Find suitable algorithm parameters (from card's list of algorithms). // FIXME: handle "no list available" (older cards?) // (Current algo parameters of the key slot should be used, then (?)) @@ -84,22 +95,15 @@ fn get_card_algo_rsa(algo_list: AlgoInfo, key_type: KeyType, rsa_bits: u16) // Get Algos for this keytype let keytype_algos: Vec<_> = algo_list.get_by_keytype(key_type); // Get RSA algo attributes - let rsa_algos: Vec<_> = keytype_algos.iter() - .map(|a| - { - if let Algo::Rsa(r) = a { - Some(r) - } else { - None - } - }) + let rsa_algos: Vec<_> = keytype_algos + .iter() + .map(|a| if let Algo::Rsa(r) = a { Some(r) } else { None }) .flatten() .collect(); // Filter card algorithms by rsa bitlength of the key we want to upload - let algo: Vec<_> = rsa_algos.iter() - .filter(|&a| a.len_n == rsa_bits) - .collect(); + let algo: Vec<_> = + rsa_algos.iter().filter(|&a| a.len_n == rsa_bits).collect(); // FIXME: handle error if no algo found let algo = *algo[0]; @@ -108,7 +112,11 @@ fn get_card_algo_rsa(algo_list: AlgoInfo, key_type: KeyType, rsa_bits: u16) } // FIXME: refactor, these checks currently pointlessly duplicate code -fn check_card_algo_ecdh(algo_list: AlgoInfo, key_type: KeyType, oid: &[u8]) -> bool { +fn check_card_algo_ecdh( + algo_list: AlgoInfo, + key_type: KeyType, + oid: &[u8], +) -> bool { // Find suitable algorithm parameters (from card's list of algorithms). // FIXME: handle "no list available" (older cards?) // (Current algo parameters of the key slot should be used, then (?)) @@ -117,15 +125,9 @@ fn check_card_algo_ecdh(algo_list: AlgoInfo, key_type: KeyType, oid: &[u8]) -> b let keytype_algos: Vec<_> = algo_list.get_by_keytype(key_type); // Get attributes - let ecdh_algos: Vec<_> = keytype_algos.iter() - .map(|a| - { - if let Algo::Ecdh(e) = a { - Some(e) - } else { - None - } - }) + let ecdh_algos: Vec<_> = keytype_algos + .iter() + .map(|a| if let Algo::Ecdh(e) = a { Some(e) } else { None }) .flatten() .collect(); @@ -134,8 +136,11 @@ fn check_card_algo_ecdh(algo_list: AlgoInfo, key_type: KeyType, oid: &[u8]) -> b } // FIXME: refactor, these checks currently pointlessly duplicate code -fn check_card_algo_ecdsa(algo_list: AlgoInfo, - key_type: KeyType, oid: &[u8]) -> bool { +fn check_card_algo_ecdsa( + algo_list: AlgoInfo, + key_type: KeyType, + oid: &[u8], +) -> bool { // Find suitable algorithm parameters (from card's list of algorithms). // FIXME: handle "no list available" (older cards?) // (Current algo parameters of the key slot should be used, then (?)) @@ -144,15 +149,15 @@ fn check_card_algo_ecdsa(algo_list: AlgoInfo, let keytype_algos: Vec<_> = algo_list.get_by_keytype(key_type); // Get attributes - let ecdsa_algos: Vec<_> = keytype_algos.iter() - .map(|a| - { - if let Algo::Ecdsa(e) = a { - Some(e) - } else { - None - } - }) + let ecdsa_algos: Vec<_> = keytype_algos + .iter() + .map(|a| { + if let Algo::Ecdsa(e) = a { + Some(e) + } else { + None + } + }) .flatten() .collect(); @@ -161,8 +166,11 @@ fn check_card_algo_ecdsa(algo_list: AlgoInfo, } // FIXME: refactor, these checks currently pointlessly duplicate code -fn check_card_algo_eddsa(algo_list: AlgoInfo, - key_type: KeyType, oid: &[u8]) -> bool { +fn check_card_algo_eddsa( + algo_list: AlgoInfo, + key_type: KeyType, + oid: &[u8], +) -> bool { // Find suitable algorithm parameters (from card's list of algorithms). // FIXME: handle "no list available" (older cards?) // (Current algo parameters of the key slot should be used, then (?)) @@ -171,15 +179,15 @@ fn check_card_algo_eddsa(algo_list: AlgoInfo, let keytype_algos: Vec<_> = algo_list.get_by_keytype(key_type); // Get attributes - let eddsa_algos: Vec<_> = keytype_algos.iter() - .map(|a| - { - if let Algo::Eddsa(e) = a { - Some(e) - } else { - None - } - }) + let eddsa_algos: Vec<_> = keytype_algos + .iter() + .map(|a| { + if let Algo::Eddsa(e) = a { + Some(e) + } else { + None + } + }) .flatten() .collect(); @@ -187,8 +195,10 @@ fn check_card_algo_eddsa(algo_list: AlgoInfo, eddsa_algos.iter().any(|e| e.oid == oid) } -fn ecc_key_cmd(ecc_key: Box, key_type: KeyType) - -> Result { +fn ecc_key_cmd( + ecc_key: Box, + key_type: KeyType, +) -> Result { let scalar_data = ecc_key.get_scalar(); let scalar_len = scalar_data.len() as u8; @@ -196,23 +206,24 @@ fn ecc_key_cmd(ecc_key: Box, key_type: KeyType) let crt = get_crt(key_type)?; // 2) "Cardholder private key template" (7F48) - let cpkt = Tlv(Tag(vec![0x7F, 0x48]), - TlvEntry::S(vec![0x92, scalar_len])); + let cpkt = Tlv(Tag(vec![0x7F, 0x48]), TlvEntry::S(vec![0x92, scalar_len])); // 3) "Cardholder private key" (5F48) let cpk = Tlv(Tag(vec![0x5F, 0x48]), TlvEntry::S(scalar_data.to_vec())); - // "Extended header list (DO 4D)" (contains the three inner TLV) - let ehl = Tlv(Tag(vec![0x4d]), - TlvEntry::C(vec![crt, cpkt, cpk])); - + let ehl = Tlv(Tag(vec![0x4d]), TlvEntry::C(vec![crt, cpkt, cpk])); // The key import uses a PUT DATA command with odd INS (DB) and an // Extended header list (DO 4D) as described in ISO 7816-8 - Ok(Command::new(0x00, 0xDB, 0x3F, 0xFF, - ehl.serialize().to_vec())) + Ok(Command::new( + 0x00, + 0xDB, + 0x3F, + 0xFF, + ehl.serialize().to_vec(), + )) } fn get_crt(key_type: KeyType) -> Result { @@ -221,22 +232,25 @@ fn get_crt(key_type: KeyType) -> Result { KeyType::Decryption => 0xB8, KeyType::Signing => 0xB6, KeyType::Authentication => 0xA4, - _ => return Err(OpenpgpCardError::InternalError - (anyhow!("Unexpected KeyType"))) + _ => { + return Err(OpenpgpCardError::InternalError(anyhow!( + "Unexpected KeyType" + ))) + } }; Ok(Tlv(Tag(vec![tag]), TlvEntry::S(vec![]))) } -fn rsa_key_cmd(key_type: KeyType, - rsa_key: Box, - algo_attrs: &RsaAttrs) -> Result { - +fn rsa_key_cmd( + key_type: KeyType, + rsa_key: Box, + algo_attrs: &RsaAttrs, +) -> Result { // Assemble key command, which contains three sub-TLV: // 1) "Control Reference Template" let crt = get_crt(key_type)?; - // 2) "Cardholder private key template" (7F48) // "describes the input and the length of the content of the following DO" @@ -265,7 +279,6 @@ fn rsa_key_cmd(key_type: KeyType, let cpkt = Tlv(Tag(vec![0x7F, 0x48]), TlvEntry::S(value)); - // 3) "Cardholder private key" (5F48) // // "represents a concatenation of the key data elements according to @@ -287,24 +300,27 @@ fn rsa_key_cmd(key_type: KeyType, let cpk = Tlv(Tag(vec![0x5F, 0x48]), TlvEntry::S(keydata)); - // "Extended header list (DO 4D)" let ehl = Tlv(Tag(vec![0x4d]), TlvEntry::C(vec![crt, cpkt, cpk])); - // The key import uses a PUT DATA command with odd INS (DB) and an // Extended header list (DO 4D) as described in ISO 7816-8 - Ok(Command::new(0x00, 0xDB, 0x3F, 0xFF, - ehl.serialize().to_vec())) + Ok(Command::new( + 0x00, + 0xDB, + 0x3F, + 0xFF, + ehl.serialize().to_vec(), + )) } /// Set algorithm attributes [4.4.3.9 Algorithm Attributes] -fn rsa_algo_attrs_cmd(key_type: KeyType, - rsa_bits: u16, - algo_attrs: &RsaAttrs) -> - Result { - +fn rsa_algo_attrs_cmd( + key_type: KeyType, + rsa_bits: u16, + algo_attrs: &RsaAttrs, +) -> Result { // Algorithm ID (01 = RSA (Encrypt or Sign)) let mut algo_attributes = vec![0x01]; @@ -318,19 +334,26 @@ fn rsa_algo_attrs_cmd(key_type: KeyType, // Import-Format of private key // (This fn currently assumes import_format "00 = standard (e, p, q)") if algo_attrs.import_format != 0 { - return Err( - anyhow!("Unexpected RSA input format (only 0 is supported)")); + return Err(anyhow!( + "Unexpected RSA input format (only 0 is supported)" + )); } algo_attributes.push(algo_attrs.import_format); // Command to PUT the algorithm attributes - Ok(commands::put_data(&[key_type.get_algorithm_tag()], algo_attributes)) + Ok(commands::put_data( + &[key_type.get_algorithm_tag()], + algo_attributes, + )) } /// Set algorithm attributes [4.4.3.9 Algorithm Attributes] -fn ecc_algo_attrs_cmd(key_type: KeyType, oid: &[u8], ecc_type: EccType) - -> Command { +fn ecc_algo_attrs_cmd( + key_type: KeyType, + oid: &[u8], + ecc_type: EccType, +) -> Command { let algo_id = match ecc_type { EccType::EdDSA => 0x16, EccType::ECDH => 0x12, @@ -345,15 +368,15 @@ fn ecc_algo_attrs_cmd(key_type: KeyType, oid: &[u8], ecc_type: EccType) commands::put_data(&[key_type.get_algorithm_tag()], algo_attributes) } -fn copy_key_to_card(oca: &OpenPGPCardAdmin, - key_type: KeyType, - ts: u64, - fp: Vec, - algo_cmd: Command, - key_cmd: Command) - -> Result<(), OpenpgpCardError> { - let fp_cmd = - commands::put_data(&[key_type.get_fingerprint_put_tag()], fp); +fn copy_key_to_card( + oca: &OpenPGPCardAdmin, + key_type: KeyType, + ts: u64, + fp: Vec, + algo_cmd: Command, + key_cmd: Command, +) -> Result<(), OpenpgpCardError> { + let fp_cmd = commands::put_data(&[key_type.get_fingerprint_put_tag()], fp); // Timestamp update let time_value: Vec = ts @@ -366,7 +389,6 @@ fn copy_key_to_card(oca: &OpenPGPCardAdmin, let time_cmd = commands::put_data(&[key_type.get_timestamp_put_tag()], time_value); - // Send all the commands let ext = Le::None; // FIXME?! diff --git a/openpgp-card/src/lib.rs b/openpgp-card/src/lib.rs index 247366c..3805227 100644 --- a/openpgp-card/src/lib.rs +++ b/openpgp-card/src/lib.rs @@ -6,17 +6,13 @@ use std::convert::TryFrom; use anyhow::{anyhow, Result}; use pcsc::*; -use apdu::{commands, Le, response::Response}; -use parse::{algo_attrs::Algo, - algo_info::AlgoInfo, - application_id::ApplicationId, - cardholder::CardHolder, - extended_cap::ExtendedCap, - extended_cap::Features, - extended_length_info::ExtendedLengthInfo, - fingerprint, - historical::Historical, - KeySet}; +use apdu::{commands, response::Response, Le}; +use parse::{ + algo_attrs::Algo, algo_info::AlgoInfo, application_id::ApplicationId, + cardholder::CardHolder, extended_cap::ExtendedCap, extended_cap::Features, + extended_length_info::ExtendedLengthInfo, fingerprint, + historical::Historical, KeySet, +}; use tlv::Tlv; use crate::errors::{OpenpgpCardError, SmartcardError}; @@ -24,14 +20,13 @@ use crate::tlv::tag::Tag; use crate::tlv::TlvEntry; use std::ops::Deref; -pub mod errors; mod apdu; mod card; +pub mod errors; mod key_upload; mod parse; mod tlv; - pub enum Hash<'a> { SHA256([u8; 0x20]), SHA384([u8; 0x30]), @@ -42,13 +37,16 @@ pub enum Hash<'a> { impl Hash<'_> { fn oid(&self) -> Option<&'static [u8]> { match self { - Self::SHA256(_) => - Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01]), - Self::SHA384(_) => - Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02]), - Self::SHA512(_) => - Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03]), - Self::EdDSA(_) => None + Self::SHA256(_) => { + Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01]) + } + Self::SHA384(_) => { + Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02]) + } + Self::SHA512(_) => { + Some(&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03]) + } + Self::EdDSA(_) => None, } } @@ -57,12 +55,11 @@ impl Hash<'_> { Self::SHA256(d) => &d[..], Self::SHA384(d) => &d[..], Self::SHA512(d) => &d[..], - Self::EdDSA(d) => d + Self::EdDSA(d) => d, } } } - /// A PGP-implementation-agnostic wrapper for private key data, to upload /// to an OpenPGP card pub trait CardUploadableKey { @@ -116,9 +113,13 @@ pub enum DecryptMe<'a> { ECDH(&'a [u8]), } - #[derive(Debug)] -pub enum Sex { NotKnown, Male, Female, NotApplicable } +pub enum Sex { + NotKnown, + Male, + Female, + NotApplicable, +} impl Sex { pub fn as_u8(&self) -> u8 { @@ -142,7 +143,6 @@ impl From for Sex { } } - /// Enum to identify one of the Key-slots on an OpenPGP card #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum KeyType { @@ -219,17 +219,24 @@ impl OpenPGPCard { /// Get all cards that can be opened as an OpenPGP card applet pub fn list_cards() -> Result> { let cards = card::get_cards().map_err(|err| anyhow!(err))?; - let ocs: Vec<_> = cards.into_iter().map(Self::open_card) - .map(|oc| oc.ok()).flatten().collect(); + let ocs: Vec<_> = cards + .into_iter() + .map(Self::open_card) + .map(|oc| oc.ok()) + .flatten() + .collect(); Ok(ocs) } /// Find an OpenPGP card by serial number and return it. pub fn open_by_serial(serial: &str) -> Result { - let cards = card::get_cards() - .map_err(|e| OpenpgpCardError::Smartcard( - SmartcardError::Error(format!("{:?}", e))))?; + let cards = card::get_cards().map_err(|e| { + OpenpgpCardError::Smartcard(SmartcardError::Error(format!( + "{:?}", + e + ))) + })?; for card in cards { let res = Self::open_card(card); @@ -248,9 +255,12 @@ impl OpenPGPCard { /// Open connection to some card and select the openpgp applet pub fn open_yolo() -> Result { - let mut cards = card::get_cards() - .map_err(|e| OpenpgpCardError::Smartcard( - SmartcardError::Error(format!("{:?}", e))))?; + let mut cards = card::get_cards().map_err(|e| { + OpenpgpCardError::Smartcard(SmartcardError::Error(format!( + "{:?}", + e + ))) + })?; // randomly use the first card in the list let card = cards.swap_remove(0); @@ -262,8 +272,7 @@ impl OpenPGPCard { fn open_card(card: Card) -> Result { let select_openpgp = commands::select_openpgp(); - let resp = - apdu::send_command(&card, select_openpgp, Le::Short, None)?; + let resp = apdu::send_command(&card, select_openpgp, Le::Short, None)?; if resp.is_ok() { // read and cache "application related data" @@ -314,7 +323,9 @@ impl OpenPGPCard { } } - pub fn get_extended_length_information(&self) -> Result> { + pub fn get_extended_length_information( + &self, + ) -> Result> { // get from cached "application related data" let eli = self.ard.find(&Tag::from([0x7F, 0x66])); @@ -337,7 +348,9 @@ impl OpenPGPCard { unimplemented!() } - pub fn get_extended_capabilities(&self) -> Result { + pub fn get_extended_capabilities( + &self, + ) -> Result { // get from cached "application related data" let ecap = self.ard.find(&Tag::from([0xc0])); @@ -355,8 +368,10 @@ impl OpenPGPCard { if let Some(aa) = aa { Algo::try_from(&aa.serialize()[..]) } else { - Err(anyhow!("Failed to get algorithm attributes for {:?}.", - key_type)) + Err(anyhow!( + "Failed to get algorithm attributes for {:?}.", + key_type + )) } } @@ -364,7 +379,9 @@ impl OpenPGPCard { unimplemented!() } - pub fn get_fingerprints(&self) -> Result, OpenpgpCardError> { + pub fn get_fingerprints( + &self, + ) -> Result, OpenpgpCardError> { // Get from cached "application related data" let fp = self.ard.find(&Tag::from([0xc5])); @@ -416,10 +433,18 @@ impl OpenPGPCard { let _eli = self.get_extended_length_information()?; // FIXME: figure out Le - let resp = apdu::send_command(&self.card, commands::get_url(), Le::Long, Some(self))?; + let resp = apdu::send_command( + &self.card, + commands::get_url(), + Le::Long, + Some(self), + )?; - log::trace!(" final response: {:x?}, data len {}", - resp, resp.raw_data().len()); + log::trace!( + " final response: {:x?}, data len {}", + resp, + resp.raw_data().len() + ); Ok(String::from_utf8_lossy(resp.data()?).to_string()) } @@ -443,8 +468,11 @@ impl OpenPGPCard { let resp = apdu::send_command(&self.card, sst, ext, Some(self))?; resp.check_ok()?; - log::trace!(" final response: {:x?}, data len {}", - resp, resp.data()?.len()); + log::trace!( + " final response: {:x?}, data len {}", + resp, + resp.data()?.len() + ); Tlv::try_from(resp.data()?) } @@ -460,7 +488,12 @@ impl OpenPGPCard { return Ok(None); } - let resp = apdu::send_command(&self.card, commands::get_algo_list(), Le::Short, Some(self))?; + let resp = apdu::send_command( + &self.card, + commands::get_algo_list(), + Le::Short, + Some(self), + )?; resp.check_ok()?; let ai = AlgoInfo::try_from(resp.data()?)?; @@ -475,9 +508,11 @@ impl OpenPGPCard { // [apdu 00 20 00 81 08 40 40 40 40 40 40 40 40] for _ in 0..4 { let verify = commands::verify_pw1_81([0x40; 8].to_vec()); - let resp = apdu::send_command(&self.card, verify, Le::None, Some(self))?; + let resp = + apdu::send_command(&self.card, verify, Le::None, Some(self))?; if !(resp.status() == [0x69, 0x82] - || resp.status() == [0x69, 0x83]) { + || resp.status() == [0x69, 0x83]) + { return Err(anyhow!("Unexpected status for reset, at pw1.")); } } @@ -486,10 +521,12 @@ impl OpenPGPCard { // [apdu 00 20 00 83 08 40 40 40 40 40 40 40 40] for _ in 0..4 { let verify = commands::verify_pw3([0x40; 8].to_vec()); - let resp = apdu::send_command(&self.card, verify, Le::None, Some(self))?; + let resp = + apdu::send_command(&self.card, verify, Le::None, Some(self))?; if !(resp.status() == [0x69, 0x82] - || resp.status() == [0x69, 0x83]) { + || resp.status() == [0x69, 0x83]) + { return Err(anyhow!("Unexpected status for reset, at pw3.")); } } @@ -510,8 +547,10 @@ impl OpenPGPCard { Ok(()) } - pub fn verify_pw1_81(self, pin: &str) - -> Result { + pub fn verify_pw1_81( + self, + pin: &str, + ) -> Result { assert!(pin.len() >= 6); // FIXME: Err let verify = commands::verify_pw1_81(pin.as_bytes().to_vec()); @@ -527,8 +566,10 @@ impl OpenPGPCard { Err(self) } - pub fn verify_pw1_82(self, pin: &str) - -> Result { + pub fn verify_pw1_82( + self, + pin: &str, + ) -> Result { assert!(pin.len() >= 6); // FIXME: Err let verify = commands::verify_pw1_82(pin.as_bytes().to_vec()); @@ -544,7 +585,10 @@ impl OpenPGPCard { Err(self) } - pub fn verify_pw3(self, pin: &str) -> Result { + pub fn verify_pw3( + self, + pin: &str, + ) -> Result { assert!(pin.len() >= 8); // FIXME: Err let verify = commands::verify_pw3(pin.as_bytes().to_vec()); @@ -561,7 +605,6 @@ impl OpenPGPCard { } } - /// An OpenPGP card after successful verification of PW1 (needs to be split /// further to model authentication for signing) pub struct OpenPGPCardUser { @@ -579,8 +622,7 @@ impl Deref for OpenPGPCardUser { impl OpenPGPCardUser { /// Decrypt the ciphertext in `dm`, on the card. - pub fn decrypt(&self, dm: DecryptMe) - -> Result, OpenpgpCardError> { + pub fn decrypt(&self, dm: DecryptMe) -> Result, OpenpgpCardError> { match dm { DecryptMe::RSA(message) => { let mut data = vec![0x0]; @@ -591,16 +633,13 @@ impl OpenPGPCardUser { } DecryptMe::ECDH(eph) => { // External Public Key - let epk = Tlv(Tag(vec![0x86]), - TlvEntry::S(eph.to_vec())); + let epk = Tlv(Tag(vec![0x86]), TlvEntry::S(eph.to_vec())); // Public Key DO - let pkdo = Tlv(Tag(vec![0x7f, 0x49]), - TlvEntry::C(vec![epk])); + let pkdo = Tlv(Tag(vec![0x7f, 0x49]), TlvEntry::C(vec![epk])); // Cipher DO - let cdo = Tlv(Tag(vec![0xa6]), - TlvEntry::C(vec![pkdo])); + let cdo = Tlv(Tag(vec![0xa6]), TlvEntry::C(vec![pkdo])); self.pso_decipher(cdo.serialize()) } @@ -609,57 +648,69 @@ impl OpenPGPCardUser { /// Run decryption operation on the smartcard /// (7.2.11 PSO: DECIPHER) - pub(crate) fn pso_decipher(&self, data: Vec) - -> Result, OpenpgpCardError> { + pub(crate) fn pso_decipher( + &self, + data: Vec, + ) -> Result, OpenpgpCardError> { // The OpenPGP card is already connected and PW1 82 has been verified let dec_cmd = commands::decryption(data); - let resp = apdu::send_command(&self.card, dec_cmd, Le::Short, Some(self))?; + let resp = + apdu::send_command(&self.card, dec_cmd, Le::Short, Some(self))?; resp.check_ok()?; Ok(resp.data().map(|d| d.to_vec())?) } - /// Sign the message in `hash`, on the card. - pub fn signature_for_hash(&self, hash: Hash) - -> Result, OpenpgpCardError> { + pub fn signature_for_hash( + &self, + hash: Hash, + ) -> Result, OpenpgpCardError> { match hash { Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => { - let tlv = Tlv(Tag(vec![0x30]), - TlvEntry::C( - vec![Tlv(Tag(vec![0x30]), - TlvEntry::C( - vec![Tlv(Tag(vec![0x06]), - // unwrapping is - // ok, for SHA* - TlvEntry::S(hash.oid().unwrap().to_vec())), - Tlv(Tag(vec![0x05]), TlvEntry::S(vec![])) - ])), - Tlv(Tag(vec!(0x04)), TlvEntry::S(hash.digest().to_vec())) - ] - )); + let tlv = Tlv( + Tag(vec![0x30]), + TlvEntry::C(vec![ + Tlv( + Tag(vec![0x30]), + TlvEntry::C(vec![ + Tlv( + Tag(vec![0x06]), + // unwrapping is + // ok, for SHA* + TlvEntry::S(hash.oid().unwrap().to_vec()), + ), + Tlv(Tag(vec![0x05]), TlvEntry::S(vec![])), + ]), + ), + Tlv( + Tag(vec![0x04]), + TlvEntry::S(hash.digest().to_vec()), + ), + ]), + ); Ok(self.compute_digital_signature(tlv.serialize())?) } - Hash::EdDSA(d) => { - Ok(self.compute_digital_signature(d.to_vec())?) - } + Hash::EdDSA(d) => Ok(self.compute_digital_signature(d.to_vec())?), } } /// Run signing operation on the smartcard /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) - pub(crate) fn compute_digital_signature(&self, data: Vec) - -> Result, OpenpgpCardError> { + pub(crate) fn compute_digital_signature( + &self, + data: Vec, + ) -> Result, OpenpgpCardError> { let dec_cmd = commands::signature(data); - let resp = apdu::send_command(&self.card, dec_cmd, Le::Short, Some(self))?; + let resp = + apdu::send_command(&self.card, dec_cmd, Le::Short, Some(self))?; Ok(resp.data().map(|d| d.to_vec())?) } } - /// An OpenPGP card after successful verification of PW3 pub struct OpenPGPCardAdmin { oc: OpenPGPCard, @@ -732,26 +783,26 @@ impl OpenPGPCardAdmin { } } - #[cfg(test)] mod test { - use super::tlv::{Tlv, TlvEntry}; use super::tlv::tag::Tag; + use super::tlv::{Tlv, TlvEntry}; #[test] fn test_tlv() { - let cpkt = - Tlv(Tag(vec![0x7F, 0x48]), - TlvEntry::S(vec![0x91, 0x03, - 0x92, 0x82, 0x01, 0x00, - 0x93, 0x82, 0x01, 0x00])); + let cpkt = Tlv( + Tag(vec![0x7F, 0x48]), + TlvEntry::S(vec![ + 0x91, 0x03, 0x92, 0x82, 0x01, 0x00, 0x93, 0x82, 0x01, 0x00, + ]), + ); - assert_eq!(cpkt.serialize(), - vec![0x7F, 0x48, - 0x0A, - 0x91, 0x03, - 0x92, 0x82, 0x01, 0x00, - 0x93, 0x82, 0x01, 0x00, - ]); + assert_eq!( + cpkt.serialize(), + vec![ + 0x7F, 0x48, 0x0A, 0x91, 0x03, 0x92, 0x82, 0x01, 0x00, 0x93, + 0x82, 0x01, 0x00, + ] + ); } } diff --git a/openpgp-card/src/parse/algo_attrs.rs b/openpgp-card/src/parse/algo_attrs.rs index 6ccf81c..1b8f3bc 100644 --- a/openpgp-card/src/parse/algo_attrs.rs +++ b/openpgp-card/src/parse/algo_attrs.rs @@ -4,10 +4,10 @@ use std::convert::TryFrom; use anyhow::Result; -use nom::{branch, bytes::complete as bytes, number::complete as number}; use nom::branch::alt; use nom::bytes::complete::tag; use nom::combinator::map; +use nom::{branch, bytes::complete as bytes, number::complete as number}; use crate::parse; @@ -35,7 +35,11 @@ pub struct EcdsaAttrs { impl EcdsaAttrs { pub fn new(curve: Curve, import_format: Option) -> Self { - Self { curve, oid: curve.oid().to_vec(), import_format } + Self { + curve, + oid: curve.oid().to_vec(), + import_format, + } } } @@ -48,7 +52,11 @@ pub struct EddsaAttrs { impl EddsaAttrs { pub fn new(curve: Curve, import_format: Option) -> Self { - Self { curve, oid: curve.oid().to_vec(), import_format } + Self { + curve, + oid: curve.oid().to_vec(), + import_format, + } } } @@ -61,7 +69,11 @@ pub struct EcdhAttrs { impl EcdhAttrs { pub fn new(curve: Curve, import_format: Option) -> Self { - Self { curve, oid: curve.oid().to_vec(), import_format } + Self { + curve, + oid: curve.oid().to_vec(), + import_format, + } } } @@ -87,24 +99,26 @@ impl Curve { NistP256r1 => &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07], NistP384r1 => &[0x2B, 0x81, 0x04, 0x00, 0x22], NistP521r1 => &[0x2B, 0x81, 0x04, 0x00, 0x23], - BrainpoolP256r1 => - &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07], - BrainpoolP384r1 => - &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0b], - BrainpoolP512r1 => - &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d], + BrainpoolP256r1 => { + &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07] + } + BrainpoolP384r1 => { + &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0b] + } + BrainpoolP512r1 => { + &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0d] + } Secp256k1 => &[0x2B, 0x81, 0x04, 0x00, 0x0A], - Ed25519 => - &[0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01], - Cv25519 => - &[0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01], + Ed25519 => &[0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01], + Cv25519 => { + &[0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01] + } Ed448 => &[0x2b, 0x65, 0x71], X448 => &[0x2b, 0x65, 0x6f], } } } - fn parse_oid_cv25519(input: &[u8]) -> nom::IResult<&[u8], Curve> { map(tag(Curve::Cv25519.oid()), |_| Curve::Cv25519)(input) } @@ -130,15 +144,21 @@ fn parse_oid_nist521(input: &[u8]) -> nom::IResult<&[u8], Curve> { } fn parse_oid_brainpool_p256r1(input: &[u8]) -> nom::IResult<&[u8], Curve> { - map(tag(Curve::BrainpoolP256r1.oid()), |_| Curve::BrainpoolP256r1)(input) + map(tag(Curve::BrainpoolP256r1.oid()), |_| { + Curve::BrainpoolP256r1 + })(input) } fn parse_oid_brainpool_p384r1(input: &[u8]) -> nom::IResult<&[u8], Curve> { - map(tag(Curve::BrainpoolP384r1.oid()), |_| Curve::BrainpoolP384r1)(input) + map(tag(Curve::BrainpoolP384r1.oid()), |_| { + Curve::BrainpoolP384r1 + })(input) } fn parse_oid_brainpool_p512r1(input: &[u8]) -> nom::IResult<&[u8], Curve> { - map(tag(Curve::BrainpoolP512r1.oid()), |_| Curve::BrainpoolP512r1)(input) + map(tag(Curve::BrainpoolP512r1.oid()), |_| { + Curve::BrainpoolP512r1 + })(input) } fn parse_oid_ed448(input: &[u8]) -> nom::IResult<&[u8], Curve> { @@ -150,12 +170,19 @@ fn parse_oid_x448(input: &[u8]) -> nom::IResult<&[u8], Curve> { } fn parse_oid(input: &[u8]) -> nom::IResult<&[u8], Curve> { - alt((parse_oid_nist256, parse_oid_nist384, parse_oid_nist521, - parse_oid_brainpool_p256r1, parse_oid_brainpool_p384r1, - parse_oid_brainpool_p512r1, - parse_oid_secp256k1, - parse_oid_ed25519, parse_oid_cv25519, - parse_oid_ed448, parse_oid_x448))(input) + alt(( + parse_oid_nist256, + parse_oid_nist384, + parse_oid_nist521, + parse_oid_brainpool_p256r1, + parse_oid_brainpool_p384r1, + parse_oid_brainpool_p512r1, + parse_oid_secp256k1, + parse_oid_ed25519, + parse_oid_cv25519, + parse_oid_ed448, + parse_oid_x448, + ))(input) } fn parse_rsa(input: &[u8]) -> nom::IResult<&[u8], Algo> { @@ -165,7 +192,14 @@ fn parse_rsa(input: &[u8]) -> nom::IResult<&[u8], Algo> { let (input, len_e) = number::be_u16(input)?; let (input, import_format) = number::u8(input)?; - Ok((input, Algo::Rsa(RsaAttrs { len_n, len_e, import_format }))) + Ok(( + input, + Algo::Rsa(RsaAttrs { + len_n, + len_e, + import_format, + }), + )) } fn parse_import_format(input: &[u8]) -> nom::IResult<&[u8], Option> { @@ -208,9 +242,7 @@ fn parse_eddsa(input: &[u8]) -> nom::IResult<&[u8], Algo> { } pub(crate) fn parse(input: &[u8]) -> nom::IResult<&[u8], Algo> { - branch::alt( - (parse_rsa, parse_ecdsa, parse_eddsa, parse_ecdh) - )(input) + branch::alt((parse_rsa, parse_ecdsa, parse_eddsa, parse_ecdh))(input) } impl TryFrom<&[u8]> for Algo { diff --git a/openpgp-card/src/parse/algo_info.rs b/openpgp-card/src/parse/algo_info.rs index cd61872..93dc6e0 100644 --- a/openpgp-card/src/parse/algo_info.rs +++ b/openpgp-card/src/parse/algo_info.rs @@ -4,18 +4,16 @@ use std::convert::TryFrom; use anyhow::Result; -use nom::{branch, bytes::complete as bytes, combinator, multi, sequence}; use nom::branch::alt; use nom::combinator::map; +use nom::{branch, bytes::complete as bytes, combinator, multi, sequence}; -use crate::KeyType; use crate::parse::algo_attrs; use crate::parse::algo_attrs::Algo; +use crate::KeyType; #[derive(Debug, Clone, Eq, PartialEq)] -pub struct AlgoInfo( - Vec<(KeyType, Algo)> -); +pub struct AlgoInfo(Vec<(KeyType, Algo)>); impl AlgoInfo { pub fn get_by_keytype(&self, kt: KeyType) -> Vec<&Algo> { @@ -54,11 +52,11 @@ fn parse_list(input: &[u8]) -> nom::IResult<&[u8], Vec<(KeyType, Algo)>> { } fn parse_tl_list(input: &[u8]) -> nom::IResult<&[u8], Vec<(KeyType, Algo)>> { - let (input, (_, _, list)) = - sequence::tuple(( - bytes::tag([0xfa]), - crate::tlv::length::length, - parse_list))(input)?; + let (input, (_, _, list)) = sequence::tuple(( + bytes::tag([0xfa]), + crate::tlv::length::length, + parse_list, + ))(input)?; Ok((input, list)) } @@ -70,10 +68,10 @@ pub(self) fn parse(input: &[u8]) -> nom::IResult<&[u8], Vec<(KeyType, Algo)>> { // -- Gnuk: do_alg_info (uint16_t tag, int with_tag) - branch::alt( - (combinator::all_consuming(parse_list), - combinator::all_consuming(parse_tl_list)) - )(input) + branch::alt(( + combinator::all_consuming(parse_list), + combinator::all_consuming(parse_tl_list), + ))(input) } impl TryFrom<&[u8]> for AlgoInfo { @@ -84,228 +82,431 @@ impl TryFrom<&[u8]> for AlgoInfo { } } - // test - #[cfg(test)] mod test { use std::convert::TryFrom; - use crate::KeyType::*; - use crate::parse::algo_attrs::*; use crate::parse::algo_attrs::Algo::*; use crate::parse::algo_attrs::Curve::*; + use crate::parse::algo_attrs::*; use crate::parse::algo_info::AlgoInfo; + use crate::KeyType::*; #[test] fn test_gnuk() { - let data = [0xc1, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc1, 0x6, - 0x1, 0x10, 0x0, 0x0, 0x20, 0x0, 0xc1, 0x9, 0x13, 0x2a, 0x86, - 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc1, 0x6, 0x13, 0x2b, 0x81, - 0x4, 0x0, 0xa, 0xc1, 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, - 0xda, 0x47, 0xf, 0x1, 0xc2, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, - 0x0, 0xc2, 0x6, 0x1, 0x10, 0x0, 0x0, 0x20, 0x0, 0xc2, 0x9, - 0x13, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc2, 0x6, - 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc2, 0xb, 0x12, 0x2b, 0x6, - 0x1, 0x4, 0x1, 0x97, 0x55, 0x1, 0x5, 0x1, 0xc3, 0x6, 0x1, 0x8, - 0x0, 0x0, 0x20, 0x0, 0xc3, 0x6, 0x1, 0x10, 0x0, 0x0, 0x20, - 0x0, 0xc3, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x3, 0x1, - 0x7, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc3, 0xa, - 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, 0xf, 0x1]; + let data = [ + 0xc1, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc1, 0x6, 0x1, 0x10, + 0x0, 0x0, 0x20, 0x0, 0xc1, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x3, 0x1, 0x7, 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, + 0xc1, 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, 0xf, 0x1, + 0xc2, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc2, 0x6, 0x1, 0x10, + 0x0, 0x0, 0x20, 0x0, 0xc2, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x3, 0x1, 0x7, 0xc2, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, + 0xc2, 0xb, 0x12, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x97, 0x55, 0x1, 0x5, + 0x1, 0xc3, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc3, 0x6, 0x1, + 0x10, 0x0, 0x0, 0x20, 0x0, 0xc3, 0x9, 0x13, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, + 0xa, 0xc3, 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, 0xf, + 0x1, + ]; let ai = AlgoInfo::try_from(data.to_vec()).unwrap(); assert_eq!( - ai, AlgoInfo( - vec![ - (Signing, Rsa(RsaAttrs { len_n: 2048, len_e: 32, import_format: 0 })), - (Signing, Rsa(RsaAttrs { len_n: 4096, len_e: 32, import_format: 0 })), - (Signing, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), - (Signing, Eddsa(EddsaAttrs::new(Ed25519, None))), - (Decryption, Rsa(RsaAttrs { len_n: 2048, len_e: 32, import_format: 0 })), - (Decryption, Rsa(RsaAttrs { len_n: 4096, len_e: 32, import_format: 0 })), - (Decryption, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Decryption, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), - (Decryption, Ecdh(EcdhAttrs::new(Cv25519, None))), - (Authentication, Rsa(RsaAttrs { len_n: 2048, len_e: 32, import_format: 0 })), - (Authentication, Rsa(RsaAttrs { len_n: 4096, len_e: 32, import_format: 0 })), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), - (Authentication, Eddsa(EddsaAttrs::new(Ed25519, None))) - ] - ) + ai, + AlgoInfo(vec![ + ( + Signing, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 32, + import_format: 0 + }) + ), + ( + Signing, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 32, + import_format: 0 + }) + ), + (Signing, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), + (Signing, Eddsa(EddsaAttrs::new(Ed25519, None))), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 32, + import_format: 0 + }) + ), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 32, + import_format: 0 + }) + ), + (Decryption, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Decryption, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), + (Decryption, Ecdh(EcdhAttrs::new(Cv25519, None))), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 32, + import_format: 0 + }) + ), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 32, + import_format: 0 + }) + ), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Authentication, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), + (Authentication, Eddsa(EddsaAttrs::new(Ed25519, None))) + ]) ); } #[test] fn test_opgp_card_34() { - let data = [0xc1, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc1, 0x6, - 0x1, 0xc, 0x0, 0x0, 0x20, 0x0, 0xc1, 0x6, 0x1, 0x10, 0x0, - 0x0, 0x20, 0x0, 0xc1, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, - 0x3d, 0x3, 0x1, 0x7, 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, - 0x22, 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc1, 0xa, - 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc1, - 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, - 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, - 0xd, 0xc2, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc2, 0x6, - 0x1, 0xc, 0x0, 0x0, 0x20, 0x0, 0xc2, 0x6, 0x1, 0x10, 0x0, - 0x0, 0x20, 0x0, 0xc2, 0x9, 0x12, 0x2a, 0x86, 0x48, 0xce, - 0x3d, 0x3, 0x1, 0x7, 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, - 0x22, 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc2, 0xa, - 0x12, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc2, - 0xa, 0x12, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, - 0xc2, 0xa, 0x12, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, - 0xd, 0xc3, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc3, 0x6, 0x1, - 0xc, 0x0, 0x0, 0x20, 0x0, 0xc3, 0x6, 0x1, 0x10, 0x0, 0x0, - 0x20, 0x0, 0xc3, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x3, - 0x1, 0x7, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x22, 0xc3, - 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc3, 0xa, 0x13, 0x2b, - 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc3, 0xa, 0x13, - 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xc3, 0xa, - 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xd]; + let data = [ + 0xc1, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, 0xc1, 0x6, 0x1, 0xc, + 0x0, 0x0, 0x20, 0x0, 0xc1, 0x6, 0x1, 0x10, 0x0, 0x0, 0x20, 0x0, + 0xc1, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, + 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x22, 0xc1, 0x6, 0x13, + 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, + 0x2, 0x8, 0x1, 0x1, 0x7, 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, + 0x2, 0x8, 0x1, 0x1, 0xb, 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, + 0x2, 0x8, 0x1, 0x1, 0xd, 0xc2, 0x6, 0x1, 0x8, 0x0, 0x0, 0x20, 0x0, + 0xc2, 0x6, 0x1, 0xc, 0x0, 0x0, 0x20, 0x0, 0xc2, 0x6, 0x1, 0x10, + 0x0, 0x0, 0x20, 0x0, 0xc2, 0x9, 0x12, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x3, 0x1, 0x7, 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, 0x22, + 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc2, 0xa, 0x12, + 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc2, 0xa, 0x12, + 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xc2, 0xa, 0x12, + 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, 0xc3, 0x6, 0x1, + 0x8, 0x0, 0x0, 0x20, 0x0, 0xc3, 0x6, 0x1, 0xc, 0x0, 0x0, 0x20, + 0x0, 0xc3, 0x6, 0x1, 0x10, 0x0, 0x0, 0x20, 0x0, 0xc3, 0x9, 0x13, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc3, 0x6, 0x13, + 0x2b, 0x81, 0x4, 0x0, 0x22, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, + 0x23, 0xc3, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, + 0x7, 0xc3, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, + 0xb, 0xc3, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, + 0xd, + ]; let ai = AlgoInfo::try_from(data.to_vec()).unwrap(); assert_eq!( - ai, AlgoInfo( - vec![ - (Signing, Rsa(RsaAttrs { len_n: 2048, len_e: 32, import_format: 0 })), - (Signing, Rsa(RsaAttrs { len_n: 3072, len_e: 32, import_format: 0 })), - (Signing, Rsa(RsaAttrs { len_n: 4096, len_e: 32, import_format: 0 })), - (Signing, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), - (Decryption, Rsa(RsaAttrs { len_n: 2048, len_e: 32, import_format: 0 })), - (Decryption, Rsa(RsaAttrs { len_n: 3072, len_e: 32, import_format: 0 })), - (Decryption, Rsa(RsaAttrs { len_n: 4096, len_e: 32, import_format: 0 })), - (Decryption, Ecdh(EcdhAttrs::new(NistP256r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(NistP384r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(NistP521r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP256r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP384r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP512r1, None))), - (Authentication, Rsa(RsaAttrs { len_n: 2048, len_e: 32, import_format: 0 })), - (Authentication, Rsa(RsaAttrs { len_n: 3072, len_e: 32, import_format: 0 })), - (Authentication, Rsa(RsaAttrs { len_n: 4096, len_e: 32, import_format: 0 })), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))) - ] - ) + ai, + AlgoInfo(vec![ + ( + Signing, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 32, + import_format: 0 + }) + ), + ( + Signing, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 32, + import_format: 0 + }) + ), + ( + Signing, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 32, + import_format: 0 + }) + ), + (Signing, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 32, + import_format: 0 + }) + ), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 32, + import_format: 0 + }) + ), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 32, + import_format: 0 + }) + ), + (Decryption, Ecdh(EcdhAttrs::new(NistP256r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(NistP384r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(NistP521r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP256r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP384r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP512r1, None))), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 32, + import_format: 0 + }) + ), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 32, + import_format: 0 + }) + ), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 32, + import_format: 0 + }) + ), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), + ( + Authentication, + Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None)) + ), + ( + Authentication, + Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None)) + ), + ( + Authentication, + Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None)) + ) + ]) ); } - #[test] fn test_yk5() { - let data = [0xfa, 0x82, 0x1, 0xe2, 0xc1, 0x6, 0x1, 0x8, 0x0, 0x0, - 0x11, 0x0, 0xc1, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xc1, - 0x6, 0x1, 0x10, 0x0, 0x0, 0x11, 0x0, 0xc1, 0x9, 0x13, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc1, 0x6, 0x13, 0x2b, - 0x81, 0x4, 0x0, 0x22, 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, - 0x23, 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc1, 0xa, - 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc1, - 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, - 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, - 0xd, 0xc1, 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, - 0xf, 0x1, 0xc1, 0xb, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x97, - 0x55, 0x1, 0x5, 0x1, 0xc2, 0x6, 0x1, 0x8, 0x0, 0x0, 0x11, - 0x0, 0xc2, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xc2, 0x6, - 0x1, 0x10, 0x0, 0x0, 0x11, 0x0, 0xc2, 0x9, 0x12, 0x2a, 0x86, - 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc2, 0x6, 0x12, 0x2b, 0x81, - 0x4, 0x0, 0x22, 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, 0x23, - 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc2, 0xa, 0x12, - 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc2, 0xa, - 0x12, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xc2, - 0xa, 0x12, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, - 0xc2, 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, 0xf, - 0x1, 0xc2, 0xb, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x97, 0x55, - 0x1, 0x5, 0x1, 0xc3, 0x6, 0x1, 0x8, 0x0, 0x0, 0x11, 0x0, - 0xc3, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xc3, 0x6, 0x1, - 0x10, 0x0, 0x0, 0x11, 0x0, 0xc3, 0x9, 0x13, 0x2a, 0x86, 0x48, - 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, - 0x0, 0x22, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc3, - 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc3, 0xa, 0x13, 0x2b, - 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc3, 0xa, 0x13, - 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xc3, 0xa, - 0x13, 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, 0xc3, - 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, 0xf, 0x1, - 0xc3, 0xb, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x97, 0x55, 0x1, - 0x5, 0x1, 0xda, 0x6, 0x1, 0x8, 0x0, 0x0, 0x11, 0x0, 0xda, - 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xda, 0x6, 0x1, 0x10, - 0x0, 0x0, 0x11, 0x0, 0xda, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, - 0x3d, 0x3, 0x1, 0x7, 0xda, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, - 0x22, 0xda, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xda, 0x6, - 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xda, 0xa, 0x13, 0x2b, 0x24, - 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xda, 0xa, 0x13, 0x2b, - 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xda, 0xa, 0x13, - 0x2b, 0x24, 0x3, 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, 0xda, 0xa, - 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0xda, 0x47, 0xf, 0x1, 0xda, - 0xb, 0x16, 0x2b, 0x6, 0x1, 0x4, 0x1, 0x97, 0x55, 0x1, 0x5, 0x1]; + let data = [ + 0xfa, 0x82, 0x1, 0xe2, 0xc1, 0x6, 0x1, 0x8, 0x0, 0x0, 0x11, 0x0, + 0xc1, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xc1, 0x6, 0x1, 0x10, + 0x0, 0x0, 0x11, 0x0, 0xc1, 0x9, 0x13, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x3, 0x1, 0x7, 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x22, + 0xc1, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc1, 0x6, 0x13, + 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, + 0x2, 0x8, 0x1, 0x1, 0x7, 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, + 0x2, 0x8, 0x1, 0x1, 0xb, 0xc1, 0xa, 0x13, 0x2b, 0x24, 0x3, 0x3, + 0x2, 0x8, 0x1, 0x1, 0xd, 0xc1, 0xa, 0x16, 0x2b, 0x6, 0x1, 0x4, + 0x1, 0xda, 0x47, 0xf, 0x1, 0xc1, 0xb, 0x16, 0x2b, 0x6, 0x1, 0x4, + 0x1, 0x97, 0x55, 0x1, 0x5, 0x1, 0xc2, 0x6, 0x1, 0x8, 0x0, 0x0, + 0x11, 0x0, 0xc2, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xc2, 0x6, + 0x1, 0x10, 0x0, 0x0, 0x11, 0x0, 0xc2, 0x9, 0x12, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, + 0x22, 0xc2, 0x6, 0x12, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc2, 0x6, + 0x12, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc2, 0xa, 0x12, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc2, 0xa, 0x12, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xc2, 0xa, 0x12, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, 0xc2, 0xa, 0x16, 0x2b, 0x6, 0x1, + 0x4, 0x1, 0xda, 0x47, 0xf, 0x1, 0xc2, 0xb, 0x16, 0x2b, 0x6, 0x1, + 0x4, 0x1, 0x97, 0x55, 0x1, 0x5, 0x1, 0xc3, 0x6, 0x1, 0x8, 0x0, + 0x0, 0x11, 0x0, 0xc3, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xc3, + 0x6, 0x1, 0x10, 0x0, 0x0, 0x11, 0x0, 0xc3, 0x9, 0x13, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, + 0x0, 0x22, 0xc3, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xc3, 0x6, + 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xc3, 0xa, 0x13, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xc3, 0xa, 0x13, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xc3, 0xa, 0x13, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, 0xc3, 0xa, 0x16, 0x2b, 0x6, 0x1, + 0x4, 0x1, 0xda, 0x47, 0xf, 0x1, 0xc3, 0xb, 0x16, 0x2b, 0x6, 0x1, + 0x4, 0x1, 0x97, 0x55, 0x1, 0x5, 0x1, 0xda, 0x6, 0x1, 0x8, 0x0, + 0x0, 0x11, 0x0, 0xda, 0x6, 0x1, 0xc, 0x0, 0x0, 0x11, 0x0, 0xda, + 0x6, 0x1, 0x10, 0x0, 0x0, 0x11, 0x0, 0xda, 0x9, 0x13, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x3, 0x1, 0x7, 0xda, 0x6, 0x13, 0x2b, 0x81, 0x4, + 0x0, 0x22, 0xda, 0x6, 0x13, 0x2b, 0x81, 0x4, 0x0, 0x23, 0xda, 0x6, + 0x13, 0x2b, 0x81, 0x4, 0x0, 0xa, 0xda, 0xa, 0x13, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0x7, 0xda, 0xa, 0x13, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0xb, 0xda, 0xa, 0x13, 0x2b, 0x24, 0x3, + 0x3, 0x2, 0x8, 0x1, 0x1, 0xd, 0xda, 0xa, 0x16, 0x2b, 0x6, 0x1, + 0x4, 0x1, 0xda, 0x47, 0xf, 0x1, 0xda, 0xb, 0x16, 0x2b, 0x6, 0x1, + 0x4, 0x1, 0x97, 0x55, 0x1, 0x5, 0x1, + ]; let ai = AlgoInfo::try_from(data.to_vec()).unwrap(); assert_eq!( - ai, AlgoInfo( - vec![ - (Signing, Rsa(RsaAttrs { len_n: 2048, len_e: 17, import_format: 0 })), - (Signing, Rsa(RsaAttrs { len_n: 3072, len_e: 17, import_format: 0 })), - (Signing, Rsa(RsaAttrs { len_n: 4096, len_e: 17, import_format: 0 })), - (Signing, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), - (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), - (Signing, Eddsa(EddsaAttrs::new(Ed25519, None))), - (Signing, Eddsa(EddsaAttrs::new(Cv25519, None))), - (Decryption, Rsa(RsaAttrs { len_n: 2048, len_e: 17, import_format: 0 })), - (Decryption, Rsa(RsaAttrs { len_n: 3072, len_e: 17, import_format: 0 })), - (Decryption, Rsa(RsaAttrs { len_n: 4096, len_e: 17, import_format: 0 })), - (Decryption, Ecdh(EcdhAttrs::new(NistP256r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(NistP384r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(NistP521r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(Secp256k1, None))), - (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP256r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP384r1, None))), - (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP512r1, None))), - (Decryption, Eddsa(EddsaAttrs::new(Ed25519, None))), - (Decryption, Eddsa(EddsaAttrs::new(Cv25519, None))), - (Authentication, Rsa(RsaAttrs { len_n: 2048, len_e: 17, import_format: 0 })), - (Authentication, Rsa(RsaAttrs { len_n: 3072, len_e: 17, import_format: 0 })), - (Authentication, Rsa(RsaAttrs { len_n: 4096, len_e: 17, import_format: 0 })), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), - (Authentication, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), - (Authentication, Eddsa(EddsaAttrs::new(Ed25519, None))), - (Authentication, Eddsa(EddsaAttrs::new(Cv25519, None))), - (Attestation, Rsa(RsaAttrs { len_n: 2048, len_e: 17, import_format: 0 })), - (Attestation, Rsa(RsaAttrs { len_n: 3072, len_e: 17, import_format: 0 })), - (Attestation, Rsa(RsaAttrs { len_n: 4096, len_e: 17, import_format: 0 })), - (Attestation, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), - (Attestation, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), - (Attestation, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), - (Attestation, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), - (Attestation, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), - (Attestation, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), - (Attestation, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), - (Attestation, Eddsa(EddsaAttrs::new(Ed25519, None))), - (Attestation, Eddsa(EddsaAttrs::new(Cv25519, None))) - ] - ) + ai, + AlgoInfo(vec![ + ( + Signing, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 17, + import_format: 0 + }) + ), + ( + Signing, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 17, + import_format: 0 + }) + ), + ( + Signing, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 17, + import_format: 0 + }) + ), + (Signing, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), + (Signing, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), + (Signing, Eddsa(EddsaAttrs::new(Ed25519, None))), + (Signing, Eddsa(EddsaAttrs::new(Cv25519, None))), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 17, + import_format: 0 + }) + ), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 17, + import_format: 0 + }) + ), + ( + Decryption, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 17, + import_format: 0 + }) + ), + (Decryption, Ecdh(EcdhAttrs::new(NistP256r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(NistP384r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(NistP521r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(Secp256k1, None))), + (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP256r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP384r1, None))), + (Decryption, Ecdh(EcdhAttrs::new(BrainpoolP512r1, None))), + (Decryption, Eddsa(EddsaAttrs::new(Ed25519, None))), + (Decryption, Eddsa(EddsaAttrs::new(Cv25519, None))), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 17, + import_format: 0 + }) + ), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 17, + import_format: 0 + }) + ), + ( + Authentication, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 17, + import_format: 0 + }) + ), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), + (Authentication, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), + (Authentication, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), + ( + Authentication, + Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None)) + ), + ( + Authentication, + Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None)) + ), + ( + Authentication, + Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None)) + ), + (Authentication, Eddsa(EddsaAttrs::new(Ed25519, None))), + (Authentication, Eddsa(EddsaAttrs::new(Cv25519, None))), + ( + Attestation, + Rsa(RsaAttrs { + len_n: 2048, + len_e: 17, + import_format: 0 + }) + ), + ( + Attestation, + Rsa(RsaAttrs { + len_n: 3072, + len_e: 17, + import_format: 0 + }) + ), + ( + Attestation, + Rsa(RsaAttrs { + len_n: 4096, + len_e: 17, + import_format: 0 + }) + ), + (Attestation, Ecdsa(EcdsaAttrs::new(NistP256r1, None))), + (Attestation, Ecdsa(EcdsaAttrs::new(NistP384r1, None))), + (Attestation, Ecdsa(EcdsaAttrs::new(NistP521r1, None))), + (Attestation, Ecdsa(EcdsaAttrs::new(Secp256k1, None))), + (Attestation, Ecdsa(EcdsaAttrs::new(BrainpoolP256r1, None))), + (Attestation, Ecdsa(EcdsaAttrs::new(BrainpoolP384r1, None))), + (Attestation, Ecdsa(EcdsaAttrs::new(BrainpoolP512r1, None))), + (Attestation, Eddsa(EddsaAttrs::new(Ed25519, None))), + (Attestation, Eddsa(EddsaAttrs::new(Cv25519, None))) + ]) ); } } diff --git a/openpgp-card/src/parse/application_id.rs b/openpgp-card/src/parse/application_id.rs index afa72aa..38e8226 100644 --- a/openpgp-card/src/parse/application_id.rs +++ b/openpgp-card/src/parse/application_id.rs @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use nom::{bytes::complete as bytes, number::complete as number}; use anyhow::Result; +use nom::{bytes::complete as bytes, number::complete as number}; use std::convert::TryFrom; use crate::parse; @@ -24,8 +24,7 @@ pub struct ApplicationId { pub serial: u32, } -fn parse(input: &[u8]) - -> nom::IResult<&[u8], ApplicationId> { +fn parse(input: &[u8]) -> nom::IResult<&[u8], ApplicationId> { let (input, _) = bytes::tag([0xd2, 0x76, 0x0, 0x1, 0x24])(input)?; let (input, application) = number::u8(input)?; @@ -36,8 +35,15 @@ fn parse(input: &[u8]) let (input, _) = nom::combinator::all_consuming(bytes::tag([0x0, 0x0]))(input)?; - Ok((input, - ApplicationId { application, version, manufacturer, serial })) + Ok(( + input, + ApplicationId { + application, + version, + manufacturer, + serial, + }, + )) } impl TryFrom<&[u8]> for ApplicationId { @@ -53,4 +59,3 @@ impl ApplicationId { format!("{:08X}", self.serial) } } - diff --git a/openpgp-card/src/parse/cardholder.rs b/openpgp-card/src/parse/cardholder.rs index 784b52d..4df229a 100644 --- a/openpgp-card/src/parse/cardholder.rs +++ b/openpgp-card/src/parse/cardholder.rs @@ -5,9 +5,9 @@ use std::convert::TryFrom; use anyhow::Result; -use crate::Sex; use crate::tlv::tag::Tag; -use crate::tlv::{TlvEntry, Tlv}; +use crate::tlv::{Tlv, TlvEntry}; +use crate::Sex; #[derive(Debug)] pub struct CardHolder { @@ -23,14 +23,17 @@ impl TryFrom<&[u8]> for CardHolder { let entry = TlvEntry::from(&data, true)?; let tlv = Tlv(Tag(vec![0x65]), entry); - let name: Option = tlv.find(&Tag::from(&[0x5b][..])) + let name: Option = tlv + .find(&Tag::from(&[0x5b][..])) .map(|v| String::from_utf8_lossy(&v.serialize()).to_string()); - let lang: Option> = tlv - .find(&Tag::from(&[0x5f, 0x2d][..])) - .map(|v| v.serialize().chunks(2) - .map(|c| [c[0] as char, c[1] as char]).collect() - ); + let lang: Option> = + tlv.find(&Tag::from(&[0x5f, 0x2d][..])).map(|v| { + v.serialize() + .chunks(2) + .map(|c| [c[0] as char, c[1] as char]) + .collect() + }); let sex = tlv .find(&Tag::from(&[0x5f, 0x35][..])) diff --git a/openpgp-card/src/parse/extended_cap.rs b/openpgp-card/src/parse/extended_cap.rs index c30db10..9cf6066 100644 --- a/openpgp-card/src/parse/extended_cap.rs +++ b/openpgp-card/src/parse/extended_cap.rs @@ -1,11 +1,11 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use nom::{number::complete as number, combinator, sequence}; -use anyhow::Result; -use std::collections::HashSet; -use crate::parse; use crate::errors::OpenpgpCardError; +use crate::parse; +use anyhow::Result; +use nom::{combinator, number::complete as number, sequence}; +use std::collections::HashSet; use std::convert::TryFrom; #[derive(Debug, Eq, PartialEq)] @@ -35,21 +35,38 @@ fn features(input: &[u8]) -> nom::IResult<&[u8], HashSet> { combinator::map(number::u8, |b| { let mut f = HashSet::new(); - if b & 0x80 != 0 { f.insert(Features::SecureMessaging); } - if b & 0x40 != 0 { f.insert(Features::GetChallenge); } - if b & 0x20 != 0 { f.insert(Features::KeyImport); } - if b & 0x10 != 0 { f.insert(Features::PwStatusChange); } - if b & 0x08 != 0 { f.insert(Features::PrivateUseDOs); } - if b & 0x04 != 0 { f.insert(Features::AlgoAttrsChangeable); } - if b & 0x02 != 0 { f.insert(Features::Aes); } - if b & 0x01 != 0 { f.insert(Features::KdfDo); } + if b & 0x80 != 0 { + f.insert(Features::SecureMessaging); + } + if b & 0x40 != 0 { + f.insert(Features::GetChallenge); + } + if b & 0x20 != 0 { + f.insert(Features::KeyImport); + } + if b & 0x10 != 0 { + f.insert(Features::PwStatusChange); + } + if b & 0x08 != 0 { + f.insert(Features::PrivateUseDOs); + } + if b & 0x04 != 0 { + f.insert(Features::AlgoAttrsChangeable); + } + if b & 0x02 != 0 { + f.insert(Features::Aes); + } + if b & 0x01 != 0 { + f.insert(Features::KdfDo); + } f })(input) } -fn parse(input: &[u8]) - -> nom::IResult<&[u8], (HashSet, u8, u16, u16, u16, u8, u8)> { +fn parse( + input: &[u8], +) -> nom::IResult<&[u8], (HashSet, u8, u16, u16, u16, u8, u8)> { nom::combinator::all_consuming(sequence::tuple(( features, number::u8, @@ -57,11 +74,10 @@ fn parse(input: &[u8]) number::be_u16, number::be_u16, number::u8, - number::u8) - ))(input) + number::u8, + )))(input) } - impl TryFrom<&[u8]> for ExtendedCap { type Error = OpenpgpCardError; @@ -75,16 +91,15 @@ impl TryFrom<&[u8]> for ExtendedCap { max_len_cardholder_cert: ec.3, max_len_special_do: ec.4, pin_2_format: ec.5 == 1, // FIXME: error if != 0|1 - mse_command: ec.6 == 1, // FIXME: error if != 0|1 + mse_command: ec.6 == 1, // FIXME: error if != 0|1 }) } } - #[cfg(test)] mod test { - use hex_literal::hex; use crate::parse::extended_cap::{ExtendedCap, Features}; + use hex_literal::hex; use std::collections::HashSet; use std::iter::FromIterator; @@ -94,11 +109,16 @@ mod test { let ec = ExtendedCap::from(&data).unwrap(); assert_eq!( - ec, ExtendedCap { - features: HashSet::from_iter( - vec![Features::GetChallenge, Features::KeyImport, - Features::PwStatusChange, Features::PrivateUseDOs, - Features::AlgoAttrsChangeable, Features::KdfDo]), + ec, + ExtendedCap { + features: HashSet::from_iter(vec![ + Features::GetChallenge, + Features::KeyImport, + Features::PwStatusChange, + Features::PrivateUseDOs, + Features::AlgoAttrsChangeable, + Features::KdfDo + ]), sm: 0x0, max_len_challenge: 0xbfe, max_len_cardholder_cert: 0x800, diff --git a/openpgp-card/src/parse/extended_length_info.rs b/openpgp-card/src/parse/extended_length_info.rs index b7fb629..f72aea5 100644 --- a/openpgp-card/src/parse/extended_length_info.rs +++ b/openpgp-card/src/parse/extended_length_info.rs @@ -1,9 +1,9 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use nom::{number::complete as number, sequence, bytes::complete::tag}; -use anyhow::Result; use crate::parse; +use anyhow::Result; +use nom::{bytes::complete::tag, number::complete as number, sequence}; #[derive(Debug, Eq, PartialEq)] pub struct ExtendedLengthInfo { @@ -11,15 +11,14 @@ pub struct ExtendedLengthInfo { pub max_response_bytes: u16, } - fn parse(input: &[u8]) -> nom::IResult<&[u8], (u16, u16)> { - let (input, (_, cmd, _, resp)) = nom::combinator::all_consuming - (sequence::tuple(( + let (input, (_, cmd, _, resp)) = + nom::combinator::all_consuming(sequence::tuple(( tag([0x2, 0x2]), number::be_u16, tag([0x2, 0x2]), - number::be_u16) - ))(input)?; + number::be_u16, + )))(input)?; Ok((input, (cmd, resp))) } diff --git a/openpgp-card/src/parse/fingerprint.rs b/openpgp-card/src/parse/fingerprint.rs index 96ffee8..a3c23b4 100644 --- a/openpgp-card/src/parse/fingerprint.rs +++ b/openpgp-card/src/parse/fingerprint.rs @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 +use anyhow::anyhow; use nom::{bytes::complete as bytes, combinator, sequence}; use std::fmt; -use anyhow::anyhow; -use crate::parse::KeySet; use crate::errors::OpenpgpCardError; +use crate::parse::KeySet; #[derive(Clone, Eq, PartialEq)] pub struct Fingerprint([u8; 20]); @@ -60,7 +60,9 @@ fn fingerprint(input: &[u8]) -> nom::IResult<&[u8], Option> { } fn fingerprints(input: &[u8]) -> nom::IResult<&[u8], KeySet> { - combinator::into(sequence::tuple((fingerprint, fingerprint, fingerprint)))(input) + combinator::into(sequence::tuple((fingerprint, fingerprint, fingerprint)))( + input, + ) } pub fn from(input: &[u8]) -> Result, OpenpgpCardError> { @@ -72,4 +74,4 @@ pub fn from(input: &[u8]) -> Result, OpenpgpCardError> { .map(|res| res.1) .map_err(|err| anyhow!("Parsing failed: {:?}", err)) .map_err(OpenpgpCardError::InternalError) -} \ No newline at end of file +} diff --git a/openpgp-card/src/parse/historical.rs b/openpgp-card/src/parse/historical.rs index 9d38e75..dec7a84 100644 --- a/openpgp-card/src/parse/historical.rs +++ b/openpgp-card/src/parse/historical.rs @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use anyhow::{anyhow, Result}; use crate::errors::OpenpgpCardError; +use anyhow::{anyhow, Result}; #[derive(Debug)] pub struct CardCapabilities { @@ -24,7 +24,6 @@ impl CardCapabilities { self.extended_length_information } - pub fn from(data: [u8; 3]) -> Self { let byte3 = data[2]; @@ -32,7 +31,11 @@ impl CardCapabilities { let extended_lc_le = byte3 & 0x40 != 0; let extended_length_information = byte3 & 0x20 != 0; - Self { command_chaining, extended_lc_le, extended_length_information } + Self { + command_chaining, + extended_lc_le, + extended_length_information, + } } } @@ -109,35 +112,39 @@ impl Historical { cc = Some([ctlv[1], ctlv[2], ctlv[3]]); ctlv.drain(0..4); } - 0 => { ctlv.drain(0..1); } - _ => unimplemented!("unexpected tlv in historical bytes") + 0 => { + ctlv.drain(0..1); + } + _ => unimplemented!("unexpected tlv in historical bytes"), } } - let sib = - match data[len - 3] { - 0 => { - // Card does not offer life cycle management, commands - // TERMINATE DF and ACTIVATE FILE are not supported - 0 - } - 3 => { - // Initialisation state - // OpenPGP application can be reset to default values with - // an ACTIVATE FILE command - 3 - } - 5 => { - // Operational state (activated) - // Card supports life cycle management, commands TERMINATE - // DF and ACTIVATE FILE are available - 5 - } - _ => { - return Err(anyhow!("unexpected status indicator in \ - historical bytes").into()); - } - }; + let sib = match data[len - 3] { + 0 => { + // Card does not offer life cycle management, commands + // TERMINATE DF and ACTIVATE FILE are not supported + 0 + } + 3 => { + // Initialisation state + // OpenPGP application can be reset to default values with + // an ACTIVATE FILE command + 3 + } + 5 => { + // Operational state (activated) + // Card supports life cycle management, commands TERMINATE + // DF and ACTIVATE FILE are available + 5 + } + _ => { + return Err(anyhow!( + "unexpected status indicator in \ + historical bytes" + ) + .into()); + } + }; // Ignore final two bytes: according to the spec, they should // show [0x90, 0x0] - but Yubikey Neo shows [0x0, 0x0]. @@ -148,8 +155,8 @@ impl Historical { Ok(Self { cib, csd, cc, sib }) } else { - Err(anyhow!("Unexpected category indicator in historical \ - bytes").into()) + Err(anyhow!("Unexpected category indicator in historical bytes") + .into()) } } } diff --git a/openpgp-card/src/parse/mod.rs b/openpgp-card/src/parse/mod.rs index f477505..6f5f66c 100644 --- a/openpgp-card/src/parse/mod.rs +++ b/openpgp-card/src/parse/mod.rs @@ -6,14 +6,14 @@ pub mod algo_attrs; pub mod algo_info; +pub mod application_id; pub mod cardholder; -pub mod historical; pub mod extended_cap; pub mod extended_length_info; pub mod fingerprint; -pub mod application_id; +pub mod historical; -use anyhow::{Error, anyhow}; +use anyhow::{anyhow, Error}; #[derive(Clone, Debug, Eq, PartialEq)] pub struct KeySet { diff --git a/openpgp-card/src/tlv/length.rs b/openpgp-card/src/tlv/length.rs index 28b3fa5..a366884 100644 --- a/openpgp-card/src/tlv/length.rs +++ b/openpgp-card/src/tlv/length.rs @@ -1,7 +1,10 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use nom::{branch, bytes::complete as bytes, combinator, number::complete as number, sequence}; +use nom::{ + branch, bytes::complete as bytes, combinator, number::complete as number, + sequence, +}; fn length1(input: &[u8]) -> nom::IResult<&[u8], u8> { combinator::verify(number::u8, |&c| c < 0x80)(input) diff --git a/openpgp-card/src/tlv/mod.rs b/openpgp-card/src/tlv/mod.rs index c508d40..0e45971 100644 --- a/openpgp-card/src/tlv/mod.rs +++ b/openpgp-card/src/tlv/mod.rs @@ -35,7 +35,7 @@ impl Tlv { let length = crate::tlv::tlv_encode_length(value.len() as u16); let mut ser = Vec::new(); - ser.extend(self.0.0.iter()); + ser.extend(self.0 .0.iter()); ser.extend(length.iter()); ser.extend(value.iter()); ser @@ -114,44 +114,45 @@ impl TlvEntry { #[cfg(test)] mod test { use super::{Tag, Tlv}; - use hex_literal::hex; - use anyhow::Result; use crate::tlv::TlvEntry; + use anyhow::Result; + use hex_literal::hex; #[test] fn test_tlv() -> Result<()> { // From OpenPGP card spec ยง 7.2.6 - let data = hex!("5B0B546573743C3C54657374695F2D0264655F350131") - .to_vec(); + let data = + hex!("5B0B546573743C3C54657374695F2D0264655F350131").to_vec(); let (input, tlv) = Tlv::parse(&data).unwrap(); - assert_eq!(tlv, - Tlv(Tag::from([0x5b]), - TlvEntry::S(hex!("546573743C3C5465737469") - .to_vec()))); + assert_eq!( + tlv, + Tlv( + Tag::from([0x5b]), + TlvEntry::S(hex!("546573743C3C5465737469").to_vec()) + ) + ); let (input, tlv) = Tlv::parse(input).unwrap(); - assert_eq!(tlv, - Tlv(Tag::from([0x5f, 0x2d]), - TlvEntry::S(hex!("6465") - .to_vec()))); + assert_eq!( + tlv, + Tlv(Tag::from([0x5f, 0x2d]), TlvEntry::S(hex!("6465").to_vec())) + ); let (input, tlv) = Tlv::parse(input).unwrap(); - assert_eq!(tlv, - Tlv(Tag::from([0x5f, 0x35]), - TlvEntry::S(hex!("31") - .to_vec()))); - + assert_eq!( + tlv, + Tlv(Tag::from([0x5f, 0x35]), TlvEntry::S(hex!("31").to_vec())) + ); assert!(input.is_empty()); Ok(()) } - #[test] fn test_tlv_yubi5() -> Result<()> { // 'Yubikey 5 NFC' output for GET DATA on "Application Related Data" @@ -168,7 +169,10 @@ mod test { assert_eq!(entry.serialize(), hex!("7d000bfe080000ff0000")); let entry = tlv.find(&Tag::from([0x4f])).unwrap(); - assert_eq!(entry.serialize(), hex!("d2760001240103040006160191800000")); + assert_eq!( + entry.serialize(), + hex!("d2760001240103040006160191800000") + ); let entry = tlv.find(&Tag::from([0x5f, 0x52])).unwrap(); assert_eq!(entry.serialize(), hex!("00730000e0059000")); @@ -203,9 +207,11 @@ mod test { let entry = tlv.find(&Tag::from([0xc6])).unwrap(); assert_eq!(entry.serialize(), hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); - let entry = tlv.find(&Tag::from([0xcd])).unwrap(); - assert_eq!(entry.serialize(), hex!("00000000000000000000000000000000")); + assert_eq!( + entry.serialize(), + hex!("00000000000000000000000000000000") + ); let entry = tlv.find(&Tag::from([0xde])).unwrap(); assert_eq!(entry.serialize(), hex!("0100020003008102")); @@ -234,17 +240,22 @@ mod test { // but has been abridged and changed. It does not represent a // complete valid OpenPGP card DO! - let a = Tlv(Tag::from(&[0x7F, 0x48][..]), - TlvEntry::S(vec![0x92, 0x03])); + let a = + Tlv(Tag::from(&[0x7F, 0x48][..]), TlvEntry::S(vec![0x92, 0x03])); - let b = Tlv(Tag::from(&[0x5F, 0x48][..]), - TlvEntry::S(vec![0x1, 0x2, 0x3])); + let b = Tlv( + Tag::from(&[0x5F, 0x48][..]), + TlvEntry::S(vec![0x1, 0x2, 0x3]), + ); - let tlv = Tlv(Tag::from(&[0x4d][..]), - TlvEntry::C(vec![a, b])); + let tlv = Tlv(Tag::from(&[0x4d][..]), TlvEntry::C(vec![a, b])); - assert_eq!(tlv.serialize(), &[0x4d, 0xb, - 0x7f, 0x48, 0x2, 0x92, 0x3, - 0x5f, 0x48, 0x3, 0x1, 0x2, 0x3]); + assert_eq!( + tlv.serialize(), + &[ + 0x4d, 0xb, 0x7f, 0x48, 0x2, 0x92, 0x3, 0x5f, 0x48, 0x3, 0x1, + 0x2, 0x3 + ] + ); } -} \ No newline at end of file +} diff --git a/openpgp-card/src/tlv/tag.rs b/openpgp-card/src/tlv/tag.rs index 9e36dfb..c82c8b4 100644 --- a/openpgp-card/src/tlv/tag.rs +++ b/openpgp-card/src/tlv/tag.rs @@ -1,7 +1,10 @@ // SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 -use nom::{branch, bytes::complete as bytes, combinator, number::complete as number, sequence}; +use nom::{ + branch, bytes::complete as bytes, combinator, number::complete as number, + sequence, +}; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Tag(pub Vec); @@ -38,9 +41,11 @@ impl From<[u8; 2]> for Tag { } } - fn multi_byte_tag(input: &[u8]) -> nom::IResult<&[u8], &[u8]> { - combinator::recognize(sequence::pair(multi_byte_tag_first, multi_byte_tag_rest))(input) + combinator::recognize(sequence::pair( + multi_byte_tag_first, + multi_byte_tag_rest, + ))(input) } fn multi_byte_tag_first(input: &[u8]) -> nom::IResult<&[u8], u8> { @@ -61,12 +66,9 @@ fn multi_byte_tag_rest(input: &[u8]) -> nom::IResult<&[u8], &[u8]> { } fn single_byte_rest(input: &[u8]) -> nom::IResult<&[u8], &[u8]> { - combinator::verify(bytes::take(1u8), - |c: &[u8]| { - c.len() == 1 && - is_first(&c[0]) && - is_last(&c[0]) - })(input) + combinator::verify(bytes::take(1u8), |c: &[u8]| { + c.len() == 1 && is_first(&c[0]) && is_last(&c[0]) + })(input) } fn multi_byte_rest(input: &[u8]) -> nom::IResult<&[u8], &[u8]> { @@ -81,19 +83,17 @@ fn multi_byte_tag_rest(input: &[u8]) -> nom::IResult<&[u8], &[u8]> { } fn single_byte_tag(input: &[u8]) -> nom::IResult<&[u8], &[u8]> { - combinator::verify(bytes::take(1u8), - |c: &[u8]| { - c.len() == 1 && - !is_multi_byte_tag_first(&c[0]) - })(input) + combinator::verify(bytes::take(1u8), |c: &[u8]| { + c.len() == 1 && !is_multi_byte_tag_first(&c[0]) + })(input) } pub(super) fn tag(input: &[u8]) -> nom::IResult<&[u8], Tag> { - combinator::map(branch::alt((multi_byte_tag, single_byte_tag)), - Tag::from)(input) + combinator::map(branch::alt((multi_byte_tag, single_byte_tag)), Tag::from)( + input, + ) } - #[cfg(test)] mod test { #[test]