Implement request for challenge

This commit is contained in:
Sosthène Guédon
2022-11-10 14:13:18 +01:00
parent 5473cccd24
commit 3ab233b8a5
4 changed files with 72 additions and 19 deletions
+4
View File
@@ -5,6 +5,8 @@
use hex_literal::hex;
use crate::state::ManagementAlgorithm;
pub const RID_LENGTH: usize = 5;
// top nibble of first byte is "category", here "A" = International
@@ -269,6 +271,8 @@ pub const YUBICO_DEFAULT_MANAGEMENT_KEY: &[u8; 24] = &hex!(
"
);
pub const YUBICO_DEFAULT_MANAGEMENT_KEY_ALG: ManagementAlgorithm = ManagementAlgorithm::Tdes;
// stolen from le yubico
pub const DISCOVERY_OBJECT: &[u8; 20] =
b"~\x12O\x0b\xa0\x00\x00\x03\x08\x00\x00\x10\x00\x01\x00_/\x02@\x00";
+2
View File
@@ -60,6 +60,8 @@ macro_rules! enum_subset {
}
}
pub(crate) use enum_subset;
pub struct Tag<'a>(&'a [u8]);
impl<'a> Tag<'a> {
pub fn new(slice: &'a [u8]) -> Self {
+30 -5
View File
@@ -30,6 +30,7 @@ pub mod vpicc;
use core::convert::TryInto;
use flexiber::EncodableHeapless;
use heapless_bytes::Bytes;
use iso7816::{Data, Status};
use trussed::client;
use trussed::{syscall, try_syscall};
@@ -37,7 +38,9 @@ use trussed::{syscall, try_syscall};
use constants::*;
pub type Result = iso7816::Result<()>;
use state::{LoadedState, State};
use state::{CommandCache, LoadedState, State};
use crate::piv_types::DynamicAuthenticationTemplate;
/// PIV authenticator Trussed app.
///
@@ -496,11 +499,33 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T>
pub fn request_for_challenge<const R: usize>(
&mut self,
_auth: GeneralAuthenticate,
_data: derp::Input<'_>,
_reply: &mut Data<R>,
data: derp::Input<'_>,
reply: &mut Data<R>,
) -> Result {
info!("Request for challenge");
todo!()
if data.len() != 0 {
warn!("Request for challenge with non empty data");
return Err(Status::IncorrectDataParameter);
}
info!("Request for challenge ");
let challenge = syscall!(self.trussed.random_bytes(
self.state
.persistent
.keys
.management_key
.alg
.challenge_length()
))
.bytes;
self.state.runtime.command_cache = Some(CommandCache::AuthenticateChallenge(
Bytes::from_slice(&challenge).unwrap(),
));
let resp = DynamicAuthenticationTemplate::with_challenge(&challenge);
resp.encode_to_heapless_vec(reply)
.map_err(|_err| {
error!("Failed to encode challenge: {_err:?}");
Status::UnspecifiedNonpersistentExecutionError
})
.map(drop)
}
pub fn request_for_witness<const R: usize>(
+36 -14
View File
@@ -13,6 +13,7 @@ use trussed::{
};
use crate::constants::*;
use crate::piv_types::Algorithms;
use crate::{Pin, Puk};
@@ -133,13 +134,36 @@ impl SlotName {
}
}
crate::container::enum_subset! {
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub enum ManagementAlgorithm: Algorithms {
Tdes,
Aes256
}
}
impl ManagementAlgorithm {
pub fn challenge_length(self) -> usize {
match self {
Self::Tdes => 8,
Self::Aes256 => 16,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct ManagementKey {
pub id: KeyId,
pub alg: ManagementAlgorithm,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct Keys {
// 9a "PIV Authentication Key" (YK: PIV Authentication)
#[serde(skip_serializing_if = "Option::is_none")]
pub authentication_key: Option<KeyId>,
// 9b "PIV Card Application Administration Key" (YK: PIV Management)
pub management_key: KeyId,
pub management_key: ManagementKey,
// 9c "Digital Signature Key" (YK: Digital Signature)
#[serde(skip_serializing_if = "Option::is_none")]
pub signature_key: Option<KeyId>,
@@ -295,17 +319,12 @@ pub struct AppSecurityStatus {
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CommandCache {
GetData(GetData),
AuthenticateManagement(AuthenticateManagement),
AuthenticateChallenge(Bytes<16>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GetData {}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AuthenticateManagement {
pub challenge: [u8; 8],
}
impl Persistent {
pub const PIN_RETRIES_DEFAULT: u8 = 3;
// hmm...!
@@ -424,19 +443,22 @@ impl Persistent {
syscall!(client
.unsafe_inject_shared_key(management_key, trussed::types::Location::Internal,))
.key;
let old_management_key = self.keys.management_key;
self.keys.management_key = new_management_key;
let old_management_key = self.keys.management_key.id;
self.keys.management_key.id = new_management_key;
self.save(client);
syscall!(client.delete(old_management_key));
}
pub fn initialize(client: &mut impl trussed::Client) -> Self {
info!("initializing PIV state");
let management_key = syscall!(client.unsafe_inject_shared_key(
YUBICO_DEFAULT_MANAGEMENT_KEY,
trussed::types::Location::Internal,
))
.key;
let management_key = ManagementKey {
id: syscall!(client.unsafe_inject_shared_key(
YUBICO_DEFAULT_MANAGEMENT_KEY,
trussed::types::Location::Internal,
))
.key,
alg: YUBICO_DEFAULT_MANAGEMENT_KEY_ALG,
};
let mut guid: [u8; 16] = syscall!(client.random_bytes(16))
.bytes