mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
Run cargo fmt
This commit is contained in:
committed by
Nicolas Stalder
parent
1922d6d97b
commit
508116066c
+56
-26
@@ -66,7 +66,6 @@ impl<'l> TryFrom<&'l [u8]> for Select<'l> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct GetData(containers::Container);
|
||||
|
||||
@@ -74,7 +73,9 @@ impl TryFrom<&[u8]> for GetData {
|
||||
type Error = Status;
|
||||
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
|
||||
let mut decoder = flexiber::Decoder::new(data);
|
||||
let tagged_slice: flexiber::TaggedSlice = decoder.decode().map_err(|_| Status::IncorrectDataParameter)?;
|
||||
let tagged_slice: flexiber::TaggedSlice = decoder
|
||||
.decode()
|
||||
.map_err(|_| Status::IncorrectDataParameter)?;
|
||||
if tagged_slice.tag() != flexiber::Tag::application(0x1C) {
|
||||
return Err(Status::IncorrectDataParameter);
|
||||
}
|
||||
@@ -155,13 +156,20 @@ pub enum Verify {
|
||||
impl TryFrom<VerifyArguments<'_>> for Verify {
|
||||
type Error = Status;
|
||||
fn try_from(arguments: VerifyArguments<'_>) -> Result<Self, Self::Error> {
|
||||
let VerifyArguments { key_reference, logout, data } = arguments;
|
||||
let VerifyArguments {
|
||||
key_reference,
|
||||
logout,
|
||||
data,
|
||||
} = arguments;
|
||||
if key_reference != VerifyKeyReference::PivPin {
|
||||
return Err(Status::FunctionNotSupported);
|
||||
}
|
||||
Ok(match (logout.0, data.len()) {
|
||||
(false, 0) => Verify::Status(key_reference),
|
||||
(false, 8) => Verify::Login(VerifyLogin::PivPin(data.try_into().map_err(|_| Status::IncorrectDataParameter)?)),
|
||||
(false, 8) => Verify::Login(VerifyLogin::PivPin(
|
||||
data.try_into()
|
||||
.map_err(|_| Status::IncorrectDataParameter)?,
|
||||
)),
|
||||
(false, _) => return Err(Status::IncorrectDataParameter),
|
||||
(true, 0) => Verify::Logout(key_reference),
|
||||
(true, _) => return Err(Status::IncorrectDataParameter),
|
||||
@@ -204,22 +212,27 @@ pub enum ChangeReference {
|
||||
impl TryFrom<ChangeReferenceArguments<'_>> for ChangeReference {
|
||||
type Error = Status;
|
||||
fn try_from(arguments: ChangeReferenceArguments<'_>) -> Result<Self, Self::Error> {
|
||||
let ChangeReferenceArguments { key_reference, data } = arguments;
|
||||
let ChangeReferenceArguments {
|
||||
key_reference,
|
||||
data,
|
||||
} = arguments;
|
||||
|
||||
use ChangeReferenceKeyReference::*;
|
||||
Ok(match (key_reference, data) {
|
||||
(GlobalPin, _) => return Err(Status::FunctionNotSupported),
|
||||
(PivPin, data) => {
|
||||
ChangeReference::ChangePin {
|
||||
old_pin: Pin::try_from(&data[..8]).map_err(|_| Status::IncorrectDataParameter)?,
|
||||
new_pin: Pin::try_from(&data[8..]).map_err(|_| Status::IncorrectDataParameter)?,
|
||||
}
|
||||
}
|
||||
(PivPin, data) => ChangeReference::ChangePin {
|
||||
old_pin: Pin::try_from(&data[..8]).map_err(|_| Status::IncorrectDataParameter)?,
|
||||
new_pin: Pin::try_from(&data[8..]).map_err(|_| Status::IncorrectDataParameter)?,
|
||||
},
|
||||
(Puk, data) => {
|
||||
use crate::commands::Puk;
|
||||
ChangeReference::ChangePuk {
|
||||
old_puk: Puk(data[..8].try_into().map_err(|_| Status::IncorrectDataParameter)?),
|
||||
new_puk: Puk(data[8..].try_into().map_err(|_| Status::IncorrectDataParameter)?),
|
||||
old_puk: Puk(data[..8]
|
||||
.try_into()
|
||||
.map_err(|_| Status::IncorrectDataParameter)?),
|
||||
new_puk: Puk(data[8..]
|
||||
.try_into()
|
||||
.map_err(|_| Status::IncorrectDataParameter)?),
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -229,7 +242,7 @@ impl TryFrom<ChangeReferenceArguments<'_>> for ChangeReference {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct ResetPinRetries {
|
||||
pub padded_pin: [u8; 8],
|
||||
pub puk: [u8; 8],
|
||||
pub puk: [u8; 8],
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for ResetPinRetries {
|
||||
@@ -321,8 +334,7 @@ pub struct AuthenticateArguments<'l> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Authenticate {
|
||||
}
|
||||
pub enum Authenticate {}
|
||||
|
||||
impl TryFrom<AuthenticateArguments<'_>> for Authenticate {
|
||||
type Error = Status;
|
||||
@@ -332,8 +344,7 @@ impl TryFrom<AuthenticateArguments<'_>> for Authenticate {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct PutData {
|
||||
}
|
||||
pub struct PutData {}
|
||||
|
||||
impl TryFrom<&[u8]> for PutData {
|
||||
type Error = Status;
|
||||
@@ -373,8 +384,7 @@ pub struct GenerateAsymmetricArguments<'l> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum GenerateAsymmetric {
|
||||
}
|
||||
pub enum GenerateAsymmetric {}
|
||||
|
||||
impl TryFrom<GenerateAsymmetricArguments<'_>> for GenerateAsymmetric {
|
||||
type Error = Status;
|
||||
@@ -392,7 +402,12 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
|
||||
///
|
||||
/// The individual piv::Command TryFroms then further interpret these validated parameters.
|
||||
fn try_from(command: &'l iso7816::Command<C>) -> Result<Self, Self::Error> {
|
||||
let (class, instruction, p1, p2) = (command.class(), command.instruction(), command.p1, command.p2);
|
||||
let (class, instruction, p1, p2) = (
|
||||
command.class(),
|
||||
command.instruction(),
|
||||
command.p1,
|
||||
command.p2,
|
||||
);
|
||||
let data = command.data();
|
||||
|
||||
if !class.secure_messaging().none() {
|
||||
@@ -406,7 +421,6 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
|
||||
// TODO: should we check `command.expected() == 0`, where specified?
|
||||
|
||||
Ok(match (class.into_inner(), instruction, p1, p2) {
|
||||
|
||||
(0x00, Instruction::Select, 0x04, 0x00) => {
|
||||
Self::Select(Select::try_from(data.as_slice())?)
|
||||
}
|
||||
@@ -418,12 +432,19 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
|
||||
(0x00, Instruction::Verify, p1, p2) => {
|
||||
let logout = VerifyLogout::try_from(p1)?;
|
||||
let key_reference = VerifyKeyReference::try_from(p2)?;
|
||||
Self::Verify(Verify::try_from(VerifyArguments { key_reference, logout, data })?)
|
||||
Self::Verify(Verify::try_from(VerifyArguments {
|
||||
key_reference,
|
||||
logout,
|
||||
data,
|
||||
})?)
|
||||
}
|
||||
|
||||
(0x00, Instruction::ChangeReferenceData, 0x00, p2) => {
|
||||
let key_reference = ChangeReferenceKeyReference::try_from(p2)?;
|
||||
Self::ChangeReference(ChangeReference::try_from(ChangeReferenceArguments { key_reference, data })?)
|
||||
Self::ChangeReference(ChangeReference::try_from(ChangeReferenceArguments {
|
||||
key_reference,
|
||||
data,
|
||||
})?)
|
||||
}
|
||||
|
||||
(0x00, Instruction::ResetRetryCounter, 0x00, 0x80) => {
|
||||
@@ -433,7 +454,11 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
|
||||
(0x00, Instruction::GeneralAuthenticate, p1, p2) => {
|
||||
let unparsed_algorithm = p1;
|
||||
let key_reference = AuthenticateKeyReference::try_from(p2)?;
|
||||
Self::Authenticate(Authenticate::try_from(AuthenticateArguments { unparsed_algorithm, key_reference, data })?)
|
||||
Self::Authenticate(Authenticate::try_from(AuthenticateArguments {
|
||||
unparsed_algorithm,
|
||||
key_reference,
|
||||
data,
|
||||
})?)
|
||||
}
|
||||
|
||||
(0x00, Instruction::PutData, 0x3F, 0xFF) => {
|
||||
@@ -442,7 +467,12 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
|
||||
|
||||
(0x00, Instruction::GenerateAsymmetricKeyPair, 0x00, p2) => {
|
||||
let key_reference = GenerateAsymmetricKeyReference::try_from(p2)?;
|
||||
Self::GenerateAsymmetric(GenerateAsymmetric::try_from(GenerateAsymmetricArguments { key_reference, data })?)
|
||||
Self::GenerateAsymmetric(GenerateAsymmetric::try_from(
|
||||
GenerateAsymmetricArguments {
|
||||
key_reference,
|
||||
data,
|
||||
},
|
||||
)?)
|
||||
}
|
||||
|
||||
_ => return Err(Status::FunctionNotSupported),
|
||||
|
||||
+9
-11
@@ -19,7 +19,8 @@ pub const DERIVED_PIV_PIX: [u8; 6] = hex!("0000 2000 0100");
|
||||
pub const PIV_TRUNCATED_AID: [u8; 9] = hex!("A000000308 00001000");
|
||||
|
||||
// pub const PIV_AID: &[u8] = &hex!("A000000308 00001000 0100");
|
||||
pub const PIV_AID: iso7816::Aid = iso7816::Aid::new_truncatable(&hex!("A000000308 00001000 0100"), 9);
|
||||
pub const PIV_AID: iso7816::Aid =
|
||||
iso7816::Aid::new_truncatable(&hex!("A000000308 00001000 0100"), 9);
|
||||
|
||||
pub const DERIVED_PIV_AID: [u8; 11] = hex!("A000000308 00002000 0100");
|
||||
|
||||
@@ -27,7 +28,6 @@ pub const APPLICATION_LABEL: &[u8] = b"SoloKeys PIV";
|
||||
pub const APPLICATION_URL: &[u8] = b"https://github.com/solokeys/piv-authenticator";
|
||||
// pub const APPLICATION_URL: &[u8] = b"https://piv.is/SoloKeys/PIV/1.0.0-alpha1";
|
||||
|
||||
|
||||
// https://git.io/JfWuD
|
||||
pub const YUBICO_OTP_PIX: [u8; 3] = hex!("200101");
|
||||
pub const YUBICO_OTP_AID: iso7816::Aid = iso7816::Aid::new(&hex!("A000000527 200101"));
|
||||
@@ -84,7 +84,7 @@ pub const SELECT: (u8, u8, u8, u8) = (
|
||||
// p2: i think this is dummy here
|
||||
0x00, // b2, b1 zero means "file occurence": first/only occurence,
|
||||
// b4, b3 zero means "file control information": return FCI template
|
||||
// 256,
|
||||
// 256,
|
||||
);
|
||||
|
||||
//
|
||||
@@ -101,12 +101,11 @@ pub const SELECT: (u8, u8, u8, u8) = (
|
||||
pub const GET_DATA: (u8, u8, u8, u8) = (
|
||||
0x00, // as before, would be 0x0C for secure messaging
|
||||
0xCB, // GET DATA. There's also `CA`, setting bit 1 here
|
||||
// means (7816-4, sec. 5.1.2): use BER-TLV, as opposed
|
||||
// to "no indication provided".
|
||||
// means (7816-4, sec. 5.1.2): use BER-TLV, as opposed
|
||||
// to "no indication provided".
|
||||
// P1, P2: 7816-4, sec. 7.4.1: bit 1 of INS set => P1,P2 identifies
|
||||
// a file. And 0x3FFF identifies current DF
|
||||
0x3F,
|
||||
0xFF,
|
||||
0x3F, 0xFF,
|
||||
// 256,
|
||||
);
|
||||
|
||||
@@ -233,7 +232,6 @@ pub const GET_DATA: (u8, u8, u8, u8) = (
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
// 6A, 80 incorrect parameter in command data field
|
||||
// 6A, 81 function not supported
|
||||
// 6A, 82 data object not found ( = NOT FOUND for files, e.g. certificate, e.g. after GET-DATA)
|
||||
@@ -420,13 +418,13 @@ pub const YUBICO_ATTESTATION_CERTIFICATE_FOR_9A: &'static [u8; 584] = &[
|
||||
];
|
||||
// pub const YUBICO_DEFAULT_MANAGEMENT_KEY: &'static [u8; 24] = b"123456781234567812345678";
|
||||
pub const YUBICO_DEFAULT_MANAGEMENT_KEY: &'static [u8; 24] = &[
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
];
|
||||
|
||||
// stolen from le yubico
|
||||
pub const DISCOVERY_OBJECT: &'static [u8; 20] = b"~\x12O\x0b\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00_/\x02@\x00";
|
||||
pub const DISCOVERY_OBJECT: &'static [u8; 20] =
|
||||
b"~\x12O\x0b\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00_/\x02@\x00";
|
||||
|
||||
// import secrets; secrets.token_bytes(16)
|
||||
pub const GUID: &'static [u8; 16] = b"\x0c\x92\xc9\x04\xd0\xdeL\xd9\xf6\xd1\xa2\x9fE3\xca\xeb";
|
||||
|
||||
+50
-52
@@ -29,7 +29,6 @@ pub enum KeyReference {
|
||||
|
||||
// 20x
|
||||
RetiredKeyManagement(RetiredIndex),
|
||||
|
||||
}
|
||||
|
||||
impl From<KeyReference> for u8 {
|
||||
@@ -85,7 +84,7 @@ impl From<Container> for ContainerId {
|
||||
use Container::*;
|
||||
Self(match container {
|
||||
CardCapabilityContainer => 0xDB00,
|
||||
CardHolderUniqueIdentifier =>0x3000,
|
||||
CardHolderUniqueIdentifier => 0x3000,
|
||||
X509CertificateFor9A => 0x0101,
|
||||
CardholderFingerprints => 0x6010,
|
||||
SecurityObject => 0x9000,
|
||||
@@ -194,64 +193,63 @@ impl TryFrom<Tag<'_>> for Container {
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Clone, Copy, PartialEq)]
|
||||
// pub struct CertInfo {
|
||||
// compressed: bool,
|
||||
// }
|
||||
|
||||
// #[derive(Clone, Copy, PartialEq)]
|
||||
// pub struct CertInfo {
|
||||
// compressed: bool,
|
||||
// }
|
||||
// impl From<CertInfo> for u8 {
|
||||
// fn from(cert_info: CertInfo) -> Self {
|
||||
// cert_info.compressed as u8
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl From<CertInfo> for u8 {
|
||||
// fn from(cert_info: CertInfo) -> Self {
|
||||
// cert_info.compressed as u8
|
||||
// }
|
||||
// }
|
||||
// impl Encodable for CertInfo {
|
||||
// fn encoded_len(&self) -> der::Result<der::Length> {
|
||||
// Length::from(1)
|
||||
// }
|
||||
|
||||
// impl Encodable for CertInfo {
|
||||
// fn encoded_len(&self) -> der::Result<der::Length> {
|
||||
// Length::from(1)
|
||||
// }
|
||||
// fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
|
||||
// encoder.encode(der::Any::new(0x71, &[u8::from(self)]))
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
|
||||
// encoder.encode(der::Any::new(0x71, &[u8::from(self)]))
|
||||
// }
|
||||
// }
|
||||
// pub struct Certificate<'a> {
|
||||
// // max bytes: 1856
|
||||
// certificate: &'a [u8], // tag: 0x70
|
||||
// // 1B
|
||||
// cert_info: CertInfo, // tag: 0x71
|
||||
// // 38
|
||||
// // mscuid: ?, // tag: 0x72
|
||||
// error_detection_code: [u8; 0], // tag: 0xFE
|
||||
// }
|
||||
|
||||
// pub struct Certificate<'a> {
|
||||
// // max bytes: 1856
|
||||
// certificate: &'a [u8], // tag: 0x70
|
||||
// // 1B
|
||||
// cert_info: CertInfo, // tag: 0x71
|
||||
// // 38
|
||||
// // mscuid: ?, // tag: 0x72
|
||||
// error_detection_code: [u8; 0], // tag: 0xFE
|
||||
// }
|
||||
// impl Encodable for CertInfo {
|
||||
// fn encoded_len(&self) -> der::Result<der::Length> {
|
||||
// Length::from(1)
|
||||
// }
|
||||
|
||||
// impl Encodable for CertInfo {
|
||||
// fn encoded_len(&self) -> der::Result<der::Length> {
|
||||
// Length::from(1)
|
||||
// }
|
||||
// fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
|
||||
// encoder.encode(der::Any::new(0x71, &[u8::from(self)]))
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
|
||||
// encoder.encode(der::Any::new(0x71, &[u8::from(self)]))
|
||||
// }
|
||||
// }
|
||||
// #[derive(Encodable)]
|
||||
// pub struct DiscoveryObject<'a> {
|
||||
// #[tlv(tag = "0x4F")]
|
||||
// piv_card_application_aid: &'a [u8; 11], // tag: 0x4F, max bytes = 12,
|
||||
// #[tlv(tag = 0x5F2f)]
|
||||
// pin_usage_policy: [u8; 2], // tag: 0x5F2F, max bytes = 2,
|
||||
// }
|
||||
|
||||
// #[derive(Encodable)]
|
||||
// pub struct DiscoveryObject<'a> {
|
||||
// #[tlv(tag = "0x4F")]
|
||||
// piv_card_application_aid: &'a [u8; 11], // tag: 0x4F, max bytes = 12,
|
||||
// #[tlv(tag = 0x5F2f)]
|
||||
// pin_usage_policy: [u8; 2], // tag: 0x5F2F, max bytes = 2,
|
||||
// }
|
||||
// impl Encodable for CertInfo {
|
||||
// fn encoded_len(&self) -> der::Result<der::Length> {
|
||||
// Length::from(1)
|
||||
// }
|
||||
|
||||
// impl Encodable for CertInfo {
|
||||
// fn encoded_len(&self) -> der::Result<der::Length> {
|
||||
// Length::from(1)
|
||||
// }
|
||||
|
||||
// fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
|
||||
// encoder.encode(der::Any::new(0x71, &[u8::from(self)]))
|
||||
// }
|
||||
// }
|
||||
// fn encode(&self, encoder: &mut Encoder<'_>) -> der::Result<()> {
|
||||
// encoder.encode(der::Any::new(0x71, &[u8::from(self)]))
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
+12
-5
@@ -1,20 +1,27 @@
|
||||
use crate::{Authenticator, /*constants::PIV_AID,*/ Result};
|
||||
|
||||
use apdu_dispatch::{app::App, command, Command, response};
|
||||
use apdu_dispatch::{app::App, command, response, Command};
|
||||
use trussed::client;
|
||||
|
||||
#[cfg(feature = "apdu-dispatch")]
|
||||
impl<T> App<{command::SIZE}, {response::SIZE}> for Authenticator<T, {command::SIZE}>
|
||||
impl<T> App<{ command::SIZE }, { response::SIZE }> for Authenticator<T, { command::SIZE }>
|
||||
where
|
||||
T: client::Client + client::Ed255 + client::Tdes
|
||||
T: client::Client + client::Ed255 + client::Tdes,
|
||||
{
|
||||
fn select(&mut self, apdu: &Command, reply: &mut response::Data) -> Result {
|
||||
self.select(apdu, reply)
|
||||
}
|
||||
|
||||
fn deselect(&mut self) { self.deselect() }
|
||||
fn deselect(&mut self) {
|
||||
self.deselect()
|
||||
}
|
||||
|
||||
fn call(&mut self, _: iso7816::Interface, apdu: &Command, reply: &mut response::Data) -> Result {
|
||||
fn call(
|
||||
&mut self,
|
||||
_: iso7816::Interface,
|
||||
apdu: &Command,
|
||||
reply: &mut response::Data,
|
||||
) -> Result {
|
||||
self.respond(apdu, reply)
|
||||
}
|
||||
}
|
||||
|
||||
+169
-117
File diff suppressed because it is too large
Load Diff
+49
-28
@@ -34,7 +34,7 @@ impl TryFrom<&[u8]> for Pin {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
_ => Err(())
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,45 +103,53 @@ impl Encodable for CryptographicAlgorithmTemplate<'_> {
|
||||
// '80'
|
||||
let cryptographic_algorithm_identifier_tag = flexiber::Tag::context(0);
|
||||
for alg in self.algorithms.iter() {
|
||||
encoder.encode(&flexiber::TaggedSlice::from(cryptographic_algorithm_identifier_tag, &[*alg as _])?)?;
|
||||
encoder.encode(&flexiber::TaggedSlice::from(
|
||||
cryptographic_algorithm_identifier_tag,
|
||||
&[*alg as _],
|
||||
)?)?;
|
||||
}
|
||||
// '06'
|
||||
let object_identifier_tag = flexiber::Tag::universal(6);
|
||||
encoder.encode(&flexiber::TaggedSlice::from(object_identifier_tag, &[0x00])?)
|
||||
encoder.encode(&flexiber::TaggedSlice::from(
|
||||
object_identifier_tag,
|
||||
&[0x00],
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Encodable, Eq, PartialEq)]
|
||||
pub struct CoexistentTagAllocationAuthorityTemplate<'l> {
|
||||
#[tlv(application, primitive, number = "0xF")] // = 0x4F
|
||||
#[tlv(application, primitive, number = "0xF")] // = 0x4F
|
||||
pub application_identifier: &'l [u8],
|
||||
}
|
||||
|
||||
impl Default for CoexistentTagAllocationAuthorityTemplate<'static> {
|
||||
fn default() -> Self {
|
||||
Self { application_identifier: crate::constants::NIST_RID }
|
||||
Self {
|
||||
application_identifier: crate::constants::NIST_RID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Encodable, Eq, PartialEq)]
|
||||
#[tlv(application, constructed, number = "0x1")] // = 0x61
|
||||
#[tlv(application, constructed, number = "0x1")] // = 0x61
|
||||
pub struct ApplicationPropertyTemplate<'l> {
|
||||
/// Application identifier of application: PIX (without RID, with version)
|
||||
#[tlv(application, primitive, number = "0xF")] // = 0x4F
|
||||
aid: &'l[u8],
|
||||
#[tlv(application, primitive, number = "0xF")] // = 0x4F
|
||||
aid: &'l [u8],
|
||||
|
||||
/// Text describing the application; e.g., for use on a man-machine interface.
|
||||
#[tlv(application, primitive, number = "0x10")] // = 0x50
|
||||
#[tlv(application, primitive, number = "0x10")] // = 0x50
|
||||
application_label: &'l [u8],
|
||||
|
||||
/// Reference to the specification describing the application.
|
||||
#[tlv(application, primitive, number = "0x50")] // = 0x5F50
|
||||
#[tlv(application, primitive, number = "0x50")] // = 0x5F50
|
||||
application_url: &'l [u8],
|
||||
|
||||
#[tlv(context, constructed, number = "0xC")] // = 0xAC
|
||||
#[tlv(context, constructed, number = "0xC")] // = 0xAC
|
||||
supported_cryptographic_algorithms: CryptographicAlgorithmTemplate<'l>,
|
||||
|
||||
#[tlv(application, constructed, number = "0x19")] // = 0x79
|
||||
#[tlv(application, constructed, number = "0x19")] // = 0x79
|
||||
coexistent_tag_allocation_authority: CoexistentTagAllocationAuthorityTemplate<'l>,
|
||||
}
|
||||
|
||||
@@ -158,7 +166,6 @@ impl Default for ApplicationPropertyTemplate<'static> {
|
||||
}
|
||||
|
||||
impl<'a> ApplicationPropertyTemplate<'a> {
|
||||
|
||||
pub const fn with_application_label(self, application_label: &'a [u8]) -> Self {
|
||||
Self {
|
||||
aid: self.aid,
|
||||
@@ -179,18 +186,22 @@ impl<'a> ApplicationPropertyTemplate<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn with_supported_cryptographic_algorithms(self, supported_cryptographic_algorithms: &'a [Algorithms]) -> Self {
|
||||
pub const fn with_supported_cryptographic_algorithms(
|
||||
self,
|
||||
supported_cryptographic_algorithms: &'a [Algorithms],
|
||||
) -> Self {
|
||||
Self {
|
||||
aid: self.aid,
|
||||
application_label: self.application_label,
|
||||
application_url: self.application_url,
|
||||
supported_cryptographic_algorithms: CryptographicAlgorithmTemplate { algorithms: supported_cryptographic_algorithms},
|
||||
supported_cryptographic_algorithms: CryptographicAlgorithmTemplate {
|
||||
algorithms: supported_cryptographic_algorithms,
|
||||
},
|
||||
coexistent_tag_allocation_authority: self.coexistent_tag_allocation_authority,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// TODO: This should be an enum of sorts, maybe.
|
||||
///
|
||||
/// The data objects that appear in the dynamic authentication template (tag '7C') in the data field
|
||||
@@ -201,40 +212,52 @@ impl<'a> ApplicationPropertyTemplate<'a> {
|
||||
/// - '80 00' Returns '80 TL <encrypted random>' (as per definition)
|
||||
/// - '81 00' Returns '81 TL <random>' (as per external authenticate example)
|
||||
#[derive(Clone, Copy, Default, Encodable, Eq, PartialEq)]
|
||||
#[tlv(application, constructed, number = "0x1C")] // = 0x7C
|
||||
#[tlv(application, constructed, number = "0x1C")] // = 0x7C
|
||||
pub struct DynamicAuthenticationTemplate<'l> {
|
||||
/// The Witness (tag '80') contains encrypted data (unrevealed fact).
|
||||
/// This data is decrypted by the card.
|
||||
#[tlv(simple = "0x80")]
|
||||
witness: Option<&'l[u8]>,
|
||||
witness: Option<&'l [u8]>,
|
||||
|
||||
/// The Challenge (tag '81') contains clear data (byte sequence),
|
||||
/// which is encrypted by the card.
|
||||
#[tlv(simple = "0x81")]
|
||||
challenge: Option<&'l[u8]>,
|
||||
challenge: Option<&'l [u8]>,
|
||||
|
||||
/// The Response (tag '82') contains either the decrypted data from tag '80'
|
||||
/// or the encrypted data from tag '81'.
|
||||
#[tlv(simple = "0x82")]
|
||||
response: Option<&'l[u8]>,
|
||||
response: Option<&'l [u8]>,
|
||||
|
||||
/// Not documented in SP-800-73-4
|
||||
#[tlv(simple = "0x85")]
|
||||
exponentiation: Option<&'l[u8]>,
|
||||
exponentiation: Option<&'l [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> DynamicAuthenticationTemplate<'a> {
|
||||
pub fn with_challenge(challenge: &'a [u8]) -> Self {
|
||||
Self { challenge: Some(challenge), ..Default::default() }
|
||||
Self {
|
||||
challenge: Some(challenge),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn with_exponentiation(exponentiation: &'a [u8]) -> Self {
|
||||
Self { exponentiation: Some(exponentiation), ..Default::default() }
|
||||
Self {
|
||||
exponentiation: Some(exponentiation),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn with_response(response: &'a [u8]) -> Self {
|
||||
Self { response: Some(response), ..Default::default() }
|
||||
Self {
|
||||
response: Some(response),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
pub fn with_witness(witness: &'a [u8]) -> Self {
|
||||
Self { witness: Some(witness), ..Default::default() }
|
||||
Self {
|
||||
witness: Some(witness),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +269,7 @@ impl<'a> DynamicAuthenticationTemplate<'a> {
|
||||
// pivy: https://git.io/JfzBo
|
||||
// https://www.idmanagement.gov/wp-content/uploads/sites/1171/uploads/TIG_SCEPACS_v2.3.pdf
|
||||
#[derive(Clone, Copy, Encodable, Eq, PartialEq)]
|
||||
#[tlv(application, primitive, number = "0x13")] // = 0x53
|
||||
#[tlv(application, primitive, number = "0x13")] // = 0x53
|
||||
pub struct CardHolderUniqueIdentifier<'l> {
|
||||
#[tlv(simple = "0x30")]
|
||||
// pivy: 26B, TIG: 25B
|
||||
@@ -269,7 +292,6 @@ pub struct CardHolderUniqueIdentifier<'l> {
|
||||
// #[tlv(simple = "0x36")]
|
||||
// // 16B, like guid
|
||||
// cardholder_uuid: Option<&'l [u8]>,
|
||||
|
||||
#[tlv(simple = "0x3E")]
|
||||
issuer_asymmetric_signature: &'l [u8],
|
||||
|
||||
@@ -384,4 +406,3 @@ pub struct DiscoveryObject {
|
||||
#[tlv(slice, application, number = "0x2f")]
|
||||
pin_usage_policy: [u8; 2], // tag: 0x5F2F, max bytes = 2,
|
||||
}
|
||||
|
||||
|
||||
+46
-39
@@ -1,10 +1,9 @@
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
|
||||
use trussed::{
|
||||
block,
|
||||
block, syscall, try_syscall,
|
||||
types::{KeyId, Location, PathBuf},
|
||||
Client as TrussedClient,
|
||||
syscall, try_syscall,
|
||||
types::{KeyId, PathBuf, Location},
|
||||
};
|
||||
|
||||
use crate::constants::*;
|
||||
@@ -37,7 +36,10 @@ pub struct Slot {
|
||||
|
||||
impl Default for Slot {
|
||||
fn default() -> Self {
|
||||
Self { key: None, pin_policy: PinPolicy::Once, /*touch_policy: TouchPolicy::Never*/ }
|
||||
Self {
|
||||
key: None,
|
||||
pin_policy: PinPolicy::Once, /*touch_policy: TouchPolicy::Never*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,10 +48,15 @@ impl Slot {
|
||||
use SlotName::*;
|
||||
match name {
|
||||
// Management => Slot { pin_policy: PinPolicy::Never, ..Default::default() },
|
||||
Signature => Slot { pin_policy: PinPolicy::Always, ..Default::default() },
|
||||
Pinless => Slot { pin_policy: PinPolicy::Never, ..Default::default() },
|
||||
Signature => Slot {
|
||||
pin_policy: PinPolicy::Always,
|
||||
..Default::default()
|
||||
},
|
||||
Pinless => Slot {
|
||||
pin_policy: PinPolicy::Never,
|
||||
..Default::default()
|
||||
},
|
||||
_ => Default::default(),
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,9 +75,9 @@ impl core::convert::TryFrom<u8> for RetiredSlotIndex {
|
||||
}
|
||||
pub enum SlotName {
|
||||
Identity,
|
||||
Management, // Personalization? Administration?
|
||||
Management, // Personalization? Administration?
|
||||
Signature,
|
||||
Decryption, // Management after all?
|
||||
Decryption, // Management after all?
|
||||
Pinless,
|
||||
Retired(RetiredSlotIndex),
|
||||
Attestation,
|
||||
@@ -78,8 +85,8 @@ pub enum SlotName {
|
||||
|
||||
impl SlotName {
|
||||
pub fn default_pin_policy(&self) -> PinPolicy {
|
||||
use SlotName::*;
|
||||
use PinPolicy::*;
|
||||
use SlotName::*;
|
||||
match *self {
|
||||
Signature => Always,
|
||||
Pinless | Management | Attestation => Never,
|
||||
@@ -88,7 +95,10 @@ impl SlotName {
|
||||
}
|
||||
|
||||
pub fn default_slot(&self) -> Slot {
|
||||
Slot { key: None, pin_policy: self.default_pin_policy() }
|
||||
Slot {
|
||||
key: None,
|
||||
pin_policy: self.default_pin_policy(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reference(&self) -> u8 {
|
||||
@@ -137,7 +147,6 @@ pub struct Keys {
|
||||
pub retired_keys: [Option<KeyId>; 20],
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct State<const C: usize> {
|
||||
pub runtime: Runtime<C>,
|
||||
@@ -156,8 +165,8 @@ impl<const C: usize> State<C> {
|
||||
// TODO: it is really not good to overwrite user data on failure to decode old state.
|
||||
// To fix this, need a flag to detect if we're "fresh", and/or initialize state in factory.
|
||||
pub fn persistent<'t, T>(&mut self, trussed: &'t mut T) -> Persistent<'t, T>
|
||||
where T: TrussedClient
|
||||
+ trussed::client::Tdes
|
||||
where
|
||||
T: TrussedClient + trussed::client::Tdes,
|
||||
{
|
||||
Persistent::load_or_initialize(trussed)
|
||||
}
|
||||
@@ -237,7 +246,6 @@ impl<T> AsRef<PersistentState> for Persistent<'_, T> {
|
||||
pub struct Runtime<const C: usize> {
|
||||
// aid: Option<
|
||||
// consecutive_pin_mismatches: u8,
|
||||
|
||||
pub global_security_status: GlobalSecurityStatus,
|
||||
// pub currently_selected_application: SelectableAid,
|
||||
pub app_security_status: AppSecurityStatus,
|
||||
@@ -299,8 +307,7 @@ pub struct Runtime<const C: usize> {
|
||||
// }
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct GlobalSecurityStatus {
|
||||
}
|
||||
pub struct GlobalSecurityStatus {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SecurityStatus {
|
||||
@@ -328,10 +335,8 @@ pub enum CommandCache {
|
||||
AuthenticateManagement(AuthenticateManagement),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct GetData {
|
||||
}
|
||||
pub struct GetData {}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct AuthenticateManagement {
|
||||
@@ -342,7 +347,6 @@ impl<'t, T> Persistent<'t, T>
|
||||
where
|
||||
T: TrussedClient + trussed::client::Tdes,
|
||||
{
|
||||
|
||||
pub const PIN_RETRIES_DEFAULT: u8 = 3;
|
||||
// hmm...!
|
||||
pub const PUK_RETRIES_DEFAULT: u8 = 5;
|
||||
@@ -444,10 +448,10 @@ where
|
||||
|
||||
pub fn set_management_key(&mut self, management_key: &[u8; 24]) {
|
||||
// let new_management_key = syscall!(self.trussed.unsafe_inject_tdes_key(
|
||||
let new_management_key = syscall!(self.trussed.unsafe_inject_shared_key(
|
||||
management_key,
|
||||
trussed::types::Location::Internal,
|
||||
)).key;
|
||||
let new_management_key = syscall!(self
|
||||
.trussed
|
||||
.unsafe_inject_shared_key(management_key, trussed::types::Location::Internal,))
|
||||
.key;
|
||||
let old_management_key = self.state.keys.management_key;
|
||||
self.state.keys.management_key = new_management_key;
|
||||
self.save();
|
||||
@@ -459,7 +463,8 @@ where
|
||||
let management_key = syscall!(trussed.unsafe_inject_shared_key(
|
||||
YUBICO_DEFAULT_MANAGEMENT_KEY,
|
||||
trussed::types::Location::Internal,
|
||||
)).key;
|
||||
))
|
||||
.key;
|
||||
|
||||
let mut guid: [u8; 16] = syscall!(trussed.random_bytes(16))
|
||||
.bytes
|
||||
@@ -489,21 +494,21 @@ where
|
||||
puk: Puk::try_from(Self::DEFAULT_PUK).unwrap(),
|
||||
timestamp: 0,
|
||||
guid,
|
||||
}
|
||||
},
|
||||
};
|
||||
state.save();
|
||||
state
|
||||
}
|
||||
|
||||
pub fn load(trussed: &'t mut T) -> Result<Self> {
|
||||
let data = block!(trussed.read_file(
|
||||
Location::Internal,
|
||||
PathBuf::from(Self::FILENAME),
|
||||
).unwrap()
|
||||
).map_err(|e| {
|
||||
let data = block!(trussed
|
||||
.read_file(Location::Internal, PathBuf::from(Self::FILENAME),)
|
||||
.unwrap())
|
||||
.map_err(|e| {
|
||||
info!("loading error: {:?}", &e);
|
||||
drop(e)
|
||||
})?.data;
|
||||
})?
|
||||
.data;
|
||||
|
||||
let previous_state: PersistentState = trussed::cbor_deserialize(&data).map_err(|e| {
|
||||
info!("cbor deser error: {:?}", e);
|
||||
@@ -511,12 +516,16 @@ where
|
||||
drop(e)
|
||||
})?;
|
||||
// horrible deser bug to forget Ok here :)
|
||||
Ok(Self { trussed, state: previous_state })
|
||||
Ok(Self {
|
||||
trussed,
|
||||
state: previous_state,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load_or_initialize(trussed: &'t mut T) -> Self {
|
||||
// todo: can't seem to combine load + initialize without code repetition
|
||||
let data = try_syscall!(trussed.read_file(Location::Internal, PathBuf::from(Self::FILENAME)));
|
||||
let data =
|
||||
try_syscall!(trussed.read_file(Location::Internal, PathBuf::from(Self::FILENAME)));
|
||||
if let Ok(data) = data {
|
||||
let previous_state = trussed::cbor_deserialize(&data.data).map_err(|e| {
|
||||
info!("cbor deser error: {:?}", e);
|
||||
@@ -524,8 +533,8 @@ where
|
||||
drop(e)
|
||||
});
|
||||
if let Ok(state) = previous_state {
|
||||
// horrible deser bug to forget Ok here :)
|
||||
return Self { trussed, state }
|
||||
// horrible deser bug to forget Ok here :)
|
||||
return Self { trussed, state };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,6 +557,4 @@ where
|
||||
self.save();
|
||||
self.state.timestamp
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ fn get_data() {
|
||||
// let cmd = cmd!("00 47 00 9A 0B AC 09 80 01 11 AA 01 02 AB 01 02");
|
||||
|
||||
// let cmd = cmd!("00 f8 00 00");
|
||||
// // without PIN, no key generation
|
||||
// // without PIN, no key generation
|
||||
setup::piv(|piv| {
|
||||
|
||||
// ykGetSerial
|
||||
|
||||
+40
-13
@@ -1,5 +1,6 @@
|
||||
trussed::platform!(Platform,
|
||||
R: rand_core::OsRng,//chacha20::ChaCha8Rng,
|
||||
trussed::platform!(
|
||||
Platform,
|
||||
R: rand_core::OsRng, //chacha20::ChaCha8Rng,
|
||||
S: store::Store,
|
||||
UI: ui::UserInterface,
|
||||
);
|
||||
@@ -8,15 +9,21 @@ const COMMAND_SIZE: usize = 3072;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cmd {
|
||||
($tt:tt) => { iso7816::Command::<3072>::try_from(&hex_literal::hex!($tt)).unwrap() }
|
||||
($tt:tt) => {
|
||||
iso7816::Command::<3072>::try_from(&hex_literal::hex!($tt)).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
pub type Piv<'service> = piv_authenticator::Authenticator<
|
||||
trussed::ClientImplementation<&'service mut trussed::service::Service<Platform>>, COMMAND_SIZE>;
|
||||
trussed::ClientImplementation<&'service mut trussed::service::Service<Platform>>,
|
||||
COMMAND_SIZE,
|
||||
>;
|
||||
|
||||
pub fn piv<R>(test: impl FnOnce(&mut Piv) -> R) -> R {
|
||||
use trussed::Interchange as _;
|
||||
unsafe { trussed::pipe::TrussedInterchange::reset_claims(); }
|
||||
unsafe {
|
||||
trussed::pipe::TrussedInterchange::reset_claims();
|
||||
}
|
||||
let trussed_platform = init_platform();
|
||||
let mut trussed_service = trussed::service::Service::new(trussed_platform);
|
||||
let client_id = "test";
|
||||
@@ -31,7 +38,7 @@ pub fn init_platform() -> Platform {
|
||||
store::InternalStorage::new(),
|
||||
store::ExternalStorage::new(),
|
||||
store::VolatileStorage::new(),
|
||||
);
|
||||
);
|
||||
let ui = ui::UserInterface::new();
|
||||
|
||||
let platform = Platform::new(rng, store, ui);
|
||||
@@ -41,28 +48,48 @@ pub fn init_platform() -> Platform {
|
||||
|
||||
pub mod ui {
|
||||
use trussed::platform::{consent, reboot, ui};
|
||||
pub struct UserInterface { start_time: std::time::Instant }
|
||||
pub struct UserInterface {
|
||||
start_time: std::time::Instant,
|
||||
}
|
||||
|
||||
impl UserInterface { pub fn new() -> Self { Self { start_time: std::time::Instant::now() } } }
|
||||
impl UserInterface {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
start_time: std::time::Instant::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl trussed::platform::UserInterface for UserInterface {
|
||||
fn check_user_presence(&mut self) -> consent::Level { consent::Level::Normal }
|
||||
fn check_user_presence(&mut self) -> consent::Level {
|
||||
consent::Level::Normal
|
||||
}
|
||||
fn set_status(&mut self, _status: ui::Status) {}
|
||||
fn refresh(&mut self) {}
|
||||
fn uptime(&mut self) -> core::time::Duration { self.start_time.elapsed() }
|
||||
fn reboot(&mut self, _to: reboot::To) -> ! { loop { continue; } }
|
||||
fn uptime(&mut self) -> core::time::Duration {
|
||||
self.start_time.elapsed()
|
||||
}
|
||||
fn reboot(&mut self, _to: reboot::To) -> ! {
|
||||
loop {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod store {
|
||||
use littlefs2::{const_ram_storage, consts, fs::{Allocation, Filesystem}};
|
||||
use littlefs2::{
|
||||
const_ram_storage, consts,
|
||||
fs::{Allocation, Filesystem},
|
||||
};
|
||||
use trussed::types::{LfsResult, LfsStorage};
|
||||
|
||||
const_ram_storage!(InternalStorage, 8192);
|
||||
const_ram_storage!(ExternalStorage, 8192);
|
||||
const_ram_storage!(VolatileStorage, 8192);
|
||||
|
||||
trussed::store!(Store,
|
||||
trussed::store!(
|
||||
Store,
|
||||
Internal: InternalStorage,
|
||||
External: ExternalStorage,
|
||||
Volatile: VolatileStorage
|
||||
|
||||
Reference in New Issue
Block a user