diff --git a/crates/attestation/assets/global-virtual-tpm-ca-03.pem b/crates/attestation/assets/global-virtual-tpm-ca-03.pem deleted file mode 100644 index a8753d0..0000000 --- a/crates/attestation/assets/global-virtual-tpm-ca-03.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFnDCCA4SgAwIBAgITMwAAAAknQOWscnsOpgAAAAAACTANBgkqhkiG9w0BAQwF -ADBpMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u -MTowOAYDVQQDEzFBenVyZSBWaXJ0dWFsIFRQTSBSb290IENlcnRpZmljYXRlIEF1 -dGhvcml0eSAyMDIzMB4XDTI1MDQyNDE4MDExN1oXDTI3MDQyNDE4MDExN1owJTEj -MCEGA1UEAxMaR2xvYmFsIFZpcnR1YWwgVFBNIENBIC0gMDMwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDYGYtis5ka0cxQkhU11jslgX6wzjR/UXQIFdUn -8juTUMJl91VokwUPX3WfXeog7mtbWyYWD8SI0BSnchRGlV8u3AhcW61/HetHqmIL -tD0c75UATi+gsTQnpwKPA/m38MGGyXFETr3xHXjilUPfIhmxO4ImuNJ0R95bZYhx -bLYmOZpVUcj8oz980An8HlIqSzrskQR6NiuEmikHkHc1/CpoNunrr8kQNPF6gxex -IrvXsKLUAuUqnNtcQWc/8Er5EN9+TdX6AOjUmKriVGbCInP1m/aC+DWH/+aJ/8aD -pKze6fe7OHh2BL9hxqIsmJAStIh4siRdLYTt8hKGmkdzOWnRAgMBAAGjggF/MIIB -ezASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwICBDAXBgNVHSUEEDAO -BgVngQUIAQYFZ4EFCAMwHQYDVR0OBBYEFGcJhvj5gV6TrfnJZOcUCtqZywotMB8G -A1UdIwQYMBaAFEv+JlqUwfYzw4NIJt3z5bBksqqVMHYGA1UdHwRvMG0wa6BpoGeG -ZWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL0F6dXJlJTIwVmly -dHVhbCUyMFRQTSUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIw -MjMuY3JsMIGDBggrBgEFBQcBAQR3MHUwcwYIKwYBBQUHMAKGZ2h0dHA6Ly93d3cu -bWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvQXp1cmUlMjBWaXJ0dWFsJTIwVFBN -JTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMy5jcnQwDQYJ -KoZIhvcNAQEMBQADggIBAJPP3Z2z1zhzUS3qSRVgyoUVnaxCGuMHzPQAZuoPBVpz -wKnv4HqyjMgT8pBtQqxkqAsg7KiqbPfO97bMCHcuqkkfHjw8yg6IYt01RjUjVPKq -lrsY2iw7hFWNWr8SGMa10JdNYNyf5dxob5+mKAwEOhLzKNwq9rM/uIvZky77pNly -RLt55XEPfBMYdI9I8uQ5Uqmrw7mVJfERMfTBhSQF9BrcajAsaLcs7qEUyj0yUdJf -cgZkfCoUEUSPr3OwLHaYeV1J6VidhIYsYo53sXXal91d60NspYgei2nJFei/+R3E -SWnGbPBW+EQ4FbvZXxu57zUMX9mM7lC+GoXLvA6/vtKShEi9ZXl2PSnBQ/R2A7b3 -AXyg4fmMLFausEk6OiuU8E/bvp+gPLOJ8YrX7SAJVuEn+koJaK5G7os5DMIh7/KM -l9cI9WxPwqoWjp4VBfrF4hDOCmKWrqtFUDQCML8qD8RTxlQKQtgeGAcNDfoAuL9K -VtSG5/iIhuyBEFYEHa3vRWbSaHCUzaHJsTmLcz4cp1VDdepzqZRVuErBzJKFnBXb -zRNW32EFmcAUKZImIsE5dgB7y7eiijf33VWNfWmK05fxzQziWFWRYlET4SVc3jMn -PBiY3N8BfK8EBOYbLvzo0qn2n3SAmPhYX3Ag6vbbIHd4Qc8DQKHRV0PB8D3jPGmD ------END CERTIFICATE----- diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index 9213334..e91d4b8 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -32,30 +32,6 @@ const MICROSOFT_RSA_DEVICES_ROOT_2021: &str = const AZURE_VIRTUAL_TPM_ROOT_2023: &str = include_str!("../../assets/azure-virtual-tpm-root-2023.pem"); -// globalVirtualTPMCA03 is the intermediate CA that issues TDX vTPM AK -// certificates Source: https://learn.microsoft.com/en-us/azure/virtual-machines/trusted-launch-faq -// Issuer: Azure Virtual TPM Root Certificate Authority 2023 -// Valid: 2025-04-24 to 2027-04-24 -const GLOBAL_VIRTUAL_TPMCA03_PEM: &str = include_str!("../../assets/global-virtual-tpm-ca-03.pem"); - -/// Legacy Azure intermediate certificates bundled with this crate. -/// -/// Deprecated verification-only fallback: this is kept only for backwards -/// compatibility with older evidence that did not serialize AIA-fetched -/// intermediates. New Azure vTPM evidence should carry the AK issuer chain -/// fetched from AIA instead of relying on this bundled, eventually-stale -/// list. -/// -/// Do not use this when generating new evidence or when deciding whether an -/// AIA-fetched issuer chain is complete. It should be removed once -/// supporting legacy evidence without `ak_intermediate_certificates_pem` is -/// no longer required. -static LEGACY_BUNDLED_AZURE_INTERMEDIATES: Lazy>> = Lazy::new(|| { - let (_type_label, cert_der) = - pem_rfc7468::decode_vec(GLOBAL_VIRTUAL_TPMCA03_PEM.as_bytes()).expect("Cannot decode PEM"); - vec![CertificateDer::from(cert_der)] -}); - /// The root anchors for azure static AZURE_ROOT_ANCHORS: Lazy>> = Lazy::new(|| { vec![ @@ -68,50 +44,17 @@ static AZURE_ROOT_ANCHORS: Lazy>> = Lazy::new(|| { /// Verify an AK certificate against pinned Azure root CAs. /// -/// This includes `LEGACY_BUNDLED_AZURE_INTERMEDIATES` as a -/// verification-only fallback so older evidence captured before AIA-fetched -/// intermediates were serialized continues to verify. +/// `intermediate_cert_ders` are untrusted evidence from the attestation (or +/// fetched from AIA during generation); verification pins the Azure roots. pub(crate) fn verify_ak_cert_with_azure_roots( ak_cert_der: &[u8], intermediate_cert_ders: &[Vec], now_secs: u64, -) -> Result<(), MaaError> { - verify_ak_cert_with_azure_roots_inner(ak_cert_der, intermediate_cert_ders, now_secs, true) -} - -/// Verify an AK certificate against pinned Azure root CAs using only the -/// intermediates supplied by the caller. -/// -/// This is used while following AIA URLs during evidence generation. After -/// each fetched issuer is appended, we call this to check whether the -/// fetched chain is already complete. It intentionally excludes the legacy -/// bundled intermediates, otherwise generation could stop early because a -/// hardcoded intermediate completed the path, and the serialized evidence -/// would still depend on that legacy fallback. -fn verify_ak_cert_with_provided_intermediates_only( - ak_cert_der: &[u8], - intermediate_cert_ders: &[Vec], - now_secs: u64, -) -> Result<(), MaaError> { - verify_ak_cert_with_azure_roots_inner(ak_cert_der, intermediate_cert_ders, now_secs, false) -} - -fn verify_ak_cert_with_azure_roots_inner( - ak_cert_der: &[u8], - intermediate_cert_ders: &[Vec], - now_secs: u64, - include_legacy_bundled_intermediates: bool, ) -> Result<(), MaaError> { let ak_cert_der: CertificateDer = ak_cert_der.into(); let end_entity_cert = EndEntityCert::try_from(&ak_cert_der)?; - - let mut intermediates = if include_legacy_bundled_intermediates { - LEGACY_BUNDLED_AZURE_INTERMEDIATES.clone() - } else { - Vec::new() - }; - intermediates.extend(intermediate_cert_ders.iter().cloned().map(CertificateDer::from)); - + let intermediates: Vec<_> = + intermediate_cert_ders.iter().cloned().map(CertificateDer::from).collect(); let now = UnixTime::since_unix_epoch(Duration::from_secs(now_secs)); end_entity_cert.verify_for_usage( @@ -145,9 +88,7 @@ pub(crate) fn fetch_ak_intermediates_from_aia( now_secs: u64, ) -> Result>, MaaError> { let mut intermediates = Vec::new(); - if verify_ak_cert_with_provided_intermediates_only(ak_cert_der, &intermediates, now_secs) - .is_ok() - { + if verify_ak_cert_with_azure_roots(ak_cert_der, &intermediates, now_secs).is_ok() { return Ok(intermediates); } @@ -159,9 +100,7 @@ pub(crate) fn fetch_ak_intermediates_from_aia( issuer_urls = fetched_issuer.ca_issuers_urls; intermediates.push(fetched_issuer.der); - if verify_ak_cert_with_provided_intermediates_only(ak_cert_der, &intermediates, now_secs) - .is_ok() - { + if verify_ak_cert_with_azure_roots(ak_cert_der, &intermediates, now_secs).is_ok() { return Ok(intermediates); } else if intermediates.len() == MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES { return Err(MaaError::AkIssuerChainTooDeep { diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index eb31173..e0953a3 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -668,7 +668,6 @@ mod test_utils { #[cfg(test)] mod tests { use super::*; - use crate::measurements::MeasurementPolicy; fn input_data_from_attestation(attestation_bytes: &[u8]) -> [u8; 64] { let attestation_document: AttestationDocument = @@ -695,76 +694,11 @@ mod tests { assert_eq!(hex::decode(var_data_values["user-data"].as_str().unwrap()).unwrap().len(), 64); } - /// Verify a stored attestation from a test-deployment on azure - #[tokio::test] - async fn test_verify() { - let attestation_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-tdx-1764662251380464271.yaml"); - - // To avoid this test stopping working when the certificate is no longer - // valid we pass in a timestamp - let now = 1771423480; - - let measurements_json = br#" - [{ - "measurement_id": "cvm-image-azure-tdx.rootfs-20241107200854.wic.vhd", - "attestation_type": "azure-tdx", - "measurements": { - "4": { - "expected": "c4a25a6d7704629f63db84d20ea8db0e9ce002b2801be9a340091fe7ac588699" - }, - "9": { - "expected": "9f4a5775122ca4703e135a9ae6041edead0064262e399df11ca85182b0f1541d" - }, - "11": { - "expected": "abd7c695ffdb6081e99636ee016d1322919c68d049b698b399d22ae215a121bf" - } - } - }] - "#; - - let measurement_policy = - MeasurementPolicy::from_json_bytes(measurements_json.to_vec()).unwrap(); - - let collateral_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-collateral02.yaml"); - - let async_collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); - let sync_collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); - let attestation_json = serde_json::to_vec( - &serde_saphyr::from_slice::(attestation_bytes).unwrap(), - ) - .unwrap(); - - let async_measurements = verify_azure_attestation_with_given_timestamp( - attestation_json.clone(), - [0; 64], // Input data - None, - async_collateral, - now, - false, - ) - .await - .unwrap(); - - let sync_measurements = verify_azure_attestation_with_given_timestamp_sync( - attestation_json, - [0; 64], // Input data - Pccs::new_without_prewarm(None), - sync_collateral, - now, - false, - ) - .unwrap(); - - assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements).unwrap(); - } - /// Verify a complete observed Azure attestation payload that includes /// AK intermediates fetched from the leaf certificate's AIA URLs. #[tokio::test] - async fn test_verify_with_observed_ak_intermediates() { + async fn test_verify() { + // generated using [capture_azure_fixture] above. let attestation_bytes: &'static [u8] = include_bytes!("../../test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml"); let collateral_bytes: &'static [u8] = include_bytes!(