mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
Reuse generic container approach from Opcard
This commit is contained in:
+40
-22
@@ -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
@@ -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()
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user