Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Add ctap hid api #539

Draft
wants to merge 4 commits into
base: dev/opensk
Choose a base branch
from
Draft

WIP Add ctap hid api #539

wants to merge 4 commits into from

Conversation

kofls
Copy link
Collaborator

@kofls kofls commented Jul 22, 2024

No description provided.

@kofls kofls requested a review from ia0 as a code owner July 22, 2024 15:06
@kofls kofls marked this pull request as draft July 22, 2024 15:07
@kofls
Copy link
Collaborator Author

kofls commented Jul 22, 2024

This is a draft PR for the CTAP HID api. I still have to implement the actual read/write using the usbd-ctaphid crate. Just wanted to get initial feedback on the approach.

I'm copying the read/write signatures we have in the usb-serial API currently. Do we also want to have the asynchronous reads/writes like we have in the usb serial api?

Copy link
Member

@ia0 ia0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! And to answer your question: Yes, we should support asynchronous API.

crates/board/src/usb.rs Outdated Show resolved Hide resolved
crates/board/src/usb/ctap.rs Outdated Show resolved Hide resolved
crates/board/src/usb/ctap.rs Outdated Show resolved Hide resolved
crates/board/src/usb/ctap.rs Show resolved Hide resolved
crates/board/src/usb/ctap.rs Outdated Show resolved Hide resolved

impl<T: HasCtapHid> Api for WithCtapHid<T> {
fn read(output: &mut [u8]) -> Result<usize, Error> {
match T::with_ctaphid(|ctap_hid| ctap_hid.pipe.read_and_handle_packet()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a hard time understanding how to use the usbd_ctaphid crate or if it is at all usable yet. Curious to see how this will look like once the PR is ready.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to figure out how to use this crate. Changed to use ctap-hid-fido2 instead

crates/prelude/src/ctap.rs Outdated Show resolved Hide resolved
crates/prelude/src/lib.rs Outdated Show resolved Hide resolved
crates/prelude/src/usb/ctap.rs Outdated Show resolved Hide resolved
Copy link
Member

@ia0 ia0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is out-of-date, there was some merged changes from main. You'll need to merge into dev/opensk. Also, it would probably be good to start using the real CI. You can try to git checkout main -- .github/workflows/ci.yml scripts/ci.sh and fix any issues when running ./scripts/ci.sh.

Comment on lines +22 to +24
/// Reads from USB serial into a buffer.
///
/// Returns the number of bytes read. This function does not block and may return zero.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Reads from USB serial into a buffer.
///
/// Returns the number of bytes read. This function does not block and may return zero.
/// Reads a CTAP packet (64 bytes) from USB.
///
/// Returns whether a packet was read. This function does not block.

Comment on lines +29 to +30
/// Length of the buffer in bytes.
len: usize,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need this now that we fix the packet size

///
/// Returns the number of bytes read. This function does not block and may return zero.
fn read "usr" {
/// Address of the buffer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Address of the buffer.
/// Address of the buffer (must be at least 64 bytes).

} -> usize
},
item! {
/// Writes to USB serial from a buffer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar changes here as for read

} -> usize
},
item! {
/// USB serial events.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// USB serial events.
/// USB CTAP events.

pub enum Event {
/// There might be data to read.
///
/// This is only guaranteed to be triggered after a short read.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// This is only guaranteed to be triggered after a short read.
/// This is only guaranteed to be triggered after an empty read.

(same below)

}

pub trait Api: Send {
/// Reads from the USB serial into a buffer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Reads from the USB serial into a buffer.
/// Reads a packet from USB CTAP HID.

Comment on lines +46 to +47
/// Returns the number of bytes read. It could be zero if there's nothing to read.
fn read(output: &mut [u8; 64]) -> Result<usize, Error>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Returns the number of bytes read. It could be zero if there's nothing to read.
fn read(output: &mut [u8; 64]) -> Result<usize, Error>;
/// Returns whether a packet was read.
fn read(output: &mut [u8; 64]) -> Result<bool, Error>;

Comment on lines +49 to +52
/// Writes from a buffer to the USB serial.
///
/// Returns the number of bytes written. It could be zero if the other side is not ready.
fn write(input: &[u8; 64]) -> Result<usize, Error>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Writes from a buffer to the USB serial.
///
/// Returns the number of bytes written. It could be zero if the other side is not ready.
fn write(input: &[u8; 64]) -> Result<usize, Error>;
/// Writes a packet to USB CTAP HID.
///
/// Returns whether the packet was written.
fn write(input: &[u8; 64]) -> Result<bool, Error>;

@@ -21,6 +21,7 @@ aes-gcm = { version = "0.10.3", default-features = false, optional = true }
bytemuck = { version = "1.16.0", default-features = false, optional = true }
ccm = { version = "0.5.0", default-features = false, optional = true }
crypto-common = { version = "0.1.6", default-features = false, optional = true }
ctap-hid-fido2 = { version = "3.5.1", default-features = false, optional = true }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This crate does not do what you think it does. It implements the client part of CTAP2, not the authenticator part. I don't think there are any crates. You might have to implement something yourself. You can implement a UsbClass directly like https://github.com/google/wasefire/blob/main/crates/protocol-usb/src/device.rs or use https://crates.io/crates/usbd-human-interface-device which might work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize that, thank you! I'll re-implement this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I agree this is quite confusing. Ideally, this should be caught by CI, but due to the conflicts it didn't run. (But maybe because it's WASM, the fact that that crate was not no-std didn't fail.)

@ia0
Copy link
Member

ia0 commented Aug 13, 2024

ccing @kaczmarczyck who might also have ideas on how to implement the authenticator side of CTAP2

}

fn read(&mut self) -> bool {
let mut data = [0; 32];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use a buffer of size 32 here?

Comment on lines +220 to +225
for i in pos .. pos + len {
if self.buffer[i] == self.delimiter {
self.frame = Some(i);
break;
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +175 to +176
frame: Option<usize>, // index of first delimiter in buffer, if any
delimiter: u8,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this delimiter, and what kind of traffic uses it?

@kaczmarczyck
Copy link

ccing @kaczmarczyck who might also have ideas on how to implement the authenticator side of CTAP2

I assume you mean CTAP HID instead of CTAP2? And you need descriptors etc? OpenSK has this for Tock:

https://github.com/google/OpenSK/blob/2.1/patches/tock/03-add-ctap-modules.patch

@ia0
Copy link
Member

ia0 commented Aug 14, 2024

I assume you mean CTAP HID instead of CTAP2?

Yes

And you need descriptors etc?

Not necessarily. It depends on the crate. I guess the HID crate would provide some support for the report. And the USB crate definitely provided support for descriptors.

(By the way, the code you reviewed was copy-pasted and will probably not make it to the end.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants