// SPDX-FileCopyrightText: 2021 Heiko Schaefer // SPDX-License-Identifier: MIT OR Apache-2.0 //! Wrapping of cards for tests. Open a list of cards, based on a //! TestConfig configuration file use anyhow::{anyhow, Result}; use serde_derive::Deserialize; use std::collections::BTreeMap; use openpgp_card::CardApp; use openpgp_card_pcsc::PcscClient; use openpgp_card_scdc::ScdClient; #[derive(Debug, Deserialize)] pub struct TestConfig { card: BTreeMap, } #[derive(Debug, Deserialize)] pub struct Card { backend: BTreeMap, config: Config, } #[derive(Clone, Debug, Deserialize)] pub struct Config { pub keygen: Option>, pub import: Option>, } /// An "opened" card, via one particular backend, with test-metadata #[derive(Debug)] pub struct TestCardApp { name: String, tc: TestCard, config: Config, } impl TestCardApp { pub(crate) fn get_card_app(&self) -> Result { self.tc.open() } pub fn get_config(&self) -> &Config { &self.config } pub fn get_name(&self) -> &str { &self.name } } impl TestConfig { pub fn load(file: &str) -> Result { let config_file = std::fs::read_to_string(file)?; let config: Self = toml::from_str(&config_file)?; Ok(config) } pub fn into_cardapps(self) -> Vec { let mut cards = vec![]; for (name, card) in self.card { for (backend, id) in &card.backend { let tc: TestCard = match backend.as_str() { "pcsc" => TestCard::Pcsc(id.to_string()), "scdc" => TestCard::Scdc(id.to_string()), _ => panic!("unexpected backend {}", backend), }; cards.push(TestCardApp { name: name.clone(), tc, config: card.config.clone(), }) } } cards } } #[derive(Debug)] pub enum TestCard { Pcsc(String), Scdc(String), } impl TestCard { pub fn open(&self) -> Result { match self { Self::Pcsc(ident) => { // Attempt to shutdown SCD, if it is running. // Ignore any errors that occur during that shutdown attempt. let res = ScdClient::shutdown_scd(None); log::trace!(" Attempt to shutdown scd: {:?}", res); for card_client in PcscClient::cards()? { let mut ca = CardApp::from(card_client); // Set Card Capabilities (chaining, command length, ..) let ard = ca.get_application_related_data()?; let app_id = ard.get_application_id()?; if app_id.ident().as_str() == ident.to_uppercase() { ca.init_caps(&ard)?; // println!("opened pcsc card {}", ident); return Ok(ca); } } Err(anyhow!("Pcsc card {} not found", ident)) } Self::Scdc(serial) => { let card_client = ScdClient::open_by_serial(None, serial)?; let mut ca = CardApp::from(card_client); // Set Card Capabilities (chaining, command length, ..) let ard = ca.get_application_related_data()?; ca.init_caps(&ard)?; // println!("opened scdc card {}", serial); Ok(ca) } } } }