Skip to content

Commit 9346173

Browse files
fix(ctap2): preserve unknown ctap status codes and add 0x17/0x18
1 parent f9d03dc commit 9346173

4 files changed

Lines changed: 245 additions & 81 deletions

File tree

libwebauthn-tests/src/virt/mod.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ use std::sync::mpsc::{Receiver, Sender};
55
use std::thread;
66
use std::thread::JoinHandle;
77

8-
use libwebauthn::proto::CtapError;
98
use libwebauthn::transport::hid::framing::{HidCommand, HidMessage};
109
use libwebauthn::transport::hid::{virtual_device, HidDevice, HidPipeBackend};
11-
use num_enum::TryFromPrimitive;
1210

1311
/// `HidPipeBackend` implementation backed by an in-process trussed-staging
1412
/// fido-authenticator. Each instance owns a worker thread that owns the
@@ -75,18 +73,14 @@ impl TrussedVirtBackend {
7573
}
7674
Err(ctaphid::error::Error::CommandError(
7775
ctaphid::error::CommandError::CborError(value),
78-
)) => match CtapError::try_from_primitive(value) {
79-
Ok(_) => {
80-
// Known CTAP error code: forward as a successful
81-
// transmission with the status byte as payload.
82-
let mut response = msg.clone();
83-
response.payload = vec![value];
84-
if resp_tx.send(response).is_err() {
85-
break;
86-
}
76+
)) => {
77+
// Forward the status byte as a successful transmission.
78+
let mut response = msg.clone();
79+
response.payload = vec![value];
80+
if resp_tx.send(response).is_err() {
81+
break;
8782
}
88-
Err(_) => panic!("Failed to parse CtapError from {value}"),
89-
},
83+
}
9084
Err(err) => panic!("failed to execute CTAP2 command: {err:?}"),
9185
}
9286
}

libwebauthn-tests/src/virt/pipe.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl<'a, const N: usize> Pipe<'a, N> {
234234
}
235235

236236
fn start_sending_error_on_channel(&mut self, channel: u32, error: CtapError) {
237-
self.buffer[0] = error as u8;
237+
self.buffer[0] = u8::from(error);
238238
let response = Response::error_on_channel(channel);
239239
self.start_sending(response);
240240
}
@@ -243,7 +243,7 @@ impl<'a, const N: usize> Pipe<'a, N> {
243243
let last_state = core::mem::replace(&mut self.state, State::Idle);
244244
let last_first_byte = self.buffer[0];
245245

246-
self.buffer[0] = error as u8;
246+
self.buffer[0] = u8::from(error);
247247
let response = Response::error_from_request(request);
248248
self.start_sending(response);
249249
self.maybe_write_packet();

libwebauthn/src/proto/ctap2/cbor/response.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::proto::error::CtapError;
22

3-
use std::convert::{TryFrom, TryInto};
3+
use std::convert::TryFrom;
44
use std::io::{Error as IOError, ErrorKind as IOErrorKind};
5-
use tracing::error;
65

76
#[derive(Debug, Clone)]
87
pub struct CborResponse {
@@ -32,13 +31,7 @@ impl TryFrom<&Vec<u8>> for CborResponse {
3231
)
3332
})?;
3433

35-
let Ok(status_code) = (*status_byte).try_into() else {
36-
error!({ code = ?*status_byte }, "Invalid CTAP error code");
37-
return Err(IOError::new(
38-
IOErrorKind::InvalidData,
39-
format!("Invalid CTAP error code: {:x}", status_byte),
40-
));
41-
};
34+
let status_code = CtapError::from(*status_byte);
4235

4336
let data = if body.is_empty() {
4437
None
@@ -48,3 +41,25 @@ impl TryFrom<&Vec<u8>> for CborResponse {
4841
Ok(CborResponse { status_code, data })
4942
}
5043
}
44+
45+
#[cfg(test)]
46+
mod tests {
47+
use super::CborResponse;
48+
use crate::proto::error::CtapError;
49+
use std::convert::TryFrom;
50+
51+
#[test]
52+
fn unknown_status_byte_is_preserved() {
53+
let response = CborResponse::try_from(&vec![0xDEu8]).expect("must not be a framing error");
54+
assert_eq!(response.status_code, CtapError::Unknown(0xDE));
55+
assert!(response.data.is_none());
56+
}
57+
58+
#[test]
59+
fn unknown_status_byte_keeps_body() {
60+
let response =
61+
CborResponse::try_from(&vec![0xF5u8, 0xAA, 0xBB]).expect("must not be a framing error");
62+
assert_eq!(response.status_code, CtapError::Unknown(0xF5));
63+
assert_eq!(response.data.as_deref(), Some(&[0xAA, 0xBB][..]));
64+
}
65+
}

0 commit comments

Comments
 (0)