Bump heapless

This commit is contained in:
Nicolas Stalder
2021-06-11 00:05:14 +02:00
parent edac42a7ad
commit 8bdee0d35e
11 changed files with 121 additions and 134 deletions
+3 -4
View File
@@ -14,8 +14,7 @@ apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch", branch = "m
delog = "0.1.0"
# flexiber = { path = "/home/nicolas/projects/flexiber", features = ["derive", "heapless"] }
flexiber = { git = "https://github.com/nickray/flexiber", branch = "main", features = ["derive", "heapless"] }
heapless = "0.6"
heapless-bytes = "0.2"
heapless = "0.7"
hex-literal = "0.3"
interchange = "0.2.0"
iso7816 = { git = "https://github.com/ycrypto/iso7816", branch = "main" }
@@ -25,8 +24,8 @@ trussed = { git = "https://github.com/trussed-dev/trussed", branch = "main" }
untrusted = "0.7"
[dev-dependencies]
littlefs2 = "0.2.1"
rand_core = { version = "0.5.1", features = ["getrandom"] }
littlefs2 = "0.3.1"
rand_core = { version = "0.6", features = ["getrandom"] }
[features]
default = []
+7 -7
View File
@@ -6,7 +6,6 @@
use core::convert::{TryFrom, TryInto};
// use flexiber::Decodable;
use heapless::ArrayLength;
use iso7816::{Instruction, Status};
pub use crate::{container as containers, piv_types, Pin, Puk};
@@ -43,7 +42,7 @@ impl<'l> Command<'l> {
/// Core method, constructs a PIV command, if the iso7816::Command is valid.
///
/// Inherent method re-exposing the `TryFrom` implementation.
pub fn try_from<C: ArrayLength<u8>>(command: &'l iso7816::Command<C>) -> Result<Self, Status> {
pub fn try_from<const C: usize>(command: &'l iso7816::Command<C>) -> Result<Self, Status> {
command.try_into()
}
}
@@ -59,10 +58,11 @@ impl<'l> TryFrom<&'l [u8]> for Select<'l> {
/// We allow ourselves the option of answering to more than just the official PIV AID.
/// For instance, to offer additional functionality, under our own RID.
fn try_from(data: &'l [u8]) -> Result<Self, Self::Error> {
Ok(match data {
crate::constants::PIV_AID => Self { aid: data },
_ => return Err(Status::NotFound),
})
if crate::constants::PIV_AID.matches(data) {
Ok(Self { aid: data })
} else {
Err(Status::NotFound)
}
}
}
@@ -383,7 +383,7 @@ impl TryFrom<GenerateAsymmetricArguments<'_>> for GenerateAsymmetric {
}
}
impl<'l, C: ArrayLength<u8>> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
impl<'l, const C: usize> TryFrom<&'l iso7816::Command<C>> for Command<'l> {
type Error = Status;
/// The first layer of unraveling the iso7816::Command onion.
///
+3 -2
View File
@@ -18,7 +18,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: &[u8] = &hex!("A000000308 00001000 0100");
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");
@@ -29,7 +30,7 @@ pub const APPLICATION_URL: &[u8] = b"https://github.com/solokeys/piv-authenticat
// https://git.io/JfWuD
pub const YUBICO_OTP_PIX: [u8; 3] = hex!("200101");
pub const YUBICO_OTP_AID: [u8; 8] = hex!("A000000527 200101");
pub const YUBICO_OTP_AID: iso7816::Aid = iso7816::Aid::new(&hex!("A000000527 200101"));
// they use it to "deauthenticate user PIN and mgmt key": https://git.io/JfWgN
pub const YUBICO_MGMT_PIX: [u8; 3] = hex!("471117");
pub const YUBICO_MGMT_AID: [u8; 8] = hex!("A000000527 471117");
+4 -21
View File
@@ -1,37 +1,20 @@
use crate::{Authenticator, constants::PIV_AID, Result};
use apdu_dispatch::{
app::{Aid, App},
command::Size as CommandSize,
Command,
response::{Data, Size as ResponseSize},
};
use apdu_dispatch::{app::App, command, Command, response, Response};
use trussed::client;
impl<T> Aid for Authenticator<CommandSize, T> {
fn aid(&self) -> &'static [u8] {
&PIV_AID
}
fn right_truncated_length(&self) -> usize {
11
}
}
#[cfg(feature = "apdu-dispatch")]
impl<T> App<CommandSize, ResponseSize> for Authenticator<CommandSize, T>
impl<T> App<{command::SIZE}, {response::SIZE}> for Authenticator<T, {command::SIZE}>
where
T: client::Client + client::Ed255 + client::Tdes
{
fn select(&mut self, apdu: &Command, reply: &mut Data) -> Result {
fn select(&mut self, apdu: &Command, reply: &mut response::Data) -> Result {
self.select(apdu, reply)
}
fn deselect(&mut self) { self.deselect() }
fn call(&mut self, _: iso7816::Interface, apdu: &Command, reply: &mut Data) -> Result {
fn call(&mut self, _: iso7816::Interface, apdu: &Command, reply: &mut response::Data) -> Result {
self.respond(apdu, reply)
}
}
+20 -36
View File
@@ -22,7 +22,6 @@ pub use piv_types::{Pin, Puk};
use core::convert::TryInto;
use flexiber::EncodableHeapless;
use heapless::ArrayLength;
use iso7816::{Data, Status};
use trussed::client;
use trussed::{syscall, try_syscall};
@@ -36,18 +35,21 @@ pub type Result = iso7816::Result<()>;
/// The `C` parameter is necessary, as PIV includes command sequences,
/// where we need to store the previous command, so we need to know how
/// much space to allocate.
pub struct Authenticator<C, T>
where
C: ArrayLength<u8>,
pub struct Authenticator<T, const C: usize>
{
state: state::State<C>,
trussed: T,
// trussed: RefCell<Trussed>,
}
impl<C, T> Authenticator<C, T>
impl<T, const C: usize> iso7816::App for Authenticator<T, C>
{
fn aid(&self) -> iso7816::Aid {
crate::constants::PIV_AID
}
}
impl<T, const C: usize> Authenticator<T, C>
where
C: ArrayLength<u8>,
T: client::Client + client::Ed255 + client::Tdes,
{
pub fn new(
@@ -70,10 +72,7 @@ where
pub fn deselect(&mut self) {
}
pub fn select<R>(&mut self, _apdu: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
pub fn select<const R: usize>(&mut self, _apdu: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
{
use piv_types::Algorithms::*;
info_now!("selecting PIV maybe");
@@ -83,7 +82,6 @@ where
.with_application_url(APPLICATION_URL)
.with_supported_cryptographic_algorithms(&[
Tdes,
Aes128,
Aes256,
P256,
Ed255,
@@ -97,9 +95,7 @@ where
Ok(())
}
pub fn respond<R>(&mut self, command: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
pub fn respond<const R: usize>(&mut self, command: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
{
// need to implement Debug on iso7816::Command
// info_now!("PIV responding to {:?}", command);
@@ -347,9 +343,7 @@ where
// - 9000, 61XX for success
// - 6982 security status
// - 6A80, 6A86 for data, P1/P2 issue
fn general_authenticate<R>(&mut self, command: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
fn general_authenticate<const R: usize>(&mut self, command: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
{
// For "SSH", we need implement A.4.2 in SP-800-73-4 Part 2, ECDSA signatures
@@ -460,9 +454,7 @@ where
Ok(())
}
fn request_for_challenge<R>(&mut self, command: &iso7816::Command<C>, remaining_data: &[u8], reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
fn request_for_challenge<const R: usize>(&mut self, command: &iso7816::Command<C>, remaining_data: &[u8], reply: &mut Data<R>) -> Result
{
// - data is of the form
// 00 87 03 9B 16 7C 14 80 08 99 6D 71 40 E7 05 DF 7F 81 08 6E EF 9C 02 00 69 73 E8
@@ -514,9 +506,7 @@ where
Ok(())
}
fn request_for_witness<R>(&mut self, command: &iso7816::Command<C>, remaining_data: &[u8], reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
fn request_for_witness<const R: usize>(&mut self, command: &iso7816::Command<C>, remaining_data: &[u8], reply: &mut Data<R>) -> Result
{
// invariants: parsed data was '7C L1 80 00' + remaining_data
@@ -692,9 +682,7 @@ where
// }
//}
fn generate_asymmetric_keypair<R>(&mut self, command: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
fn generate_asymmetric_keypair<const R: usize>(&mut self, command: &iso7816::Command<C>, reply: &mut Data<R>) -> Result
{
if !self.state.runtime.app_security_status.management_verified {
return Err(Status::SecurityStatusNotSatisfied);
@@ -868,7 +856,7 @@ where
try_syscall!(self.trussed.write_file(
trussed::types::Location::Internal,
trussed::types::PathBuf::from(b"printed-information"),
trussed::types::Message::try_from_slice(data).unwrap(),
trussed::types::Message::from_slice(data).unwrap(),
None,
)).map_err(|_| Status::NotEnoughMemory)?;
@@ -893,7 +881,7 @@ where
try_syscall!(self.trussed.write_file(
trussed::types::Location::Internal,
trussed::types::PathBuf::from(b"authentication-key.x5c"),
trussed::types::Message::try_from_slice(data).unwrap(),
trussed::types::Message::from_slice(data).unwrap(),
None,
)).map_err(|_| Status::NotEnoughMemory)?;
@@ -912,9 +900,7 @@ where
// }
// todo!();
fn get_data<R>(&mut self, container: container::Container, reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
fn get_data<const R: usize>(&mut self, container: container::Container, reply: &mut Data<R>) -> Result
{
// TODO: check security status, else return Status::SecurityStatusNotSatisfied
@@ -978,7 +964,7 @@ where
// // '5F FF01' (754B)
// YubicoObjects::AttestationCertificate => {
// let data = Data<R>::try_from_slice(YUBICO_ATTESTATION_CERTIFICATE).unwrap();
// let data = Data<R>::from_slice(YUBICO_ATTESTATION_CERTIFICATE).unwrap();
// reply.extend_from_slice(&data).ok();
// }
@@ -987,9 +973,7 @@ where
Ok(())
}
fn yubico_piv_extension<R>(&mut self, command: &iso7816::Command<C>, instruction: YubicoPivExtension, reply: &mut Data<R>) -> Result
where
R: ArrayLength<u8>,
fn yubico_piv_extension<const R: usize>(&mut self, command: &iso7816::Command<C>, instruction: YubicoPivExtension, reply: &mut Data<R>) -> Result
{
info_now!("yubico extension: {:?}", &instruction);
match instruction {
+18 -5
View File
@@ -52,6 +52,11 @@ impl TryFrom<&[u8]> for Puk {
#[repr(u8)]
#[derive(Clone, Copy, Eq, PartialEq)]
// As additional reference, see:
// https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15
//
// This GP ISO standard contains PIV types as subset (although SM is not quite clear),
// references Opacity ZKM.
pub enum Algorithms {
Tdes = 0x3,
Rsa1k = 0x6,
@@ -62,12 +67,20 @@ pub enum Algorithms {
P256 = 0x11,
P384 = 0x14,
/// non-standard! in piv-go though!
Ed255 = 0x22,
/// non-standard!
X255 = 0x23,
// // non-standard! in piv-go though!
// Ed255_prev = 0x22,
/// non-standard! picked by Alex, but maybe due for removal
// https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15
P521 = 0x15,
// non-standard!
Rsa3k = 0xE0,
Rsa4k = 0xE1,
Ed255 = 0xE2,
X255 = 0xE3,
Ed448 = 0xE4,
X448 = 0xE5,
// non-standard! picked by Alex, but maybe due for removal
P256Sha1 = 0xF0,
P256Sha256 = 0xF1,
P384Sha1 = 0xF2,
+46 -47
View File
@@ -1,5 +1,4 @@
use core::convert::{TryFrom, TryInto};
use heapless::ArrayLength;
use trussed::{
block,
@@ -140,14 +139,14 @@ pub struct Keys {
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct State<C: ArrayLength<u8>> {
pub struct State<const C: usize> {
pub runtime: Runtime<C>,
// temporary "state", to be removed again
// pub hack: Hack,
// trussed: RefCell<Trussed<S>>,
}
impl<C: ArrayLength<u8>> State<C> {
impl<const C: usize> State<C> {
pub fn new() -> Self {
Default::default()
}
@@ -196,7 +195,7 @@ impl<C: ArrayLength<u8>> State<C> {
// if valid_bytes {
// Ok(Self {
// // padded_pin: padded_pin.try_into().unwrap(),
// pin: Bytes::try_from_slice(padded_pin).unwrap(),//padded_pin.try_into().unwrap(),
// pin: Bytes::from_slice(padded_pin).unwrap(),//padded_pin.try_into().unwrap(),
// })
// } else {
// Err(())
@@ -235,69 +234,69 @@ impl<T> AsRef<PersistentState> for Persistent<'_, T> {
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Runtime<C: ArrayLength<u8>> {
pub struct Runtime<const C: usize> {
// aid: Option<
// consecutive_pin_mismatches: u8,
pub global_security_status: GlobalSecurityStatus,
pub currently_selected_application: SelectableAid,
// pub currently_selected_application: SelectableAid,
pub app_security_status: AppSecurityStatus,
pub command_cache: Option<CommandCache>,
pub chained_command: Option<iso7816::Command<C>>,
}
pub trait Aid {
const AID: &'static [u8];
const RIGHT_TRUNCATED_LENGTH: usize;
// pub trait Aid {
// const AID: &'static [u8];
// const RIGHT_TRUNCATED_LENGTH: usize;
fn len() -> usize {
Self::AID.len()
}
// fn len() -> usize {
// Self::AID.len()
// }
fn full() -> &'static [u8] {
Self::AID
}
// fn full() -> &'static [u8] {
// Self::AID
// }
fn right_truncated() -> &'static [u8] {
&Self::AID[..Self::RIGHT_TRUNCATED_LENGTH]
}
// fn right_truncated() -> &'static [u8] {
// &Self::AID[..Self::RIGHT_TRUNCATED_LENGTH]
// }
fn pix() -> &'static [u8] {
&Self::AID[5..]
}
// fn pix() -> &'static [u8] {
// &Self::AID[5..]
// }
fn rid() -> &'static [u8] {
&Self::AID[..5]
}
}
// fn rid() -> &'static [u8] {
// &Self::AID[..5]
// }
// }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum SelectableAid {
Piv(PivAid),
YubicoOtp(YubicoOtpAid),
}
// #[derive(Copy, Clone, Debug, Eq, PartialEq)]
// pub enum SelectableAid {
// Piv(PivAid),
// YubicoOtp(YubicoOtpAid),
// }
impl Default for SelectableAid {
fn default() -> Self {
Self::Piv(Default::default())
}
}
// impl Default for SelectableAid {
// fn default() -> Self {
// Self::Piv(Default::default())
// }
// }
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct PivAid {}
// #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
// pub struct PivAid {}
impl Aid for PivAid {
const AID: &'static [u8] = &PIV_AID;
const RIGHT_TRUNCATED_LENGTH: usize = 9;
}
// impl Aid for PivAid {
// const AID: &'static [u8] = &PIV_AID;
// const RIGHT_TRUNCATED_LENGTH: usize = 9;
// }
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct YubicoOtpAid {}
// #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
// pub struct YubicoOtpAid {}
impl Aid for YubicoOtpAid {
const AID: &'static [u8] = &YUBICO_OTP_AID;
const RIGHT_TRUNCATED_LENGTH: usize = 8;
}
// impl Aid for YubicoOtpAid {
// const AID: &'static [u8] = &YUBICO_OTP_AID;
// const RIGHT_TRUNCATED_LENGTH: usize = 8;
// }
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct GlobalSecurityStatus {
+4 -1
View File
@@ -17,6 +17,9 @@ fn gen_keypair() {
// without PIN, no key generation
setup::piv(|piv| {
assert_eq!(Err(SecurityStatusNotSatisfied), piv.respond(&cmd));
// not currently implemented
//
// let mut response = iso7816::Data::<16>::default();
// assert_eq!(Err(SecurityStatusNotSatisfied), piv.respond(&cmd, &mut response));
});
}
+6 -4
View File
@@ -11,12 +11,14 @@ fn get_data() {
// let cmd = cmd!("00 f8 00 00");
// // without PIN, no key generation
setup::piv(|piv| {
// ykGetSerial
// println!("{}", hex_str!(&piv.respond(&cmd!("00 f8 00 00")).unwrap()));
// panic!();
piv.respond(&cmd!("00 f8 00 00")).unwrap();
// assert_eq!([].as_ref(), piv.respond(&cmd!("00 f8 00 00")).unwrap());
// ykGetVersion
piv.respond(&cmd!("00 fd 00 00")).unwrap();
// let mut response = iso7816::Data::<16>::default();
// piv.respond(&cmd!("00 f8 00 00"), &mut response).unwrap();
// // assert_eq!([].as_ref(), piv.respond(&cmd!("00 f8 00 00")).unwrap());
// // ykGetVersion
// piv.respond(&cmd!("00 fd 00 00"), &mut response).unwrap();
});
}
+4 -3
View File
@@ -18,8 +18,9 @@ mod setup;
fn put_data() {
setup::piv(|piv| {
let _response = piv.respond(&cmd!(
"00 DB 3F FF 23 5C 03 5F C1 09 53 1C 88 1A 89 18 AA 81 D5 48 A5 EC 26 01 60 BA 06 F6 EC 3B B6 05 00 2E B6 3D 4B 28 7F 86"
)).unwrap();
// let mut response = iso7816::Data::<16>::default();
// piv.respond(&cmd!(
// "00 DB 3F FF 23 5C 03 5F C1 09 53 1C 88 1A 89 18 AA 81 D5 48 A5 EC 26 01 60 BA 06 F6 EC 3B B6 05 00 2E B6 3D 4B 28 7F 86"
// ), &mut response).unwrap();
});
}
+6 -4
View File
@@ -4,12 +4,15 @@ trussed::platform!(Platform,
UI: ui::UserInterface,
);
const COMMAND_SIZE: usize = 3072;
#[macro_export]
macro_rules! cmd {
($tt:tt) => { iso7816::Command::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>>>;
pub type Piv<'service> = piv_authenticator::Authenticator<
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 _;
@@ -52,8 +55,7 @@ pub mod ui {
}
pub mod store {
pub use heapless::consts;
use littlefs2::{const_ram_storage, fs::{Allocation, Filesystem}};
use littlefs2::{const_ram_storage, consts, fs::{Allocation, Filesystem}};
use trussed::types::{LfsResult, LfsStorage};
const_ram_storage!(InternalStorage, 8192);