diff --git a/crates/attestation/src/apple.rs b/crates/attestation/src/apple.rs index b693d257..67bfc6bb 100644 --- a/crates/attestation/src/apple.rs +++ b/crates/attestation/src/apple.rs @@ -34,6 +34,7 @@ const ACL: &[u8] = &[ 0x63, 0x30, 0x05, 0xa6, 0x03, 0x02, 0x01, 0x01, ]; const PRODUCTION_AAGUID: &[u8; 16] = b"appattest\0\0\0\0\0\0\0"; +const AUTH_DATA_FLAGS: u8 = 0xc0; const APP_ATTEST_ROOT_CA_BASE64: &str = "MIICITCCAaegAwIBAgIQC/O+DvHN0uD7jG5yH2IXmDAKBggqhkjOPQQDAzBSMSYwJAYDVQQDDB1BcHBsZSBBcHAgQXR0ZXN0YXRpb24gUm9vdCBDQTETMBEGA1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0yMDAzMTgxODMyNTNaFw00NTAzMTUwMDAwMDBaMFIxJjAkBgNVBAMMHUFwcGxlIEFwcCBBdHRlc3RhdGlvbiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAERTHhmLW07ATaFQIEVwTtT4dyctdhNbJhFs/Ii2FdCgAHGbpphY3+d8qjuDngIN3WVhQUBHAoMeQ/cLiP1sOUtgjqK9auYen1mMEvRq9Sk3Jm5X8U62H+xTD3FE9TgS41o0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSskRBTM72+aEH/pwyp5frq5eWKoTAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwQgFGnByvsiVbpTKwSga0kP0e8EeDS4+sQmTvb7vn53O5+FRXgeLhpJ06ysC5PrOyAjEAp5U4xDgEgllF7En3VcE3iexZZtKeYnpqtijVoyFraWVIyd/dganmrduC1bmTBGwD"; /// Apple's pinned App Attestation Root CA in DER form. @@ -316,7 +317,11 @@ fn attestation_auth_data( data: &[u8], rp_id_hash: [u8; 32], ) -> Result, AttestationError> { - if data.len() < 55 || data[..32] != rp_id_hash || data[32] != 0x40 || data[33..37] != [0; 4] { + if data.len() < 55 + || data[..32] != rp_id_hash + || data[32] != AUTH_DATA_FLAGS + || data[33..37] != [0; 4] + { return Err(AttestationError::Credential); } if data[37..53] != *PRODUCTION_AAGUID { @@ -339,7 +344,7 @@ fn attestation_auth_data( } fn assertion_auth_data(data: &[u8]) -> Result { - if data.len() < 37 || data[32] != 0x40 { + if data.len() < 37 || data[32] != AUTH_DATA_FLAGS { return Err(AttestationError::Binding); } let cd_hash = apple_cd_hash(&data[37..], "Apple authenticator extensions")?; diff --git a/crates/attestation/tests/apple.rs b/crates/attestation/tests/apple.rs index 751bdc11..03e82eda 100644 --- a/crates/attestation/tests/apple.rs +++ b/crates/attestation/tests/apple.rs @@ -17,10 +17,10 @@ use serde_bytes::ByteBuf; use sha2::{Digest as _, Sha256}; const APP_ID: &str = "2F53L9ZR3N.ai.hellas.app-attest-spike"; -const FIXTURE_VALIDATION_TIME: u64 = 1_784_384_387; +const FIXTURE_VALIDATION_TIME: u64 = 1_790_996_283; const REAL_CD_HASH: [u8; 32] = [ - 0xcb, 0x92, 0xa8, 0x90, 0x91, 0x54, 0x57, 0xb2, 0x26, 0xfe, 0xa9, 0xbe, 0x77, 0x8f, 0xc6, 0xa2, - 0x99, 0x94, 0xa2, 0xc6, 0x0d, 0xfa, 0xa6, 0x03, 0x71, 0xe9, 0xe2, 0x64, 0xd8, 0x54, 0x13, 0x06, + 0x36, 0x31, 0x40, 0xc0, 0x91, 0xe0, 0xfa, 0x85, 0xfe, 0xee, 0xb4, 0xce, 0x51, 0x5e, 0xdd, 0xca, + 0xe8, 0xcf, 0x6d, 0xb4, 0x5b, 0x93, 0xb2, 0xca, 0x72, 0x23, 0x91, 0xa3, 0xa6, 0x4c, 0x10, 0x06, ]; struct Fixture { @@ -31,16 +31,16 @@ struct Fixture { } fn fixture() -> Fixture { - fn field(name: &str) -> &'static str { - include_str!("fixtures/real-app-attest.json") - .lines() + let json = include_str!("fixtures/real-app-attest.json"); + let field = |name: &str| { + json.lines() .find_map(|line| { let (key, value) = line.trim().split_once(" : ")?; (key.trim_matches('"') == name) .then(|| value.trim_end_matches(',').trim_matches('"')) }) .unwrap() - } + }; Fixture { attestation_object_base64: field("attestationObjectBase64"), attestation_client_data_hash_hex: field("attestationClientDataHashHex"), @@ -112,7 +112,7 @@ fn assertion( let mut authenticator_data = Vec::new(); authenticator_data.extend_from_slice(&rp_id_hash); - authenticator_data.push(0x40); + authenticator_data.push(0xc0); authenticator_data.extend_from_slice(&counter.to_be_bytes()); authenticator_data.extend_from_slice(&extension_bytes); signed_assertion(signing_key, authenticator_data, client_data_hash) @@ -180,7 +180,7 @@ fn real_assertion_verifies_with_app_rp_id_and_direct_cd_hash_allowlist() { assert_eq!(claims.cd_hash, REAL_CD_HASH); assert_eq!(appraise_apple(&claims, &policy), AppleVerdict::Accepted); - let legacy_hashed_cd_policy = ApplePolicy { + let hashed_cd_policy = ApplePolicy { expected_rp_id_hash: apple_app_id_hash(APP_ID), allowed_cd_hashes: vec![Sha256::digest(REAL_CD_HASH).into()], }; @@ -189,7 +189,7 @@ fn real_assertion_verifies_with_app_rp_id_and_direct_cd_hash_allowlist() { &assertion, &client_data_hash, ®istered, - &legacy_hashed_cd_policy, + &hashed_cd_policy, ), Err(AttestationError::Credential) ); @@ -204,8 +204,8 @@ fn credential_identity_extracts_real_build_identity_without_rp_id_relation() { assert_eq!(identity.public_key, registered_fixture(&fixture).public_key); assert_eq!(identity.rp_id_hash, apple_app_id_hash(APP_ID)); assert_eq!(identity.cd_hash, REAL_CD_HASH); - let legacy_rp_id_hash: [u8; 32] = Sha256::digest(identity.cd_hash).into(); - assert_ne!(apple_app_id_hash(APP_ID), legacy_rp_id_hash); + let hashed_cd_hash: [u8; 32] = Sha256::digest(identity.cd_hash).into(); + assert_ne!(apple_app_id_hash(APP_ID), hashed_cd_hash); } #[test] @@ -284,7 +284,7 @@ fn rejects_signed_assertion_that_omits_cd_hash_evidence() { }; let mut authenticator_data = Vec::new(); authenticator_data.extend_from_slice(&rp_id_hash); - authenticator_data.push(0x40); + authenticator_data.push(0xc0); authenticator_data.extend_from_slice(&1_u32.to_be_bytes()); let assertion = signed_assertion(&signing_key, authenticator_data, &client_data_hash); @@ -294,6 +294,62 @@ fn rejects_signed_assertion_that_omits_cd_hash_evidence() { ); } +#[test] +fn rejects_credential_with_invalid_authenticator_flags() { + let credential = fixture_credential(&fixture()); + let mut object: BTreeMap = + ciborium::from_reader(credential.attestation.as_slice()).unwrap(); + + for flags in [0x00, 0x40, 0x80, 0xc1] { + object.get_mut("authData").unwrap().as_bytes_mut().unwrap()[32] = flags; + let mut attestation = Vec::new(); + ciborium::into_writer(&object, &mut attestation).unwrap(); + + assert_eq!( + apple_credential_identity(&attestation), + Err(AttestationError::Credential) + ); + assert_eq!( + register_apple( + &AppleCredential { + attestation, + client_data_hash: credential.client_data_hash, + }, + apple_app_id_hash(APP_ID), + apple_app_attest_root_ca(), + AnchorTime(FIXTURE_VALIDATION_TIME), + ), + Err(AttestationError::Credential) + ); + } +} + +#[test] +fn rejects_signed_assertion_with_invalid_authenticator_flags() { + let fixture = fixture(); + let signing_key = signing_key(); + let registered = registered(&signing_key); + let client_data_hash = decode_hex_32(fixture.assertion_client_data_hash_hex); + let assertion = decode_base64(fixture.assertion_object_base64); + let mut object: BTreeMap = + ciborium::from_reader(assertion.as_slice()).unwrap(); + let mut auth_data = object.remove("authenticatorData").unwrap().into_vec(); + let policy = ApplePolicy { + expected_rp_id_hash: apple_app_id_hash(APP_ID), + allowed_cd_hashes: vec![REAL_CD_HASH], + }; + + for flags in [0x00, 0x40, 0x80, 0xc1] { + auth_data[32] = flags; + let assertion = signed_assertion(&signing_key, auth_data.clone(), &client_data_hash); + + assert_eq!( + verify_apple_assertion(&assertion, &client_data_hash, ®istered, &policy), + Err(AttestationError::Binding) + ); + } +} + #[test] fn repeated_verification_does_not_advance_counter_state() { let signing_key = signing_key(); diff --git a/crates/attestation/tests/fixtures/real-app-attest.json b/crates/attestation/tests/fixtures/real-app-attest.json index bfe0c388..80959f5e 100644 --- a/crates/attestation/tests/fixtures/real-app-attest.json +++ b/crates/attestation/tests/fixtures/real-app-attest.json @@ -1,44 +1,6 @@ { - "appAttestSupported" : true, - "artifacts" : { - "assertionClientDataHashHex" : "df4bbe79ea41b84fc6aec3935e949f40698d5c714667aa1a7be446de959541ca", - "assertionNonceBase64" : "7G6339ApM45JA2/Bk1nJX0WdvQhycOGfyc0CAwJk9Xc=", - "assertionObjectBase64" : "omlzaWduYXR1cmVYSDBGAiEArgYZlV4ENGjcEL2VxZ+VV+AKIR4t0+CHtnQYsQGJaCQCIQDKtWNuxQ/aPsF2b9ofegvPA7BHZB3TQIWOKTEgefmXGHFhdXRoZW50aWNhdG9yRGF0YViZl3UZ9S7UG1oAfJ1f4CeSJqkc2TZAHMPIDLB1ASegE0tAAAAAAaN1YXBwbGVfY2RfaGFzaF9oYXNoXzAxWCDLkqiQkVRXsib+qb53j8aimZSixg36pgNx6eJk2FQTBnVhcHBsZV9jZF9oYXNoX3R5cGVfMDFBAngcYXBwbGVfdmFsaWRhdGlvbl9jYXRlZ29yeV8wMUQGAAAA", - "assertionPayloadBase64" : "aGVsbGFzLmFwcGxlLWFwcC1hdHRlc3Qtc3Bpa2UuYXNzZXJ0aW9uLnYxAOxut9/QKTOOSQNvwZNZyV9Fnb0IcnDhn8nNAgMCZPV3", - "attestationChallengeBase64" : "GD3UMXdx6WT/5pKeDvaQVCiQEOoPBNEMoCgTzSssXZU=", - "attestationClientDataHashHex" : "26c08c91dc152cdaecb81a3a5384dbc87e4502c996d1fa4aee637525db499734", - "attestationObjectBase64" : "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", - "keyIdentifier" : "gbxSfmDc1Jkgjf6idf4SLy/Ir9+z+A8pEI1v+qfcdOY=" - }, - "bundleIdentifier" : "ai.hellas.app-attest-spike", - "capturedAt" : "2026-07-18T14:19:43Z", - "operatingSystem" : "Version 27.0 (Build 26A5378n)", - "schema" : "hellas.apple-app-attest-spike.v1", - "steps" : [ - { - "detail" : "true", - "name" : "isSupported", - "outcome" : "passed" - }, - { - "detail" : "gbxSfmDc1Jkgjf6idf4SLy/Ir9+z+A8pEI1v+qfcdOY=", - "name" : "generateKey", - "outcome" : "passed" - }, - { - "detail" : "received 5968 bytes", - "name" : "attestKey", - "outcome" : "passed" - }, - { - "detail" : "received 258 bytes", - "name" : "generateAssertion", - "outcome" : "passed" - }, - { - "detail" : "generateKey -> attestKey -> generateAssertion", - "name" : "end-to-end", - "outcome" : "passed" - } - ] -} \ No newline at end of file + "attestationObjectBase64" : "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", + "attestationClientDataHashHex" : "e5a2902c3e6603b8f3230c74e543dfb1c88d738709c3e3e63ccae697251ea4dc", + "assertionObjectBase64" : "omlzaWduYXR1cmVYRzBFAiAjCdbtIHxiktZ9XiKkrbAm86549C9DqS9YoSnyCg5AHwIhAJaQ9rx9pOyn6sDQSzwtcamnLUwcbxHIdBzrnyFOzKzUcWF1dGhlbnRpY2F0b3JEYXRhWJmXdRn1LtQbWgB8nV/gJ5ImqRzZNkAcw8gMsHUBJ6ATS8AAAAABo3VhcHBsZV9jZF9oYXNoX2hhc2hfMDFYIDYxQMCR4PqF/u60zlFe3croz220W5OyynIjkaOmTBAGdWFwcGxlX2NkX2hhc2hfdHlwZV8wMUECeBxhcHBsZV92YWxpZGF0aW9uX2NhdGVnb3J5XzAxRAYAAAA=", + "assertionClientDataHashHex" : "e5a2902c3e6603b8f3230c74e543dfb1c88d738709c3e3e63ccae697251ea4dc" +} diff --git a/crates/chain/src/node/tests.rs b/crates/chain/src/node/tests.rs index e20fec74..3b7a564c 100644 --- a/crates/chain/src/node/tests.rs +++ b/crates/chain/src/node/tests.rs @@ -926,17 +926,27 @@ fn full_node_and_validator_execution_roles_share_the_same_directory() { let archive = archive.start_unbuffered(mailbox.clone(), (receiver, resolver)); let execution = execution.start(); let database = mailbox.subscribe_databases().await; - assert_eq!( - pipeline::restore( - &indexer, - &database, - &owner, - startup.into_iter().chain(processed).max() - ) - .await - .unwrap(), - 1 - ); + // Database attachment precedes replay of blocks whose execution + // was committed before shutdown but not yet acknowledged. + let restored = tokio::time::timeout(Duration::from_secs(10), async { + loop { + let height = pipeline::restore( + &indexer, + &database, + &owner, + startup.into_iter().chain(processed).max(), + ) + .await + .unwrap(); + if height > 0 { + break height; + } + tokio::time::sleep(Duration::from_millis(5)).await; + } + }) + .await + .unwrap(); + assert_eq!(restored, 1); assert_eq!(database.read().await.root(), first.snapshot.state_root); let client = LocalLightClient::new( database.clone(), @@ -986,13 +996,12 @@ fn full_node_and_validator_execution_roles_share_the_same_directory() { .unwrap(); let node = FullNode::start(fixture.config.clone()).await.unwrap(); node.0.core.observe(&second).unwrap(); + let view = tokio::time::timeout(Duration::from_secs(10), node.wait_ready()) + .await + .unwrap() + .unwrap(); assert_eq!( - node.view() - .unwrap() - .client() - .get_state_root() - .await - .unwrap(), + view.client().get_state_root().await.unwrap(), Some(second.snapshot.state_root) ); node.0.core.apply(fixture.next().await).await.unwrap(); diff --git a/crates/client/src/iroh/tests.rs b/crates/client/src/iroh/tests.rs index 8323e833..6d3e6295 100644 --- a/crates/client/src/iroh/tests.rs +++ b/crates/client/src/iroh/tests.rs @@ -109,7 +109,7 @@ fn apple_assertion( let mut authenticator_data = Vec::new(); authenticator_data.extend_from_slice(&rp_id_hash); - authenticator_data.push(0x40); + authenticator_data.push(0xc0); authenticator_data.extend_from_slice(&counter.to_be_bytes()); authenticator_data.extend_from_slice(&extension_bytes); let digest = Sha256::digest([authenticator_data.as_slice(), client_data_hash].concat()); @@ -264,12 +264,11 @@ fn apple_enrollment_is_registered_once_per_trust_anchor() { "../../../attestation/tests/fixtures/real-app-attest.json" )) .unwrap(); - let artifacts = &fixture["artifacts"]; let attestation_object = STANDARD - .decode(artifacts["attestationObjectBase64"].as_str().unwrap()) + .decode(fixture["attestationObjectBase64"].as_str().unwrap()) .unwrap(); let client_data_hash: [u8; 32] = - hex::decode(artifacts["attestationClientDataHashHex"].as_str().unwrap()) + hex::decode(fixture["attestationClientDataHashHex"].as_str().unwrap()) .unwrap() .try_into() .unwrap(); @@ -278,7 +277,7 @@ fn apple_enrollment_is_registered_once_per_trust_anchor() { let enrollment = AppleAppAttestEnrollment { attestation_object, client_data_hash, - validation_time: 1_784_384_387, + validation_time: 1_790_996_283, }; let first = apple.registered_credential(&enrollment).unwrap(); diff --git a/crates/sdk/src/provider/grant_tests.rs b/crates/sdk/src/provider/grant_tests.rs index 9f7b829e..45978ed8 100644 --- a/crates/sdk/src/provider/grant_tests.rs +++ b/crates/sdk/src/provider/grant_tests.rs @@ -77,14 +77,18 @@ async fn tls_fixture() -> ( ) { use rcgen::*; let mut params = CertificateParams::default(); + params + .distinguished_name + .push(DnType::CommonName, "Hellas test CA"); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); params.key_usages = vec![KeyUsagePurpose::KeyCertSign]; let ca = CertifiedIssuer::self_signed(params, KeyPair::generate().unwrap()).unwrap(); let key = KeyPair::generate().unwrap(); - let leaf = CertificateParams::new(vec!["localhost".into()]) - .unwrap() - .signed_by(&key, &ca) - .unwrap(); + let mut params = CertificateParams::new(vec!["localhost".into()]).unwrap(); + params + .distinguished_name + .push(DnType::CommonName, "localhost"); + let leaf = params.signed_by(&key, &ca).unwrap(); let config = rustls::ServerConfig::builder_with_provider(Arc::new( rustls::crypto::ring::default_provider(), ))