Import Reply struct from opcard

This commit is contained in:
Sosthène Guédon
2022-12-16 11:32:44 +01:00
parent 6faea4b982
commit bd6b2e6f32
2 changed files with 151 additions and 14 deletions
+17 -14
View File
@@ -21,6 +21,7 @@ pub mod derp;
#[cfg(feature = "apdu-dispatch")]
mod dispatch;
pub mod piv_types;
mod reply;
pub mod state;
pub use piv_types::{AsymmetricAlgorithms, Pin, Puk};
@@ -39,6 +40,7 @@ use trussed::{client, syscall, try_syscall};
use constants::*;
pub type Result = iso7816::Result<()>;
use reply::Reply;
use state::{AdministrationAlgorithm, CommandCache, LoadedState, State, TouchPolicy};
use crate::piv_types::DynamicAuthenticationTemplate;
@@ -90,7 +92,7 @@ where
// The way apdu-dispatch currently works, this would deselect, resetting security indicators.
pub fn deselect(&mut self) {}
pub fn select<const R: usize>(&mut self, reply: &mut Data<R>) -> Result {
pub fn select<const R: usize>(&mut self, mut reply: Reply<'_, R>) -> Result {
use piv_types::Algorithms::*;
info!("selecting PIV maybe");
@@ -100,7 +102,7 @@ where
.with_supported_cryptographic_algorithms(&[Tdes, Aes256, P256, Ed25519, X25519]);
application_property_template
.encode_to_heapless_vec(reply)
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning: {:02X?}", reply);
Ok(())
@@ -114,6 +116,7 @@ where
info!("PIV responding to {:?}", command);
let parsed_command: Command = command.try_into()?;
info!("parsed: {:?}", &parsed_command);
let reply = Reply(reply);
match parsed_command {
Command::Verify(verify) => self.load()?.verify(verify),
@@ -140,7 +143,7 @@ where
fn get_data<const R: usize>(
&mut self,
container: container::Container,
reply: &mut Data<R>,
mut reply: Reply<'_, R>,
) -> Result {
// TODO: check security status, else return Status::SecurityStatusNotSatisfied
@@ -162,7 +165,7 @@ where
// '5FC1 07' (351B)
Container::CardCapabilityContainer => {
piv_types::CardCapabilityContainer::default()
.encode_to_heapless_vec(reply)
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning CCC {:02X?}", reply);
}
@@ -172,7 +175,7 @@ where
let guid = self.state.persistent(&mut self.trussed)?.guid();
piv_types::CardHolderUniqueIdentifier::default()
.with_guid(guid)
.encode_to_heapless_vec(reply)
.encode_to_heapless_vec(*reply)
.unwrap();
info!("returning CHUID {:02X?}", reply);
}
@@ -218,7 +221,7 @@ where
&mut self,
data: &[u8],
instruction: YubicoPivExtension,
reply: &mut Data<R>,
mut reply: Reply<'_, R>,
) -> Result {
info!("yubico extension: {:?}", &instruction);
match instruction {
@@ -283,7 +286,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
data: &[u8],
_touch_policy: TouchPolicy,
_reply: &mut Data<R>,
_reply: Reply<'_, R>,
) -> Result {
// cmd := apdu{
// instruction: insSetMGMKey,
@@ -475,7 +478,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
auth: GeneralAuthenticate,
data: &[u8],
reply: &mut Data<R>,
reply: Reply<'_, R>,
) -> Result {
// For "SSH", we need implement A.4.2 in SP-800-73-4 Part 2, ECDSA signatures
//
@@ -523,7 +526,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
auth: GeneralAuthenticate,
data: derp::Input<'_>,
_reply: &mut Data<R>,
_reply: Reply<'_, R>,
) -> Result {
info!("Request for response");
let alg = self.state.persistent.keys.administration.alg;
@@ -565,7 +568,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
_auth: GeneralAuthenticate,
_data: derp::Input<'_>,
_reply: &mut Data<R>,
_reply: Reply<'_, R>,
) -> Result {
info!("Request for exponentiation");
todo!()
@@ -575,7 +578,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
auth: GeneralAuthenticate,
data: derp::Input<'_>,
reply: &mut Data<R>,
mut reply: Reply<'_, R>,
) -> Result {
let alg = self.state.persistent.keys.administration.alg;
if !data.is_empty() {
@@ -592,7 +595,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
Bytes::from_slice(&challenge).unwrap(),
));
let resp = DynamicAuthenticationTemplate::with_challenge(&challenge);
resp.encode_to_heapless_vec(reply)
resp.encode_to_heapless_vec(*reply)
.map_err(|_err| {
error!("Failed to encode challenge: {_err:?}");
Status::UnspecifiedNonpersistentExecutionError
@@ -604,7 +607,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
_auth: GeneralAuthenticate,
_data: derp::Input<'_>,
_reply: &mut Data<R>,
_reply: Reply<'_, R>,
) -> Result {
info!("Request for witness");
todo!()
@@ -614,7 +617,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
&mut self,
reference: AsymmetricKeyReference,
data: &[u8],
reply: &mut Data<R>,
reply: Reply<'_, R>,
) -> Result {
if !self
.state
+134
View File
@@ -0,0 +1,134 @@
// Copyright (C) 2022 Nitrokey GmbH
// SPDX-License-Identifier: LGPL-3.0-only
use iso7816::Status;
use core::ops::{Deref, DerefMut};
#[derive(Debug)]
pub struct Reply<'v, const R: usize>(pub &'v mut heapless::Vec<u8, R>);
impl<'v, const R: usize> Deref for Reply<'v, R> {
type Target = &'v mut heapless::Vec<u8, R>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'v, const R: usize> DerefMut for Reply<'v, R> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'v, const R: usize> Reply<'v, R> {
/// Extend the reply and return an error otherwise
/// The MoreAvailable and GET RESPONSE mechanisms are handled by adpu_dispatch
///
/// Named expand and not extend to avoid conflicts with Deref
pub fn expand(&mut self, data: &[u8]) -> Result<(), Status> {
self.0.extend_from_slice(data).map_err(|_| {
error!("Buffer full");
Status::NotEnoughMemory
})
}
fn serialize_len(len: usize) -> Result<heapless::Vec<u8, 3>, Status> {
let mut buf = heapless::Vec::new();
if let Ok(len) = u8::try_from(len) {
if len <= 0x7f {
buf.extend_from_slice(&[len]).ok();
} else {
buf.extend_from_slice(&[0x81, len]).ok();
}
} else if let Ok(len) = u16::try_from(len) {
let arr = len.to_be_bytes();
buf.extend_from_slice(&[0x82, arr[0], arr[1]]).ok();
} else {
error!("Length too long to be encoded");
return Err(Status::UnspecifiedNonpersistentExecutionError);
}
Ok(buf)
}
/// Prepend the length to some data.
///
/// Input:
/// AAAAAAAAAABBBBBBB
/// ↑
/// offset
///
/// Output:
///
/// AAAAAAAAAA 7 BBBBBBB
/// (There are seven Bs, the length is encoded as specified in § 4.4.4)
pub fn prepend_len(&mut self, offset: usize) -> Result<(), Status> {
if self.len() < offset {
error!("`prepend_len` called with offset lower than buffer length");
return Err(Status::UnspecifiedNonpersistentExecutionError);
}
let len = self.len() - offset;
let encoded = Self::serialize_len(len)?;
self.extend_from_slice(&encoded).map_err(|_| {
error!("Buffer full");
Status::UnspecifiedNonpersistentExecutionError
})?;
self[offset..].rotate_right(encoded.len());
Ok(())
}
pub fn append_len(&mut self, len: usize) -> Result<(), Status> {
let encoded = Self::serialize_len(len)?;
self.extend_from_slice(&encoded).map_err(|_| {
error!("Buffer full");
Status::UnspecifiedNonpersistentExecutionError
})
}
pub fn lend(&mut self) -> Reply<'_, R> {
Reply(self.0)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
#[test]
fn prep_length() {
let mut tmp = heapless::Vec::<u8, 1000>::new();
let mut buf = Reply(&mut tmp);
let offset = buf.len();
buf.extend_from_slice(&[0; 0]).unwrap();
buf.prepend_len(offset).unwrap();
assert_eq!(&buf[offset..], [0]);
let offset = buf.len();
buf.extend_from_slice(&[0; 20]).unwrap();
buf.prepend_len(offset).unwrap();
let mut expected = vec![20];
expected.extend_from_slice(&[0; 20]);
assert_eq!(&buf[offset..], expected,);
let offset = buf.len();
buf.extend_from_slice(&[1; 127]).unwrap();
buf.prepend_len(offset).unwrap();
let mut expected = vec![127];
expected.extend_from_slice(&[1; 127]);
assert_eq!(&buf[offset..], expected);
let offset = buf.len();
buf.extend_from_slice(&[2; 128]).unwrap();
buf.prepend_len(offset).unwrap();
let mut expected = vec![0x81, 128];
expected.extend_from_slice(&[2; 128]);
assert_eq!(&buf[offset..], expected);
let offset = buf.len();
buf.extend_from_slice(&[3; 256]).unwrap();
buf.prepend_len(offset).unwrap();
let mut expected = vec![0x82, 0x01, 0x00];
expected.extend_from_slice(&[3; 256]);
assert_eq!(&buf[offset..], expected);
}
}