Skip to content

Commit

Permalink
tests: Add ctap1 upgrade test
Browse files Browse the repository at this point in the history
  • Loading branch information
robin-nitrokey committed Jun 24, 2024
1 parent 867db75 commit 9ece796
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 8 deletions.
48 changes: 48 additions & 0 deletions tests/ctap1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use iso7816::{
command::{class::Class, instruction::Instruction, CommandBuilder, ExpectedLen},
response::Status,
};
use littlefs2::path;
use p256::ecdsa::{signature::Verifier as _, DerSignature, VerifyingKey};
use x509_parser::public_key::PublicKey;

Expand Down Expand Up @@ -86,6 +87,53 @@ fn test_authenticate_wrong_keyhandle() {
});
}

#[test]
fn test_authenticate_upgrade() {
// manually extracted after running register on commit 79b05b576863236fe54750b18e862ce0801f2040
let state: &[u8] = &hex!("A5726B65795F656E6372797074696F6E5F6B65795010926EC1ACF475A6ED273BD951BC4A6E706B65795F7772617070696E675F6B65795061743976EDACA263BD30DE70ADFBAF0B781A636F6E73656375746976655F70696E5F6D69736D617463686573006870696E5F68617368F66974696D657374616D7001");
let key_encryption_key: &[u8] = &hex!("00020003A0BAA6066B22616147F242DEC9C4B450F6189A10EE036C36E697E647B2C1D3E1000000000000000000000000");
let key_wrapping_key: &[u8] = &hex!("000200037719CE721FB206F9788BB7E550777C03795ECFE0B211AB7D50C5C2CE21B43E8E010000000000000000000000");
let files = &[
(path!("fido/dat/persistent-state.cbor"), state),
(
path!("fido/sec/10926ec1acf475a6ed273bd951bc4a6e"),
key_encryption_key,
),
(
path!("fido/sec/61743976edaca263bd30de70adfbaf0b"),
key_wrapping_key,
),
];

virt::run_ctaphid_with_files(files, |device| {
let application = &hex!("f0e6a6a97042a4f1f1c87f5f7d44315b2d852c2df5c7991cc66241bf7072d1c4");
let keyhandle = hex!("A3005878B3F2499ACECB2C08F437DEF0F41929BD4DCFBCA7D43E893B18799BA61F6D84A36EAFCB87D9E833AEA1FE68BABD27A4B89C83C32EC25B092D915D9EA207ECA4BDE5A06E3CDCCFE0E93600AC28A6A8A61E4A1C6881C67E252F00425672427CFC59463B097364F45FD050F8E6BE1C6CD45C1F7D9B5732E334A8014C533D8BF37EEF0D8D7D16B6DF025055B1A6492F5607139EF420D47051A5F3");
let user_key = &hex!("04AE6B38AE33494A3A58A9FED8A1C5DA2683F510A69B9DE4D8849648485ECDCC21918E6124F6E0B71E7B3C5D92F08EC38D3161E236FF72743923141E97089AA2C4");
let register = Register {
user_key: VerifyingKey::from_sec1_bytes(user_key).unwrap(),
keyhandle: keyhandle.into(),
};

let challenge = &hex!("ccd6ee2e47baef244d49a222db496bad0ef5b6f93aa7cc4d30c4821b3b9dbc57");

// check-only
let err = authenticate(&device, 7, challenge, application, &register)
.err()
.unwrap();
assert_eq!(err, Status::ConditionsOfUseNotSatisfied);

// enforce user presence
let response = authenticate(&device, 3, challenge, application, &register).unwrap();
assert_eq!(response.user_presence & 1, 1);
assert_eq!(response.counter, 1);

// don’t enforce user presence
let response = authenticate(&device, 8, challenge, application, &register).unwrap();
assert_eq!(response.user_presence & 1, 0);
assert_eq!(response.counter, 2);
});
}

fn version<D: HidDevice>(device: &Device<D>) -> Vec<u8> {
let command = build_command(3, 0, &[]);
exec(device, &command).unwrap()
Expand Down
41 changes: 33 additions & 8 deletions tests/virt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ use ctaphid_dispatch::{
types::{Channel, Requester},
};
use fido_authenticator::{Authenticator, Config, Conforming};
use littlefs2::path;
use littlefs2::{path, path::Path};
use rand::{
distributions::{Distribution, Uniform},
RngCore as _,
};
use trussed::{
backend::BackendId,
platform::Platform as _,
Expand All @@ -43,14 +47,24 @@ const ATTESTATION_KEY: &[u8] = include_bytes!("../data/fido-key.trussed");
static INIT_LOGGER: Once = Once::new();

pub fn run_ctaphid<F, T>(f: F) -> T
where
F: FnOnce(ctaphid::Device<Device>) -> T + Send,
T: Send,
{
run_ctaphid_with_files(&[], f)
}
pub fn run_ctaphid_with_files<F, T>(files: &[(&Path, &[u8])], f: F) -> T
where
F: FnOnce(ctaphid::Device<Device>) -> T + Send,
T: Send,
{
INIT_LOGGER.call_once(|| {
env_logger::init();
});
with_client(|client| {
let mut files = Vec::from(files);
files.push((path!("fido/x5c/00"), ATTESTATION_CERT));
files.push((path!("fido/sec/00"), ATTESTATION_KEY));
with_client(&files, |client| {
let mut authenticator = Authenticator::new(
client,
Conforming {},
Expand Down Expand Up @@ -209,16 +223,27 @@ impl HidDevice for Device<'_> {
}
}

fn with_client<F, T>(f: F) -> T
fn with_client<F, T>(files: &[(&Path, &[u8])], f: F) -> T
where
F: FnOnce(Client<Ram>) -> T,
{
virt::with_platform(Ram::default(), |platform| {
virt::with_platform(Ram::default(), |mut platform| {
// virt always uses the same seed -- request some random bytes to reach a somewhat random
// state
let uniform = Uniform::from(0..64);
let n = uniform.sample(&mut rand::thread_rng());
for _ in 0..n {
platform.rng().next_u32();
}

let ifs = platform.store().ifs();
ifs.create_dir_all(path!("fido/x5c")).unwrap();
ifs.create_dir_all(path!("fido/sec")).unwrap();
ifs.write(path!("fido/x5c/00"), ATTESTATION_CERT).unwrap();
ifs.write(path!("fido/sec/00"), ATTESTATION_KEY).unwrap();

for (path, content) in files {
if let Some(dir) = path.parent() {
ifs.create_dir_all(&dir).unwrap();
}
ifs.write(path, content).unwrap();
}

platform.run_client_with_backends(
"fido",
Expand Down

0 comments on commit 9ece796

Please sign in to comment.