Add write to the environment
This commit is contained in:
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
11
src/env/mod.rs
vendored
@@ -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
15
src/env/test/mod.rs
vendored
@@ -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
19
src/env/tock/mod.rs
vendored
@@ -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() {
|
||||||
|
|||||||
17
src/lib.rs
17
src/lib.rs
@@ -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")]
|
||||||
|
|||||||
Reference in New Issue
Block a user