1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
// SPDX-FileCopyrightText: Heiko Schaefer <heiko@schaefer.name>
// 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 std::collections::BTreeMap;
use anyhow::Result;
use card_backend_pcsc::PcscBackend;
use card_backend_scdc::ScdBackend;
use openpgp_card::state::Open;
use openpgp_card::Error;
use serde::Deserialize;
// const SHARE_MODE: Option<ShareMode> = Some(ShareMode::Shared);
#[derive(Debug, Deserialize)]
pub struct TestConfig {
card: BTreeMap<String, Card>,
}
#[derive(Debug, Deserialize)]
pub struct Card {
backend: BTreeMap<String, String>,
config: Config,
}
#[derive(Clone, Debug, Deserialize)]
pub struct Config {
pub keygen: Option<Vec<String>>,
pub import: Option<Vec<String>>,
}
/// An "opened" card, via one particular backend, with test-metadata
#[derive(Debug)]
pub struct TestCardData {
name: String,
tc: TestCard,
config: Config,
}
impl TestCardData {
pub fn get_card(&self) -> Result<openpgp_card::Card<Open>> {
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<Self> {
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<TestCardData> {
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(TestCardData {
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<openpgp_card::Card<Open>> {
match self {
Self::Pcsc(ident) => {
// Attempt to shutdown SCD, if it is running.
// Ignore any errors that occur during that shutdown attempt.
let res = ScdBackend::shutdown_scd(None);
log::trace!(" Attempt to shutdown scd: {:?}", res);
// Make three attempts to open the card before failing
// (this can be useful in ShareMode::Exclusive)
let mut i = 1;
let card: Result<openpgp_card::Card<Open>, Error> = loop {
i += 1;
let cards = PcscBackend::card_backends(None)?;
let res = openpgp_card::Card::<Open>::open_by_ident(cards, ident);
println!("Got result for card: {}", ident);
if let Err(e) = &res {
println!("Result is an error: {:x?}", e);
} else {
println!("Result is a happy card");
}
if let Ok(res) = res {
break Ok(res);
}
if i > 3 {
break Err(Error::NotFound(format!("Couldn't open card {}", ident)));
}
// sleep for 100ms
println!("Will sleep for 100ms");
std::thread::sleep(std::time::Duration::from_millis(100));
};
Ok(card?)
}
Self::Scdc(serial) => {
let backend = ScdBackend::open_by_serial(None, serial)?;
Ok(openpgp_card::Card::<Open>::new(backend)?)
}
}
}
}
|