Reuse generic container approach from Opcard

This commit is contained in:
Sosthène Guédon
2022-12-16 11:34:08 +01:00
parent 25bd7c1a71
commit 22f4669ec7
3 changed files with 192 additions and 100 deletions
+40 -22
View File
@@ -242,8 +242,26 @@ pub enum Container {
PrintedInformation,
DiscoveryObject,
KeyHistoryObject,
RetiredX509Certificate(RetiredIndex),
RetiredCert01,
RetiredCert02,
RetiredCert03,
RetiredCert04,
RetiredCert05,
RetiredCert06,
RetiredCert07,
RetiredCert08,
RetiredCert09,
RetiredCert10,
RetiredCert11,
RetiredCert12,
RetiredCert13,
RetiredCert14,
RetiredCert15,
RetiredCert16,
RetiredCert17,
RetiredCert18,
RetiredCert19,
RetiredCert20,
CardholderIrisImages,
BiometricInformationTemplatesGroupTemplate,
SecureMessagingCertificateSigner,
@@ -309,26 +327,26 @@ impl TryFrom<&[u8]> for Container {
hex!("5FC109") => PrintedInformation,
hex!("7E") => DiscoveryObject,
hex!("5FC10D") => RetiredX509Certificate(RetiredIndex(1)),
hex!("5FC10E") => RetiredX509Certificate(RetiredIndex(2)),
hex!("5FC10F") => RetiredX509Certificate(RetiredIndex(3)),
hex!("5FC110") => RetiredX509Certificate(RetiredIndex(4)),
hex!("5FC111") => RetiredX509Certificate(RetiredIndex(5)),
hex!("5FC112") => RetiredX509Certificate(RetiredIndex(6)),
hex!("5FC113") => RetiredX509Certificate(RetiredIndex(7)),
hex!("5FC114") => RetiredX509Certificate(RetiredIndex(8)),
hex!("5FC115") => RetiredX509Certificate(RetiredIndex(9)),
hex!("5FC116") => RetiredX509Certificate(RetiredIndex(10)),
hex!("5FC117") => RetiredX509Certificate(RetiredIndex(11)),
hex!("5FC118") => RetiredX509Certificate(RetiredIndex(12)),
hex!("5FC119") => RetiredX509Certificate(RetiredIndex(13)),
hex!("5FC11A") => RetiredX509Certificate(RetiredIndex(14)),
hex!("5FC11B") => RetiredX509Certificate(RetiredIndex(15)),
hex!("5FC11C") => RetiredX509Certificate(RetiredIndex(16)),
hex!("5FC11D") => RetiredX509Certificate(RetiredIndex(17)),
hex!("5FC11E") => RetiredX509Certificate(RetiredIndex(18)),
hex!("5FC11F") => RetiredX509Certificate(RetiredIndex(19)),
hex!("5FC120") => RetiredX509Certificate(RetiredIndex(20)),
hex!("5FC10D") => RetiredCert01,
hex!("5FC10E") => RetiredCert02,
hex!("5FC10F") => RetiredCert03,
hex!("5FC110") => RetiredCert04,
hex!("5FC111") => RetiredCert05,
hex!("5FC112") => RetiredCert06,
hex!("5FC113") => RetiredCert07,
hex!("5FC114") => RetiredCert08,
hex!("5FC115") => RetiredCert09,
hex!("5FC116") => RetiredCert10,
hex!("5FC117") => RetiredCert11,
hex!("5FC118") => RetiredCert12,
hex!("5FC119") => RetiredCert13,
hex!("5FC11A") => RetiredCert14,
hex!("5FC11B") => RetiredCert15,
hex!("5FC11C") => RetiredCert16,
hex!("5FC11D") => RetiredCert17,
hex!("5FC11E") => RetiredCert18,
hex!("5FC11F") => RetiredCert19,
hex!("5FC120") => RetiredCert20,
hex!("5FC121") => CardholderIrisImages,
hex!("7F61") => BiometricInformationTemplatesGroupTemplate,
+77 -78
View File
@@ -123,7 +123,7 @@ where
Command::ChangeReference(change_reference) => {
self.load()?.change_reference(change_reference)
}
Command::GetData(container) => self.get_data(container, reply),
Command::GetData(container) => self.load()?.get_data(container, reply),
Command::Select(_aid) => self.select(reply),
Command::GeneralAuthenticate(authenticate) => {
self.load()?
@@ -140,83 +140,6 @@ where
}
}
fn get_data<const R: usize>(
&mut self,
container: container::Container,
mut reply: Reply<'_, R>,
) -> Result {
// TODO: check security status, else return Status::SecurityStatusNotSatisfied
// Table 3, Part 1, SP 800-73-4
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=30
use crate::container::Container;
match container {
Container::DiscoveryObject => {
// Err(Status::InstructionNotSupportedOrInvalid)
reply.extend_from_slice(DISCOVERY_OBJECT).ok();
// todo!("discovery object"),
}
Container::BiometricInformationTemplatesGroupTemplate => {
return Err(Status::InstructionNotSupportedOrInvalid);
// todo!("biometric information template"),
}
// '5FC1 07' (351B)
Container::CardCapabilityContainer => {
piv_types::CardCapabilityContainer::default()
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning CCC {:02X?}", reply);
}
// '5FC1 02' (351B)
Container::CardHolderUniqueIdentifier => {
let guid = self.state.persistent(&mut self.trussed)?.guid();
piv_types::CardHolderUniqueIdentifier::default()
.with_guid(guid)
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning CHUID {:02X?}", reply);
}
// // '5FC1 05' (351B)
// Container::X509CertificateForPivAuthentication => {
// // return Err(Status::NotFound);
// // info!("loading 9a cert");
// // it seems like fetching this certificate is the way Filo's agent decides
// // whether the key is "already setup":
// // https://github.com/FiloSottile/yubikey-agent/blob/8781bc0082db5d35712a2244e3ab3086f415dd59/setup.go#L69-L70
// let data = try_syscall!(self.trussed.read_file(
// trussed::types::Location::Internal,
// trussed::types::PathBuf::from(b"authentication-key.x5c"),
// )).map_err(|_| {
// // info!("error loading: {:?}", &e);
// Status::NotFound
// } )?.data;
// // todo: cleanup
// let tag = flexiber::Tag::application(0x13); // 0x53
// flexiber::TaggedSlice::from(tag, &data)
// .unwrap()
// .encode_to_heapless_vec(reply)
// .unwrap();
// }
// // '5F FF01' (754B)
// YubicoObjects::AttestationCertificate => {
// let data = Data<R>::from_slice(YUBICO_ATTESTATION_CERTIFICATE).unwrap();
// reply.extend_from_slice(&data).ok();
// }
_ => {
warn!("Unimplemented GET DATA object: {container:?}");
return Err(Status::FunctionNotSupported);
}
}
Ok(())
}
pub fn yubico_piv_extension<const R: usize>(
&mut self,
data: &[u8],
@@ -959,6 +882,82 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
Err(Status::IncorrectDataParameter)
}
fn get_data<const R: usize>(
&mut self,
container: container::Container,
mut reply: Reply<'_, R>,
) -> Result {
// TODO: check security status, else return Status::SecurityStatusNotSatisfied
// Table 3, Part 1, SP 800-73-4
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=30
use crate::container::Container;
match container {
Container::DiscoveryObject => {
// Err(Status::InstructionNotSupportedOrInvalid)
reply.extend_from_slice(DISCOVERY_OBJECT).ok();
// todo!("discovery object"),
}
Container::BiometricInformationTemplatesGroupTemplate => {
return Err(Status::InstructionNotSupportedOrInvalid);
// todo!("biometric information template"),
}
// '5FC1 07' (351B)
Container::CardCapabilityContainer => {
piv_types::CardCapabilityContainer::default()
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning CCC {:02X?}", reply);
}
// '5FC1 02' (351B)
Container::CardHolderUniqueIdentifier => {
let guid = self.state.persistent.guid();
piv_types::CardHolderUniqueIdentifier::default()
.with_guid(guid)
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning CHUID {:02X?}", reply);
}
// // '5FC1 05' (351B)
// Container::X509CertificateForPivAuthentication => {
// // return Err(Status::NotFound);
// // info!("loading 9a cert");
// // it seems like fetching this certificate is the way Filo's agent decides
// // whether the key is "already setup":
// // https://github.com/FiloSottile/yubikey-agent/blob/8781bc0082db5d35712a2244e3ab3086f415dd59/setup.go#L69-L70
// let data = try_syscall!(self.trussed.read_file(
// trussed::types::Location::Internal,
// trussed::types::PathBuf::from(b"authentication-key.x5c"),
// )).map_err(|_| {
// // info!("error loading: {:?}", &e);
// Status::NotFound
// } )?.data;
// // todo: cleanup
// let tag = flexiber::Tag::application(0x13); // 0x53
// flexiber::TaggedSlice::from(tag, &data)
// .unwrap()
// .encode_to_heapless_vec(reply)
// .unwrap();
// }
// // '5F FF01' (754B)
// YubicoObjects::AttestationCertificate => {
// let data = Data<R>::from_slice(YUBICO_ATTESTATION_CERTIFICATE).unwrap();
// reply.extend_from_slice(&data).ok();
// }
_ => {
warn!("Unimplemented GET DATA object: {container:?}");
return Err(Status::FunctionNotSupported);
}
}
Ok(())
}
// match container {
// containers::Container::CardHolderUniqueIdentifier =>
// piv_types::CardHolderUniqueIdentifier::default()
+75
View File
@@ -13,6 +13,7 @@ use trussed::{
types::{KeyId, KeySerialization, Location, Mechanism, PathBuf, StorageAttributes},
};
use crate::container::Container;
use crate::{constants::*, piv_types::AsymmetricAlgorithms};
use crate::{
container::{AsymmetricKeyReference, SecurityCondition},
@@ -493,3 +494,77 @@ fn load_if_exists(
},
}
}
#[derive(Clone, Copy, Debug)]
pub struct ContainerStorage(Container);
impl ContainerStorage {
fn path(self) -> PathBuf {
PathBuf::from(match self.0 {
Container::CardCapabilityContainer => "CardCapabilityContainer",
Container::CardHolderUniqueIdentifier => "CardHolderUniqueIdentifier",
Container::X509CertificateFor9A => "X509CertificateFor9A",
Container::CardholderFingerprints => "CardholderFingerprints",
Container::SecurityObject => "SecurityObject",
Container::CardholderFacialImage => "CardholderFacialImage",
Container::X509CertificateFor9E => "X509CertificateFor9E",
Container::X509CertificateFor9C => "X509CertificateFor9C",
Container::X509CertificateFor9D => "X509CertificateFor9D",
Container::PrintedInformation => "PrintedInformation",
Container::DiscoveryObject => "DiscoveryObject",
Container::KeyHistoryObject => "KeyHistoryObject",
Container::RetiredCert01 => "RetiredCert01",
Container::RetiredCert02 => "RetiredCert02",
Container::RetiredCert03 => "RetiredCert03",
Container::RetiredCert04 => "RetiredCert04",
Container::RetiredCert05 => "RetiredCert05",
Container::RetiredCert06 => "RetiredCert06",
Container::RetiredCert07 => "RetiredCert07",
Container::RetiredCert08 => "RetiredCert08",
Container::RetiredCert09 => "RetiredCert09",
Container::RetiredCert10 => "RetiredCert10",
Container::RetiredCert11 => "RetiredCert11",
Container::RetiredCert12 => "RetiredCert12",
Container::RetiredCert13 => "RetiredCert13",
Container::RetiredCert14 => "RetiredCert14",
Container::RetiredCert15 => "RetiredCert15",
Container::RetiredCert16 => "RetiredCert16",
Container::RetiredCert17 => "RetiredCert17",
Container::RetiredCert18 => "RetiredCert18",
Container::RetiredCert19 => "RetiredCert19",
Container::RetiredCert20 => "RetiredCert20",
Container::CardholderIrisImages => "CardholderIrisImages",
Container::BiometricInformationTemplatesGroupTemplate => {
"BiometricInformationTemplatesGroupTemplate"
}
Container::SecureMessagingCertificateSigner => "SecureMessagingCertificateSigner",
Container::PairingCodeReferenceDataContainer => "PairingCodeReferenceDataContainer",
})
}
fn default(self) -> &'static [u8] {
todo!()
}
pub fn load(
self,
client: &mut impl trussed::Client,
) -> Result<Bytes<MAX_MESSAGE_LENGTH>, Status> {
load_if_exists(client, Location::Internal, &self.path())
.map(|data| data.unwrap_or_else(|| Bytes::from_slice(self.default()).unwrap()))
}
pub fn save(self, client: &mut impl trussed::Client, bytes: &[u8]) -> Result<(), Status> {
let msg = Bytes::from(heapless::Vec::try_from(bytes).map_err(|_| {
error!("Buffer full");
Status::IncorrectDataParameter
})?);
try_syscall!(client.write_file(Location::Internal, self.path(), msg, None)).map_err(
|_err| {
error!("Failed to store data: {_err:?}");
Status::UnspecifiedNonpersistentExecutionError
},
)?;
Ok(())
}
}