Add write to the environment

This commit is contained in:
Julien Cretin
2022-03-04 15:09:44 +01:00
parent dcc053c6cb
commit f09e5a77e8
6 changed files with 152 additions and 88 deletions

View File

@@ -26,10 +26,6 @@ use crate::env::Env;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
use arrayref::{array_ref, array_refs}; use arrayref::{array_ref, array_refs};
#[cfg(feature = "debug_ctap")]
use core::fmt::Write;
#[cfg(feature = "debug_ctap")]
use libtock_drivers::console::Console;
use libtock_drivers::timer::{ClockValue, Duration, Timestamp}; use libtock_drivers::timer::{ClockValue, Duration, Timestamp};
// CTAP specification (version 20190130) section 8.1 // CTAP specification (version 20190130) section 8.1
@@ -159,14 +155,12 @@ impl CtapHid {
.parse_packet(packet, Timestamp::<isize>::from_clock_value(clock_value)) .parse_packet(packet, Timestamp::<isize>::from_clock_value(clock_value))
{ {
Ok(Some(message)) => { Ok(Some(message)) => {
#[cfg(feature = "debug_ctap")] debug_ctap!(env, "Received message: {:02x?}", message);
writeln!(&mut Console::new(), "Received message: {:02x?}", message).unwrap();
let cid = message.cid; let cid = message.cid;
if !self.has_valid_channel(&message) { if !self.has_valid_channel(&message) {
#[cfg(feature = "debug_ctap")] debug_ctap!(env, "Invalid channel: {:02x?}", cid);
writeln!(&mut Console::new(), "Invalid channel: {:02x?}", cid).unwrap(); return CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_CHANNEL);
return CtapHid::error_message(cid, CtapHid::ERR_INVALID_CHANNEL);
} }
// If another command arrives, stop winking to prevent accidential button touches. // If another command arrives, stop winking to prevent accidential button touches.
self.wink_permission = TimedPermission::waiting(); self.wink_permission = TimedPermission::waiting();
@@ -176,7 +170,7 @@ impl CtapHid {
CtapHid::COMMAND_MSG => { CtapHid::COMMAND_MSG => {
// If we don't have CTAP1 backward compatibilty, this command is invalid. // If we don't have CTAP1 backward compatibilty, this command is invalid.
#[cfg(not(feature = "with_ctap1"))] #[cfg(not(feature = "with_ctap1"))]
return CtapHid::error_message(cid, CtapHid::ERR_INVALID_CMD); return CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_CMD);
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
match ctap1::Ctap1Command::process_command( match ctap1::Ctap1Command::process_command(
@@ -185,9 +179,9 @@ impl CtapHid {
ctap_state, ctap_state,
clock_value, clock_value,
) { ) {
Ok(payload) => CtapHid::ctap1_success_message(cid, &payload), Ok(payload) => CtapHid::ctap1_success_message(env, cid, &payload),
Err(ctap1_status_code) => { Err(ctap1_status_code) => {
CtapHid::ctap1_error_message(cid, ctap1_status_code) CtapHid::ctap1_error_message(env, cid, ctap1_status_code)
} }
} }
} }
@@ -199,11 +193,14 @@ impl CtapHid {
// TODO: Send keep-alive packets in the meantime. // TODO: Send keep-alive packets in the meantime.
let response = let response =
ctap_state.process_command(env, &message.payload, cid, clock_value); ctap_state.process_command(env, &message.payload, cid, clock_value);
if let Some(iterator) = CtapHid::split_message(Message { if let Some(iterator) = CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_CBOR, Message {
payload: response, cid,
}) { cmd: CtapHid::COMMAND_CBOR,
payload: response,
},
) {
iterator iterator
} else { } else {
// Handle the case of a payload > 7609 bytes. // Handle the case of a payload > 7609 bytes.
@@ -213,20 +210,23 @@ impl CtapHid {
// //
// The error payload that we send instead is 1 <= 7609 bytes, so it is // The error payload that we send instead is 1 <= 7609 bytes, so it is
// safe to unwrap() the result. // safe to unwrap() the result.
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_CBOR, Message {
payload: vec![ cid,
Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR as u8, cmd: CtapHid::COMMAND_CBOR,
], payload: vec![
}) Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR as u8,
],
},
)
.unwrap() .unwrap()
} }
} }
// CTAP specification (version 20190130) section 8.1.9.1.3 // CTAP specification (version 20190130) section 8.1.9.1.3
CtapHid::COMMAND_INIT => { CtapHid::COMMAND_INIT => {
if message.payload.len() != 8 { if message.payload.len() != 8 {
return CtapHid::error_message(cid, CtapHid::ERR_INVALID_LEN); return CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_LEN);
} }
let new_cid = if cid == CtapHid::CHANNEL_BROADCAST { let new_cid = if cid == CtapHid::CHANNEL_BROADCAST {
@@ -248,11 +248,14 @@ impl CtapHid {
payload[16] = CtapHid::CAPABILITIES; payload[16] = CtapHid::CAPABILITIES;
// This unwrap is safe because the payload length is 17 <= 7609 bytes. // This unwrap is safe because the payload length is 17 <= 7609 bytes.
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_INIT, Message {
payload, cid,
}) cmd: CtapHid::COMMAND_INIT,
payload,
},
)
.unwrap() .unwrap()
} }
// CTAP specification (version 20190130) section 8.1.9.1.4 // CTAP specification (version 20190130) section 8.1.9.1.4
@@ -260,7 +263,7 @@ impl CtapHid {
// Pong the same message. // Pong the same message.
// This unwrap is safe because if we could parse the incoming message, it's // This unwrap is safe because if we could parse the incoming message, it's
// payload length must be <= 7609 bytes. // payload length must be <= 7609 bytes.
CtapHid::split_message(message).unwrap() CtapHid::split_message(env, message).unwrap()
} }
// CTAP specification (version 20190130) section 8.1.9.1.5 // CTAP specification (version 20190130) section 8.1.9.1.5
CtapHid::COMMAND_CANCEL => { CtapHid::COMMAND_CANCEL => {
@@ -272,22 +275,25 @@ impl CtapHid {
// CTAP specification (version 20190130) section 8.1.9.2.1 // CTAP specification (version 20190130) section 8.1.9.2.1
CtapHid::COMMAND_WINK => { CtapHid::COMMAND_WINK => {
if !message.payload.is_empty() { if !message.payload.is_empty() {
return CtapHid::error_message(cid, CtapHid::ERR_INVALID_LEN); return CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_LEN);
} }
self.wink_permission = self.wink_permission =
TimedPermission::granted(clock_value, CtapHid::WINK_TIMEOUT_DURATION); TimedPermission::granted(clock_value, CtapHid::WINK_TIMEOUT_DURATION);
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_WINK, Message {
payload: vec![], cid,
}) cmd: CtapHid::COMMAND_WINK,
payload: vec![],
},
)
.unwrap() .unwrap()
} }
// CTAP specification (version 20190130) section 8.1.9.2.2 // CTAP specification (version 20190130) section 8.1.9.2.2
// TODO: implement LOCK // TODO: implement LOCK
_ => { _ => {
// Unknown or unsupported command. // Unknown or unsupported command.
CtapHid::error_message(cid, CtapHid::ERR_INVALID_CMD) CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_CMD)
} }
} }
} }
@@ -299,18 +305,18 @@ impl CtapHid {
if !self.is_allocated_channel(cid) if !self.is_allocated_channel(cid)
&& error != receive::Error::UnexpectedContinuation && error != receive::Error::UnexpectedContinuation
{ {
CtapHid::error_message(cid, CtapHid::ERR_INVALID_CHANNEL) CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_CHANNEL)
} else { } else {
match error { match error {
receive::Error::UnexpectedChannel => { receive::Error::UnexpectedChannel => {
CtapHid::error_message(cid, CtapHid::ERR_CHANNEL_BUSY) CtapHid::error_message(env, cid, CtapHid::ERR_CHANNEL_BUSY)
} }
receive::Error::UnexpectedInit => { receive::Error::UnexpectedInit => {
// TODO: Should we send another error code in this case? // TODO: Should we send another error code in this case?
// Technically, we were expecting a sequence number and got another // Technically, we were expecting a sequence number and got another
// byte, although the command/seqnum bit has higher-level semantics // byte, although the command/seqnum bit has higher-level semantics
// than sequence numbers. // than sequence numbers.
CtapHid::error_message(cid, CtapHid::ERR_INVALID_SEQ) CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_SEQ)
} }
receive::Error::UnexpectedContinuation => { receive::Error::UnexpectedContinuation => {
// CTAP specification (version 20190130) section 8.1.5.4 // CTAP specification (version 20190130) section 8.1.5.4
@@ -318,13 +324,13 @@ impl CtapHid {
HidPacketIterator::none() HidPacketIterator::none()
} }
receive::Error::UnexpectedSeq => { receive::Error::UnexpectedSeq => {
CtapHid::error_message(cid, CtapHid::ERR_INVALID_SEQ) CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_SEQ)
} }
receive::Error::UnexpectedLen => { receive::Error::UnexpectedLen => {
CtapHid::error_message(cid, CtapHid::ERR_INVALID_LEN) CtapHid::error_message(env, cid, CtapHid::ERR_INVALID_LEN)
} }
receive::Error::Timeout => { receive::Error::Timeout => {
CtapHid::error_message(cid, CtapHid::ERR_MSG_TIMEOUT) CtapHid::error_message(env, cid, CtapHid::ERR_MSG_TIMEOUT)
} }
} }
} }
@@ -345,13 +351,16 @@ impl CtapHid {
cid != CtapHid::CHANNEL_RESERVED && u32::from_be_bytes(cid) as usize <= self.allocated_cids cid != CtapHid::CHANNEL_RESERVED && u32::from_be_bytes(cid) as usize <= self.allocated_cids
} }
fn error_message(cid: ChannelID, error_code: u8) -> HidPacketIterator { fn error_message<E: Env>(env: &mut E, cid: ChannelID, error_code: u8) -> HidPacketIterator {
// This unwrap is safe because the payload length is 1 <= 7609 bytes. // This unwrap is safe because the payload length is 1 <= 7609 bytes.
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_ERROR, Message {
payload: vec![error_code], cid,
}) cmd: CtapHid::COMMAND_ERROR,
payload: vec![error_code],
},
)
.unwrap() .unwrap()
} }
@@ -379,23 +388,29 @@ impl CtapHid {
} }
} }
fn split_message(message: Message) -> Option<HidPacketIterator> { fn split_message<E: Env>(env: &mut E, message: Message) -> Option<HidPacketIterator> {
#[cfg(feature = "debug_ctap")] debug_ctap!(env, "Sending message: {:02x?}", message);
writeln!(&mut Console::new(), "Sending message: {:02x?}", message).unwrap();
HidPacketIterator::new(message) HidPacketIterator::new(message)
} }
pub fn keepalive(cid: ChannelID, status: KeepaliveStatus) -> HidPacketIterator { pub fn keepalive<E: Env>(
env: &mut E,
cid: ChannelID,
status: KeepaliveStatus,
) -> HidPacketIterator {
let status_code = match status { let status_code = match status {
KeepaliveStatus::Processing => 1, KeepaliveStatus::Processing => 1,
KeepaliveStatus::UpNeeded => 2, KeepaliveStatus::UpNeeded => 2,
}; };
// This unwrap is safe because the payload length is 1 <= 7609 bytes. // This unwrap is safe because the payload length is 1 <= 7609 bytes.
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_KEEPALIVE, Message {
payload: vec![status_code], cid,
}) cmd: CtapHid::COMMAND_KEEPALIVE,
payload: vec![status_code],
},
)
.unwrap() .unwrap()
} }
@@ -404,30 +419,41 @@ impl CtapHid {
} }
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
fn ctap1_error_message( fn ctap1_error_message<E: Env>(
env: &mut E,
cid: ChannelID, cid: ChannelID,
error_code: ctap1::Ctap1StatusCode, error_code: ctap1::Ctap1StatusCode,
) -> HidPacketIterator { ) -> HidPacketIterator {
// This unwrap is safe because the payload length is 2 <= 7609 bytes // This unwrap is safe because the payload length is 2 <= 7609 bytes
let code: u16 = error_code.into(); let code: u16 = error_code.into();
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_MSG, Message {
payload: code.to_be_bytes().to_vec(), cid,
}) cmd: CtapHid::COMMAND_MSG,
payload: code.to_be_bytes().to_vec(),
},
)
.unwrap() .unwrap()
} }
#[cfg(feature = "with_ctap1")] #[cfg(feature = "with_ctap1")]
fn ctap1_success_message(cid: ChannelID, payload: &[u8]) -> HidPacketIterator { fn ctap1_success_message<E: Env>(
env: &mut E,
cid: ChannelID,
payload: &[u8],
) -> HidPacketIterator {
let mut response = payload.to_vec(); let mut response = payload.to_vec();
let code: u16 = ctap1::Ctap1StatusCode::SW_SUCCESS.into(); let code: u16 = ctap1::Ctap1StatusCode::SW_SUCCESS.into();
response.extend_from_slice(&code.to_be_bytes()); response.extend_from_slice(&code.to_be_bytes());
CtapHid::split_message(Message { CtapHid::split_message(
cid, env,
cmd: CtapHid::COMMAND_MSG, Message {
payload: response, cid,
}) cmd: CtapHid::COMMAND_MSG,
payload: response,
},
)
.unwrap() .unwrap()
} }
} }

View File

@@ -74,15 +74,11 @@ use alloc::vec::Vec;
use arrayref::array_ref; use arrayref::array_ref;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom; use core::convert::TryFrom;
#[cfg(feature = "debug_ctap")]
use core::fmt::Write;
use crypto::ecdsa; use crypto::ecdsa;
use crypto::hmac::{hmac_256, verify_hmac_256}; use crypto::hmac::{hmac_256, verify_hmac_256};
use crypto::rng256::Rng256; use crypto::rng256::Rng256;
use crypto::sha256::Sha256; use crypto::sha256::Sha256;
use crypto::Hash256; use crypto::Hash256;
#[cfg(feature = "debug_ctap")]
use libtock_drivers::console::Console;
use libtock_drivers::timer::{ClockValue, Duration}; use libtock_drivers::timer::{ClockValue, Duration};
use sk_cbor as cbor; use sk_cbor as cbor;
use sk_cbor::cbor_map_options; use sk_cbor::cbor_map_options;
@@ -461,8 +457,7 @@ impl<E: Env> CtapState<E> {
now: ClockValue, now: ClockValue,
) -> Vec<u8> { ) -> Vec<u8> {
let cmd = Command::deserialize(command_cbor); let cmd = Command::deserialize(command_cbor);
#[cfg(feature = "debug_ctap")] debug_ctap!(env, "Received command: {:#?}", cmd);
writeln!(&mut Console::new(), "Received command: {:#?}", cmd).unwrap();
match cmd { match cmd {
Ok(command) => { Ok(command) => {
// Correct behavior between CTAP1 and CTAP2 isn't defined yet. Just a guess. // Correct behavior between CTAP1 and CTAP2 isn't defined yet. Just a guess.
@@ -536,8 +531,7 @@ impl<E: Env> CtapState<E> {
} }
Command::AuthenticatorVendorUpgradeInfo => self.process_vendor_upgrade_info(), Command::AuthenticatorVendorUpgradeInfo => self.process_vendor_upgrade_info(),
}; };
#[cfg(feature = "debug_ctap")] debug_ctap!(env, "Sending response: {:#?}", response);
writeln!(&mut Console::new(), "Sending response: {:#?}", response).unwrap();
match response { match response {
Ok(response_data) => { Ok(response_data) => {
let mut response_vec = vec![0x00]; let mut response_vec = vec![0x00];

11
src/env/mod.rs vendored
View File

@@ -13,7 +13,7 @@ pub trait UserPresence {
/// Blocks for user presence. /// Blocks for user presence.
/// ///
/// Returns an error in case of timeout or keepalive error. /// Returns an error in case of timeout or keepalive error.
fn check(&self, cid: ChannelID) -> Result<(), Ctap2StatusCode>; fn check(&mut self, cid: ChannelID) -> Result<(), Ctap2StatusCode>;
} }
/// Describes what CTAP needs to function. /// Describes what CTAP needs to function.
@@ -23,6 +23,7 @@ pub trait Env {
type Storage: Storage; type Storage: Storage;
type UpgradeStorage: UpgradeStorage; type UpgradeStorage: UpgradeStorage;
type FirmwareProtection: FirmwareProtection; type FirmwareProtection: FirmwareProtection;
type Write: core::fmt::Write;
fn rng(&mut self) -> &mut Self::Rng; fn rng(&mut self) -> &mut Self::Rng;
fn user_presence(&mut self) -> &mut Self::UserPresence; fn user_presence(&mut self) -> &mut Self::UserPresence;
@@ -38,4 +39,12 @@ pub trait Env {
fn upgrade_storage(&mut self) -> StorageResult<Self::UpgradeStorage>; fn upgrade_storage(&mut self) -> StorageResult<Self::UpgradeStorage>;
fn firmware_protection(&mut self) -> &mut Self::FirmwareProtection; fn firmware_protection(&mut self) -> &mut Self::FirmwareProtection;
/// Creates a write instance for debugging.
///
/// This API doesn't return a reference such that drop may flush. This matches the Tock
/// environment. Non-Tock embedded environments should use the defmt feature (to be implemented
/// using the defmt crate) and ignore this API. Non-embedded environments may either use this
/// API or use the log feature (to be implemented using the log crate).
fn write(&mut self) -> Self::Write;
} }

15
src/env/test/mod.rs vendored
View File

@@ -17,6 +17,14 @@ pub struct TestUserPresence {
check: Box<dyn Fn(ChannelID) -> Result<(), Ctap2StatusCode>>, check: Box<dyn Fn(ChannelID) -> Result<(), Ctap2StatusCode>>,
} }
pub struct TestWrite;
impl core::fmt::Write for TestWrite {
fn write_str(&mut self, _: &str) -> core::fmt::Result {
Ok(())
}
}
impl TestEnv { impl TestEnv {
pub fn new() -> Self { pub fn new() -> Self {
let rng = ThreadRng256 {}; let rng = ThreadRng256 {};
@@ -34,7 +42,7 @@ impl TestUserPresence {
} }
impl UserPresence for TestUserPresence { impl UserPresence for TestUserPresence {
fn check(&self, cid: ChannelID) -> Result<(), Ctap2StatusCode> { fn check(&mut self, cid: ChannelID) -> Result<(), Ctap2StatusCode> {
(self.check)(cid) (self.check)(cid)
} }
} }
@@ -51,6 +59,7 @@ impl Env for TestEnv {
type Storage = BufferStorage; type Storage = BufferStorage;
type UpgradeStorage = BufferUpgradeStorage; type UpgradeStorage = BufferUpgradeStorage;
type FirmwareProtection = Self; type FirmwareProtection = Self;
type Write = TestWrite;
fn rng(&mut self) -> &mut Self::Rng { fn rng(&mut self) -> &mut Self::Rng {
&mut self.rng &mut self.rng
@@ -82,4 +91,8 @@ impl Env for TestEnv {
fn firmware_protection(&mut self) -> &mut Self::FirmwareProtection { fn firmware_protection(&mut self) -> &mut Self::FirmwareProtection {
self self
} }
fn write(&mut self) -> Self::Write {
TestWrite
}
} }

19
src/env/tock/mod.rs vendored
View File

@@ -10,7 +10,6 @@ use core::sync::atomic::{AtomicBool, Ordering};
use crypto::rng256::TockRng256; use crypto::rng256::TockRng256;
use libtock_core::result::{CommandError, EALREADY}; use libtock_core::result::{CommandError, EALREADY};
use libtock_drivers::buttons::{self, ButtonState}; use libtock_drivers::buttons::{self, ButtonState};
#[cfg(feature = "debug_ctap")]
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
use libtock_drivers::result::{FlexUnwrap, TockError}; use libtock_drivers::result::{FlexUnwrap, TockError};
use libtock_drivers::timer::Duration; use libtock_drivers::timer::Duration;
@@ -58,8 +57,8 @@ pub unsafe fn steal_storage() -> StorageResult<SyscallStorage> {
} }
impl UserPresence for TockEnv { impl UserPresence for TockEnv {
fn check(&self, cid: ChannelID) -> Result<(), Ctap2StatusCode> { fn check(&mut self, cid: ChannelID) -> Result<(), Ctap2StatusCode> {
check_user_presence(cid) check_user_presence(self, cid)
} }
} }
@@ -82,6 +81,7 @@ impl Env for TockEnv {
type Storage = SyscallStorage; type Storage = SyscallStorage;
type UpgradeStorage = SyscallUpgradeStorage; type UpgradeStorage = SyscallUpgradeStorage;
type FirmwareProtection = Self; type FirmwareProtection = Self;
type Write = Console;
fn rng(&mut self) -> &mut Self::Rng { fn rng(&mut self) -> &mut Self::Rng {
&mut self.rng &mut self.rng
@@ -104,6 +104,10 @@ impl Env for TockEnv {
fn firmware_protection(&mut self) -> &mut Self::FirmwareProtection { fn firmware_protection(&mut self) -> &mut Self::FirmwareProtection {
self self
} }
fn write(&mut self) -> Self::Write {
Console::new()
}
} }
/// Asserts a boolean is false and sets it to true. /// Asserts a boolean is false and sets it to true.
@@ -114,10 +118,11 @@ fn assert_once(b: &mut bool) {
// Returns whether the keepalive was sent, or false if cancelled. // Returns whether the keepalive was sent, or false if cancelled.
fn send_keepalive_up_needed( fn send_keepalive_up_needed(
env: &mut TockEnv,
cid: ChannelID, cid: ChannelID,
timeout: Duration<isize>, timeout: Duration<isize>,
) -> Result<(), Ctap2StatusCode> { ) -> Result<(), Ctap2StatusCode> {
let keepalive_msg = CtapHid::keepalive(cid, KeepaliveStatus::UpNeeded); let keepalive_msg = CtapHid::keepalive(env, cid, KeepaliveStatus::UpNeeded);
for mut pkt in keepalive_msg { for mut pkt in keepalive_msg {
let status = usb_ctap_hid::send_or_recv_with_timeout(&mut pkt, timeout); let status = usb_ctap_hid::send_or_recv_with_timeout(&mut pkt, timeout);
match status { match status {
@@ -228,13 +233,13 @@ pub fn switch_off_leds() {
const KEEPALIVE_DELAY_MS: isize = 100; const KEEPALIVE_DELAY_MS: isize = 100;
pub const KEEPALIVE_DELAY: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS); pub const KEEPALIVE_DELAY: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS);
fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> { fn check_user_presence(env: &mut TockEnv, cid: ChannelID) -> Result<(), Ctap2StatusCode> {
// The timeout is N times the keepalive delay. // The timeout is N times the keepalive delay.
const TIMEOUT_ITERATIONS: usize = const TIMEOUT_ITERATIONS: usize =
crate::ctap::TOUCH_TIMEOUT_MS as usize / KEEPALIVE_DELAY_MS as usize; crate::ctap::TOUCH_TIMEOUT_MS as usize / KEEPALIVE_DELAY_MS as usize;
// First, send a keep-alive packet to notify that the keep-alive status has changed. // First, send a keep-alive packet to notify that the keep-alive status has changed.
send_keepalive_up_needed(cid, KEEPALIVE_DELAY)?; send_keepalive_up_needed(env, cid, KEEPALIVE_DELAY)?;
// Listen to the button presses. // Listen to the button presses.
let button_touched = Cell::new(false); let button_touched = Cell::new(false);
@@ -284,7 +289,7 @@ fn check_user_presence(cid: ChannelID) -> Result<(), Ctap2StatusCode> {
// so that LEDs blink with a consistent pattern. // so that LEDs blink with a consistent pattern.
if keepalive_expired.get() { if keepalive_expired.get() {
// Do not return immediately, because we must clean up still. // Do not return immediately, because we must clean up still.
keepalive_response = send_keepalive_up_needed(cid, KEEPALIVE_DELAY); keepalive_response = send_keepalive_up_needed(env, cid, KEEPALIVE_DELAY);
} }
if button_touched.get() || keepalive_response.is_err() { if button_touched.get() || keepalive_response.is_err() {

View File

@@ -24,6 +24,23 @@ use crate::ctap::CtapState;
use crate::env::Env; use crate::env::Env;
use libtock_drivers::timer::ClockValue; use libtock_drivers::timer::ClockValue;
// Those macros should eventually be split into trace, debug, info, warn, and error macros when
// adding either the defmt or log feature and crate dependency.
#[cfg(feature = "debug_ctap")]
macro_rules! debug_ctap {
($env: expr, $($rest:tt)*) => {
use core::fmt::Write;
writeln!($env.write(), $($rest)*).unwrap();
};
}
#[cfg(not(feature = "debug_ctap"))]
macro_rules! debug_ctap {
($env: expr, $($rest:tt)*) => {
// To avoid unused variable warnings.
let _ = $env;
};
}
pub mod api; pub mod api;
// Implementation details must be public for testing (in particular fuzzing). // Implementation details must be public for testing (in particular fuzzing).
#[cfg(feature = "std")] #[cfg(feature = "std")]