use super::*;
use crate::passkey::main::attestation::utils::integer_to_i64;
use ciborium::value::Value;
use ring::digest;
use sha2::Digest;
fn create_test_auth_data() -> Vec<u8> {
let mut auth_data = Vec::new();
let rp_id_hash = digest::digest(&digest::SHA256, "example.com".as_bytes());
auth_data.extend_from_slice(rp_id_hash.as_ref());
auth_data.push(0x01 | 0x04 | 0x40);
auth_data.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]);
auth_data.extend_from_slice(&[0x01; 16]);
auth_data.extend_from_slice(&[0x00, 0x10]); auth_data.extend_from_slice(&[0x02; 16]);
let public_key_entries = vec![
(Value::Integer(1i64.into()), Value::Integer(2i64.into())), (Value::Integer(3i64.into()), Value::Integer((-7i64).into())), (Value::Integer((-1i64).into()), Value::Integer(1i64.into())), (Value::Integer((-2i64).into()), Value::Bytes(vec![0x02; 32])), (Value::Integer((-3i64).into()), Value::Bytes(vec![0x03; 32])), ];
let public_key = Value::Map(public_key_entries);
let mut public_key_bytes = Vec::new();
ciborium::ser::into_writer(&public_key, &mut public_key_bytes).unwrap();
auth_data.extend_from_slice(&public_key_bytes);
auth_data
}
fn create_test_auth_data_rsa() -> Vec<u8> {
let mut auth_data = Vec::new();
let rp_id_hash = digest::digest(&digest::SHA256, "example.com".as_bytes());
auth_data.extend_from_slice(rp_id_hash.as_ref());
auth_data.push(0x01 | 0x04 | 0x40);
auth_data.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]);
auth_data.extend_from_slice(&[0x01; 16]);
auth_data.extend_from_slice(&[0x00, 0x10]); auth_data.extend_from_slice(&[0x02; 16]);
let modulus = vec![0x04; 256]; let exponent = vec![0x01, 0x00, 0x01]; let public_key_entries = vec![
(Value::Integer(1i64.into()), Value::Integer(3i64.into())), (
Value::Integer(3i64.into()),
Value::Integer((-257i64).into()),
), (Value::Integer((-1i64).into()), Value::Bytes(modulus)), (Value::Integer((-2i64).into()), Value::Bytes(exponent)), ];
let public_key = Value::Map(public_key_entries);
let mut public_key_bytes = Vec::new();
ciborium::ser::into_writer(&public_key, &mut public_key_bytes).unwrap();
auth_data.extend_from_slice(&public_key_bytes);
auth_data
}
fn create_test_client_data_hash() -> Vec<u8> {
let client_data = r#"{"type":"webauthn.create","challenge":"dGVzdGNoYWxsZW5nZQ","origin":"https://example.com"}"#;
let hash = digest::digest(&digest::SHA256, client_data.as_bytes());
hash.as_ref().to_vec()
}
fn create_test_tpm_att_stmt(
include_ver: bool,
include_alg: bool,
include_sig: bool,
include_x5c: bool,
include_pub_area: bool,
include_cert_info: bool,
) -> Vec<(CborValue, CborValue)> {
let mut att_stmt = Vec::new();
if include_ver {
att_stmt.push((
Value::Text("ver".to_string()),
Value::Text("2.0".to_string()),
));
}
if include_alg {
att_stmt.push((
Value::Text("alg".to_string()),
Value::Integer((-257i64).into()), ));
}
if include_sig {
att_stmt.push((
Value::Text("sig".to_string()),
Value::Bytes(vec![0x01, 0x02, 0x03, 0x04]), ));
}
if include_x5c {
let cert_bytes = create_test_x509_certificate();
let certs = vec![Value::Bytes(cert_bytes)];
att_stmt.push((Value::Text("x5c".to_string()), Value::Array(certs)));
}
if include_pub_area {
att_stmt.push((
Value::Text("pubArea".to_string()),
Value::Bytes(create_test_rsa_pub_area()),
));
}
if include_cert_info {
att_stmt.push((
Value::Text("certInfo".to_string()),
Value::Bytes(create_test_cert_info()),
));
}
att_stmt
}
fn create_test_x509_certificate() -> Vec<u8> {
vec![
0x30, 0x82, 0x02, 0x76, 0x30, 0x82, 0x01, 0x5e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09,
0x00, 0xf1, 0xc2, 0x60, 0x8b, 0x0f, 0xc5, 0x5e, 0x7c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x00, 0x30, 0x1e, 0x17, 0x0d,
0x32, 0x33, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
0x32, 0x34, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x00,
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xc2, 0x63, 0xb1, 0x6a, 0xc3, 0x8e, 0xd0, 0x8b, 0x4c, 0x8e, 0x3b, 0xa0,
0x4c, 0x85, 0x6c, 0x65, 0x7c, 0x4b, 0x32, 0x5c, 0x1a, 0x1e, 0x7a, 0x62, 0x79, 0x8f, 0x9a,
0x0e, 0x1e, 0x28, 0xd8, 0x2c, 0x77, 0xab, 0x93, 0x3b, 0x97, 0x06, 0xd0, 0x8e, 0x3a, 0x10,
0xf8, 0x9b, 0x26, 0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c, 0x8e, 0xac, 0x2e, 0x8c,
0x8f, 0x39, 0x1e, 0xd6, 0x29, 0x3e, 0x73, 0x6e, 0xd1, 0x5a, 0x4e, 0x3a, 0x2c, 0x84, 0x97,
0x1b, 0x5e, 0x73, 0xb2, 0x7a, 0xf8, 0x1c, 0x9d, 0x38, 0x6c, 0x91, 0x4e, 0x8c, 0x1e, 0x73,
0x6e, 0x40, 0x5e, 0x3f, 0x73, 0x6e, 0x5b, 0x10, 0x7c, 0x8e, 0x2b, 0x38, 0x1e, 0x73, 0x6e,
0xaa, 0x14, 0x8c, 0x8e, 0x3a, 0x10, 0xf8, 0x9b, 0x26, 0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79,
0xb4, 0x5c, 0x8e, 0xac, 0x2e, 0x8c, 0x8f, 0x39, 0x1e, 0xd6, 0x29, 0x3e, 0x73, 0x6e, 0xd1,
0x5a, 0x4e, 0x3a, 0x2c, 0x84, 0x97, 0x1b, 0x5e, 0x73, 0xb2, 0x7a, 0xf8, 0x1c, 0x9d, 0x38,
0x6c, 0x9e, 0x4e, 0x8c, 0x1e, 0x73, 0x6e, 0x40, 0x5e, 0x3f, 0x73, 0x6e, 0x5b, 0x10, 0x7c,
0x8e, 0x2b, 0x38, 0x1e, 0x73, 0x6e, 0xaa, 0x14, 0x8c, 0x8e, 0x3a, 0x10, 0xf8, 0x9b, 0x26,
0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c, 0x8e, 0xac, 0x2e, 0x8c, 0x8f, 0x39, 0x1e,
0xd6, 0x29, 0x3e, 0x73, 0x6e, 0xd1, 0x5a, 0x4e, 0x3a, 0x2c, 0x84, 0x97, 0x1b, 0x5e, 0x73,
0xb2, 0x7a, 0xf8, 0x1c, 0x9d, 0x38, 0x6c, 0x4e, 0x8c, 0x1e, 0x73, 0x6e, 0x40, 0x5e, 0x3f,
0x73, 0x6e, 0x5b, 0x10, 0x7c, 0x8e, 0x2b, 0x38, 0x1e, 0x73, 0x6e, 0xaa, 0x14, 0x8c, 0x8e,
0x3a, 0x10, 0xf8, 0x9b, 0x26, 0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c, 0x8e, 0xac,
0x2e, 0x8c, 0x8f, 0x39, 0x1e, 0xd6, 0x29, 0x3e, 0x73, 0x6e, 0xd1, 0x5a, 0x4e, 0x3a, 0x2c,
0x84, 0x97, 0x1b, 0x5e, 0x73, 0xb2, 0x7a, 0xf8, 0x1c, 0x9d, 0x38, 0x6c, 0x9e, 0x4e, 0x8c,
0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x89, 0x73, 0x2c, 0x3f, 0x6e,
0x79, 0xb4, 0x5c, 0x8e, 0xac, 0x2e, 0x8c, 0x8f, 0x39, 0x1e, 0xd6, 0x29, 0x3e, 0x73, 0x6e,
0xd1, 0x5a, 0x4e, 0x3a, 0x2c, 0x84, 0x97, 0x1b, 0x5e, 0x73, 0xb2, 0x7a, 0xf8, 0x1c, 0x9d,
0x38, 0x6c, 0x9e, 0x4e, 0x8c, 0x1e, 0x73, 0x6e, 0x40, 0x5e, 0x3f, 0x73, 0x6e, 0x5b, 0x10,
0x7c, 0x8e, 0x2b, 0x38, 0x1e, 0x73, 0x6e, 0xaa, 0x14, 0x8c, 0x8e, 0x3a, 0x10, 0xf8, 0x9b,
0x26, 0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c, 0x8e, 0xac, 0x2e, 0x8c, 0x8f, 0x39,
0x1e, 0xd6, 0x29, 0x3e, 0x73, 0x6e, 0xd1, 0x5a, 0x4e, 0x3a, 0x2c, 0x84, 0x97, 0x1b, 0x5e,
0x73, 0xb2, 0x7a, 0xf8, 0x1c, 0x9d, 0x38, 0x6c, 0x9e, 0x4e, 0x8c, 0x1e, 0x73, 0x6e, 0x40,
0x5e, 0x3f, 0x73, 0x6e, 0x5b, 0x10, 0x7c, 0x8e, 0x2b, 0x38, 0x1e, 0x73, 0x6e, 0xaa, 0x14,
0x8c, 0x8e, 0x3a, 0x10, 0xf8, 0x9b, 0x26, 0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c,
0x8e, 0xac, 0x2e, 0x8c, 0x8f, 0x39, 0x1e, 0xd6, 0x29, 0x3e, 0x73, 0x6e, 0xd1, 0x5a, 0x4e,
0x3a, 0x2c, 0x84, 0x97, 0x1b, 0x5e, 0x73, 0xb2, 0x7a, 0xf8, 0x1c, 0x9d, 0x38, 0x6c, 0x9e,
0x4e, 0x8c, 0x1e, 0x73, 0x6e, 0x40, 0x5e, 0x3f, 0x73, 0x6e, 0x5b, 0x10, 0x7c, 0x8e, 0x2b,
0x38, 0x1e, 0x73, 0x6e, 0xaa, 0x14, 0x8c, 0x8e, 0x3a, 0x10, 0xf8, 0x9b, 0x26, 0x5b, 0x30,
0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c, 0x8e, 0xac, 0x2e, 0x8c, 0x8f, 0x39, 0x1e, 0xd6, 0x29,
0x3e, 0x73, 0x6e, 0xd1, 0x5a, 0x4e, 0x3a, 0x2c, 0x84, 0x97, 0x1b, 0x5e, 0x73, 0xb2, 0x7a,
0xf8, 0x1c, 0x9d, 0x38, 0x6c, 0x9e, 0x4e, 0x8c, 0x1e, 0x73, 0x6e, 0x40, 0x5e, 0x3f, 0x73,
0x6e, 0x5b, 0x10, 0x7c, 0x8e, 0x2b, 0x38, 0x1e, 0x73, 0x6e, 0xaa, 0x14, 0x8c, 0x8e, 0x3a,
0x10, 0xf8, 0x9b, 0x26, 0x5b, 0x30, 0x3f, 0x73, 0x6e, 0x79, 0xb4, 0x5c, 0x8e,
]
}
fn create_test_rsa_pub_area() -> Vec<u8> {
let mut pub_area = Vec::new();
pub_area.extend_from_slice(&[0x00, 0x01]);
pub_area.extend_from_slice(&[0x00, 0x0B]);
pub_area.extend_from_slice(&[0x00, 0x04, 0x00, 0x72]);
pub_area.extend_from_slice(&[0x00, 0x00]);
pub_area.extend_from_slice(&[0x00, 0x10]);
pub_area.extend_from_slice(&[0x00, 0x10]);
pub_area.extend_from_slice(&[0x08, 0x00]);
pub_area.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]);
let modulus = vec![0x04; 256]; pub_area.extend_from_slice(&(modulus.len() as u16).to_be_bytes());
pub_area.extend_from_slice(&modulus);
pub_area
}
fn create_test_ecc_pub_area() -> Vec<u8> {
let mut pub_area = Vec::new();
pub_area.extend_from_slice(&[0x00, 0x23]);
pub_area.extend_from_slice(&[0x00, 0x0B]);
pub_area.extend_from_slice(&[0x00, 0x04, 0x00, 0x72]);
pub_area.extend_from_slice(&[0x00, 0x00]);
pub_area.extend_from_slice(&[0x00, 0x10]);
pub_area.extend_from_slice(&[0x00, 0x10]);
pub_area.extend_from_slice(&[0x00, 0x03]);
pub_area.extend_from_slice(&[0x00, 0x10]);
let x_coord = vec![0x02; 32]; let y_coord = vec![0x03; 32];
pub_area.extend_from_slice(&(x_coord.len() as u16).to_be_bytes());
pub_area.extend_from_slice(&x_coord);
pub_area.extend_from_slice(&(y_coord.len() as u16).to_be_bytes());
pub_area.extend_from_slice(&y_coord);
pub_area
}
fn create_test_cert_info() -> Vec<u8> {
let mut cert_info = Vec::new();
cert_info.extend_from_slice(&TPM_GENERATED_VALUE.to_be_bytes());
cert_info.extend_from_slice(&TPM_ST_ATTEST_CERTIFY.to_be_bytes());
cert_info.extend_from_slice(&[0x00, 0x00]);
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let mut hasher = sha2::Sha256::new();
hasher.update(&auth_data);
hasher.update(&client_data_hash);
let hash = hasher.finalize();
cert_info.extend_from_slice(&(hash.len() as u16).to_be_bytes());
cert_info.extend_from_slice(&hash);
cert_info.extend_from_slice(&[0x00; 16]);
cert_info.extend_from_slice(&[0x00; 8]);
cert_info.extend_from_slice(&[0x00, 0x0B]);
let pub_area = create_test_rsa_pub_area();
let mut hasher = sha2::Sha256::new();
hasher.update(&pub_area);
let name_hash = hasher.finalize();
cert_info.extend_from_slice(&((2 + name_hash.len()) as u16).to_be_bytes());
cert_info.extend_from_slice(&[0x00, 0x0B]);
cert_info.extend_from_slice(&name_hash);
cert_info
}
#[test]
fn test_verify_tpm_attestation_missing_ver() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(false, true, true, true, true, true);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing version in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_missing_alg() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(true, false, true, true, true, true);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing algorithm in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_missing_sig() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(true, true, false, true, true, true);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing signature in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_missing_x5c() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(true, true, true, false, true, true);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing certificate chain in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_missing_pub_area() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(true, true, true, true, false, true);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing pubArea in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_missing_cert_info() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(true, true, true, true, true, false);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing certInfo in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_invalid_version() {
let auth_data = create_test_auth_data_rsa();
let client_data_hash = create_test_client_data_hash();
let mut att_stmt = create_test_tpm_att_stmt(true, true, true, true, true, true);
att_stmt[0] = (
Value::Text("ver".to_string()),
Value::Text("1.0".to_string()),
);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Unsupported TPM version: 1.0"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_tpm_attestation_unsupported_algorithm() {
let auth_data = create_test_auth_data_rsa();
let client_data_hash = create_test_client_data_hash();
let mut att_stmt = create_test_tpm_att_stmt(true, true, true, true, true, true);
att_stmt[1] = (
Value::Text("alg".to_string()),
Value::Integer(999i64.into()),
);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
match result {
Err(PasskeyError::Verification(msg)) => {
println!("Actual error message: '{msg}'");
assert!(msg.contains("Unsupported algorithm for TPM attestation: 999"));
}
Err(other_error) => {
println!("Got different error type: {other_error:?}");
panic!("Expected PasskeyError::Verification, got: {other_error:?}");
}
Ok(_) => panic!("Expected error but got success"),
}
}
#[test]
fn test_verify_tpm_attestation_empty_x5c() {
let auth_data = create_test_auth_data_rsa();
let client_data_hash = create_test_client_data_hash();
let mut att_stmt = create_test_tpm_att_stmt(true, true, true, false, true, true);
att_stmt.push((Value::Text("x5c".to_string()), Value::Array(vec![])));
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Missing certificate chain in TPM attestation"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_aaguid_match_mismatch() {
let auth_data = create_test_auth_data();
let cert_aaguid = [0x02; 16];
let result = verify_aaguid_match(cert_aaguid, &auth_data);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(
msg.contains("AAGUID in AIK certificate does not match AAGUID in authenticator data")
);
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_aaguid_match_short_auth_data() {
let short_auth_data = vec![0x01; 50]; let cert_aaguid = [0x01; 16];
let result = verify_aaguid_match(cert_aaguid, &short_auth_data);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Authenticator data too short to contain AAGUID"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_extract_public_key_from_pub_area_too_short() {
let short_pub_area = vec![0x01; 4];
let result = extract_public_key_from_pub_area(&short_pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("TPM pubArea too short to parse header"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_extract_public_key_from_pub_area_unsupported_algorithm() {
let mut pub_area = Vec::new();
pub_area.extend_from_slice(&[0xFF, 0xFF]); pub_area.extend_from_slice(&[0x00, 0x0B]); pub_area.extend_from_slice(&[0x00; 8]);
let result = extract_public_key_from_pub_area(&pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Unsupported TPM algorithm type: ffff"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_extract_rsa_pub_area_insufficient_data() {
let mut pub_area = Vec::new();
pub_area.extend_from_slice(&[0x00, 0x01]); pub_area.extend_from_slice(&[0x00, 0x0B]); pub_area.extend_from_slice(&[0x00; 8]);
let result = extract_public_key_from_pub_area(&pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("TPM pubArea too short"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_extract_ecc_public_key_from_pub_area() {
let pub_area = create_test_ecc_pub_area();
let result = extract_public_key_from_pub_area(&pub_area);
assert!(result.is_ok());
if let Ok(KeyDetails::Ecc { x, y }) = result {
assert_eq!(x.len(), 32);
assert_eq!(y.len(), 32);
assert_eq!(x, vec![0x02; 32]);
assert_eq!(y, vec![0x03; 32]);
} else {
panic!("Expected ECC key details");
}
}
#[test]
fn test_verify_public_key_match_key_type_mismatch() {
let auth_data = create_test_auth_data(); let pub_area = create_test_rsa_pub_area();
let result = verify_public_key_match(&auth_data, &pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Key type mismatch or unsupported key type"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_public_key_match_rsa_success() {
let auth_data = create_test_auth_data_rsa();
let pub_area = create_test_rsa_pub_area();
let result = verify_public_key_match(&auth_data, &pub_area);
assert!(result.is_ok());
}
#[test]
fn test_verify_public_key_match_rsa_modulus_mismatch() {
let auth_data = create_test_auth_data_rsa();
let mut pub_area = create_test_rsa_pub_area();
let modulus_start = pub_area.len() - 256; pub_area[modulus_start] = 0xFF;
let result = verify_public_key_match(&auth_data, &pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("RSA modulus mismatch between credential and TPM key"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_cert_info_too_short() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let pub_area = create_test_rsa_pub_area();
let short_cert_info = vec![0x01; 5];
let result = verify_cert_info(&short_cert_info, &auth_data, &client_data_hash, &pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("TPM certInfo too short for basic parsing"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_cert_info_invalid_magic() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let pub_area = create_test_rsa_pub_area();
let mut cert_info = create_test_cert_info();
cert_info[0] = 0x00;
let result = verify_cert_info(&cert_info, &auth_data, &client_data_hash, &pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Invalid magic value"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_verify_cert_info_invalid_type() {
let auth_data = create_test_auth_data();
let client_data_hash = create_test_client_data_hash();
let pub_area = create_test_rsa_pub_area();
let mut cert_info = create_test_cert_info();
cert_info[4] = 0x00; cert_info[5] = 0x00;
let result = verify_cert_info(&cert_info, &auth_data, &client_data_hash, &pub_area);
assert!(result.is_err());
if let Err(PasskeyError::Verification(msg)) = result {
assert!(msg.contains("Invalid attestation type"));
} else {
panic!("Expected PasskeyError::Verification");
}
}
#[test]
fn test_extract_credential_public_key_no_at_flag() {
let mut auth_data = create_test_auth_data();
auth_data[32] &= !0x40;
let result = extract_credential_public_key(&auth_data);
assert!(result.is_err());
if let Err(PasskeyError::AuthenticatorData(msg)) = result {
assert!(msg.contains("Attested credential data not present"));
} else {
panic!("Expected PasskeyError::AuthenticatorData");
}
}
#[test]
fn test_extract_credential_public_key_short_auth_data() {
let short_auth_data = vec![0x01; 30];
let result = extract_credential_public_key(&short_auth_data);
assert!(result.is_err());
if let Err(PasskeyError::AuthenticatorData(msg)) = result {
assert!(msg.contains("Attested credential data not present"));
} else {
panic!("Expected PasskeyError::AuthenticatorData");
}
}
#[test]
fn test_extract_credential_public_key_insufficient_cred_id_length() {
let mut auth_data = Vec::new();
auth_data.extend_from_slice(&[0x01; 32]); auth_data.push(0x40); auth_data.extend_from_slice(&[0x00; 4]); auth_data.extend_from_slice(&[0x01; 16]); auth_data.push(0x00);
let result = extract_credential_public_key(&auth_data);
assert!(result.is_err());
if let Err(PasskeyError::AuthenticatorData(msg)) = result {
assert!(msg.contains("Authenticator data too short for credential ID length"));
} else {
panic!("Expected PasskeyError::AuthenticatorData");
}
}
#[test]
fn test_extract_credential_public_key_success() {
let auth_data = create_test_auth_data();
let result = extract_credential_public_key(&auth_data);
assert!(result.is_ok());
if let Ok(Value::Map(key_map)) = result {
let kty = key_map.iter().find(|(k, _)| {
if let Value::Integer(i) = k {
integer_to_i64(i) == 1 } else {
false
}
});
if let Some((_, Value::Integer(kty_val))) = kty {
assert_eq!(integer_to_i64(kty_val), 2); } else {
panic!("Expected kty field in credential public key");
}
} else {
panic!("Expected CBOR map for credential public key");
}
}
#[test]
fn test_verify_tpm_attestation_success() {
let auth_data = create_test_auth_data_rsa();
let client_data_hash = create_test_client_data_hash();
let att_stmt = create_test_tpm_att_stmt(true, true, true, true, true, true);
let result = verify_tpm_attestation(&auth_data, &client_data_hash, &att_stmt);
assert!(result.is_err());
}