mirror of
https://github.com/trussed-dev/fido-authenticator.git
synced 2026-06-20 04:16:16 -07:00
tests: Add Request trait and reply types
This commit is contained in:
+11
-19
@@ -3,13 +3,8 @@
|
||||
mod virt;
|
||||
mod webauthn;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ciborium::Value;
|
||||
use ctap_types::ctap2::Operation;
|
||||
|
||||
use virt::Ctap2Error;
|
||||
use webauthn::{MakeCredentialRequest, PubKeyCredParam, Rp, User};
|
||||
use webauthn::{GetInfo, MakeCredential, PubKeyCredParam, Rp, User};
|
||||
|
||||
#[test]
|
||||
fn test_ping() {
|
||||
@@ -21,10 +16,9 @@ fn test_ping() {
|
||||
#[test]
|
||||
fn test_get_info() {
|
||||
virt::run_ctap2(|device| {
|
||||
let reply: BTreeMap<u8, Value> = device.call(Operation::GetInfo, &Value::Null).unwrap();
|
||||
let versions: Vec<String> = reply.get(&1).unwrap().deserialized().unwrap();
|
||||
assert!(versions.contains(&"FIDO_2_0".to_owned()));
|
||||
assert!(versions.contains(&"FIDO_2_1".to_owned()));
|
||||
let reply = device.exec(GetInfo).unwrap();
|
||||
assert!(reply.versions.contains(&"FIDO_2_0".to_owned()));
|
||||
assert!(reply.versions.contains(&"FIDO_2_1".to_owned()));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,13 +30,11 @@ fn test_make_credential() {
|
||||
.name("john.doe")
|
||||
.display_name("John Doe");
|
||||
let pub_key_cred_params = vec![PubKeyCredParam::new("public-key", -7)];
|
||||
let request = MakeCredentialRequest::new(b"", rp, user, pub_key_cred_params);
|
||||
let reply: BTreeMap<u8, Value> = device
|
||||
.call(Operation::MakeCredential, &request.into())
|
||||
.unwrap();
|
||||
assert_eq!(reply.get(&1).unwrap(), &Value::from("packed"));
|
||||
assert!(reply.contains_key(&2));
|
||||
assert!(reply.contains_key(&3));
|
||||
let request = MakeCredential::new(b"", rp, user, pub_key_cred_params);
|
||||
let reply = device.exec(request).unwrap();
|
||||
assert_eq!(reply.fmt, "packed");
|
||||
assert!(reply.auth_data.is_bytes());
|
||||
assert!(reply.att_stmt.is_map());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,8 +46,8 @@ fn test_make_credential_invalid_params() {
|
||||
.name("john.doe")
|
||||
.display_name("John Doe");
|
||||
let pub_key_cred_params = vec![PubKeyCredParam::new("public-key", -11)];
|
||||
let request = MakeCredentialRequest::new(b"", rp, user, pub_key_cred_params);
|
||||
let result = device.call::<Value>(Operation::MakeCredential, &request.into());
|
||||
let request = MakeCredential::new(b"", rp, user, pub_key_cred_params);
|
||||
let result = device.exec(request);
|
||||
assert_eq!(result, Err(Ctap2Error(0x26)));
|
||||
});
|
||||
}
|
||||
|
||||
+8
-10
@@ -13,7 +13,6 @@ use std::{
|
||||
};
|
||||
|
||||
use ciborium::Value;
|
||||
use ctap_types::ctap2::Operation;
|
||||
use ctaphid::{
|
||||
error::{RequestError, ResponseError},
|
||||
HidDevice, HidDeviceInfo,
|
||||
@@ -23,9 +22,10 @@ use ctaphid_dispatch::{
|
||||
types::{Channel, Requester},
|
||||
};
|
||||
use fido_authenticator::{Authenticator, Config, Conforming};
|
||||
use serde::de::DeserializeOwned;
|
||||
use trussed_staging::virt;
|
||||
|
||||
use crate::webauthn::Request;
|
||||
|
||||
use pipe::Pipe;
|
||||
|
||||
static INIT_LOGGER: Once = Once::new();
|
||||
@@ -92,23 +92,21 @@ where
|
||||
pub struct Ctap2<'a>(ctaphid::Device<Device<'a>>);
|
||||
|
||||
impl Ctap2<'_> {
|
||||
pub fn call<T: DeserializeOwned>(
|
||||
&self,
|
||||
operation: Operation,
|
||||
data: &Value,
|
||||
) -> Result<T, Ctap2Error> {
|
||||
pub fn exec<R: Request>(&self, request: R) -> Result<R::Reply, Ctap2Error> {
|
||||
let request = request.into();
|
||||
let mut serialized = Vec::new();
|
||||
ciborium::into_writer(data, &mut serialized).unwrap();
|
||||
ciborium::into_writer(&request, &mut serialized).unwrap();
|
||||
let reply = self
|
||||
.0
|
||||
.ctap2(operation.into(), &serialized)
|
||||
.ctap2(R::COMMAND, &serialized)
|
||||
.map_err(|err| match err {
|
||||
ctaphid::error::Error::CommandError(ctaphid::error::CommandError::CborError(
|
||||
value,
|
||||
)) => Ctap2Error(value),
|
||||
err => panic!("failed to execute CTAP2 command: {err:?}"),
|
||||
})?;
|
||||
Ok(ciborium::from_reader(reply.as_slice()).unwrap())
|
||||
let value: Value = ciborium::from_reader(reply.as_slice()).unwrap();
|
||||
Ok(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-4
@@ -1,3 +1,5 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ciborium::Value;
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -15,6 +17,12 @@ impl From<Map> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Request: Into<Value> {
|
||||
const COMMAND: u8;
|
||||
|
||||
type Reply: From<Value>;
|
||||
}
|
||||
|
||||
pub struct Rp {
|
||||
id: String,
|
||||
name: Option<String>,
|
||||
@@ -108,14 +116,14 @@ impl From<PubKeyCredParam> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MakeCredentialRequest {
|
||||
pub struct MakeCredential {
|
||||
client_data_hash: Vec<u8>,
|
||||
rp: Rp,
|
||||
user: User,
|
||||
pub_key_cred_params: Vec<PubKeyCredParam>,
|
||||
}
|
||||
|
||||
impl MakeCredentialRequest {
|
||||
impl MakeCredential {
|
||||
pub fn new(
|
||||
client_data_hash: impl Into<Vec<u8>>,
|
||||
rp: Rp,
|
||||
@@ -131,8 +139,8 @@ impl MakeCredentialRequest {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MakeCredentialRequest> for Value {
|
||||
fn from(request: MakeCredentialRequest) -> Value {
|
||||
impl From<MakeCredential> for Value {
|
||||
fn from(request: MakeCredential) -> Value {
|
||||
let mut map = Map::default();
|
||||
map.push(1, request.client_data_hash);
|
||||
map.push(2, request.rp);
|
||||
@@ -148,3 +156,54 @@ impl From<MakeCredentialRequest> for Value {
|
||||
map.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Request for MakeCredential {
|
||||
const COMMAND: u8 = 0x01;
|
||||
|
||||
type Reply = MakeCredentialReply;
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct MakeCredentialReply {
|
||||
pub fmt: String,
|
||||
pub auth_data: Value,
|
||||
pub att_stmt: Value,
|
||||
}
|
||||
|
||||
impl From<Value> for MakeCredentialReply {
|
||||
fn from(value: Value) -> Self {
|
||||
let mut map: BTreeMap<u8, Value> = value.deserialized().unwrap();
|
||||
Self {
|
||||
fmt: map.remove(&1).unwrap().deserialized().unwrap(),
|
||||
auth_data: map.remove(&2).unwrap(),
|
||||
att_stmt: map.remove(&3).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GetInfo;
|
||||
|
||||
impl From<GetInfo> for Value {
|
||||
fn from(_: GetInfo) -> Self {
|
||||
Self::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl Request for GetInfo {
|
||||
const COMMAND: u8 = 0x04;
|
||||
|
||||
type Reply = GetInfoReply;
|
||||
}
|
||||
|
||||
pub struct GetInfoReply {
|
||||
pub versions: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<Value> for GetInfoReply {
|
||||
fn from(value: Value) -> Self {
|
||||
let mut map: BTreeMap<u8, Value> = value.deserialized().unwrap();
|
||||
Self {
|
||||
versions: map.remove(&1).unwrap().deserialized().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user