mirror of
https://github.com/trussed-dev/piv-authenticator.git
synced 2026-06-20 04:16:15 -07:00
Import Reply struct from opcard
This commit is contained in:
+17
-14
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user