extern crate core;
pub mod algorithm;
mod apdu;
pub mod card_do;
mod commands;
pub mod crypto_data;
mod errors;
mod keys;
mod oid;
mod tags;
mod tlv;
use std::convert::{TryFrom, TryInto};
use card_backend::{CardBackend, CardCaps, CardTransaction, PinType, SmartcardError};
use tags::{ShortTag, Tags};
use crate::algorithm::{AlgorithmAttributes, AlgorithmInformation};
use crate::apdu::command::Command;
use crate::apdu::response::RawResponse;
use crate::card_do::{
ApplicationIdentifier, ApplicationRelatedData, CardholderRelatedData, ExtendedCapabilities,
ExtendedLengthInfo, Fingerprint, HistoricalBytes, KdfDo, KeyGenerationTime, Lang,
PWStatusBytes, SecuritySupportTemplate, Sex, UserInteractionFlag,
};
use crate::crypto_data::{CardUploadableKey, Cryptogram, Hash, PublicKeyMaterial};
pub use crate::errors::{Error, StatusBytes};
use crate::tlv::tag::Tag;
use crate::tlv::value::Value;
use crate::tlv::Tlv;
const OPENPGP_APPLICATION: &[u8] = &[0xD2, 0x76, 0x00, 0x01, 0x24, 0x01];
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[non_exhaustive]
pub enum KeyType {
Signing,
Decryption,
Authentication,
Attestation,
}
impl KeyType {
fn algorithm_tag(&self) -> ShortTag {
match self {
Self::Signing => Tags::AlgorithmAttributesSignature,
Self::Decryption => Tags::AlgorithmAttributesDecryption,
Self::Authentication => Tags::AlgorithmAttributesAuthentication,
Self::Attestation => Tags::AlgorithmAttributesAttestation,
}
.into()
}
fn fingerprint_put_tag(&self) -> ShortTag {
match self {
Self::Signing => Tags::FingerprintSignature,
Self::Decryption => Tags::FingerprintDecryption,
Self::Authentication => Tags::FingerprintAuthentication,
Self::Attestation => Tags::FingerprintAttestation,
}
.into()
}
fn timestamp_put_tag(&self) -> ShortTag {
match self {
Self::Signing => Tags::GenerationTimeSignature,
Self::Decryption => Tags::GenerationTimeDecryption,
Self::Authentication => Tags::GenerationTimeAuthentication,
Self::Attestation => Tags::GenerationTimeAttestation,
}
.into()
}
}
#[derive(Debug)]
struct CardImmutable {
aid: ApplicationIdentifier,
ec: ExtendedCapabilities,
hb: Option<HistoricalBytes>, eli: Option<ExtendedLengthInfo>,
ai: Option<Option<AlgorithmInformation>>, }
pub struct Card {
card: Box<dyn CardBackend + Send + Sync>,
card_caps: Option<CardCaps>,
immutable: Option<CardImmutable>,
}
impl Card {
pub fn new<B>(backend: B) -> Result<Self, Error>
where
B: Into<Box<dyn CardBackend + Send + Sync>>,
{
let card: Box<dyn CardBackend + Send + Sync> = backend.into();
let mut op = Self {
card,
card_caps: None,
immutable: None,
};
let (caps, imm) = {
let mut tx = op.transaction()?;
tx.select()?;
let ard = tx.application_related_data()?;
let mut ext_support = false;
let mut chaining_support = false;
if let Ok(hist) = ard.historical_bytes() {
if let Some(cc) = hist.card_capabilities() {
chaining_support = cc.command_chaining();
ext_support = cc.extended_lc_le();
}
}
let ext_cap = ard.extended_capabilities()?;
let (max_cmd_bytes, max_rsp_bytes) = if let Ok(Some(eli)) =
ard.extended_length_information()
{
(eli.max_command_bytes(), eli.max_response_bytes())
} else if let (Some(cmd), Some(rsp)) = (ext_cap.max_cmd_len(), ext_cap.max_resp_len()) {
(cmd, rsp)
} else {
(255, 255)
};
let pw_status = ard.pw_status_bytes()?;
let pw1_max = pw_status.pw1_max_len();
let pw3_max = pw_status.pw3_max_len();
let caps = CardCaps::new(
ext_support,
chaining_support,
max_cmd_bytes,
max_rsp_bytes,
pw1_max,
pw3_max,
);
let imm = CardImmutable {
aid: ard.application_id()?,
ec: ard.extended_capabilities()?,
hb: Some(ard.historical_bytes()?),
eli: ard.extended_length_information()?,
ai: None, };
drop(tx);
let caps = op.card.limit_card_caps(caps);
(caps, imm)
};
log::trace!("set card_caps to: {:x?}", caps);
op.card_caps = Some(caps);
log::trace!("set immutable card state to: {:x?}", imm);
op.immutable = Some(imm);
Ok(op)
}
pub fn into_card(self) -> Box<dyn CardBackend + Send + Sync> {
self.card
}
pub fn transaction(&mut self) -> Result<Transaction, Error> {
let card_caps = &mut self.card_caps;
let immutable = &mut self.immutable;
let tx = self.card.transaction(Some(OPENPGP_APPLICATION))?;
if tx.was_reset() {
}
Ok(Transaction {
tx,
card_caps,
immutable,
})
}
}
pub struct Transaction<'a> {
tx: Box<dyn CardTransaction + Send + Sync + 'a>,
card_caps: &'a Option<CardCaps>,
immutable: &'a mut Option<CardImmutable>,
}
impl<'a> Transaction<'a> {
pub(crate) fn tx(&mut self) -> &mut dyn CardTransaction {
self.tx.as_mut()
}
pub(crate) fn send_command(
&mut self,
cmd: Command,
expect_reply: bool,
) -> Result<RawResponse, Error> {
apdu::send_command(&mut *self.tx, cmd, *self.card_caps, expect_reply)
}
pub fn select(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: select");
self.send_command(commands::select_openpgp(), false)?
.try_into()
}
pub fn terminate_df(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: terminate_df");
self.send_command(commands::terminate_df(), false)?;
Ok(())
}
pub fn activate_file(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: activate_file");
self.send_command(commands::activate_file(), false)?;
Ok(())
}
pub fn feature_pinpad_verify(&self) -> bool {
self.tx.feature_pinpad_verify()
}
pub fn feature_pinpad_modify(&self) -> bool {
self.tx.feature_pinpad_modify()
}
pub fn application_related_data(&mut self) -> Result<ApplicationRelatedData, Error> {
log::info!("OpenPgpTransaction: application_related_data");
let resp = self.send_command(commands::application_related_data(), true)?;
let value = Value::from(resp.data()?, true)?;
log::trace!(" ARD value: {:02x?}", value);
Ok(ApplicationRelatedData(Tlv::new(
Tags::ApplicationRelatedData,
value,
)))
}
fn card_immutable(&self) -> Result<&CardImmutable, Error> {
if let Some(imm) = &self.immutable {
Ok(imm)
} else {
Err(Error::InternalError(
"Unexpected state of immutable cache".to_string(),
))
}
}
pub fn application_identifier(&self) -> Result<ApplicationIdentifier, Error> {
Ok(self.card_immutable()?.aid)
}
pub fn extended_capabilities(&self) -> Result<ExtendedCapabilities, Error> {
Ok(self.card_immutable()?.ec)
}
pub fn historical_bytes(&self) -> Result<Option<HistoricalBytes>, Error> {
Ok(self.card_immutable()?.hb)
}
pub fn extended_length_info(&self) -> Result<Option<ExtendedLengthInfo>, Error> {
Ok(self.card_immutable()?.eli)
}
#[allow(dead_code)]
fn algorithm_information_cached(&mut self) -> Result<Option<AlgorithmInformation>, Error> {
if self.immutable.is_none() {
return Err(Error::InternalError(
"Unexpected state of immutable cache".to_string(),
));
}
if self.immutable.as_ref().unwrap().ai.is_none() {
let ai = self.algorithm_information()?;
self.immutable.as_mut().unwrap().ai = Some(ai);
}
Ok(self.immutable.as_ref().unwrap().ai.clone().unwrap())
}
pub fn url(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: url");
self.send_command(commands::url(), true)?.try_into()
}
pub fn login_data(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: login_data");
self.send_command(commands::login_data(), true)?.try_into()
}
pub fn cardholder_related_data(&mut self) -> Result<CardholderRelatedData, Error> {
log::info!("OpenPgpTransaction: cardholder_related_data");
let resp = self.send_command(commands::cardholder_related_data(), true)?;
resp.data()?.try_into()
}
pub fn security_support_template(&mut self) -> Result<SecuritySupportTemplate, Error> {
log::info!("OpenPgpTransaction: security_support_template");
let resp = self.send_command(commands::security_support_template(), true)?;
let tlv = Tlv::try_from(resp.data()?)?;
let dst = tlv.find(Tags::DigitalSignatureCounter).ok_or_else(|| {
Error::NotFound("Couldn't get DigitalSignatureCounter DO".to_string())
})?;
if let Value::S(data) = dst {
let mut data = data.to_vec();
if data.len() != 3 {
return Err(Error::ParseError(format!(
"Unexpected length {} for DigitalSignatureCounter DO",
data.len()
)));
}
data.insert(0, 0); let data: [u8; 4] = data.try_into().unwrap();
let dsc: u32 = u32::from_be_bytes(data);
Ok(SecuritySupportTemplate { dsc })
} else {
Err(Error::NotFound(
"Failed to process SecuritySupportTemplate".to_string(),
))
}
}
#[allow(dead_code)]
pub fn cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: cardholder_certificate");
self.send_command(commands::cardholder_certificate(), true)?
.try_into()
}
pub fn next_cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: next_cardholder_certificate");
self.send_command(commands::get_next_cardholder_certificate(), true)?
.try_into()
}
pub fn kdf_do(&mut self) -> Result<KdfDo, Error> {
log::info!("OpenPgpTransaction: kdf_do");
let kdf_do = self
.send_command(commands::kdf_do(), true)?
.data()?
.try_into()?;
log::trace!(" KDF DO value: {:02x?}", kdf_do);
Ok(kdf_do)
}
pub fn algorithm_information(&mut self) -> Result<Option<AlgorithmInformation>, Error> {
log::info!("OpenPgpTransaction: algorithm_information");
let resp = self.send_command(commands::algo_info(), true)?;
let ai = resp.data()?.try_into()?;
Ok(Some(ai))
}
pub fn attestation_certificate(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: attestation_certificate");
self.send_command(commands::attestation_certificate(), true)?
.try_into()
}
pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: firmware_version");
self.send_command(commands::firmware_version(), true)?
.try_into()
}
pub fn set_identity(&mut self, id: u8) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: set_identity");
let resp = self.send_command(commands::set_identity(id), false);
if let Err(Error::Smartcard(SmartcardError::NotTransacted)) = resp {
Ok(vec![])
} else {
resp?.try_into()
}
}
pub fn select_data(&mut self, num: u8, tag: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: select_data");
let tlv = Tlv::new(
Tags::GeneralReference,
Value::C(vec![Tlv::new(Tags::TagList, Value::S(tag.to_vec()))]),
);
let mut data = tlv.serialize();
if let Ok(version) = self.firmware_version() {
if version.len() == 3
&& version[0] == 5
&& (version[1] < 4 || (version[1] == 4 && version[2] <= 3))
{
assert!(data.len() <= 255);
data.insert(0, data.len() as u8);
}
}
let cmd = commands::select_data(num, data);
self.send_command(cmd, true)?.check_ok()?;
Ok(())
}
pub fn private_use_do(&mut self, num: u8) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: private_use_do");
if !(1..=4).contains(&num) {
return Err(Error::UnsupportedFeature(format!(
"Illegal Private Use DO num '{}'",
num,
)));
}
let cmd = commands::private_use_do(num);
self.send_command(cmd, true)?.try_into()
}
pub fn factory_reset(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: factory_reset");
for _ in 0..4 {
let resp = self.verify_pw1_sign(&[0x40; 8]);
if !(matches!(
resp,
Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied))
| Err(Error::CardStatus(StatusBytes::AuthenticationMethodBlocked))
| Err(Error::CardStatus(
StatusBytes::ExecutionErrorNonVolatileMemoryUnchanged
))
| Err(Error::CardStatus(StatusBytes::PasswordNotChecked(_)))
| Err(Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied))
)) {
return Err(Error::InternalError(
"Unexpected status for reset, at pw1.".into(),
));
}
}
for _ in 0..4 {
let resp = self.verify_pw3(&[0x40; 8]);
if !(matches!(
resp,
Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied))
| Err(Error::CardStatus(StatusBytes::AuthenticationMethodBlocked))
| Err(Error::CardStatus(
StatusBytes::ExecutionErrorNonVolatileMemoryUnchanged
))
| Err(Error::CardStatus(StatusBytes::PasswordNotChecked(_)))
| Err(Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied))
)) {
return Err(Error::InternalError(
"Unexpected status for reset, at pw3.".into(),
));
}
}
self.terminate_df()?;
self.activate_file()?;
Ok(())
}
pub fn verify_pw1_sign(&mut self, pin: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: verify_pw1_sign");
let cmd = commands::verify_pw1_81(pin.to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn verify_pw1_sign_pinpad(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: verify_pw1_sign_pinpad");
let cc = *self.card_caps;
let res = self.tx().pinpad_verify(PinType::Sign, &cc)?;
RawResponse::try_from(res)?.try_into()
}
pub fn check_pw1_sign(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: check_pw1_sign");
let verify = commands::verify_pw1_81(vec![]);
self.send_command(verify, false)?.try_into()
}
pub fn verify_pw1_user(&mut self, pin: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: verify_pw1_user");
let verify = commands::verify_pw1_82(pin.to_vec());
self.send_command(verify, false)?.try_into()
}
pub fn verify_pw1_user_pinpad(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: verify_pw1_user_pinpad");
let cc = *self.card_caps;
let res = self.tx().pinpad_verify(PinType::User, &cc)?;
RawResponse::try_from(res)?.try_into()
}
pub fn check_pw1_user(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: check_pw1_user");
let verify = commands::verify_pw1_82(vec![]);
self.send_command(verify, false)?.try_into()
}
pub fn verify_pw3(&mut self, pin: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: verify_pw3");
let verify = commands::verify_pw3(pin.to_vec());
self.send_command(verify, false)?.try_into()
}
pub fn verify_pw3_pinpad(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: verify_pw3_pinpad");
let cc = *self.card_caps;
let res = self.tx().pinpad_verify(PinType::Admin, &cc)?;
RawResponse::try_from(res)?.try_into()
}
pub fn check_pw3(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: check_pw3");
let verify = commands::verify_pw3(vec![]);
self.send_command(verify, false)?.try_into()
}
pub fn change_pw1(&mut self, old: &[u8], new: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: change_pw1");
let mut data = vec![];
data.extend(old);
data.extend(new);
let change = commands::change_pw1(data);
self.send_command(change, false)?.try_into()
}
pub fn change_pw1_pinpad(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: change_pw1_pinpad");
let cc = *self.card_caps;
let res = self.tx().pinpad_modify(PinType::Sign, &cc)?;
RawResponse::try_from(res)?.try_into()
}
pub fn change_pw3(&mut self, old: &[u8], new: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: change_pw3");
let mut data = vec![];
data.extend(old);
data.extend(new);
let change = commands::change_pw3(data);
self.send_command(change, false)?.try_into()
}
pub fn change_pw3_pinpad(&mut self) -> Result<(), Error> {
log::info!("OpenPgpTransaction: change_pw3_pinpad");
let cc = *self.card_caps;
let res = self.tx().pinpad_modify(PinType::Admin, &cc)?;
RawResponse::try_from(res)?.try_into()
}
pub fn reset_retry_counter_pw1(
&mut self,
new_pw1: &[u8],
resetting_code: Option<&[u8]>,
) -> Result<(), Error> {
log::info!("OpenPgpTransaction: reset_retry_counter_pw1");
let cmd = commands::reset_retry_counter_pw1(resetting_code, new_pw1);
self.send_command(cmd, false)?.try_into()
}
pub fn decipher(&mut self, dm: Cryptogram) -> Result<Vec<u8>, Error> {
match dm {
Cryptogram::RSA(message) => {
let mut data = vec![0x0];
data.extend_from_slice(message);
self.pso_decipher(data)
}
Cryptogram::ECDH(eph) => {
let epk = Tlv::new(Tags::ExternalPublicKey, Value::S(eph.to_vec()));
let pkdo = Tlv::new(Tags::PublicKey, Value::C(vec![epk]));
let cdo = Tlv::new(Tags::Cipher, Value::C(vec![pkdo]));
self.pso_decipher(cdo.serialize())
}
}
}
pub fn pso_decipher(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: pso_decipher");
let dec_cmd = commands::decryption(data);
let resp = self.send_command(dec_cmd, true)?;
Ok(resp.data()?.to_vec())
}
pub fn manage_security_environment(
&mut self,
for_operation: KeyType,
key_ref: KeyType,
) -> Result<(), Error> {
log::info!("OpenPgpTransaction: manage_security_environment");
if !matches!(for_operation, KeyType::Authentication | KeyType::Decryption)
|| !matches!(key_ref, KeyType::Authentication | KeyType::Decryption)
{
return Err(Error::UnsupportedAlgo("Only Decryption and Authentication keys can be manipulated by manage_security_environment".to_string()));
}
let cmd = commands::manage_security_environment(for_operation, key_ref);
let resp = self.send_command(cmd, false)?;
resp.check_ok()?;
Ok(())
}
pub fn signature_for_hash(&mut self, hash: Hash) -> Result<Vec<u8>, Error> {
self.pso_compute_digital_signature(digestinfo(hash))
}
pub fn pso_compute_digital_signature(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: pso_compute_digital_signature");
let cds_cmd = commands::signature(data);
let resp = self.send_command(cds_cmd, true)?;
Ok(resp.data().map(|d| d.to_vec())?)
}
pub fn authenticate_for_hash(&mut self, hash: Hash) -> Result<Vec<u8>, Error> {
self.internal_authenticate(digestinfo(hash))
}
pub fn internal_authenticate(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
log::info!("OpenPgpTransaction: internal_authenticate");
let ia_cmd = commands::internal_authenticate(data);
let resp = self.send_command(ia_cmd, true)?;
Ok(resp.data().map(|d| d.to_vec())?)
}
pub fn set_private_use_do(&mut self, num: u8, data: Vec<u8>) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_private_use_do");
if !(1..=4).contains(&num) {
return Err(Error::UnsupportedFeature(format!(
"Illegal Private Use DO num '{}'",
num,
)));
}
let cmd = commands::put_private_use_do(num, data);
self.send_command(cmd, true)?.try_into()
}
pub fn set_login(&mut self, login: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_login");
let cmd = commands::put_login_data(login.to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_name(&mut self, name: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_name");
let cmd = commands::put_name(name.to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_lang(&mut self, lang: &[Lang]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_lang");
let bytes: Vec<_> = lang.iter().flat_map(|&l| Vec::<u8>::from(l)).collect();
let cmd = commands::put_lang(bytes);
self.send_command(cmd, false)?.try_into()
}
pub fn set_sex(&mut self, sex: Sex) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_sex");
let cmd = commands::put_sex((&sex).into());
self.send_command(cmd, false)?.try_into()
}
pub fn set_url(&mut self, url: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_url");
let cmd = commands::put_url(url.to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_cardholder_certificate(&mut self, data: Vec<u8>) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_cardholder_certificate");
let cmd = commands::put_cardholder_certificate(data);
self.send_command(cmd, false)?.try_into()
}
pub fn set_algorithm_attributes(
&mut self,
key_type: KeyType,
algorithm_attributes: &AlgorithmAttributes,
) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_algorithm_attributes");
let ecap = self.extended_capabilities()?;
if !ecap.algo_attrs_changeable() {
return Ok(());
}
let cmd = commands::put_data(
key_type.algorithm_tag(),
algorithm_attributes.to_data_object()?,
);
self.send_command(cmd, false)?.try_into()
}
pub fn set_pw_status_bytes(
&mut self,
pw_status: &PWStatusBytes,
long: bool,
) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_pw_status_bytes");
let data = pw_status.serialize_for_put(long);
let cmd = commands::put_pw_status(data);
self.send_command(cmd, false)?.try_into()
}
pub fn set_fingerprint(&mut self, fp: Fingerprint, key_type: KeyType) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_fingerprint");
let cmd = commands::put_data(key_type.fingerprint_put_tag(), fp.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_ca_fingerprint_1(&mut self, fp: Fingerprint) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_ca_fingerprint_1");
let cmd = commands::put_data(Tags::CaFingerprint1, fp.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_ca_fingerprint_2(&mut self, fp: Fingerprint) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_ca_fingerprint_2");
let cmd = commands::put_data(Tags::CaFingerprint2, fp.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_ca_fingerprint_3(&mut self, fp: Fingerprint) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_ca_fingerprint_3");
let cmd = commands::put_data(Tags::CaFingerprint3, fp.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_creation_time(
&mut self,
time: KeyGenerationTime,
key_type: KeyType,
) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_creation_time");
let time_value: Vec<u8> = time.get().to_be_bytes().to_vec();
let cmd = commands::put_data(key_type.timestamp_put_tag(), time_value);
self.send_command(cmd, false)?.try_into()
}
pub fn set_resetting_code(&mut self, resetting_code: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_resetting_code");
let cmd = commands::put_data(Tags::ResettingCode, resetting_code.to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_pso_enc_dec_key(&mut self, key: &[u8]) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_pso_enc_dec_key");
let cmd = commands::put_data(Tags::PsoEncDecKey, key.to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_uif_pso_cds(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_uif_pso_cds");
let cmd = commands::put_data(Tags::UifSig, uif.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_uif_pso_dec(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_uif_pso_dec");
let cmd = commands::put_data(Tags::UifDec, uif.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_uif_pso_aut(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_uif_pso_aut");
let cmd = commands::put_data(Tags::UifAuth, uif.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn set_uif_attestation(&mut self, uif: &UserInteractionFlag) -> Result<(), Error> {
log::info!("OpenPgpTransaction: set_uif_attestation");
let cmd = commands::put_data(Tags::UifAttestation, uif.as_bytes().to_vec());
self.send_command(cmd, false)?.try_into()
}
pub fn generate_attestation(&mut self, key_type: KeyType) -> Result<(), Error> {
log::info!("OpenPgpTransaction: generate_attestation");
let key = match key_type {
KeyType::Signing => 0x01,
KeyType::Decryption => 0x02,
KeyType::Authentication => 0x03,
_ => return Err(Error::InternalError("Unexpected KeyType".to_string())),
};
let cmd = commands::generate_attestation(key);
self.send_command(cmd, false)?.try_into()
}
pub fn key_import(
&mut self,
key: Box<dyn CardUploadableKey>,
key_type: KeyType,
) -> Result<(), Error> {
keys::key_import(self, key, key_type)
}
pub fn generate_key(
&mut self,
fp_from_pub: fn(
&PublicKeyMaterial,
KeyGenerationTime,
KeyType,
) -> Result<Fingerprint, Error>,
key_type: KeyType,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
let ard = self.application_related_data()?; let cur_algo = ard.algorithm_attributes(key_type)?;
keys::gen_key_set_metadata(self, fp_from_pub, &cur_algo, key_type)
}
pub fn public_key(&mut self, key_type: KeyType) -> Result<PublicKeyMaterial, Error> {
keys::public_key(self, key_type)
}
}
fn digestinfo(hash: Hash) -> Vec<u8> {
match hash {
Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => {
let tlv = Tlv::new(
Tags::Sequence,
Value::C(vec![
Tlv::new(
Tags::Sequence,
Value::C(vec![
Tlv::new(
Tags::ObjectIdentifier,
Value::S(hash.oid().unwrap().to_vec()),
),
Tlv::new(Tags::Null, Value::S(vec![])),
]),
),
Tlv::new(Tags::OctetString, Value::S(hash.digest().to_vec())),
]),
);
tlv.serialize()
}
Hash::EdDSA(d) => d.to_vec(),
Hash::ECDSA(d) => d.to_vec(),
}
}