extern crate core;
mod errors;
pub mod ocard;
pub mod state;
use card_backend::{CardBackend, SmartcardError};
use secrecy::SecretString;
pub use crate::errors::Error;
use crate::ocard::algorithm::{AlgoSimple, AlgorithmAttributes, AlgorithmInformation};
use crate::ocard::crypto::{CardUploadableKey, PublicKeyMaterial};
use crate::ocard::data::{
ApplicationIdentifier, CardholderRelatedData, ExtendedCapabilities, ExtendedLengthInfo,
Fingerprint, HistoricalBytes, KdfDo, KeyGenerationTime, KeyInformation, KeySet, Lang,
PWStatusBytes, Sex, TouchPolicy, UserInteractionFlag,
};
use crate::ocard::{kdf::map_pin, KeyType};
use crate::state::{Admin, Open, Sign, State, Transaction, User};
enum Cached<T> {
Uncached,
None,
Value(T),
}
pub(crate) enum PinType {
Pw1,
Rc,
Pw3,
}
pub struct OptionalPin(Option<SecretString>);
impl From<Option<SecretString>> for OptionalPin {
fn from(value: Option<SecretString>) -> Self {
OptionalPin(value)
}
}
impl From<SecretString> for OptionalPin {
fn from(value: SecretString) -> Self {
OptionalPin(Some(value))
}
}
pub struct Card<S>
where
S: State,
{
state: S,
}
impl Card<Open> {
pub fn open_by_ident(
cards: impl Iterator<Item = Result<Box<dyn CardBackend + Send + Sync>, SmartcardError>>,
ident: &str,
) -> Result<Self, Error> {
for b in cards.filter_map(|c| c.ok()) {
let mut card = Self::new(b)?;
let aid = {
let mut tx = card.transaction()?;
tx.state.ard().application_id()?
};
if aid.ident() == ident.to_ascii_uppercase() {
return Ok(card);
}
}
Err(Error::InternalError(format!(
"Couldn't find card {}",
ident
)))
}
pub fn new<B>(backend: B) -> Result<Self, Error>
where
B: Into<Box<dyn CardBackend + Send + Sync>>,
{
let pgp = crate::ocard::OpenPGP::new(backend)?;
Ok(Card::<Open> {
state: Open { pgp },
})
}
pub fn transaction(&mut self) -> Result<Card<Transaction<'_>>, Error> {
let opt = self.state.pgp.transaction()?;
Card::<Transaction>::new(opt)
}
pub fn into_backend(self) -> Box<dyn CardBackend + Send + Sync> {
self.state.pgp.into_card()
}
}
impl<'a> Card<Transaction<'a>> {
fn new(mut opt: crate::ocard::Transaction<'a>) -> Result<Self, Error> {
let ard = opt.application_related_data()?;
Ok(Self {
state: Transaction::new(opt, ard),
})
}
pub fn card(&mut self) -> &mut crate::ocard::Transaction<'a> {
&mut self.state.opt
}
pub fn invalidate_cache(&mut self) -> Result<(), Error> {
self.state.invalidate_cache();
Ok(())
}
pub fn feature_pinpad_verify(&mut self) -> bool {
self.state.opt.feature_pinpad_verify()
}
pub fn feature_pinpad_modify(&mut self) -> bool {
self.state.opt.feature_pinpad_modify()
}
pub fn verify_user_pin(&mut self, pin: SecretString) -> Result<(), Error> {
let pin = map_pin(pin, PinType::Pw1, self.state.kdf_do())?;
self.state.opt.verify_pw1_user(pin)?;
self.state.pw1 = true;
Ok(())
}
pub fn verify_user_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt();
self.state.opt.verify_pw1_user_pinpad()?;
self.state.pw1 = true;
Ok(())
}
pub fn verify_user_signing_pin(&mut self, pin: SecretString) -> Result<(), Error> {
let pin = map_pin(pin, PinType::Pw1, self.state.kdf_do())?;
self.state.opt.verify_pw1_sign(pin)?;
self.state.pw1_sign = true;
Ok(())
}
pub fn verify_user_signing_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt();
self.state.opt.verify_pw1_sign_pinpad()?;
self.state.pw1_sign = true;
Ok(())
}
pub fn verify_admin_pin(&mut self, pin: SecretString) -> Result<(), Error> {
let pin = map_pin(pin, PinType::Pw3, self.state.kdf_do())?;
self.state.opt.verify_pw3(pin)?;
self.state.pw3 = true;
Ok(())
}
pub fn verify_admin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt();
self.state.opt.verify_pw3_pinpad()?;
self.state.pw3 = true;
Ok(())
}
pub fn check_user_verified(&mut self) -> Result<(), Error> {
self.state.opt.check_pw1_user()
}
pub fn check_admin_verified(&mut self) -> Result<(), Error> {
self.state.opt.check_pw3()
}
pub fn change_user_pin(&mut self, old: SecretString, new: SecretString) -> Result<(), Error> {
let old = map_pin(old, PinType::Pw1, self.state.kdf_do())?;
let new = map_pin(new, PinType::Pw1, self.state.kdf_do())?;
self.state.opt.change_pw1(old, new)
}
pub fn change_user_pin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt();
self.state.opt.change_pw1_pinpad()
}
pub fn reset_user_pin(&mut self, rst: SecretString, new: SecretString) -> Result<(), Error> {
let rst = map_pin(rst, PinType::Rc, self.state.kdf_do())?;
let new = map_pin(new, PinType::Pw1, self.state.kdf_do())?;
self.state.opt.reset_retry_counter_pw1(new, Some(rst))
}
pub fn change_admin_pin(&mut self, old: SecretString, new: SecretString) -> Result<(), Error> {
let old = map_pin(old, PinType::Pw3, self.state.kdf_do())?;
let new = map_pin(new, PinType::Pw3, self.state.kdf_do())?;
self.state.opt.change_pw3(old, new)
}
pub fn change_admin_pin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt();
self.state.opt.change_pw3_pinpad()
}
pub fn to_user_card<'b, P>(&'b mut self, pin: P) -> Result<Card<User<'a, 'b>>, Error>
where
P: Into<OptionalPin>,
{
let pin: OptionalPin = pin.into();
if let Some(pin) = pin.0 {
self.verify_user_pin(pin)?;
}
Ok(Card::<User> {
state: User { tx: self },
})
}
pub fn to_signing_card<'b, P>(&'b mut self, pin: P) -> Result<Card<Sign<'a, 'b>>, Error>
where
P: Into<OptionalPin>,
{
let pin: OptionalPin = pin.into();
if let Some(pin) = pin.0 {
self.verify_user_signing_pin(pin)?;
}
Ok(Card::<Sign> {
state: Sign { tx: self },
})
}
pub fn to_admin_card<'b, P>(&'b mut self, pin: P) -> Result<Card<Admin<'a, 'b>>, Error>
where
P: Into<OptionalPin>,
{
let pin: OptionalPin = pin.into();
if let Some(pin) = pin.0 {
self.verify_admin_pin(pin)?;
}
Ok(Card::<Admin> {
state: Admin { tx: self },
})
}
pub fn application_identifier(&self) -> Result<ApplicationIdentifier, Error> {
self.state.opt.application_identifier()
}
pub fn extended_capabilities(&self) -> Result<ExtendedCapabilities, Error> {
self.state.opt.extended_capabilities()
}
pub fn historical_bytes(&self) -> Result<HistoricalBytes, Error> {
match self.state.opt.historical_bytes()? {
Some(hb) => Ok(hb),
None => Err(Error::NotFound(
"Card doesn't have historical bytes DO".to_string(),
)),
}
}
pub fn extended_length_information(&self) -> Result<Option<ExtendedLengthInfo>, Error> {
self.state.opt.extended_length_info()
}
pub fn pw_status_bytes(&mut self) -> Result<PWStatusBytes, Error> {
self.state.ard().pw_status_bytes()
}
pub fn algorithm_attributes(
&mut self,
key_type: KeyType,
) -> Result<AlgorithmAttributes, Error> {
self.state.ard().algorithm_attributes(key_type)
}
pub fn fingerprints(&mut self) -> Result<KeySet<Fingerprint>, Error> {
self.state.ard().fingerprints()
}
pub fn fingerprint(&mut self, key_type: KeyType) -> Result<Option<Fingerprint>, Error> {
let fp = match key_type {
KeyType::Signing => self.fingerprints()?.signature().cloned(),
KeyType::Decryption => self.fingerprints()?.decryption().cloned(),
KeyType::Authentication => self.fingerprints()?.authentication().cloned(),
KeyType::Attestation => self.state.ard().attestation_key_fingerprint()?,
};
Ok(fp)
}
pub fn key_generation_times(&mut self) -> Result<KeySet<KeyGenerationTime>, Error> {
self.state.ard().key_generation_times()
}
pub fn key_generation_time(
&mut self,
key_type: KeyType,
) -> Result<Option<KeyGenerationTime>, Error> {
let ts = match key_type {
KeyType::Signing => self.key_generation_times()?.signature().cloned(),
KeyType::Decryption => self.key_generation_times()?.decryption().cloned(),
KeyType::Authentication => self.key_generation_times()?.authentication().cloned(),
KeyType::Attestation => self.state.ard().attestation_key_generation_time()?,
};
Ok(ts)
}
pub fn key_information(&mut self) -> Result<Option<KeyInformation>, Error> {
self.state.ard().key_information()
}
pub fn user_interaction_flag(
&mut self,
key_type: KeyType,
) -> Result<Option<UserInteractionFlag>, Error> {
match key_type {
KeyType::Signing => self.state.ard().uif_pso_cds(),
KeyType::Decryption => self.state.ard().uif_pso_dec(),
KeyType::Authentication => self.state.ard().uif_pso_aut(),
KeyType::Attestation => self.state.ard().uif_attestation(),
}
}
pub fn ca_fingerprints(&mut self) -> Result<[Option<Fingerprint>; 3], Error> {
self.state.ard().ca_fingerprints()
}
pub fn private_use_do(&mut self, num: u8) -> Result<Vec<u8>, Error> {
self.state.opt.private_use_do(num)
}
pub fn login_data(&mut self) -> Result<Vec<u8>, Error> {
self.state.opt.login_data()
}
pub fn url(&mut self) -> Result<String, Error> {
Ok(String::from_utf8_lossy(&self.state.opt.url()?).to_string())
}
pub fn cardholder_related_data(&mut self) -> Result<CardholderRelatedData, Error> {
self.state.opt.cardholder_related_data()
}
fn latin1_to_string(s: &[u8]) -> String {
s.iter().map(|&c| c as char).collect()
}
pub fn cardholder_name(&mut self) -> Result<String, Error> {
let crd = self.state.opt.cardholder_related_data()?;
match crd.name() {
Some(name) => Ok(Self::latin1_to_string(name)),
None => Ok("".to_string()),
}
}
pub fn digital_signature_count(&mut self) -> Result<u32, Error> {
Ok(self
.state
.opt
.security_support_template()?
.signature_count())
}
pub fn select_data(&mut self, num: u8, tag: &[u8]) -> Result<(), Error> {
self.state.opt.select_data(num, tag)
}
pub fn cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
self.state.opt.cardholder_certificate()
}
pub fn next_cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
self.state.opt.next_cardholder_certificate()
}
pub fn kdf_do(&mut self) -> Result<KdfDo, Error> {
if let Some(kdf) = self.state.kdf_do() {
Ok(kdf.clone())
} else {
Err(Error::NotFound("No KDF DO found".to_string()))
}
}
pub fn algorithm_information(&mut self) -> Result<Option<AlgorithmInformation>, Error> {
let ec = self.extended_capabilities()?;
if !ec.algo_attrs_changeable() {
return Ok(None);
}
self.state.opt.algorithm_information()
}
pub fn manage_security_environment(
&mut self,
for_operation: KeyType,
key_ref: KeyType,
) -> Result<(), Error> {
self.state
.opt
.manage_security_environment(for_operation, key_ref)
}
pub fn attestation_certificate(&mut self) -> Result<Vec<u8>, Error> {
self.state.opt.attestation_certificate()
}
pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> {
self.state.opt.firmware_version()
}
pub fn set_identity(&mut self, id: u8) -> Result<(), Error> {
let _ = self.state.opt.set_identity(id)?;
Ok(())
}
pub fn public_key_material(&mut self, key_type: KeyType) -> Result<PublicKeyMaterial, Error> {
self.state.opt.public_key(key_type)
}
pub fn factory_reset(&mut self) -> Result<(), Error> {
self.state.opt.factory_reset()
}
}
impl<'app> Card<User<'app, '_>> {
fn card(&mut self) -> &mut crate::ocard::Transaction<'app> {
&mut self.state.tx.state.opt
}
pub fn set_private_use_do(&mut self, num: u8, data: Vec<u8>) -> Result<(), Error> {
self.card().set_private_use_do(num, data)
}
}
impl<'app, 'open> Card<Sign<'app, 'open>> {
fn card(&mut self) -> &mut crate::ocard::Transaction<'app> {
&mut self.state.tx.state.opt
}
pub fn generate_attestation(
&mut self,
key_type: KeyType,
touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> Result<(), Error> {
if let Some(uif) = self.state.tx.state.ard().uif_attestation()? {
if uif.touch_policy().touch_required() {
(touch_prompt)();
}
}
self.card().generate_attestation(key_type)
}
}
impl<'app> Card<Admin<'app, '_>> {
pub fn as_transaction(&'_ mut self) -> &mut Card<Transaction<'app>> {
self.state.tx
}
fn card(&mut self) -> &mut crate::ocard::Transaction<'app> {
&mut self.state.tx.state.opt
}
}
impl Card<Admin<'_, '_>> {
pub fn set_cardholder_name(&mut self, name: &str) -> Result<(), Error> {
if !name.is_ascii() {
return Err(Error::InternalError("Invalid char in name".into()));
};
if name.len() >= 40 {
return Err(Error::InternalError("name too long".into()));
}
self.card().set_name(name.as_bytes())
}
pub fn set_lang(&mut self, lang: &[Lang]) -> Result<(), Error> {
if lang.len() > 8 {
return Err(Error::InternalError("lang too long".into()));
}
self.card().set_lang(lang)
}
pub fn set_sex(&mut self, sex: Sex) -> Result<(), Error> {
self.card().set_sex(sex)
}
pub fn set_private_use_do(&mut self, num: u8, data: Vec<u8>) -> Result<(), Error> {
self.card().set_private_use_do(num, data)
}
pub fn set_login_data(&mut self, login_data: &[u8]) -> Result<(), Error> {
self.card().set_login(login_data)
}
pub fn set_url(&mut self, url: &str) -> Result<(), Error> {
if !url.is_ascii() {
return Err(Error::InternalError("Invalid char in url".into()));
}
let ec = self.state.tx.extended_capabilities()?;
if url.len() <= ec.max_len_special_do().unwrap_or(u16::MAX) as usize {
self.card().set_url(url.as_bytes())
} else {
Err(Error::InternalError("URL too long".into()))
}
}
pub fn set_pw_status_bytes(
&mut self,
pw_status: &PWStatusBytes,
long: bool,
) -> Result<(), Error> {
self.card().set_pw_status_bytes(pw_status, long)
}
pub fn set_user_pin_signing_validity(&mut self, once: bool) -> Result<(), Error> {
let mut pws = self.as_transaction().pw_status_bytes()?;
pws.set_pw1_cds_valid_once(once);
self.set_pw_status_bytes(&pws, false)
}
pub fn set_touch_policy(&mut self, key: KeyType, policy: TouchPolicy) -> Result<(), Error> {
let uif = match key {
KeyType::Signing => self.state.tx.state.ard().uif_pso_cds()?,
KeyType::Decryption => self.state.tx.state.ard().uif_pso_dec()?,
KeyType::Authentication => self.state.tx.state.ard().uif_pso_aut()?,
KeyType::Attestation => self.state.tx.state.ard().uif_attestation()?,
};
if let Some(mut uif) = uif {
uif.set_touch_policy(policy);
match key {
KeyType::Signing => self.card().set_uif_pso_cds(&uif)?,
KeyType::Decryption => self.card().set_uif_pso_dec(&uif)?,
KeyType::Authentication => self.card().set_uif_pso_aut(&uif)?,
KeyType::Attestation => self.card().set_uif_attestation(&uif)?,
}
} else {
return Err(Error::UnsupportedFeature(
"User Interaction Flag not available".into(),
));
};
Ok(())
}
pub fn reset_user_pin(&mut self, new: SecretString) -> Result<(), Error> {
let new = map_pin(new, PinType::Pw1, self.state.tx.state.kdf_do())?;
self.card().reset_retry_counter_pw1(new, None)
}
pub fn set_resetting_code(&mut self, pin: SecretString) -> Result<(), Error> {
let pin = map_pin(pin, PinType::Rc, self.state.tx.state.kdf_do())?;
self.card().set_resetting_code(pin)
}
pub fn set_pso_enc_dec_key(&mut self, key: &[u8]) -> Result<(), Error> {
self.card().set_pso_enc_dec_key(key)
}
pub fn import_key(
&mut self,
key: Box<dyn CardUploadableKey>,
key_type: KeyType,
) -> Result<(), Error> {
self.card().key_import(key, key_type)
}
pub fn set_algorithm(&mut self, key_type: KeyType, algo: AlgoSimple) -> Result<(), Error> {
let attr = algo.matching_algorithm_attributes(self.card(), key_type)?;
self.set_algorithm_attributes(key_type, &attr)
}
pub fn set_algorithm_attributes(
&mut self,
key_type: KeyType,
algorithm_attributes: &AlgorithmAttributes,
) -> Result<(), Error> {
self.card()
.set_algorithm_attributes(key_type, algorithm_attributes)
}
pub fn generate_key(
&mut self,
fp_from_pub: fn(
&PublicKeyMaterial,
KeyGenerationTime,
KeyType,
) -> Result<Fingerprint, Error>,
key_type: KeyType,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
self.card().generate_key(fp_from_pub, key_type)
}
}