blob: a6d2d572f13947b49e14e2f7c35c9a32a8f40211 [file] [log] [blame]
#![no_std]
#![feature(alloc_error_handler)]
extern crate alloc;
use core::alloc::Layout;
use core::cell::Cell;
use core::fmt::{Debug, Error, Formatter};
use core::time::Duration;
use ctap2_authenticator::credentials::{RpCredential, UserCredential};
use ctap2_authenticator::usbhid::{
CtapHidCapabilities, CtapHidPlatform, KeepaliveResponse, TransactionProcessor,
};
use ctap2_authenticator::Authenticator;
use ctap2_authenticator::{
AuthenticatorPlatform, CredentialDescriptorList, CtapOptions, PublicKey, Signature,
};
use libtock::ctap::{CtapRecvBuffer, CtapSendBuffer};
use libtock::println;
use libtock::result::TockResult;
use libtock::syscalls;
/// This is the provided implementation of `CtapHidPlatform` to be used in the `UsbContext`
pub(crate) struct UsbKeyHidPlatform {}
impl UsbKeyHidPlatform {
pub fn new() -> Self {
Self {}
}
}
impl CtapHidPlatform for UsbKeyHidPlatform {
// Should be kept in sync with the Crates version if possible
const MAJOR_VERSION: u8 = 0;
const MINOR_VERSION: u8 = 0;
const BUILD_VERSION: u8 = 0;
const CAPABILITIES: CtapHidCapabilities = CtapHidCapabilities {
wink: true,
cbor: true,
msg: false,
};
fn wink(&mut self) {}
fn cancel(&mut self) {
unimplemented!()
}
fn keepalive_needed(&mut self) -> KeepaliveResponse {
unimplemented!()
}
fn start_timer(&mut self) {
unimplemented!()
}
fn has_timed_out(&mut self) -> bool {
unimplemented!()
}
}
#[derive(Clone, Copy)]
pub struct HmacKeyCredential(pub(crate) [u8; 40]);
impl AsRef<[u8]> for HmacKeyCredential {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Debug for HmacKeyCredential {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(
f,
"HmacKeyCredential {{ mac: {:?}, nonce: {:?} }}",
&self.0[..32],
&self.0[32..]
)
}
}
impl PartialEq for HmacKeyCredential {
fn eq(&self, other: &Self) -> bool {
self.0[..] == other.0[..]
}
}
impl Eq for HmacKeyCredential {}
const ITERATOR_MAX_LENGTH: usize = 8;
pub struct HmacCredentialQueue {
index: usize,
length: usize,
list: [Option<(HmacKeyCredential, u32)>; ITERATOR_MAX_LENGTH],
}
impl HmacCredentialQueue {
pub(crate) fn new() -> Self {
Self {
index: 0,
length: 0,
list: [None; ITERATOR_MAX_LENGTH],
}
}
pub(crate) fn len(&self) -> usize {
self.length
}
}
impl Iterator for HmacCredentialQueue {
type Item = (HmacKeyCredential, u32);
fn next(&mut self) -> Option<Self::Item> {
if self.list[self.index].is_some() {
self.index += 1;
self.list[self.index - 1]
} else {
None
}
}
}
#[derive(Debug)]
pub(crate) struct CtapPlatform;
impl AuthenticatorPlatform for CtapPlatform {
const AAGUID: [u8; 16] = [
0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc,
0x7d,
];
const CERTIFICATE: Option<&'static [u8]> = None;
const MAX_MSG_LENGTH: u16 = 7609;
const SUPPORTED_OPTIONS: CtapOptions = CtapOptions {
plat: None,
rk: Some(true),
client_pin: None,
up: Some(true),
uv: Some(false),
};
type CredentialId = HmacKeyCredential;
type PublicKeyBuffer = [u8; 32];
type SignatureBuffer = [u8; 32];
type CredentialIterator = HmacCredentialQueue;
fn reset(&mut self) -> Result<(), ()> {
unimplemented!()
}
fn check_exclude_list(&mut self, _rp_id: &str, _list: CredentialDescriptorList) -> bool {
unimplemented!()
}
fn locate_credentials(
&mut self,
_rp_id: &str,
list: Option<CredentialDescriptorList>,
) -> (u16, Self::CredentialIterator) {
match list {
None => (0, HmacCredentialQueue::new()),
Some(_list) => {
let result = HmacCredentialQueue::new();
// TODO Add location
(result.len() as u16, result)
}
}
}
fn create_credential(
&mut self,
_rp: RpCredential<&[u8], &str>,
_user: UserCredential<&[u8], &str>,
) -> (Self::CredentialId, PublicKey<Self::PublicKeyBuffer>, u32) {
unimplemented!()
}
fn attest(
&mut self,
_id: &Self::CredentialId,
_data: &[u8],
) -> Option<Signature<Self::SignatureBuffer>> {
unimplemented!();
}
fn sign(
&mut self,
_id: &Self::CredentialId,
_data: &[u8],
) -> Option<Signature<Self::SignatureBuffer>> {
unimplemented!();
}
fn start_timeout(&mut self) {
unimplemented!()
}
fn has_timed_out(&mut self, _time: Duration) -> bool {
unimplemented!()
}
}
#[alloc_error_handler]
unsafe fn alloc_error_handler(_: Layout) -> ! {
println!("alloc_error_handler called");
loop {
syscalls::raw::yieldk();
}
}
#[libtock::main]
async fn main() -> TockResult<()> {
let mut tp: Cell<TransactionProcessor<&'static mut [u8], UsbKeyHidPlatform>>;
let mut temp_buffer = [0; libtock::ctap::RECV_BUFFER_SIZE];
let mut drivers = libtock::retrieve_drivers()?;
drivers.console.create_console();
println!("Starting CTAP feature example");
let ctap_driver = drivers.ctap.init_driver()?;
let mut recv_buffer = CtapRecvBuffer::default();
let recv_buffer = ctap_driver.init_recv_buffer(&mut recv_buffer)?;
let mut send_buffer = CtapSendBuffer::default();
let mut send_buffer = ctap_driver.init_send_buffer(&mut send_buffer)?;
static mut BUFFER: &'static mut [u8] = &mut [0; 2048];
unsafe {
tp = Cell::new(TransactionProcessor::new(BUFFER, UsbKeyHidPlatform::new()));
}
let mut authenticator = Authenticator::create(CtapPlatform);
let mut callback = |sent, _| {
let mut looping = true;
recv_buffer.read_bytes(&mut temp_buffer[..]);
let temp_tp = tp.get_mut();
let mut poll_msg = if sent == 0 { Some(&temp_buffer) } else { None };
while looping {
looping = false;
let (maybe_request, maybe_data) = temp_tp.poll(poll_msg);
if let Some(request) = maybe_request {
let response = authenticator.process(request);
temp_tp.response(response);
looping = true;
}
if let Some(mut data) = maybe_data {
send_buffer.write_bytes(&mut data[0..]);
let _ = ctap_driver.send_data();
}
poll_msg = None;
}
let _ = ctap_driver.allow_receive();
};
let _subscription = ctap_driver.subscribe(&mut callback)?;
ctap_driver.allow_receive()?;
loop {
unsafe { syscalls::raw::yieldk() };
}
}