mirror of
https://github.com/trussed-dev/fido-authenticator.git
synced 2026-06-20 04:16:16 -07:00
Add test case for credential ID stability
This patch adds a test case that ensures that the calculated credential ID for a credential that was created using the old (unstripped) format is the same as the one generated originally. Otherwise, the platform or the RP could reject assertions because of a changed credential ID.
This commit is contained in:
@@ -68,6 +68,7 @@ littlefs2 = "0.5.0"
|
||||
log = "0.4.21"
|
||||
p256 = { version = "0.13.2", features = ["ecdh"] }
|
||||
rand = "0.8.4"
|
||||
rand_chacha = "0.3"
|
||||
sha2 = "0.10"
|
||||
serde_test = "1.0.176"
|
||||
trussed = { version = "0.1", features = ["virt"] }
|
||||
|
||||
@@ -601,9 +601,17 @@ impl From<&FullCredential> for StrippedCredential {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use hex_literal::hex;
|
||||
use littlefs2_core::path;
|
||||
use rand::SeedableRng as _;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use trussed::{
|
||||
client::{Chacha8Poly1305, Sha256},
|
||||
key::{Kind, Secrecy},
|
||||
store::keystore::{ClientKeystore, Keystore as _},
|
||||
types::Location,
|
||||
virt::{self, Ram},
|
||||
Platform as _,
|
||||
};
|
||||
|
||||
fn credential_data() -> CredentialData {
|
||||
@@ -630,6 +638,30 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
fn old_credential_data() -> CredentialData {
|
||||
CredentialData {
|
||||
rp: LocalPublicKeyCredentialRpEntity {
|
||||
id: String::from("John Doe"),
|
||||
name: None,
|
||||
},
|
||||
user: LocalPublicKeyCredentialUserEntity {
|
||||
id: Bytes::from_slice(&[1, 2, 3]).unwrap(),
|
||||
icon: None,
|
||||
name: None,
|
||||
display_name: None,
|
||||
},
|
||||
creation_time: 123,
|
||||
use_counter: false,
|
||||
algorithm: -7,
|
||||
key: Key::WrappedKey(Bytes::from_slice(&[1, 2, 3]).unwrap()),
|
||||
hmac_secret: Some(false),
|
||||
cred_protect: None,
|
||||
use_short_id: None,
|
||||
large_blob_key: None,
|
||||
third_party_payment: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn random_byte_array<const N: usize>() -> ByteArray<N> {
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
let mut bytes = [0; N];
|
||||
@@ -733,6 +765,85 @@ mod test {
|
||||
assert_eq!(credential_data, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn old_credential_id() {
|
||||
// generated with v0.1.1-nitrokey.4 (NK3 firmware version v1.4.0)
|
||||
const OLD_ID: &[u8] = &hex!("A300583A71AEF80C4DA56033D66EB3266E9ACB8D84923D13F89BCBCE9FF30D8CD77ED968A436CA3D39C49999EC0F69A289CB2A65A08ABF251DEB21BB4B56014C00000000000000000000000002504DF499ABDAE80F5615C870985B74A799");
|
||||
const SERIALIZED_DATA: &[u8] = &hex!(
|
||||
"A700A1626964684A6F686E20446F6501A16269644301020302187B03F404260582014301020306F4"
|
||||
);
|
||||
const SERIALIZED_CREDENTIAL: &[u8] = &hex!("A3000201A700A1626964684A6F686E20446F6501A16269644301020302187B03F404260582014301020306F4024C000000000000000000000000");
|
||||
|
||||
virt::with_platform(Ram::default(), |mut platform| {
|
||||
let kek = [0; 44];
|
||||
let client_id = path!("fido");
|
||||
let kek = {
|
||||
let rng = ChaCha8Rng::from_rng(platform.rng()).unwrap();
|
||||
let mut keystore = ClientKeystore::new(client_id.into(), rng, platform.store());
|
||||
keystore
|
||||
.store_key(
|
||||
Location::Internal,
|
||||
Secrecy::Secret,
|
||||
Kind::Symmetric32Nonce(12),
|
||||
&kek,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
platform.run_client(client_id.as_str(), |mut client| {
|
||||
let data = old_credential_data();
|
||||
let rp_id_hash = syscall!(client.hash_sha256(data.rp.id.as_ref())).hash;
|
||||
let credential_id = CredentialId(Bytes::from_slice(OLD_ID).unwrap());
|
||||
let encrypted_serialized =
|
||||
EncryptedSerializedCredential::try_from(credential_id).unwrap();
|
||||
let serialized = syscall!(client.decrypt_chacha8poly1305(
|
||||
kek,
|
||||
&encrypted_serialized.0.ciphertext,
|
||||
&rp_id_hash,
|
||||
&encrypted_serialized.0.nonce,
|
||||
&encrypted_serialized.0.tag,
|
||||
))
|
||||
.plaintext
|
||||
.unwrap();
|
||||
|
||||
let full = FullCredential::deserialize(&serialized).unwrap();
|
||||
assert_eq!(
|
||||
full,
|
||||
FullCredential {
|
||||
ctap: CtapVersion::Fido21Pre,
|
||||
data,
|
||||
nonce: [0; 12].into(),
|
||||
}
|
||||
);
|
||||
|
||||
let stripped_credential = full.strip();
|
||||
|
||||
let serialized_data: Bytes<1024> =
|
||||
trussed::cbor_serialize_bytes(&stripped_credential.data).unwrap();
|
||||
assert_eq!(
|
||||
delog::hexstr!(&serialized_data).to_string(),
|
||||
delog::hexstr!(SERIALIZED_DATA).to_string()
|
||||
);
|
||||
|
||||
let serialized_credential: Bytes<1024> =
|
||||
trussed::cbor_serialize_bytes(&stripped_credential).unwrap();
|
||||
assert_eq!(
|
||||
delog::hexstr!(&serialized_credential).to_string(),
|
||||
delog::hexstr!(SERIALIZED_CREDENTIAL).to_string()
|
||||
);
|
||||
|
||||
let credential = Credential::Full(full);
|
||||
let id = credential
|
||||
.id(&mut client, kek, rp_id_hash.as_ref().try_into().unwrap())
|
||||
.unwrap()
|
||||
.0;
|
||||
assert_eq!(
|
||||
delog::hexstr!(&id).to_string(),
|
||||
delog::hexstr!(OLD_ID).to_string()
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn credential_ids() {
|
||||
trussed::virt::with_ram_client("fido", |mut client| {
|
||||
|
||||
Reference in New Issue
Block a user