From d3c644b89bd00f3b94c13f3e8d258f499b92e0d8 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 6 Mar 2026 09:26:36 +0100 Subject: [PATCH 1/2] Use attestation crate from new `attested-tls` repo --- Cargo.lock | 4 +- Cargo.toml | 6 +- attestation/Cargo.toml | 59 -- attestation/src/azure/ak_certificate.rs | 202 ----- attestation/src/azure/mod.rs | 456 ---------- attestation/src/azure/nv_index.rs | 21 - attestation/src/dcap.rs | 255 ------ attestation/src/lib.rs | 549 ------------ attestation/src/measurements.rs | 833 ------------------ attestation/src/test_helpers.rs | 13 - attestation/test-assets/azure-collateral.json | 1 - .../test-assets/azure-collateral02.json | 1 - .../test-assets/azure-tdx-1764662251380464271 | 1 - .../azure_failed_dcap_quote_10.bin | Bin 5006 -> 0 bytes .../test-assets/dcap-quote-collateral-00.json | 1 - .../test-assets/dcap-tdx-1766059550570652607 | Bin 8000 -> 0 bytes attestation/test-assets/hclreport.bin | Bin 2600 -> 0 bytes attestation/test-assets/measurements.json | 50 -- attestation/test-assets/measurements_2.json | 5 - attested-tls/Cargo.toml | 10 +- attested-tls/src/test_helpers.rs | 2 +- 21 files changed, 9 insertions(+), 2460 deletions(-) delete mode 100644 attestation/Cargo.toml delete mode 100644 attestation/src/azure/ak_certificate.rs delete mode 100644 attestation/src/azure/mod.rs delete mode 100644 attestation/src/azure/nv_index.rs delete mode 100644 attestation/src/dcap.rs delete mode 100644 attestation/src/lib.rs delete mode 100644 attestation/src/measurements.rs delete mode 100644 attestation/src/test_helpers.rs delete mode 100644 attestation/test-assets/azure-collateral.json delete mode 100644 attestation/test-assets/azure-collateral02.json delete mode 100644 attestation/test-assets/azure-tdx-1764662251380464271 delete mode 100644 attestation/test-assets/azure_failed_dcap_quote_10.bin delete mode 100644 attestation/test-assets/dcap-quote-collateral-00.json delete mode 100644 attestation/test-assets/dcap-tdx-1766059550570652607 delete mode 100644 attestation/test-assets/hclreport.bin delete mode 100644 attestation/test-assets/measurements.json delete mode 100644 attestation/test-assets/measurements_2.json diff --git a/Cargo.lock b/Cargo.lock index f30b0c1..f2aa5c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -506,6 +506,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attestation" version = "0.0.1" +source = "git+https://github.com/flashbots/attested-tls?branch=peg%2Fadd-attestation-crate#f330b2ff9913a6dd6c25f17c2a289058c5a32c8d" dependencies = [ "anyhow", "az-tdx-vtpm", @@ -525,7 +526,6 @@ dependencies = [ "serde", "serde_json", "tdx-quote", - "tempfile", "thiserror 2.0.17", "time", "tokio", @@ -1178,7 +1178,7 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dcap-qvl" version = "0.3.12" -source = "git+https://github.com/flashbots/dcap-qvl.git?branch=peg%2Fazure-outdated-tcp-override#3d1d4ba96add015ad23109c4df5fb6730182efaa" +source = "git+https://github.com/flashbots/dcap-qvl.git?branch=peg%2Fazure-outdated-tcp-override#b61d8f3ffb59f225d7b98220e2185a66f1c7f8c7" dependencies = [ "anyhow", "asn1_der", diff --git a/Cargo.toml b/Cargo.toml index 305efca..bfb5ab9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = [".", "attestation-provider-server", "attested-tls", "attestation"] +members = [".", "attestation-provider-server", "attested-tls"] [package] name = "attested-tls-proxy" @@ -13,9 +13,7 @@ keywords = ["attested-TLS", "CVM", "TDX"] [dependencies] attested-tls = { path = "attested-tls", default-features = false } tokio = { version = "1.48.0", features = ["full"] } -tokio-rustls = { version = "0.26.4", default-features = false, features = [ - "ring", -] } +tokio-rustls = { version = "0.26.4", default-features = false } x509-parser = { version = "0.18.0", features = ["verify"] } thiserror = "2.0.17" clap = { version = "4.5.51", features = ["derive", "env"] } diff --git a/attestation/Cargo.toml b/attestation/Cargo.toml deleted file mode 100644 index 2b6dc8b..0000000 --- a/attestation/Cargo.toml +++ /dev/null @@ -1,59 +0,0 @@ -[package] -name = "attestation" -version = "0.0.1" -edition = "2024" -license = "MIT" -description = "Attestation generation and verification, and measurement policy handling" -repository = "https://github.com/flashbots/attested-tls-proxy" -keywords = ["attestation", "CVM", "TDX"] - -[dependencies] -tokio = { version = "1.48.0", features = ["fs"] } -tokio-rustls = { version = "0.26.4", default-features = false, features = [ - "ring", -] } -x509-parser = "0.18.0" -thiserror = "2.0.17" -anyhow = "1.0.100" -pem-rfc7468 = { version = "0.7.0", features = ["std"] } -configfs-tsm = "0.0.2" -rand_core = { version = "0.6.4", features = ["getrandom"] } -dcap-qvl = { git = "https://github.com/flashbots/dcap-qvl.git", branch = "peg/azure-outdated-tcp-override", features = ["danger-allow-tcb-override"] } -hex = "0.4.3" -http = "1.3.1" -serde_json = "1.0.145" -serde = "1.0.228" -base64 = "0.22.1" -reqwest = { version = "0.12.23", default-features = false, features = [ - "rustls-tls-webpki-roots-no-provider", -] } -tracing = "0.1.41" -parity-scale-codec = "3.7.5" -openssl = "0.10.75" -num-bigint = "0.4.6" -webpki = { package = "rustls-webpki", version = "0.103.8" } -time = "0.3.47" -once_cell = "1.21.3" - -# Used for azure vTPM attestation support -az-tdx-vtpm = { version = "0.7.4", optional = true } -tss-esapi = { version = "7.6.0", optional = true } - -# Used by test helpers -tdx-quote = { version = "0.0.5", features = ["mock"], optional = true } - -[dev-dependencies] -tempfile = "3.23.0" -tdx-quote = { version = "0.0.5", features = ["mock"] } - -[features] -default = [] - -# Adds support for Microsoft Azure attestation generation and verification -azure = ["tss-esapi", "az-tdx-vtpm"] - -# Exposes helper functions for testing - do not enable in production as this allows dangerous configuration -test-helpers = [] - -# Allows mock quotes used in tests -mock = ["tdx-quote"] diff --git a/attestation/src/azure/ak_certificate.rs b/attestation/src/azure/ak_certificate.rs deleted file mode 100644 index 0e4d258..0000000 --- a/attestation/src/azure/ak_certificate.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! Generation and verification of AK certificates from the vTPM -use crate::azure::{MaaError, nv_index}; -use once_cell::sync::Lazy; -use std::time::Duration; -use tokio_rustls::rustls::pki_types::{CertificateDer, TrustAnchor, UnixTime}; -use webpki::EndEntityCert; - -/// The NV index where we expect to be able to read the AK certificate from the vTPM -const TPM_AK_CERT_IDX: u32 = 0x1C101D0; - -// microsoftRSADevicesRoot2021 is the root CA certificate used to sign Azure TDX vTPM certificates. -// This is different from the AME root CA used by TrustedLaunch VMs. -// The certificate can be downloaded from: -// http://www.microsoft.com/pkiops/certs/Microsoft%20RSA%20Devices%20Root%20CA%202021.crt -const MICROSOFT_RSA_DEVICES_ROOT_2021: &str = "-----BEGIN CERTIFICATE----- -MIIFkjCCA3qgAwIBAgIQGWCAkS2F96VGa+6hm2M3rjANBgkqhkiG9w0BAQwFADBa -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSsw -KQYDVQQDEyJNaWNyb3NvZnQgUlNBIERldmljZXMgUm9vdCBDQSAyMDIxMB4XDTIx -MDgyNjIzMzkxOFoXDTQ2MDgyNjIzNDcxNFowWjELMAkGA1UEBhMCVVMxHjAcBgNV -BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IFJT -QSBEZXZpY2VzIFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC -AgoCggIBALF4kgr3bAptorWmkrM6u47osmLfg67KxZPE4W74Zw5Bu64tjEuzegcB -6lFkoXi2V4eLdIRshk3l14jul6ghCML/6gh4hYiTExky3XMY05wg0d1o+AdhuyvC -anXvQZratosnL+KhR2qFeagthciIrCibIIKX91LvqRl/Eg8uo82fl30gieB40Sun -Pe/SfMJLb7AYbQ95yHK8G1lTFUHkIfPbAY6SfkOBUpNJ6UAtjlAmIaHYpdcdOayf -qXyhW3+Hf0Ou2wiKYJihCqh3TaI2hqmiv4p4CScug9sDcTyafA6OYLyTe3vx7Krn -BOUvkSkTj80GrXSKCWnrw+bE7z0deptPuLS6+n83ImLsBZ3XYhX4iUPmTRSU9vr7 -q0cZA8P8zAzLaeN+uK14l92u/7TMhkp5etmLE9DMd9MtnsLZSy18UpW4ZlBXxt9Z -w/RFKStlNbK5ILsI2HdSjgkF0DxZtNnCiEQehMu5DBfCdXo1P90iJhfF1MD+2Kh5 -xeuDQEC7Dh3gUSXIkOm/72u1fE52r0uY+aH1TCQGbCrijI9Jf78lFbI7L6Ll3YAa -89MrDs2tAQG0SaJdabh4k5orqaJOgaqrrq61RzcMjlZGI3dOdL+f6romKOccFkm0 -k+gwjvZ9xaJ5i9SB6Lq/GrA8YxzjmKHHVPmGGdm/v93R0oNGfyvxAgMBAAGjVDBS -MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSERIYG -AJg/LKqzxYnzrC7J5p0JAzAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwF -AAOCAgEAd3RAo42nyNbVvj+mxZ03VV+ceU6nCdgIS8RZfZBxf+lqupRzKUV9UW59 -IRCSeMH3gHfGSVhmwH1AJHkFIhd5meSShF4lPPmvYMmrbfOrwiUunqz2aix/QkRp -geMOe10wm6dEHHAw/eNi3PWhc+jdGJNV0SdnqcwJg/t5db8Y7RCVW+tG3DtEa63U -B4sGNlBbaUffdSdYL5TCRXm2mkcCWruu/gmDTgoabFmI4j9ss0shsIxwqVVEq2zk -EH1ypZrHSmVrTRh9hPHWpkOxnh9yqpGDXcSll09ZZUBUhx7YUX6p+BTVWnuuyR4T -bXS8P6fUS5Q2WF0WR07BrGYlBqomsEwMhth1SmBKn6tXfQyWkgr4pVl5XkkC7Bfv -pmw90csy8ycwog+x4L9kO1Nr6OPwnJ9V39oMifNDxnvYVBX7EhjoiARPp+97feNJ -YwMt4Os/WSeD++IhBB9xVsrI+jZufySQ02C/w1LBFR6zPy+a+v+6WlvMxDBEDWOj -JyDQ6kzkWxIG35klzLnwHybuIsFIIR1QGL1l47eW2dM4hB9oCay6z3FX5xYBIFvA -yp8up+KbjfH/NIWfPBXhYMW64DagB9P2cW5LBRz+AzDA+JF/OdYpb6vxv3lzjLQb -U9zMFwSrzEF5o2Aa/n+xZ90Naj78AYaTM18DalA17037fjucDN8= ------END CERTIFICATE-----"; - -// azureVirtualTPMRoot2023 is the root CA for Azure vTPM (used by both Trusted Launch and TDX) -// Source: https://learn.microsoft.com/en-us/azure/virtual-machines/trusted-launch-faq -// Valid until: 2048-06-01 -const AZURE_VIRTUAL_TPM_ROOT_2023: &str = "-----BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQUfQx2iySCIpOKeDZKd5KpzANBgkqhkiG9w0BAQwFADBp -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTow -OAYDVQQDEzFBenVyZSBWaXJ0dWFsIFRQTSBSb290IENlcnRpZmljYXRlIEF1dGhv -cml0eSAyMDIzMB4XDTIzMDYwMTE4MDg1M1oXDTQ4MDYwMTE4MTU0MVowaTELMAkG -A1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE6MDgGA1UE -AxMxQXp1cmUgVmlydHVhbCBUUE0gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkg -MjAyMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALoMMwvdRJ7+bW00 -adKE1VemNqJS+268Ure8QcfZXVOsVO22+PL9WRoPnWo0r5dVoomYGbobh4HC72s9 -sGY6BGRe+Ui2LMwuWnirBtOjaJ34r1ZieNMcVNJT/dXW5HN/HLlm/gSKlWzqCEx6 -gFFAQTvyYl/5jYI4Oe05zJ7ojgjK/6ZHXpFysXnyUITJ9qgjn546IJh/G5OMC3mD -fFU7A/GAi+LYaOHSzXj69Lk1vCftNq9DcQHtB7otO0VxFkRLaULcfu/AYHM7FC/S -q6cJb9Au8K/IUhw/5lJSXZawLJwHpcEYzETm2blad0VHsACaLNucZL5wBi8GEusQ -9Wo8W1p1rUCMp89pufxa3Ar9sYZvWeJlvKggWcQVUlhvvIZEnT+fteEvwTdoajl5 -qSvZbDPGCPjb91rSznoiLq8XqgQBBFjnEiTL+ViaZmyZPYUsBvBY3lKXB1l2hgga -hfBIag4j0wcgqlL82SL7pAdGjq0Fou6SKgHnkkrV5CNxUBBVMNCwUoj5mvEjd5mF -7XPgfM98qNABb2Aqtfl+VuCkU/G1XvFoTqS9AkwbLTGFMS9+jCEU2rw6wnKuGv1T -x9iuSdNvsXt8stx4fkVeJvnFpJeAIwBZVgKRSTa3w3099k0mW8qGiMnwCI5SfdZ2 -SJyD4uEmszsnieE6wAWd1tLLg1jvAgMBAAGjVDBSMA4GA1UdDwEB/wQEAwIBhjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRL/iZalMH2M8ODSCbd8+WwZLKqlTAQ -BgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEALgNAyg8I0ANNO/8I -2BhpTOsbywN2YSmShAmig5h4sCtaJSM1dRXwA+keY6PCXQEt/PRAQAiHNcOF5zbu -OU1Bw/Z5Z7k9okt04eu8CsS2Bpc+POg9js6lBtmigM5LWJCH1goMD0kJYpzkaCzx -1TdD3yjo0xSxgGhabk5Iu1soD3OxhUyIFcxaluhwkiVINt3Jhy7G7VJTlEwkk21A -oOrQxUsJH0f2GXjYShS1r9qLPzLf7ykcOm62jHGmLZVZujBzLIdNk1bljP9VuGW+ -cISBwzkNeEMMFufcL2xh6s/oiUnXicFWvG7E6ioPnayYXrHy3Rh68XLnhfpzeCzv -bz/I4yMV38qGo/cAY2OJpXUuuD/ZbI5rT+lRBEkDW1kxHP8cpwkRwGopV8+gX2KS -UucIIN4l8/rrNDEX8T0b5U+BUqiO7Z5YnxCya/H0ZIwmQnTlLRTU2fW+OGG+xyIr -jMi/0l6/yWPUkIAkNtvS/yO7USRVLPbtGVk3Qre6HcqacCXzEjINcJhGEVg83Y8n -M+Y+a9J0lUnHytMSFZE85h88OseRS2QwqjozUo2j1DowmhSSUv9Na5Ae22ycciBk -EZSq8a4rSlwqthaELNpeoTLUk6iVoUkK/iLvaMvrkdj9yJY1O/gvlfN2aiNTST/2 -bd+PA4RBToG9rXn6vNkUWdbLibU= ------END CERTIFICATE-----"; - -// 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 = "-----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-----"; - -/// The intermediate chain for azure -static GLOBAL_VIRTUAL_TPMCA03: 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![ - // Microsoft RSA Devices Root CA 2021 (older VMs) - pem_to_trust_anchor(MICROSOFT_RSA_DEVICES_ROOT_2021), - // Azure Virtual TPM Root CA 2023 (TDX + newer trusted launch) - pem_to_trust_anchor(AZURE_VIRTUAL_TPM_ROOT_2023), - ] -}); - -/// Verify an AK certificate against azure root CA -pub fn verify_ak_cert_with_azure_roots(ak_cert_der: &[u8], now_secs: u64) -> Result<(), MaaError> { - let ak_cert_der: CertificateDer = ak_cert_der.into(); - let end_entity_cert = EndEntityCert::try_from(&ak_cert_der)?; - - let now = UnixTime::since_unix_epoch(Duration::from_secs(now_secs)); - - end_entity_cert.verify_for_usage( - webpki::ALL_VERIFICATION_ALGS, - &AZURE_ROOT_ANCHORS, - &GLOBAL_VIRTUAL_TPMCA03, - now, - AnyEku, - None, - None, - )?; - tracing::debug!("Successfully verified AK certificate from vTPM"); - - Ok(()) -} - -/// Retrieve an AK certificate from the vTPM -pub fn read_ak_certificate_from_tpm() -> Result, tss_esapi::Error> { - tracing::debug!("Reading AK certificate from vTPM"); - let mut context = nv_index::get_session_context()?; - nv_index::read_nv_index(&mut context, TPM_AK_CERT_IDX) -} - -/// Convert a PEM-encoded cert into a TrustAnchor -fn pem_to_trust_anchor(pem: &str) -> TrustAnchor<'static> { - let (_type_label, der_vec) = pem_rfc7468::decode_vec(pem.as_bytes()).unwrap(); - // Leaking is ok here because plan is to set this up so it is only called once - let leaked: &'static [u8] = Box::leak(der_vec.into_boxed_slice()); - let cert_der: &'static CertificateDer<'static> = - Box::leak(Box::new(CertificateDer::from(leaked))); - webpki::anchor_from_trusted_cert(cert_der).expect("Failed to create trust anchor") -} - -/// Allows any EKU - we could change this to only accept 1.3.6.1.4.1.567.10.3.12 which is the EKU -/// given in the AK certificate -struct AnyEku; - -impl webpki::ExtendedKeyUsageValidator for AnyEku { - fn validate(&self, _iter: webpki::KeyPurposeIdIter<'_, '_>) -> Result<(), webpki::Error> { - Ok(()) - } -} - -#[cfg(test)] -#[tokio::test] -async fn root_should_be_fresh() { - let response = reqwest::get( - "http://www.microsoft.com/pkiops/certs/Microsoft%20RSA%20Devices%20Root%20CA%202021.crt", - ) - .await - .unwrap(); - let ca_der = response.bytes().await.unwrap(); - assert_eq!( - pem_rfc7468::decode_vec(MICROSOFT_RSA_DEVICES_ROOT_2021.as_bytes()) - .unwrap() - .1, - ca_der - ); -} diff --git a/attestation/src/azure/mod.rs b/attestation/src/azure/mod.rs deleted file mode 100644 index 78e45f6..0000000 --- a/attestation/src/azure/mod.rs +++ /dev/null @@ -1,456 +0,0 @@ -//! Microsoft Azure vTPM attestation evidence generation and verification -mod ak_certificate; -mod nv_index; -use ak_certificate::{read_ak_certificate_from_tpm, verify_ak_cert_with_azure_roots}; - -use az_tdx_vtpm::{hcl, imds, vtpm}; -use base64::{Engine as _, engine::general_purpose::URL_SAFE as BASE64_URL_SAFE}; -use dcap_qvl::QuoteCollateralV3; -use num_bigint::BigUint; -use openssl::{error::ErrorStack, pkey::PKey}; -use serde::{Deserialize, Serialize}; -use thiserror::Error; -use x509_parser::prelude::*; - -use crate::{dcap::verify_dcap_attestation_with_given_timestamp, measurements::MultiMeasurements}; - -/// The attestation evidence payload that gets sent over the channel -#[derive(Debug, Serialize, Deserialize)] -struct AttestationDocument { - /// TDX quote from the IMDS - tdx_quote_base64: String, - /// Serialized HCL report - hcl_report_base64: String, - /// vTPM related evidence - tpm_attestation: TpmAttest, -} - -/// TPM related components of the attestation document -#[derive(Debug, Serialize, Deserialize)] -struct TpmAttest { - /// Attestation Key certificate from vTPM - ak_certificate_pem: String, - /// vTPM quote - quote: vtpm::Quote, - /// Raw TCG event log bytes (UEFI + IMA) [currently not used] - /// - /// `/sys/kernel/security/ima/ascii_runtime_measurements`, - /// `/sys/kernel/security/tpm0/binary_bios_measurements`, - event_log: Vec, - /// Optional platform / instance metadata used to bind or verify the AK [currently not used] - instance_info: Option>, -} - -/// Generate a TDX attestation on Azure -pub async fn create_azure_attestation(input_data: [u8; 64]) -> Result, MaaError> { - let hcl_report_bytes = vtpm::get_report_with_report_data(&input_data)?; - - let hcl = hcl::HclReport::new(hcl_report_bytes.clone())?; - - let td_report_from_hcl = hcl.try_into()?; - - // This makes a request to Azure Instance metadata service and gives us a binary response - let td_quote_bytes = imds::get_td_quote(&td_report_from_hcl)?; - - let ak_certificate_der = read_ak_certificate_from_tpm()?; - - let tpm_attestation = TpmAttest { - ak_certificate_pem: pem_rfc7468::encode_string( - "CERTIFICATE", - pem_rfc7468::LineEnding::default(), - &ak_certificate_der, - )?, - quote: vtpm::get_quote(&input_data[..32])?, - event_log: Vec::new(), - instance_info: None, - }; - - let attestation_document = AttestationDocument { - tdx_quote_base64: BASE64_URL_SAFE.encode(&td_quote_bytes), - hcl_report_base64: BASE64_URL_SAFE.encode(&hcl_report_bytes), - tpm_attestation, - }; - - tracing::info!("Successfully generated azure attestation: {attestation_document:?}"); - Ok(serde_json::to_vec(&attestation_document)?) -} - -/// Verify a TDX attestation from Azure -pub async fn verify_azure_attestation( - input: Vec, - expected_input_data: [u8; 64], - pccs_url: Option, - override_azure_outdated_tcb: bool, -) -> Result { - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .expect("Time went backwards") - .as_secs(); - - verify_azure_attestation_with_given_timestamp( - input, - expected_input_data, - pccs_url, - None, - now, - override_azure_outdated_tcb, - ) - .await -} - -/// Do the verification, passing in the current time -/// This allows us to test this function without time checks going out of date -async fn verify_azure_attestation_with_given_timestamp( - input: Vec, - expected_input_data: [u8; 64], - pccs_url: Option, - collateral: Option, - now: u64, - override_azure_outdated_tcb: bool, -) -> Result { - let attestation_document: AttestationDocument = serde_json::from_slice(&input)?; - tracing::info!("Attempting to verifiy azure attestation: {attestation_document:?}"); - - let hcl_report_bytes = BASE64_URL_SAFE.decode(attestation_document.hcl_report_base64)?; - - let hcl_report = hcl::HclReport::new(hcl_report_bytes)?; - let var_data_hash = hcl_report.var_data_sha256(); - - // Check that HCL var data hash matches TDX quote report data - let mut expected_tdx_input_data = [0u8; 64]; - expected_tdx_input_data[..32].copy_from_slice(&var_data_hash); - - // Do DCAP verification - let tdx_quote_bytes = BASE64_URL_SAFE.decode(attestation_document.tdx_quote_base64)?; - let _dcap_measurements = verify_dcap_attestation_with_given_timestamp( - tdx_quote_bytes, - expected_tdx_input_data, - pccs_url, - collateral, - now, - override_azure_outdated_tcb, - ) - .await?; - - let hcl_ak_pub = hcl_report.ak_pub()?; - - // Get attestation key from runtime claims - let (ak_from_claims, user_data_input) = { - let runtime_data_raw = hcl_report.var_data(); - let claims: HclRuntimeClaims = serde_json::from_slice(runtime_data_raw)?; - - let ak_jwk = claims - .keys - .iter() - .find(|k| k.kid == "HCLAkPub") - .ok_or(MaaError::ClaimsMissingHCLAkPub)?; - - let user_data = claims - .user_data - .as_deref() - .ok_or(MaaError::ClaimsMissingUserData)?; - let user_data_bytes = hex::decode(user_data)?; - let user_data_input: [u8; 64] = user_data_bytes - .try_into() - .map_err(|_| MaaError::ClaimsUserDataBadLength)?; - - (RsaPubKey::from_jwk(ak_jwk)?, user_data_input) - }; - - // Check that the TD report input data matches the HCL var data hash - let td_report: az_tdx_vtpm::tdx::TdReport = hcl_report.try_into()?; - if var_data_hash != td_report.report_mac.reportdata[..32] { - return Err(MaaError::TdReportInputMismatch); - } - if user_data_input != expected_input_data { - return Err(MaaError::ClaimsUserDataInputMismatch); - } - - // Verify the vTPM quote - let vtpm_quote = attestation_document.tpm_attestation.quote; - let hcl_ak_pub_der = hcl_ak_pub - .key - .try_to_der() - .map_err(|_| MaaError::JwkConversion)?; - let pub_key = PKey::public_key_from_der(&hcl_ak_pub_der)?; - vtpm_quote.verify(&pub_key, &expected_input_data[..32])?; - - let pcrs = vtpm_quote.pcrs_sha256(); - - // Parse AK certificate - let (_type_label, ak_certificate_der) = pem_rfc7468::decode_vec( - attestation_document - .tpm_attestation - .ak_certificate_pem - .as_bytes(), - )?; - - let (remaining_bytes, ak_certificate) = X509Certificate::from_der(&ak_certificate_der)?; - - // Check that AK public key matches that from TPM quote and HCL claims - let ak_from_certificate = RsaPubKey::from_certificate(&ak_certificate)?; - let ak_from_hcl = RsaPubKey::from_openssl_pubkey(&pub_key)?; - if ak_from_claims != ak_from_hcl { - return Err(MaaError::AkFromClaimsNotEqualAkFromHcl); - } - if ak_from_claims != ak_from_certificate { - return Err(MaaError::AkFromClaimsNotEqualAkFromCertificate); - } - - // Strip trailing data from AK certificate - let leaf_len = ak_certificate_der.len() - remaining_bytes.len(); - let ak_certificate_der_without_trailing_data = &ak_certificate_der[..leaf_len]; - - // Verify the AK certificate against microsoft root cert - verify_ak_cert_with_azure_roots(ak_certificate_der_without_trailing_data, now)?; - - Ok(MultiMeasurements::from_pcrs(pcrs)) -} - -/// JSON Web Key used in [HclRuntimeClaims] -#[derive(Debug, Deserialize)] -struct Jwk { - #[allow(unused)] - pub kty: String, - pub kid: String, - #[allow(unused)] - pub n: Option, - #[allow(unused)] - pub e: Option, - // other fields ignored -} - -/// The internal data structure for HCL runtime claims -#[derive(Debug, serde::Deserialize)] -struct HclRuntimeClaims { - keys: Vec, - #[allow(unused)] - #[serde(rename = "vm-configuration")] - vm_config: Option, - #[serde(rename = "user-data")] - user_data: Option, -} - -/// This is only used as a common type to compare public keys with different formats -#[derive(Debug, PartialEq)] -struct RsaPubKey { - n: BigUint, - e: BigUint, -} - -impl RsaPubKey { - fn from_jwk(jwk: &Jwk) -> Result { - if jwk.kty != "RSA" { - return Err(MaaError::NotRsa); - } - - use base64::engine::general_purpose::URL_SAFE_NO_PAD; - let n_bytes = URL_SAFE_NO_PAD.decode(jwk.n.clone().ok_or(MaaError::JwkParse)?)?; - let e_bytes = URL_SAFE_NO_PAD.decode(jwk.e.clone().ok_or(MaaError::JwkParse)?)?; - - Ok(Self { - n: BigUint::from_bytes_be(&n_bytes), - e: BigUint::from_bytes_be(&e_bytes), - }) - } - - fn from_certificate(cert: &X509Certificate) -> Result { - let spki = cert.public_key(); - let rsa_from_cert = match spki.parsed() { - Ok(x509_parser::public_key::PublicKey::RSA(rsa)) => rsa, - _ => return Err(MaaError::NotRsa), - }; - - Ok(Self { - n: BigUint::from_bytes_be(rsa_from_cert.modulus), - e: BigUint::from_bytes_be(rsa_from_cert.exponent), - }) - } - - fn from_openssl_pubkey(key: &PKey) -> Result { - let rsa_from_pkey = key.rsa()?; - - Ok(Self { - n: BigUint::from_bytes_be(&rsa_from_pkey.n().to_vec()), - e: BigUint::from_bytes_be(&rsa_from_pkey.e().to_vec()), - }) - } -} - -/// An error when generating or verifying a Microsoft Azure vTPM attestation -#[derive(Error, Debug)] -pub enum MaaError { - #[error("Report: {0}")] - Report(#[from] az_tdx_vtpm::report::ReportError), - #[error("IMDS: {0}")] - Imds(#[from] imds::ImdsError), - #[error("vTPM report: {0}")] - VtpmReport(#[from] az_tdx_vtpm::vtpm::ReportError), - #[error("HCL: {0}")] - Hcl(#[from] hcl::HclError), - #[error("JSON: {0}")] - Json(#[from] serde_json::Error), - #[error("vTPM quote: {0}")] - VtpmQuote(#[from] vtpm::QuoteError), - #[error("AK public key: {0}")] - AkPub(#[from] vtpm::AKPubError), - #[error("vTPM quote could not be verified: {0}")] - TpmQuoteVerify(#[from] vtpm::VerifyError), - #[error("vTPM read: {0}")] - TssEsapi(#[from] tss_esapi::Error), - #[error("PEM encode: {0}")] - Pem(#[from] pem_rfc7468::Error), - #[error("TD report input does not match hashed HCL var data")] - TdReportInputMismatch, - #[error("Base64 decode: {0}")] - Base64(#[from] base64::DecodeError), - #[error("Hex decode: {0}")] - Hex(#[from] hex::FromHexError), - #[error("Attestation Key from HCL runtime claims does not match that from HCL report")] - AkFromClaimsNotEqualAkFromHcl, - #[error( - "Attestation Key from HCL runtime claims does not match that from attestation key certificate" - )] - AkFromClaimsNotEqualAkFromCertificate, - #[error("WebPKI: {0}")] - WebPki(#[from] webpki::Error), - #[error("X509 parse: {0}")] - X509Parse(#[from] x509_parser::asn1_rs::Err), - #[error("X509: {0}")] - X509(#[from] x509_parser::error::X509Error), - #[error("Cannot encode JSON web key as DER")] - JwkConversion, - #[error("OpenSSL: {0}")] - OpenSSL(#[from] ErrorStack), - #[error("Cannot extract measurements from quote")] - CannotExtractMeasurementsFromQuote, - #[error("Expected AK key to be RSA")] - NotRsa, - #[error("JSON web key has missing field")] - JwkParse, - #[error("HCL runtime claims is missing HCLAkPub field")] - ClaimsMissingHCLAkPub, - #[error("HCL runtime claims is missing user-data field")] - ClaimsMissingUserData, - #[error("HCL runtime claims user-data must decode to exactly 64 bytes")] - ClaimsUserDataBadLength, - #[error("HCL runtime claims user-data does not match expected report input data")] - ClaimsUserDataInputMismatch, - #[error("DCAP verification: {0}")] - DcapVerification(#[from] crate::dcap::DcapVerificationError), -} - -#[cfg(test)] -mod tests { - use crate::measurements::MeasurementPolicy; - - use super::*; - - fn input_data_from_attestation(attestation_bytes: &[u8]) -> [u8; 64] { - let attestation_document: AttestationDocument = - serde_json::from_slice(attestation_bytes).unwrap(); - let hcl_report_bytes = BASE64_URL_SAFE - .decode(attestation_document.hcl_report_base64) - .unwrap(); - let hcl_report = hcl::HclReport::new(hcl_report_bytes).unwrap(); - let claims: HclRuntimeClaims = serde_json::from_slice(hcl_report.var_data()).unwrap(); - let user_data_hex = claims.user_data.unwrap(); - hex::decode(user_data_hex).unwrap().try_into().unwrap() - } - - #[tokio::test] - async fn test_decode_hcl() { - // From cvm-reverse-proxy/internal/attestation/azure/tdx/testdata/hclreport.bin - let hcl_bytes: &'static [u8] = include_bytes!("../../test-assets/hclreport.bin"); - - let hcl_report = hcl::HclReport::new(hcl_bytes.to_vec()).unwrap(); - let hcl_var_data = hcl_report.var_data(); - let var_data_values: serde_json::Value = serde_json::from_slice(&hcl_var_data).unwrap(); - - // Check that it contains 64 byte user data - 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"); - - // 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()) - .await - .unwrap(); - - let collateral_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-collateral02.json"); - - let collateral = serde_json::from_slice(collateral_bytes).unwrap(); - - let measurements = verify_azure_attestation_with_given_timestamp( - attestation_bytes.to_vec(), - [0; 64], // Input data - None, - collateral, - now, - false, - ) - .await - .unwrap(); - - measurement_policy.check_measurement(&measurements).unwrap(); - } - - #[tokio::test] - async fn test_verify_fails_on_input_mismatch() { - let attestation_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-tdx-1764662251380464271"); - let now = 1771423480; - - let mut expected_input_data = input_data_from_attestation(attestation_bytes); - expected_input_data[63] ^= 0x01; - - let collateral_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-collateral02.json"); - let collateral = serde_json::from_slice(collateral_bytes).unwrap(); - - let err = verify_azure_attestation_with_given_timestamp( - attestation_bytes.to_vec(), - expected_input_data, - None, - Some(collateral), - now, - false, - ) - .await - .unwrap_err(); - - assert!(matches!(err, MaaError::ClaimsUserDataInputMismatch)); - } -} diff --git a/attestation/src/azure/nv_index.rs b/attestation/src/azure/nv_index.rs deleted file mode 100644 index 2d448ac..0000000 --- a/attestation/src/azure/nv_index.rs +++ /dev/null @@ -1,21 +0,0 @@ -use tss_esapi::{ - Context, - handles::NvIndexTpmHandle, - interface_types::{resource_handles::NvAuth, session_handles::AuthSession}, - tcti_ldr::{DeviceConfig, TctiNameConf}, -}; - -pub fn get_session_context() -> Result { - let conf: TctiNameConf = TctiNameConf::Device(DeviceConfig::default()); - let mut context = Context::new(conf)?; - let auth_session = AuthSession::Password; - context.set_sessions((Some(auth_session), None, None)); - Ok(context) -} - -pub fn read_nv_index(ctx: &mut Context, index: u32) -> Result, tss_esapi::Error> { - tracing::debug!("Reading from TPM, nv index: {index}"); - let nv_tpm_handle = NvIndexTpmHandle::new(index)?; - let buf = tss_esapi::abstraction::nv::read_full(ctx, NvAuth::Owner, nv_tpm_handle)?; - Ok(buf.to_vec()) -} diff --git a/attestation/src/dcap.rs b/attestation/src/dcap.rs deleted file mode 100644 index c1b70c6..0000000 --- a/attestation/src/dcap.rs +++ /dev/null @@ -1,255 +0,0 @@ -//! Data Center Attestation Primitives (DCAP) evidence generation and verification -use crate::{AttestationError, measurements::MultiMeasurements}; - -use configfs_tsm::QuoteGenerationError; -use dcap_qvl::{ - QuoteCollateralV3, - collateral::get_collateral_for_fmspc, - quote::{Quote, Report}, - tcb_info::TcbInfo, -}; -use thiserror::Error; - -/// FMSPC with which to override TCB level checks on Azure (not used for GCP or other platforms) -const AZURE_BAD_FMSPC: &str = "90C06F000000"; - -/// For fetching collateral directly from Intel, if no PCCS is specified -pub const PCS_URL: &str = "https://api.trustedservices.intel.com"; - -/// Quote generation using configfs_tsm -pub async fn create_dcap_attestation(input_data: [u8; 64]) -> Result, AttestationError> { - let quote = generate_quote(input_data)?; - tracing::info!("Generated TDX quote of {} bytes", quote.len()); - Ok(quote) -} - -/// Verify a DCAP TDX quote, and return the measurement values -#[cfg(not(any(test, feature = "mock")))] -pub async fn verify_dcap_attestation( - input: Vec, - expected_input_data: [u8; 64], - pccs_url: Option, -) -> Result { - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH)? - .as_secs(); - let override_azure_outdated_tcb = false; - verify_dcap_attestation_with_given_timestamp( - input, - expected_input_data, - pccs_url, - None, - now, - override_azure_outdated_tcb, - ) - .await -} - -/// Allows the timestamp to be given, making it possible to test with existing attestations -/// -/// If collateral is given, it is used instead of contacting PCCS (used in tests) -pub async fn verify_dcap_attestation_with_given_timestamp( - input: Vec, - expected_input_data: [u8; 64], - pccs_url: Option, - collateral: Option, - now: u64, - override_azure_outdated_tcb: bool, -) -> Result { - let quote = Quote::parse(&input)?; - tracing::info!("Verifying DCAP attestation: {quote:?}"); - - let ca = quote.ca()?; - let fmspc = hex::encode_upper(quote.fmspc()?); - - // Override outdated TCB only if we are on Azure and the FMSPC is known to be outdated - let override_outdated_tcb = if override_azure_outdated_tcb { - |mut tcb_info: TcbInfo| { - if tcb_info.fmspc == AZURE_BAD_FMSPC { - for tcb_level in &mut tcb_info.tcb_levels { - if tcb_level.tcb.sgx_components[7].svn > 3 { - tcb_level.tcb.sgx_components[7].svn = 3 - } - } - } - tcb_info - } - } else { - |tcb_info: TcbInfo| tcb_info - }; - - let collateral = match collateral { - Some(c) => c, - None => { - get_collateral_for_fmspc( - &pccs_url.clone().unwrap_or(PCS_URL.to_string()), - fmspc, - ca, - false, // Indicates not SGX - ) - .await? - } - }; - - let _verified_report = dcap_qvl::verify::verify_with_tcb_override( - &input, - &collateral, - now, - override_outdated_tcb, - )?; - - let measurements = MultiMeasurements::from_dcap_qvl_quote("e)?; - - if get_quote_input_data(quote.report) != expected_input_data { - return Err(DcapVerificationError::InputMismatch); - } - - Ok(measurements) -} - -#[cfg(any(test, feature = "mock"))] -pub async fn verify_dcap_attestation( - input: Vec, - expected_input_data: [u8; 64], - _pccs_url: Option, -) -> Result { - // In tests we use mock quotes which will fail to verify - let quote = tdx_quote::Quote::from_bytes(&input)?; - if quote.report_input_data() != expected_input_data { - return Err(DcapVerificationError::InputMismatch); - } - Ok(MultiMeasurements::from_tdx_quote("e)) -} - -/// Create a mock quote for testing on non-confidential hardware -#[cfg(any(test, feature = "mock"))] -fn generate_quote(input: [u8; 64]) -> Result, QuoteGenerationError> { - let attestation_key = tdx_quote::SigningKey::random(&mut rand_core::OsRng); - let provisioning_certification_key = tdx_quote::SigningKey::random(&mut rand_core::OsRng); - Ok(tdx_quote::Quote::mock( - attestation_key.clone(), - provisioning_certification_key.clone(), - input, - b"Mock cert chain".to_vec(), - ) - .as_bytes()) -} - -/// Create a quote -#[cfg(not(any(test, feature = "mock")))] -fn generate_quote(input: [u8; 64]) -> Result, QuoteGenerationError> { - configfs_tsm::create_tdx_quote(input) -} - -/// Given a [Report] get the input data regardless of report type -pub fn get_quote_input_data(report: Report) -> [u8; 64] { - match report { - Report::TD10(r) => r.report_data, - Report::TD15(r) => r.base.report_data, - Report::SgxEnclave(r) => r.report_data, - } -} - -/// An error when verifying a DCAP attestation -#[derive(Error, Debug)] -pub enum DcapVerificationError { - #[error("Quote input is not as expected")] - InputMismatch, - #[error("SGX quote given when TDX quote expected")] - SgxNotSupported, - #[error("System Time: {0}")] - SystemTime(#[from] std::time::SystemTimeError), - #[error("DCAP quote verification: {0}")] - DcapQvl(#[from] anyhow::Error), - #[cfg(any(test, feature = "mock"))] - #[error("Quote parse: {0}")] - QuoteParse(#[from] tdx_quote::QuoteParseError), -} - -#[cfg(test)] -mod tests { - use crate::measurements::MeasurementPolicy; - - use super::*; - #[tokio::test] - async fn test_dcap_verify() { - let attestation_bytes: &'static [u8] = - include_bytes!("../test-assets/dcap-tdx-1766059550570652607"); - - // To avoid this test stopping working when the certificate is no longer valid we pass in a - // timestamp - let now = 1769509141; - - let measurements_json = br#" - [{ - "measurement_id": "cvm-image-azure-tdx.rootfs-20241107200854.wic.vhd", - "attestation_type": "dcap-tdx", - "measurements": { - "0": { "expected": "a5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694"}, - "1": { "expected": "0564ec85d8d7cbaebde0f6cce94f3b15722c656b610426abbfde11a5e14e9a9ee07c752df120b85267bb6c6c743a9301"}, - "2": { "expected": "d6b50192d3c4a98ac0a58e12b1e547edd02d79697c1fb9faa2f6fd0b150553b23f399e6d63612699b208468da7b748f3"}, - "3": { "expected": "b26c7be2db28613938cd75fd4173b963130712acb710f2820f9f0519e93f781dbabd7ba945870f499826d0ed169c5b42"}, - "4": { "expected": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} - } - }] - "#; - - let measurement_policy = MeasurementPolicy::from_json_bytes(measurements_json.to_vec()) - .await - .unwrap(); - - let collateral_bytes: &'static [u8] = - include_bytes!("../test-assets/dcap-quote-collateral-00.json"); - - let collateral = serde_json::from_slice(collateral_bytes).unwrap(); - - let measurements = verify_dcap_attestation_with_given_timestamp( - attestation_bytes.to_vec(), - [ - 116, 39, 106, 100, 143, 31, 212, 145, 244, 116, 162, 213, 44, 114, 216, 80, 227, - 118, 129, 87, 180, 62, 194, 151, 169, 145, 116, 130, 189, 119, 39, 139, 161, 136, - 37, 136, 57, 29, 25, 86, 182, 246, 70, 106, 216, 184, 220, 205, 85, 245, 114, 33, - 173, 129, 180, 32, 247, 70, 250, 141, 176, 248, 99, 125, - ], - None, - Some(collateral), - now, - false, - ) - .await - .unwrap(); - - measurement_policy.check_measurement(&measurements).unwrap(); - } - - // This specifically tests a quote which has outdated TCB level from Azure - #[tokio::test] - async fn test_dcap_verify_azure_override() { - let attestation_bytes: &'static [u8] = - include_bytes!("../test-assets/azure_failed_dcap_quote_10.bin"); - - // To avoid this test stopping working when the certificate is no longer valid we pass in a - // timestamp - let now = 1771414156; - - let collateral_bytes: &'static [u8] = - include_bytes!("../test-assets/azure-collateral.json"); - - let collateral = serde_json::from_slice(collateral_bytes).unwrap(); - - let _measurements = verify_dcap_attestation_with_given_timestamp( - attestation_bytes.to_vec(), - [ - 210, 20, 43, 100, 53, 152, 235, 95, 174, 43, 200, 82, 157, 215, 154, 85, 139, 41, - 248, 104, 204, 187, 101, 49, 203, 40, 218, 185, 220, 228, 119, 40, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - None, - Some(collateral), - now, - true, - ) - .await - .unwrap(); - } -} diff --git a/attestation/src/lib.rs b/attestation/src/lib.rs deleted file mode 100644 index a6496cb..0000000 --- a/attestation/src/lib.rs +++ /dev/null @@ -1,549 +0,0 @@ -//! CVM attestation generation and verification - -#[cfg(feature = "azure")] -pub mod azure; -pub mod dcap; -pub mod measurements; - -#[cfg(any(test, feature = "test-helpers"))] -pub mod test_helpers; - -use measurements::MultiMeasurements; -use parity_scale_codec::{Decode, Encode}; -use serde::{Deserialize, Serialize}; -use std::{ - fmt::{self, Display, Formatter}, - net::IpAddr, - time::{Duration, SystemTime, UNIX_EPOCH}, -}; - -use thiserror::Error; - -use crate::{dcap::DcapVerificationError, measurements::MeasurementPolicy}; - -const GCP_METADATA_API: &str = - "http://metadata.google.internal/computeMetadata/v1/project/project-id"; - -/// This is the type sent over the channel to provide an attestation -#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)] -pub struct AttestationExchangeMessage { - /// What CVM platform is used (including none) - pub attestation_type: AttestationType, - /// The attestation evidence as bytes - in the case of DCAP this is a quote - pub attestation: Vec, -} - -impl AttestationExchangeMessage { - /// Create an empty attestation payload for the case that we are running in a non-confidential - /// environment - pub fn without_attestation() -> Self { - Self { - attestation_type: AttestationType::None, - attestation: Vec::new(), - } - } -} - -/// Type of attestaion used -/// Only supported (or soon-to-be supported) types are given -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(rename_all = "kebab-case")] -pub enum AttestationType { - /// No attestion - None, - /// TDX on Google Cloud Platform - GcpTdx, - /// TDX on Azure, with MAA - AzureTdx, - /// TDX on Qemu (no cloud platform) - QemuTdx, - /// DCAP TDX - DcapTdx, -} - -impl AttestationType { - /// Matches the names used by Constellation aTLS - pub fn as_str(&self) -> &'static str { - match self { - AttestationType::None => "none", - AttestationType::AzureTdx => "azure-tdx", - AttestationType::QemuTdx => "qemu-tdx", - AttestationType::GcpTdx => "gcp-tdx", - AttestationType::DcapTdx => "dcap-tdx", - } - } - - /// Detect what platform we are on by attempting an attestation - pub async fn detect() -> Result { - // First attempt azure, if the feature is present - #[cfg(feature = "azure")] - { - if azure::create_azure_attestation([0; 64]).await.is_ok() { - return Ok(AttestationType::AzureTdx); - } - } - // Otherwise try DCAP quote - this internally checks that the quote provider is `tdx_guest` - if configfs_tsm::create_tdx_quote([0; 64]).is_ok() { - if running_on_gcp().await? { - return Ok(AttestationType::GcpTdx); - } else { - return Ok(AttestationType::DcapTdx); - } - } - Ok(AttestationType::None) - } -} - -/// SCALE encode (used over the wire) -impl Encode for AttestationType { - fn encode(&self) -> Vec { - self.as_str().encode() - } -} - -/// SCALE decode -impl Decode for AttestationType { - fn decode( - input: &mut I, - ) -> Result { - let s: String = String::decode(input)?; - serde_json::from_str(&format!("\"{s}\"")).map_err(|_| "Failed to decode enum".into()) - } -} - -impl Display for AttestationType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(self.as_str()) - } -} - -/// Can generate a local attestation based on attestation type -#[derive(Debug, Clone)] -pub struct AttestationGenerator { - pub attestation_type: AttestationType, - attestation_provider_url: Option, -} - -impl AttestationGenerator { - /// Create an attesation generator with given attestation type - pub fn new( - attestation_type: AttestationType, - attestation_provider_url: Option, - ) -> Result { - // If an attestation provider is given, normalize the URL and check that it looks like a local IP - let attestation_provider_url = attestation_provider_url - .map(map_attestation_provider_url) - .transpose()?; - - Ok(Self { - attestation_type, - attestation_provider_url, - }) - } - - /// Detect what confidential compute platform is present and create the appropriate attestation - /// generator - pub async fn detect() -> Result { - Self::new_with_detection(None, None).await - } - - /// Do not generate attestations - pub fn with_no_attestation() -> Self { - Self { - attestation_type: AttestationType::None, - attestation_provider_url: None, - } - } - - /// Create an [AttestationGenerator] detecting the attestation type if it is not given - pub async fn new_with_detection( - attestation_type_string: Option, - attestation_provider_url: Option, - ) -> Result { - if attestation_provider_url.is_some() { - // If a remote provide is used, dont do detection - let attestation_type = serde_json::from_value(serde_json::Value::String( - attestation_type_string.ok_or(AttestationError::AttestationTypeNotGiven)?, - ))?; - return Self::new(attestation_type, attestation_provider_url); - }; - - let attestation_type_string = attestation_type_string.unwrap_or_else(|| "auto".to_string()); - let attestation_type = if attestation_type_string == "auto" { - tracing::info!("Doing attestation type detection..."); - AttestationType::detect().await? - } else { - serde_json::from_value(serde_json::Value::String(attestation_type_string))? - }; - tracing::info!("Local platform: {attestation_type}"); - - Self::new(attestation_type, None) - } - - /// Generate an attestation exchange message with given input data - pub async fn generate_attestation( - &self, - input_data: [u8; 64], - ) -> Result { - if let Some(url) = &self.attestation_provider_url { - Self::use_attestation_provider(url, self.attestation_type, input_data).await - } else { - Ok(AttestationExchangeMessage { - attestation_type: self.attestation_type, - attestation: self.generate_attestation_bytes(input_data).await?, - }) - } - } - - /// Generate attestation evidence bytes based on attestation type, with given input data - async fn generate_attestation_bytes( - &self, - input_data: [u8; 64], - ) -> Result, AttestationError> { - match self.attestation_type { - AttestationType::None => Ok(Vec::new()), - AttestationType::AzureTdx => { - #[cfg(feature = "azure")] - { - Ok(azure::create_azure_attestation(input_data).await?) - } - #[cfg(not(feature = "azure"))] - { - tracing::error!( - "Attempted to generate an azure attestation but the `azure` feature not enabled" - ); - Err(AttestationError::AttestationTypeNotSupported) - } - } - _ => dcap::create_dcap_attestation(input_data).await, - } - } - - /// Generate an attestation by using an external service for the attestation generation - async fn use_attestation_provider( - url: &str, - attestation_type: AttestationType, - input_data: [u8; 64], - ) -> Result { - let url = format!("{}/attest/{}", url, hex::encode(input_data)); - - let response = reqwest::get(url) - .await - .map_err(|err| AttestationError::AttestationProvider(err.to_string()))? - .bytes() - .await - .map_err(|err| AttestationError::AttestationProvider(err.to_string()))? - .to_vec(); - - // If the response is not already wrapped in an attestation exchange message, wrap it in - // one - if let Ok(message) = AttestationExchangeMessage::decode(&mut &response[..]) { - Ok(message) - } else { - Ok(AttestationExchangeMessage { - attestation_type, - attestation: response, - }) - } - } -} - -/// Allows remote attestations to be verified -#[derive(Clone, Debug)] -pub struct AttestationVerifier { - /// The measurement policy with accepted values and attestation types - pub measurement_policy: MeasurementPolicy, - /// If this is empty, anything will be accepted - but measurements are always injected into HTTP - /// headers, so that they can be verified upstream - /// A PCCS service to use - defaults to Intel PCS - pub pccs_url: Option, - /// Whether to log quotes to a file - pub log_dcap_quote: bool, - /// Whether to override outdated TCB when on Azure - pub override_azure_outdated_tcb: bool, -} - -impl AttestationVerifier { - /// Create an [AttestationVerifier] which will allow no remote attestation - pub fn expect_none() -> Self { - Self { - measurement_policy: MeasurementPolicy::expect_none(), - pccs_url: None, - log_dcap_quote: false, - override_azure_outdated_tcb: false, - } - } - - /// Expect mock measurements used in tests - #[cfg(any(test, feature = "test-helpers"))] - pub fn mock() -> Self { - Self { - measurement_policy: MeasurementPolicy::mock(), - pccs_url: None, - log_dcap_quote: false, - override_azure_outdated_tcb: false, - } - } - - /// Verify an attestation, and ensure the measurements match one of our accepted measurements - pub async fn verify_attestation( - &self, - attestation_exchange_message: AttestationExchangeMessage, - expected_input_data: [u8; 64], - ) -> Result, AttestationError> { - let attestation_type = attestation_exchange_message.attestation_type; - tracing::debug!("Verifing {attestation_type} attestation"); - - if self.log_dcap_quote { - log_attestation(&attestation_exchange_message).await; - } - - let measurements = match attestation_type { - AttestationType::None => { - if self.has_remote_attestion() { - return Err(AttestationError::AttestationTypeNotAccepted); - } - if attestation_exchange_message.attestation.is_empty() { - return Ok(None); - } else { - return Err(AttestationError::AttestationGivenWhenNoneExpected); - } - } - AttestationType::AzureTdx => { - #[cfg(feature = "azure")] - { - azure::verify_azure_attestation( - attestation_exchange_message.attestation, - expected_input_data, - self.pccs_url.clone(), - self.override_azure_outdated_tcb, - ) - .await? - } - #[cfg(not(feature = "azure"))] - { - return Err(AttestationError::AttestationTypeNotSupported); - } - } - _ => { - dcap::verify_dcap_attestation( - attestation_exchange_message.attestation, - expected_input_data, - self.pccs_url.clone(), - ) - .await? - } - }; - - // Do a measurement / attestation type policy check - self.measurement_policy.check_measurement(&measurements)?; - - tracing::debug!("Verification successful"); - Ok(Some(measurements)) - } - - /// Whether we allow no remote attestation - pub fn has_remote_attestion(&self) -> bool { - self.measurement_policy.has_remote_attestion() - } -} - -/// Write attestation data to a log file -async fn log_attestation(attestation: &AttestationExchangeMessage) { - if attestation.attestation_type != AttestationType::None { - let timestamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_nanos(); - - let filename = format!("quotes/{}-{}", attestation.attestation_type, timestamp); - if let Err(err) = tokio::fs::write(&filename, attestation.attestation.clone()).await { - tracing::warn!("Failed to write {filename}: {err}"); - } - } -} - -/// Test whether it looks like we are running on GCP by hitting the metadata API -async fn running_on_gcp() -> Result { - let mut headers = reqwest::header::HeaderMap::new(); - headers.insert( - "Metadata-Flavor", - "Google".parse().expect("Cannot parse header"), - ); - - let client = reqwest::Client::builder() - .timeout(Duration::from_millis(200)) - .default_headers(headers) - .build()?; - - let resp = client.get(GCP_METADATA_API).send().await; - - if let Ok(r) = resp { - return Ok(r.status().is_success() - && r.headers() - .get("Metadata-Flavor") - .map(|v| v == "Google") - .unwrap_or(false)); - } - - Ok(false) -} - -/// If an attestion provider service is used, we ensure that it looks like a local IP -/// -/// This is to avoid dangerous configuration where the attestation is provided by a remote machine -/// -/// This by no means guarantees a safe configuration -fn map_attestation_provider_url(url: String) -> Result { - // Fist put it in the format that reqwest expects - let url = if url.starts_with("http://") || url.starts_with("https://") { - url.to_string() - } else { - format!("http://{}", url.trim_start_matches("http://")) - }; - - let url = url.strip_suffix('/').unwrap_or(&url).to_string(); - - // If compiled in test mode, skip this check - if !cfg!(test) { - let parsed = url - .parse::() - .or_else(|_| { - // Try parsing as a URL to extract host - let parsed = url.parse::().map_err(|_| "Invalid URL")?; - - let host = parsed.host().ok_or("URL missing host")?; - - host.parse::() - .map_err(|_| "Only local IP addresses may be used as attestation provider URL") - .map(|ip| std::net::SocketAddr::new(ip, 0)) - }) - .map_err(|e| AttestationError::AttestationProviderUrl(e.to_string()))?; - - if !is_local_ip(parsed.ip()) { - return Err(AttestationError::AttestationProviderUrl( - "Given URL does not appear to contain a local IP address".to_string(), - )); - } - } - Ok(url) -} - -/// Check if an IP address looks like it is local -fn is_local_ip(ip: IpAddr) -> bool { - match ip { - IpAddr::V4(v4) => v4.is_private() || v4.is_loopback() || v4.is_link_local(), - IpAddr::V6(v6) => v6.is_loopback() || v6.is_unique_local() || v6.is_unicast_link_local(), - } -} - -/// An error when generating or verifying an attestation -#[derive(Error, Debug)] -pub enum AttestationError { - #[error("Certificate chain is empty")] - NoCertificate, - #[error("X509 parse: {0}")] - X509Parse(#[from] x509_parser::asn1_rs::Err), - #[error("X509: {0}")] - X509(#[from] x509_parser::error::X509Error), - #[error("Configuration mismatch - expected no remote attestation")] - AttestationGivenWhenNoneExpected, - #[error("Configfs-tsm quote generation: {0}")] - QuoteGeneration(#[from] configfs_tsm::QuoteGenerationError), - #[error("DCAP verification: {0}")] - DcapVerification(#[from] DcapVerificationError), - #[error("Attestation type not supported")] - AttestationTypeNotSupported, - #[error("Attestation type not accepted")] - AttestationTypeNotAccepted, - #[error("Measurements not accepted")] - MeasurementsNotAccepted, - #[cfg(feature = "azure")] - #[error("MAA: {0}")] - Maa(#[from] azure::MaaError), - #[error("If using a an attestation provider an attestation type must be given")] - AttestationTypeNotGiven, - #[error("Attestation provider server: {0}")] - AttestationProvider(String), - #[error("Attestation provider URL: {0}")] - AttestationProviderUrl(String), - #[error("JSON: {0}")] - SerdeJson(#[from] serde_json::Error), - #[error("HTTP client: {0}")] - Reqwest(#[from] reqwest::Error), -} - -#[cfg(test)] -mod tests { - use super::*; - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - use tokio::net::TcpListener; - - async fn spawn_test_attestation_provider_server(body: Vec) -> std::net::SocketAddr { - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - - tokio::spawn(async move { - if let Ok((mut socket, _)) = listener.accept().await { - let mut buf = [0u8; 1024]; - let _ = socket.read(&mut buf).await; - - let response = format!( - "HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", - body.len() - ); - let _ = socket.write_all(response.as_bytes()).await; - let _ = socket.write_all(&body).await; - let _ = socket.shutdown().await; - } - }); - - addr - } - - #[tokio::test] - async fn attestation_detection_does_not_panic() { - // We dont enforce what platform the test is run on, only that the function does not panic - let _ = AttestationGenerator::new_with_detection(None, None).await; - } - - #[tokio::test] - async fn running_on_gcp_check_does_not_panic() { - let _ = running_on_gcp().await; - } - - #[tokio::test] - async fn attestation_provider_response_is_wrapped_if_needed() { - let input_data = [0u8; 64]; - - let encoded_message = AttestationExchangeMessage { - attestation_type: AttestationType::None, - attestation: vec![1, 2, 3], - } - .encode(); - - let encoded_addr = spawn_test_attestation_provider_server(encoded_message).await; - let encoded_url = format!("http://{encoded_addr}"); - let decoded = AttestationGenerator::use_attestation_provider( - &encoded_url, - AttestationType::GcpTdx, - input_data, - ) - .await - .unwrap(); - assert_eq!(decoded.attestation_type, AttestationType::None); - assert_eq!(decoded.attestation, vec![1, 2, 3]); - - let raw_addr = spawn_test_attestation_provider_server(vec![9, 8]).await; - let raw_url = format!("http://{raw_addr}"); - let wrapped = AttestationGenerator::use_attestation_provider( - &raw_url, - AttestationType::DcapTdx, - input_data, - ) - .await - .unwrap(); - assert_eq!(wrapped.attestation_type, AttestationType::DcapTdx); - assert_eq!(wrapped.attestation, vec![9, 8]); - } -} diff --git a/attestation/src/measurements.rs b/attestation/src/measurements.rs deleted file mode 100644 index 798bf47..0000000 --- a/attestation/src/measurements.rs +++ /dev/null @@ -1,833 +0,0 @@ -//! Measurements and policy for enforcing them when validating a remote attestation -use crate::{AttestationError, AttestationType, dcap::DcapVerificationError}; -use std::{collections::HashMap, path::PathBuf}; -use std::{fmt, fmt::Formatter}; - -use dcap_qvl::quote::Report; -use http::{HeaderValue, header::InvalidHeaderValue}; -use serde::Deserialize; -use thiserror::Error; - -/// Represents the measurement register types in a TDX quote -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[repr(u8)] -pub enum DcapMeasurementRegister { - MRTD, - RTMR0, - RTMR1, - RTMR2, - RTMR3, -} - -impl TryFrom for DcapMeasurementRegister { - type Error = MeasurementFormatError; - - fn try_from(value: u8) -> Result { - match value { - 0 => Ok(Self::MRTD), - 1 => Ok(Self::RTMR0), - 2 => Ok(Self::RTMR1), - 3 => Ok(Self::RTMR2), - 4 => Ok(Self::RTMR3), - _ => Err(MeasurementFormatError::BadRegisterIndex), - } - } -} - -/// Represents a set of measurements values for one of the supported CVM platforms -#[derive(Clone, PartialEq)] -pub enum MultiMeasurements { - Dcap(HashMap), - Azure(HashMap), - NoAttestation, -} - -impl fmt::Debug for MultiMeasurements { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::Dcap(measurements) => f - .debug_tuple("Dcap") - .field(&DcapHexDebug(measurements)) - .finish(), - Self::Azure(measurements) => f - .debug_tuple("Azure") - .field(&AzureHexDebug(measurements)) - .finish(), - Self::NoAttestation => f.write_str("NoAttestation"), - } - } -} - -/// Used to display measurements as hex -struct DcapHexDebug<'a>(&'a HashMap); - -impl fmt::Debug for DcapHexDebug<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut entries: Vec<_> = self.0.iter().collect(); - entries.sort_by_key(|(register, _)| (*register).clone() as u8); - - let mut map = f.debug_map(); - for (register, value) in entries { - let hex_value = hex::encode(value); - map.entry(register, &hex_value); - } - map.finish() - } -} - -/// Used to display measurements as hex -struct AzureHexDebug<'a>(&'a HashMap); - -impl fmt::Debug for AzureHexDebug<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let mut entries: Vec<_> = self.0.iter().collect(); - entries.sort_by_key(|(index, _)| **index); - - let mut map = f.debug_map(); - for (index, value) in entries { - let hex_value = hex::encode(value); - map.entry(index, &hex_value); - } - map.finish() - } -} - -/// Expected measurement values for policy enforcement -#[derive(Debug, Clone, PartialEq)] -pub enum ExpectedMeasurements { - Dcap(HashMap>), - Azure(HashMap>), - NoAttestation, -} - -impl MultiMeasurements { - /// Convert to the JSON format used in HTTP headers - pub fn to_header_format(&self) -> Result { - let measurements_map = match self { - MultiMeasurements::Dcap(dcap_measurements) => dcap_measurements - .iter() - .map(|(register, value)| ((register.clone() as u8).to_string(), hex::encode(value))) - .collect(), - MultiMeasurements::Azure(azure_measurements) => azure_measurements - .iter() - .map(|(index, value)| (index.to_string(), hex::encode(value))) - .collect(), - MultiMeasurements::NoAttestation => HashMap::new(), - }; - - Ok(HeaderValue::from_str(&serde_json::to_string( - &measurements_map, - )?)?) - } - - /// Parse the JSON used in HTTP headers - pub fn from_header_format( - input: &str, - attestation_type: AttestationType, - ) -> Result { - let measurements_map: HashMap = serde_json::from_str(input)?; - - Ok(match attestation_type { - AttestationType::AzureTdx => Self::Azure( - measurements_map - .into_iter() - .map(|(k, v)| { - Ok(( - k as u32, - hex::decode(v)? - .try_into() - .map_err(|_| MeasurementFormatError::BadLength)?, - )) - }) - .collect::>()?, - ), - AttestationType::None => Self::NoAttestation, - _ => { - let measurements_map = measurements_map - .into_iter() - .map(|(k, v)| { - Ok(( - k.try_into()?, - hex::decode(v)? - .try_into() - .map_err(|_| MeasurementFormatError::BadLength)?, - )) - }) - .collect::>()?; - Self::Dcap(measurements_map) - } - }) - } - - /// Given a quote from the dcap_qvl library, extract the measurements - pub fn from_dcap_qvl_quote( - quote: &dcap_qvl::quote::Quote, - ) -> Result { - let report = match quote.report { - Report::TD10(report) => report, - Report::TD15(report) => report.base, - Report::SgxEnclave(_) => { - return Err(DcapVerificationError::SgxNotSupported); - } - }; - Ok(Self::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, report.mr_td), - (DcapMeasurementRegister::RTMR0, report.rt_mr0), - (DcapMeasurementRegister::RTMR1, report.rt_mr1), - (DcapMeasurementRegister::RTMR2, report.rt_mr2), - (DcapMeasurementRegister::RTMR3, report.rt_mr3), - ]))) - } - - #[cfg(any(test, feature = "mock"))] - pub fn from_tdx_quote(quote: &tdx_quote::Quote) -> Self { - Self::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, quote.mrtd()), - (DcapMeasurementRegister::RTMR0, quote.rtmr0()), - (DcapMeasurementRegister::RTMR1, quote.rtmr1()), - (DcapMeasurementRegister::RTMR2, quote.rtmr2()), - (DcapMeasurementRegister::RTMR3, quote.rtmr3()), - ])) - } - - pub fn from_pcrs<'a>(pcrs: impl Iterator) -> Self { - Self::Azure( - pcrs.copied() - .enumerate() - .map(|(index, value)| (index as u32, value)) - .collect(), - ) - } -} - -/// An error when converting measurements / to or from HTTP header format -#[derive(Error, Debug)] -pub enum MeasurementFormatError { - #[error("JSON: {0}")] - Json(#[from] serde_json::Error), - #[error("Missing value: {0}")] - MissingValue(String), - #[error("Invalid header value: {0}")] - BadHeaderValue(#[from] InvalidHeaderValue), - #[error("IO: {0}")] - Io(#[from] std::io::Error), - #[error("Attestation type not valid")] - AttestationTypeNotValid, - #[error("Hex: {0}")] - Hex(#[from] hex::FromHexError), - #[error("Expected 48 byte value")] - BadLength, - #[error("TDX quote register index must be in the ranger 0-3")] - BadRegisterIndex, - #[error("ParseInt: {0}")] - ParseInt(#[from] std::num::ParseIntError), - #[error("Failed to read measurements from URL: {0}")] - Reqwest(#[from] reqwest::Error), - #[error("Measurement entry for register '{0}' has both 'expected' and 'expected_any'")] - BothExpectedAndExpectedAny(String), - #[error("Measurement entry for register '{0}' has neither 'expected' nor 'expected_any'")] - NoExpectedValue(String), - #[error("Measurement entry for register '{0}' has empty 'expected_any' list")] - EmptyExpectedAny(String), -} - -/// An accepted measurement value given in the measurements file -#[derive(Clone, Debug, PartialEq)] -pub struct MeasurementRecord { - /// An identifier, for example the name and version of the corresponding OS image - pub measurement_id: String, - /// The expected measurement register values - pub measurements: ExpectedMeasurements, -} - -impl MeasurementRecord { - pub fn allow_no_attestation() -> Self { - Self { - measurement_id: "Allow no attestation".to_string(), - measurements: ExpectedMeasurements::NoAttestation, - } - } - - pub fn allow_any_measurement(attestation_type: AttestationType) -> Self { - Self { - measurement_id: format!("Any measurement for {attestation_type}"), - measurements: match attestation_type { - AttestationType::None => ExpectedMeasurements::NoAttestation, - AttestationType::AzureTdx => ExpectedMeasurements::Azure(HashMap::new()), - _ => ExpectedMeasurements::Dcap(HashMap::new()), - }, - } - } -} - -/// Represents the measurement policy -/// -/// This is a set of acceptable attestation types (CVM platforms) which may or may not enforce -/// acceptable measurement values for each attestation type -#[derive(Clone, Debug)] -pub struct MeasurementPolicy { - /// A map of accepted attestation types to accepted measurement values - /// A value of None means accept any measurement value for this measurement type - pub(crate) accepted_measurements: Vec, -} - -impl MeasurementPolicy { - /// This will only allow no attestation - and will reject it if one is given - pub fn expect_none() -> Self { - Self { - accepted_measurements: vec![MeasurementRecord::allow_no_attestation()], - } - } - - /// Allow any measurements with the given attestation type - pub fn single_attestation_type(attestation_type: AttestationType) -> Self { - Self { - accepted_measurements: vec![MeasurementRecord::allow_any_measurement(attestation_type)], - } - } - - /// Accept any attestation type with any measurements - pub fn accept_anything() -> Self { - Self { - accepted_measurements: vec![ - MeasurementRecord::allow_no_attestation(), - MeasurementRecord::allow_any_measurement(AttestationType::DcapTdx), - MeasurementRecord::allow_any_measurement(AttestationType::QemuTdx), - MeasurementRecord::allow_any_measurement(AttestationType::GcpTdx), - MeasurementRecord::allow_any_measurement(AttestationType::AzureTdx), - ], - } - } - - /// Accept any TDX attestation regardless of platform - pub fn tdx() -> Self { - Self { - accepted_measurements: vec![ - MeasurementRecord::allow_any_measurement(AttestationType::DcapTdx), - MeasurementRecord::allow_any_measurement(AttestationType::QemuTdx), - MeasurementRecord::allow_any_measurement(AttestationType::GcpTdx), - MeasurementRecord::allow_any_measurement(AttestationType::AzureTdx), - ], - } - } - - /// Expect mock measurements used in tests - #[cfg(any(test, feature = "mock"))] - pub fn mock() -> Self { - Self { - accepted_measurements: vec![MeasurementRecord { - measurement_id: "test".to_string(), - measurements: ExpectedMeasurements::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, vec![[0; 48]]), - (DcapMeasurementRegister::RTMR0, vec![[0; 48]]), - (DcapMeasurementRegister::RTMR1, vec![[0; 48]]), - (DcapMeasurementRegister::RTMR2, vec![[0; 48]]), - (DcapMeasurementRegister::RTMR3, vec![[0; 48]]), - ])), - }], - } - } - - /// Given an attestation type and set of measurements, check whether they are acceptable - pub fn check_measurement( - &self, - measurements: &MultiMeasurements, - ) -> Result<(), AttestationError> { - if self - .accepted_measurements - .iter() - .any(|measurement_record| match measurements { - MultiMeasurements::Dcap(dcap_measurements) => { - if let ExpectedMeasurements::Dcap(expected) = &measurement_record.measurements { - // All measurements in our policy must be given and must match - for (k, v) in expected.iter() { - match dcap_measurements.get(k) { - Some(actual_value) if v.iter().any(|v| actual_value == v) => {} - _ => return false, - } - } - return true; - } - false - } - MultiMeasurements::Azure(azure_measurements) => { - if let ExpectedMeasurements::Azure(expected) = &measurement_record.measurements - { - for (k, v) in expected.iter() { - match azure_measurements.get(k) { - Some(actual_value) if v.iter().any(|v| actual_value == v) => {} - _ => return false, - } - } - return true; - } - false - } - MultiMeasurements::NoAttestation => { - matches!( - measurement_record.measurements, - ExpectedMeasurements::NoAttestation - ) - } - }) - { - Ok(()) - } else { - Err(AttestationError::MeasurementsNotAccepted) - } - } - - /// Whether or not we require attestation - pub fn has_remote_attestion(&self) -> bool { - !self - .accepted_measurements - .iter() - .any(|a| a.measurements == ExpectedMeasurements::NoAttestation) - } - - /// Given either a URL or the path to a file, parse the measurement policy from JSON - pub async fn from_file_or_url(file_or_url: String) -> Result { - if file_or_url.starts_with("https://") || file_or_url.starts_with("http://") { - let measurements_json = reqwest::get(file_or_url).await?.bytes().await?; - Self::from_json_bytes(measurements_json.to_vec()).await - } else { - Self::from_file(file_or_url.into()).await - } - } - - /// Given the path to a JSON file containing measurements, return a [MeasurementPolicy] - pub async fn from_file(measurement_file: PathBuf) -> Result { - let measurements_json = tokio::fs::read(measurement_file).await?; - Self::from_json_bytes(measurements_json).await - } - - /// Parse from JSON - pub async fn from_json_bytes(json_bytes: Vec) -> Result { - #[derive(Debug, Deserialize)] - struct MeasurementRecordSimple { - measurement_id: Option, - attestation_type: String, - measurements: Option>, - } - - /// Measurement entry for a single register in the measurements JSON file. - /// Use `expected_any` for new configurations; `expected` is deprecated. - #[derive(Debug, Deserialize)] - struct MeasurementEntry { - /// Deprecated: use `expected_any` instead. Single hex-encoded expected value. - #[serde(default)] - expected: Option, - /// List of acceptable hex-encoded values (OR semantics - any value matches). - #[serde(default)] - expected_any: Option>, - } - - fn parse_measurement_entry( - entry: &MeasurementEntry, - register_name: &str, - ) -> Result, MeasurementFormatError> { - match (&entry.expected, &entry.expected_any) { - (Some(single), None) => { - let bytes: [u8; N] = hex::decode(single)? - .try_into() - .map_err(|_| MeasurementFormatError::BadLength)?; - Ok(vec![bytes]) - } - (None, Some(any_list)) => { - if any_list.is_empty() { - return Err(MeasurementFormatError::EmptyExpectedAny( - register_name.to_string(), - )); - } - let values = any_list - .iter() - .map(|hex_str| { - hex::decode(hex_str)? - .try_into() - .map_err(|_| MeasurementFormatError::BadLength) - }) - .collect::, _>>()?; - Ok(values) - } - (Some(_), Some(_)) => Err(MeasurementFormatError::BothExpectedAndExpectedAny( - register_name.to_string(), - )), - (None, None) => Err(MeasurementFormatError::NoExpectedValue( - register_name.to_string(), - )), - } - } - - let measurements_simple: Vec = - serde_json::from_slice(&json_bytes)?; - - let mut measurement_policy = Vec::new(); - - for measurement in measurements_simple { - let attestation_type = - serde_json::from_value(serde_json::Value::String(measurement.attestation_type))?; - - if let Some(measurements) = measurement.measurements { - let expected_measurements = match attestation_type { - AttestationType::AzureTdx => { - let azure_measurements = measurements - .iter() - .map(|(index_str, entry)| { - let index: u32 = index_str.parse()?; - - if index > 23 { - return Err(MeasurementFormatError::BadRegisterIndex); - } - - Ok((index, parse_measurement_entry::<32>(entry, index_str)?)) - }) - .collect::>, MeasurementFormatError>>( - )?; - ExpectedMeasurements::Azure(azure_measurements) - } - AttestationType::None => ExpectedMeasurements::NoAttestation, - _ => ExpectedMeasurements::Dcap( - measurements - .iter() - .map(|(index_str, entry)| { - let index: u8 = index_str.parse()?; - Ok(( - DcapMeasurementRegister::try_from(index)?, - parse_measurement_entry::<48>(entry, index_str)?, - )) - }) - .collect::>, - MeasurementFormatError, - >>()?, - ), - }; - - measurement_policy.push(MeasurementRecord { - measurement_id: measurement.measurement_id.unwrap_or_default(), - measurements: expected_measurements, - }); - } else { - measurement_policy.push(MeasurementRecord::allow_any_measurement(attestation_type)); - }; - } - - Ok(MeasurementPolicy { - accepted_measurements: measurement_policy, - }) - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashSet; - - use crate::test_helpers::mock_dcap_measurements; - - use super::*; - - #[tokio::test] - async fn test_read_measurements_file() { - let specific_measurements = - MeasurementPolicy::from_file("test-assets/measurements.json".into()) - .await - .unwrap(); - - assert_eq!(specific_measurements.accepted_measurements.len(), 3); - - let m = &specific_measurements.accepted_measurements[0]; - if let ExpectedMeasurements::Azure(a) = &m.measurements { - assert_eq!( - a.keys().collect::>(), - HashSet::from([&9, &4, &11]) - ); - } else { - panic!("Unexpected measurement type"); - } - - let m = &specific_measurements.accepted_measurements[1]; - if let ExpectedMeasurements::Azure(a) = &m.measurements { - assert_eq!(a.keys().collect::>(), HashSet::from([&9, &4])); - } else { - panic!("Unexpected measurement type"); - } - - let m = &specific_measurements.accepted_measurements[2]; - if let ExpectedMeasurements::Dcap(d) = &m.measurements { - assert!(d.contains_key(&DcapMeasurementRegister::MRTD)); - assert!(d.contains_key(&DcapMeasurementRegister::RTMR0)); - assert!(d.contains_key(&DcapMeasurementRegister::RTMR1)); - assert!(d.contains_key(&DcapMeasurementRegister::RTMR2)); - assert!(d.contains_key(&DcapMeasurementRegister::RTMR3)); - } else { - panic!("Unexpected measurement type"); - } - - // Will not match mock measurements - assert!(matches!( - specific_measurements - .check_measurement(&mock_dcap_measurements()) - .unwrap_err(), - AttestationError::MeasurementsNotAccepted - )); - - // Will not match another attestation type - assert!(matches!( - specific_measurements - .check_measurement(&MultiMeasurements::NoAttestation) - .unwrap_err(), - AttestationError::MeasurementsNotAccepted - )); - - // A non-specific measurement fails - assert!(matches!( - specific_measurements - .check_measurement(&MultiMeasurements::Azure(HashMap::new())) - .unwrap_err(), - AttestationError::MeasurementsNotAccepted - )); - } - - #[tokio::test] - async fn test_read_measurements_file_non_specific() { - // This specifies a particular attestation type, but not specific measurements - let allowed_attestation_type = - MeasurementPolicy::from_file("test-assets/measurements_2.json".into()) - .await - .unwrap(); - - allowed_attestation_type - .check_measurement(&mock_dcap_measurements()) - .unwrap(); - - // Will not match another attestation type - assert!(matches!( - allowed_attestation_type - .check_measurement(&MultiMeasurements::NoAttestation) - .unwrap_err(), - AttestationError::MeasurementsNotAccepted - )); - } - - #[tokio::test] - async fn test_read_remote_buildernet_measurements() { - // Check that the buildernet measurements are available and parse correctly - let policy = MeasurementPolicy::from_file_or_url( - "https://measurements.builder.flashbots.net".to_string(), - ) - .await - .unwrap(); - - assert!(!policy.accepted_measurements.is_empty()); - - assert!(matches!( - policy - .check_measurement(&MultiMeasurements::NoAttestation) - .unwrap_err(), - AttestationError::MeasurementsNotAccepted - )); - - // A non-specific measurement fails - assert!(matches!( - policy - .check_measurement(&MultiMeasurements::Azure(HashMap::new())) - .unwrap_err(), - AttestationError::MeasurementsNotAccepted - )); - } - - #[tokio::test] - async fn test_parse_expected_any() { - let json = r#"[ - { - "measurement_id": "test-any", - "attestation_type": "dcap-tdx", - "measurements": { - "0": { - "expected_any": [ - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" - ] - } - } - } - ]"#; - - let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()) - .await - .unwrap(); - assert_eq!(policy.accepted_measurements.len(), 1); - - let record = &policy.accepted_measurements[0]; - if let ExpectedMeasurements::Dcap(dcap) = &record.measurements { - let expected = dcap.get(&DcapMeasurementRegister::MRTD).unwrap(); - assert_eq!(expected.len(), 2); - } else { - panic!("Expected ExpectedMeasurements::Dcap"); - } - } - - #[tokio::test] - async fn test_check_measurement_with_or_semantics() { - let json = r#"[ - { - "measurement_id": "test-or", - "attestation_type": "dcap-tdx", - "measurements": { - "0": { - "expected_any": [ - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" - ] - } - } - } - ]"#; - - let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()) - .await - .unwrap(); - - // First value should match - let measurements1 = - MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0u8; 48])])); - assert!(policy.check_measurement(&measurements1).is_ok()); - - // Second value should also match - let measurements2 = MultiMeasurements::Dcap(HashMap::from([( - DcapMeasurementRegister::MRTD, - [0x11u8; 48], - )])); - assert!(policy.check_measurement(&measurements2).is_ok()); - - // Different value should not match - let measurements3 = MultiMeasurements::Dcap(HashMap::from([( - DcapMeasurementRegister::MRTD, - [0x22u8; 48], - )])); - assert!(policy.check_measurement(&measurements3).is_err()); - } - - #[tokio::test] - async fn test_parse_both_expected_and_expected_any_error() { - let json = r#"[ - { - "attestation_type": "dcap-tdx", - "measurements": { - "0": { - "expected": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "expected_any": ["111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"] - } - } - } - ]"#; - - let result = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).await; - assert!(matches!( - result, - Err(MeasurementFormatError::BothExpectedAndExpectedAny(_)) - )); - } - - #[tokio::test] - async fn test_parse_neither_expected_nor_expected_any_error() { - let json = r#"[ - { - "attestation_type": "dcap-tdx", - "measurements": { - "0": {} - } - } - ]"#; - - let result = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).await; - assert!(matches!( - result, - Err(MeasurementFormatError::NoExpectedValue(_)) - )); - } - - #[tokio::test] - async fn test_parse_empty_expected_any_error() { - let json = r#"[ - { - "attestation_type": "dcap-tdx", - "measurements": { - "0": { - "expected_any": [] - } - } - } - ]"#; - - let result = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).await; - assert!(matches!( - result, - Err(MeasurementFormatError::EmptyExpectedAny(_)) - )); - } - - #[tokio::test] - async fn test_mixed_expected_and_expected_any_in_different_registers() { - let json = r#"[ - { - "measurement_id": "mixed-test", - "attestation_type": "dcap-tdx", - "measurements": { - "0": { - "expected": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - }, - "1": { - "expected_any": [ - "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - "222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222" - ] - } - } - } - ]"#; - - let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()) - .await - .unwrap(); - - // Both match (single + first of any) - let measurements1 = MultiMeasurements::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, [0u8; 48]), - (DcapMeasurementRegister::RTMR0, [0x11u8; 48]), - ])); - assert!(policy.check_measurement(&measurements1).is_ok()); - - // Both match (single + second of any) - let measurements2 = MultiMeasurements::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, [0u8; 48]), - (DcapMeasurementRegister::RTMR0, [0x22u8; 48]), - ])); - assert!(policy.check_measurement(&measurements2).is_ok()); - - // Single matches but any doesn't - let measurements3 = MultiMeasurements::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, [0u8; 48]), - (DcapMeasurementRegister::RTMR0, [0x33u8; 48]), - ])); - assert!(policy.check_measurement(&measurements3).is_err()); - } - - #[test] - fn test_multi_measurements_debug_prints_hex() { - let dcap = MultiMeasurements::Dcap(HashMap::from([( - DcapMeasurementRegister::MRTD, - [0xabu8; 48], - )])); - let dcap_debug = format!("{dcap:?}"); - assert!(dcap_debug.contains("Dcap")); - assert!(dcap_debug.contains("abababab")); - assert!(!dcap_debug.contains("[171")); - - let azure = MultiMeasurements::Azure(HashMap::from([(9u32, [0x11u8; 32])])); - let azure_debug = format!("{azure:?}"); - assert!(azure_debug.contains("Azure")); - assert!(azure_debug.contains("11111111")); - assert!(!azure_debug.contains("[17")); - } -} diff --git a/attestation/src/test_helpers.rs b/attestation/src/test_helpers.rs deleted file mode 100644 index 706e08e..0000000 --- a/attestation/src/test_helpers.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::{MultiMeasurements, measurements::DcapMeasurementRegister}; -use std::collections::HashMap; - -/// All-zero measurment values used in some tests -pub fn mock_dcap_measurements() -> MultiMeasurements { - MultiMeasurements::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, [0u8; 48]), - (DcapMeasurementRegister::RTMR0, [0u8; 48]), - (DcapMeasurementRegister::RTMR1, [0u8; 48]), - (DcapMeasurementRegister::RTMR2, [0u8; 48]), - (DcapMeasurementRegister::RTMR3, [0u8; 48]), - ])) -} diff --git a/attestation/test-assets/azure-collateral.json b/attestation/test-assets/azure-collateral.json deleted file mode 100644 index bd64f8a..0000000 --- a/attestation/test-assets/azure-collateral.json +++ /dev/null @@ -1 +0,0 @@ -{"pck_crl_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","root_ca_crl":"308201203081c8020101300a06082a8648ce3d0403023068311a301806035504030c11496e74656c2053475820526f6f74204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3235303332303131323135375a170d3236303430333131323135375aa02f302d300a0603551d140403020101301f0603551d2304183016801422650cd65a9d3489f383b49552bf501b392706ac300a06082a8648ce3d0403020347003044022030c9fce1438da0a94e4fffdd46c9650e393be6e5a7862d4e4e73527932d04af302206539efe3f734c3d7df20d9dfc4630e1c7ff0439a0f8ece101f15b5eaff9b4f33","pck_crl":"30820d1730820cbd020101300a06082a8648ce3d04030230703122302006035504030c19496e74656c205347582050434b20506c6174666f726d204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3236303231383130343131355a170d3236303332303130343131355a30820be9303302146fc34e5023e728923435d61aa4b83c618166ad35170d3236303231383130343131355a300c300a0603551d1504030a01013034021500efae6e9715fca13b87e333e8261ed6d990a926ad170d3236303231383130343131355a300c300a0603551d1504030a01013034021500fd608648629cba73078b4d492f4b3ea741ad08cd170d3236303231383130343131355a300c300a0603551d1504030a010130340215008af924184e1d5afddd73c3d63a12f5e8b5737e56170d3236303231383130343131355a300c300a0603551d1504030a01013034021500b1257978cfa9ccdd0759abf8c5ca72fae3a78a9b170d3236303231383130343131355a300c300a0603551d1504030a01013033021474fea614a972be0e2843f2059835811ed872f9b3170d3236303231383130343131355a300c300a0603551d1504030a01013034021500f9c4ef56b3ab48d577e108baedf4bf88014214b9170d3236303231383130343131355a300c300a0603551d1504030a010130330214071de0778f9e5fc4f2878f30d6b07c9a30e6b30b170d3236303231383130343131355a300c300a0603551d1504030a01013034021500cde2424f972cea94ff239937f4d80c25029dd60b170d3236303231383130343131355a300c300a0603551d1504030a0101303302146c3319e5109b64507d3cf1132ce00349ef527319170d3236303231383130343131355a300c300a0603551d1504030a01013034021500df08d756b66a7497f43b5bb58ada04d3f4f7a937170d3236303231383130343131355a300c300a0603551d1504030a01013033021428af485b6cf67e409a39d5cb5aee4598f7a8fa7b170d3236303231383130343131355a300c300a0603551d1504030a01013034021500fb8b2daec092cada8aa9bc4ff2f1c20d0346668c170d3236303231383130343131355a300c300a0603551d1504030a01013034021500cd4850ac52bdcc69a6a6f058c8bc57bbd0b5f864170d3236303231383130343131355a300c300a0603551d1504030a01013034021500994dd3666f5275fb805f95dd02bd50cb2679d8ad170d3236303231383130343131355a300c300a0603551d1504030a0101303302140702136900252274d9035eedf5457462fad0ef4c170d3236303231383130343131355a300c300a0603551d1504030a01013033021461f2bf73e39b4e04aa27d801bd73d24319b5bf80170d3236303231383130343131355a300c300a0603551d1504030a0101303302143992be851b96902eff38959e6c2eff1b0651a4b5170d3236303231383130343131355a300c300a0603551d1504030a0101303302140fda43a00b68ea79b7c2deaeac0b498bdfb2af90170d3236303231383130343131355a300c300a0603551d1504030a010130330214639f139a5040fdcff191e8a4fb1bf086ed603971170d3236303231383130343131355a300c300a0603551d1504030a01013034021500959d533f9249dc1e513544cdc830bf19b7f1f301170d3236303231383130343131355a300c300a0603551d1504030a0101303302147ae37748a9f912f4c63ba7ab07c593ce1d1d1181170d3236303231383130343131355a300c300a0603551d1504030a01013033021413884b33269938c195aa170fca75da177538df0b170d3236303231383130343131355a300c300a0603551d1504030a0101303402150085d3c9381b77a7e04d119c9e5ad6749ff3ffab87170d3236303231383130343131355a300c300a0603551d1504030a0101303402150093887ca4411e7a923bd1fed2819b2949f201b5b4170d3236303231383130343131355a300c300a0603551d1504030a0101303302142498dc6283930996fd8bf23a37acbe26a3bed457170d3236303231383130343131355a300c300a0603551d1504030a010130340215008a66f1a749488667689cc3903ac54c662b712e73170d3236303231383130343131355a300c300a0603551d1504030a01013034021500afc13610bdd36cb7985d106481a880d3a01fda07170d3236303231383130343131355a300c300a0603551d1504030a01013034021500efe04b2c33d036aac96ca673bf1e9a47b64d5cbb170d3236303231383130343131355a300c300a0603551d1504030a0101303402150083d9ac8d8bb509d1c6c809ad712e8430559ed7f3170d3236303231383130343131355a300c300a0603551d1504030a0101303302147931fd50b5071c1bbfc5b7b6ded8b45b9d8b8529170d3236303231383130343131355a300c300a0603551d1504030a0101303302141fa20e2970bde5d57f7b8ddf8339484e1f1d0823170d3236303231383130343131355a300c300a0603551d1504030a0101303302141e87b2c3b32d8d23e411cef34197b95af0c8adf5170d3236303231383130343131355a300c300a0603551d1504030a010130340215009afd2ee90a473550a167d996911437c7502d1f09170d3236303231383130343131355a300c300a0603551d1504030a0101303302144481b0f11728a13b696d3ea9c770a0b15ec58dda170d3236303231383130343131355a300c300a0603551d1504030a01013034021500a7859f57982ef0e67d37bc8ef2ef5ac835ff1aa9170d3236303231383130343131355a300c300a0603551d1504030a010130340215009d67753b81e47090aea763fbec4c4549bcdb9933170d3236303231383130343131355a300c300a0603551d1504030a01013033021434bfbb7a1d9c568147e118b614f7b76ed3ef68df170d3236303231383130343131355a300c300a0603551d1504030a0101303302142c3cc6fe9279db1516d5ce39f2a898cda5a175e1170d3236303231383130343131355a300c300a0603551d1504030a010130330214717948687509234be979e4b7dce6f31bef64b68c170d3236303231383130343131355a300c300a0603551d1504030a010130340215009d76ef2c39c136e8658b6e7396b1d7445a27631f170d3236303231383130343131355a300c300a0603551d1504030a01013034021500c3e025fca995f36f59b48467939e3e34e6361a6f170d3236303231383130343131355a300c300a0603551d1504030a010130340215008c5f6b3257da05b17429e2e61ba965d67330606a170d3236303231383130343131355a300c300a0603551d1504030a01013034021500a17c51722ec1e0c3278fe8bdf052059cbec4e648170d3236303231383130343131355a300c300a0603551d1504030a01013033021411c943b866fa04944e3057e5a67146596475a023170d3236303231383130343131355a300c300a0603551d1504030a01013034021500be6913785406155454a28885a515b3da5767d3a9170d3236303231383130343131355a300c300a0603551d1504030a0101303302140ac5ec91bd934c07b9ea41625e9cc09681002eb0170d3236303231383130343131355a300c300a0603551d1504030a0101303302146d51a0eabc1f9a1e9ddd5b36bdda1631ae6c182a170d3236303231383130343131355a300c300a0603551d1504030a01013034021500a52c5d71c4166b4fc0ded8b679951e5ee9193de5170d3236303231383130343131355a300c300a0603551d1504030a010130330214249779aedd85fcac93c8853516be5428c26b3bf8170d3236303231383130343131355a300c300a0603551d1504030a01013033021434ba4fd76bde5309210cf1dd1ffb494c638a9157170d3236303231383130343131355a300c300a0603551d1504030a010130330214043e04919daae13443248395094d2a2eacfc76fe170d3236303231383130343131355a300c300a0603551d1504030a01013033021447fc577d2d094cbdf270715ed6848a93855ad34b170d3236303231383130343131355a300c300a0603551d1504030a0101303302147d62a2f5e6f386e469653fffff045d0a8178e8e7170d3236303231383130343131355a300c300a0603551d1504030a01013034021500c4ed45fe026bb6a47eaec35ea80b7ef407ce062c170d3236303231383130343131355a300c300a0603551d1504030a01013034021500cf9831077a3ca4f1a2c56867bf55b18eccbeffd8170d3236303231383130343131355a300c300a0603551d1504030a0101303302146c2b81d7ea2e436720ce29f1d0b1ccb7a218600f170d3236303231383130343131355a300c300a0603551d1504030a0101a02f302d300a0603551d140403020101301f0603551d23041830168014956f5dcdbd1be1e94049c9d4f433ce01570bde54300a06082a8648ce3d0403020348003045022100f00668672d1a3079ecea223cc81ce18abb14c7945b485d4b2cd744bff993c95c02203055c33fdacd3b52c61c4a043945a6e607d8b361db1082cc2aa93dd7e83e377b","tcb_info_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","tcb_info":"{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2026-02-18T10:58:51Z\",\"nextUpdate\":\"2026-03-20T10:58:51Z\",\"fmspc\":\"90C06F000000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":18,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":3,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":4,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-01036\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]}]}","tcb_info_signature":"bdd7c459dbae4634650fd5f7a6bab2f89f4c081e043ecd76dda8dd00362732b889ad8dcdb93daa18cdb5cda6d5aa9092908f5465863d390ebe23da7dd46a5f2f","qe_identity_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","qe_identity":"{\"id\":\"TD_QE\",\"version\":2,\"issueDate\":\"2026-02-18T10:42:15Z\",\"nextUpdate\":\"2026-03-20T10:42:15Z\",\"tcbEvaluationDataNumber\":18,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]}","qe_identity_signature":"85037e9d4dbf39bc6f7f404e29fdf920e96d9e6e6f4afd288fcbe085c59bd52f09da1c284f13bbd342f2c787b6dba3003db958a75134b136bca068272f2392bf"} diff --git a/attestation/test-assets/azure-collateral02.json b/attestation/test-assets/azure-collateral02.json deleted file mode 100644 index 57f251c..0000000 --- a/attestation/test-assets/azure-collateral02.json +++ /dev/null @@ -1 +0,0 @@ -{"pck_crl_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","root_ca_crl":"308201203081c8020101300a06082a8648ce3d0403023068311a301806035504030c11496e74656c2053475820526f6f74204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3235303332303131323135375a170d3236303430333131323135375aa02f302d300a0603551d140403020101301f0603551d2304183016801422650cd65a9d3489f383b49552bf501b392706ac300a06082a8648ce3d0403020347003044022030c9fce1438da0a94e4fffdd46c9650e393be6e5a7862d4e4e73527932d04af302206539efe3f734c3d7df20d9dfc4630e1c7ff0439a0f8ece101f15b5eaff9b4f33","pck_crl":"30820d1730820cbd020101300a06082a8648ce3d04030230703122302006035504030c19496e74656c205347582050434b20506c6174666f726d204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3236303231383133343132305a170d3236303332303133343132305a30820be9303302146fc34e5023e728923435d61aa4b83c618166ad35170d3236303231383133343132305a300c300a0603551d1504030a01013034021500efae6e9715fca13b87e333e8261ed6d990a926ad170d3236303231383133343132305a300c300a0603551d1504030a01013034021500fd608648629cba73078b4d492f4b3ea741ad08cd170d3236303231383133343132305a300c300a0603551d1504030a010130340215008af924184e1d5afddd73c3d63a12f5e8b5737e56170d3236303231383133343132305a300c300a0603551d1504030a01013034021500b1257978cfa9ccdd0759abf8c5ca72fae3a78a9b170d3236303231383133343132305a300c300a0603551d1504030a01013033021474fea614a972be0e2843f2059835811ed872f9b3170d3236303231383133343132305a300c300a0603551d1504030a01013034021500f9c4ef56b3ab48d577e108baedf4bf88014214b9170d3236303231383133343132305a300c300a0603551d1504030a010130330214071de0778f9e5fc4f2878f30d6b07c9a30e6b30b170d3236303231383133343132305a300c300a0603551d1504030a01013034021500cde2424f972cea94ff239937f4d80c25029dd60b170d3236303231383133343132305a300c300a0603551d1504030a0101303302146c3319e5109b64507d3cf1132ce00349ef527319170d3236303231383133343132305a300c300a0603551d1504030a01013034021500df08d756b66a7497f43b5bb58ada04d3f4f7a937170d3236303231383133343132305a300c300a0603551d1504030a01013033021428af485b6cf67e409a39d5cb5aee4598f7a8fa7b170d3236303231383133343132305a300c300a0603551d1504030a01013034021500fb8b2daec092cada8aa9bc4ff2f1c20d0346668c170d3236303231383133343132305a300c300a0603551d1504030a01013034021500cd4850ac52bdcc69a6a6f058c8bc57bbd0b5f864170d3236303231383133343132305a300c300a0603551d1504030a01013034021500994dd3666f5275fb805f95dd02bd50cb2679d8ad170d3236303231383133343132305a300c300a0603551d1504030a0101303302140702136900252274d9035eedf5457462fad0ef4c170d3236303231383133343132305a300c300a0603551d1504030a01013033021461f2bf73e39b4e04aa27d801bd73d24319b5bf80170d3236303231383133343132305a300c300a0603551d1504030a0101303302143992be851b96902eff38959e6c2eff1b0651a4b5170d3236303231383133343132305a300c300a0603551d1504030a0101303302140fda43a00b68ea79b7c2deaeac0b498bdfb2af90170d3236303231383133343132305a300c300a0603551d1504030a010130330214639f139a5040fdcff191e8a4fb1bf086ed603971170d3236303231383133343132305a300c300a0603551d1504030a01013034021500959d533f9249dc1e513544cdc830bf19b7f1f301170d3236303231383133343132305a300c300a0603551d1504030a0101303302147ae37748a9f912f4c63ba7ab07c593ce1d1d1181170d3236303231383133343132305a300c300a0603551d1504030a01013033021413884b33269938c195aa170fca75da177538df0b170d3236303231383133343132305a300c300a0603551d1504030a0101303402150085d3c9381b77a7e04d119c9e5ad6749ff3ffab87170d3236303231383133343132305a300c300a0603551d1504030a0101303402150093887ca4411e7a923bd1fed2819b2949f201b5b4170d3236303231383133343132305a300c300a0603551d1504030a0101303302142498dc6283930996fd8bf23a37acbe26a3bed457170d3236303231383133343132305a300c300a0603551d1504030a010130340215008a66f1a749488667689cc3903ac54c662b712e73170d3236303231383133343132305a300c300a0603551d1504030a01013034021500afc13610bdd36cb7985d106481a880d3a01fda07170d3236303231383133343132305a300c300a0603551d1504030a01013034021500efe04b2c33d036aac96ca673bf1e9a47b64d5cbb170d3236303231383133343132305a300c300a0603551d1504030a0101303402150083d9ac8d8bb509d1c6c809ad712e8430559ed7f3170d3236303231383133343132305a300c300a0603551d1504030a0101303302147931fd50b5071c1bbfc5b7b6ded8b45b9d8b8529170d3236303231383133343132305a300c300a0603551d1504030a0101303302141fa20e2970bde5d57f7b8ddf8339484e1f1d0823170d3236303231383133343132305a300c300a0603551d1504030a0101303302141e87b2c3b32d8d23e411cef34197b95af0c8adf5170d3236303231383133343132305a300c300a0603551d1504030a010130340215009afd2ee90a473550a167d996911437c7502d1f09170d3236303231383133343132305a300c300a0603551d1504030a0101303302144481b0f11728a13b696d3ea9c770a0b15ec58dda170d3236303231383133343132305a300c300a0603551d1504030a01013034021500a7859f57982ef0e67d37bc8ef2ef5ac835ff1aa9170d3236303231383133343132305a300c300a0603551d1504030a010130340215009d67753b81e47090aea763fbec4c4549bcdb9933170d3236303231383133343132305a300c300a0603551d1504030a01013033021434bfbb7a1d9c568147e118b614f7b76ed3ef68df170d3236303231383133343132305a300c300a0603551d1504030a0101303302142c3cc6fe9279db1516d5ce39f2a898cda5a175e1170d3236303231383133343132305a300c300a0603551d1504030a010130330214717948687509234be979e4b7dce6f31bef64b68c170d3236303231383133343132305a300c300a0603551d1504030a010130340215009d76ef2c39c136e8658b6e7396b1d7445a27631f170d3236303231383133343132305a300c300a0603551d1504030a01013034021500c3e025fca995f36f59b48467939e3e34e6361a6f170d3236303231383133343132305a300c300a0603551d1504030a010130340215008c5f6b3257da05b17429e2e61ba965d67330606a170d3236303231383133343132305a300c300a0603551d1504030a01013034021500a17c51722ec1e0c3278fe8bdf052059cbec4e648170d3236303231383133343132305a300c300a0603551d1504030a01013033021411c943b866fa04944e3057e5a67146596475a023170d3236303231383133343132305a300c300a0603551d1504030a01013034021500be6913785406155454a28885a515b3da5767d3a9170d3236303231383133343132305a300c300a0603551d1504030a0101303302140ac5ec91bd934c07b9ea41625e9cc09681002eb0170d3236303231383133343132305a300c300a0603551d1504030a0101303302146d51a0eabc1f9a1e9ddd5b36bdda1631ae6c182a170d3236303231383133343132305a300c300a0603551d1504030a01013034021500a52c5d71c4166b4fc0ded8b679951e5ee9193de5170d3236303231383133343132305a300c300a0603551d1504030a010130330214249779aedd85fcac93c8853516be5428c26b3bf8170d3236303231383133343132305a300c300a0603551d1504030a01013033021434ba4fd76bde5309210cf1dd1ffb494c638a9157170d3236303231383133343132305a300c300a0603551d1504030a010130330214043e04919daae13443248395094d2a2eacfc76fe170d3236303231383133343132305a300c300a0603551d1504030a01013033021447fc577d2d094cbdf270715ed6848a93855ad34b170d3236303231383133343132305a300c300a0603551d1504030a0101303302147d62a2f5e6f386e469653fffff045d0a8178e8e7170d3236303231383133343132305a300c300a0603551d1504030a01013034021500c4ed45fe026bb6a47eaec35ea80b7ef407ce062c170d3236303231383133343132305a300c300a0603551d1504030a01013034021500cf9831077a3ca4f1a2c56867bf55b18eccbeffd8170d3236303231383133343132305a300c300a0603551d1504030a0101303302146c2b81d7ea2e436720ce29f1d0b1ccb7a218600f170d3236303231383133343132305a300c300a0603551d1504030a0101a02f302d300a0603551d140403020101301f0603551d23041830168014956f5dcdbd1be1e94049c9d4f433ce01570bde54300a06082a8648ce3d0403020348003045022100e1e8ddb6a667812ff2852e3c764b1b26b56054ae3fe92193fee6667ffe6c9b90022032d28f902c8fa5847b1485012a3142009dce4b73149f47d352ff39ca8ccef68f","tcb_info_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","tcb_info":"{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2026-02-18T13:58:55Z\",\"nextUpdate\":\"2026-03-20T13:58:55Z\",\"fmspc\":\"90C06F000000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":18,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":3,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":4,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-01036\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]}]}","tcb_info_signature":"27ac2c478618bd416a34465fafe5e87652f146587698ad2225a3304477e7cffd1e174ac19a0d49fc1ae74887bad88462cb34f16799523bd2439df0276ed7650c","qe_identity_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","qe_identity":"{\"id\":\"TD_QE\",\"version\":2,\"issueDate\":\"2026-02-18T13:42:19Z\",\"nextUpdate\":\"2026-03-20T13:42:19Z\",\"tcbEvaluationDataNumber\":18,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]}","qe_identity_signature":"913a99658067c5fd96fbb1589b2524f1947ad3a0026b59865f6b61c0e8cd77a46e09b45c436cf5c5feeac2af63254ea0b3e766f4bd6952ba991d21e819c28787"} diff --git a/attestation/test-assets/azure-tdx-1764662251380464271 b/attestation/test-assets/azure-tdx-1764662251380464271 deleted file mode 100644 index fce573d..0000000 --- a/attestation/test-assets/azure-tdx-1764662251380464271 +++ /dev/null @@ -1 +0,0 @@ -{"tdx_quote_base64":"BAACAIEAAAAAAAAAk5pyM_ecTKmUCg2zlX8GB3Thpre77mKg7jpNBav8PEkAAAAABwEDAAAAAAAAAAAAAAAAAEm2b6pFHRnrvb6JNxuNrytlqjmE7JARA0Pp4u7BFq8IhQ-iDjsaqah013plOA7n5gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAADnGAYAAAAAABK9vBYJ7wZtt6nseybXUJNG9MpG6EYnQJbLJZObHnEZRAYcoZowxnQ_HlmRSO7kUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7HT144wmd5zTW6UINWARezcB0-_vIpFW7C7FnsrogOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQEAAAdJ_oh6mN-g_v_0efzadA_DOWFK2jYy9p-h269PwkEI4tB-zdOYEa8Uv9hECJmRBRgVQ4z4q2gSz7P56NgkQGmercwydyxD9mf5PwaMAOdpOKJNtwow7lCT3oqVghyxhUPqIP5O_j2a8Dz9-Tpa1cQuZpSiimuRmchsKX3gPO3O8GAEoQAAADAxkbBP8ABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAOcAAAAAAAAA5aOntdgwwpU7mFNMbFmjo0_cNOkz9_WJjwqFzwiEa8oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANyeKnxvlI8XR040p_xD7QMPfBVj8bq932NAyC4OVKjFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHpJi_9CXp9wO3djOvudEoQR5boWPVXYM6F7X8QIwOVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVQhcPV03wFyimgChXn5NVWfyQTse-BNQdLQotqL9Hf7Ft-i9mrUpeS7sanh8nDPB08_JariTf0DrJuO5Lmf8yIAAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHwUAYg4AAC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFOGpDQ0JKZWdBd0lCQWdJVkFQbnErb2llZDBLNlhjREN5aUlXc01ESG51bFJNQW9HQ0NxR1NNNDlCQU1DCk1IQXhJakFnQmdOVkJBTU1HVWx1ZEdWc0lGTkhXQ0JRUTBzZ1VHeGhkR1p2Y20wZ1EwRXhHakFZQmdOVkJBb00KRVVsdWRHVnNJRU52Y25CdmNtRjBhVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRQpDQXdDUTBFeEN6QUpCZ05WQkFZVEFsVlRNQjRYRFRJMU1EY3lPVEUxTXpNeE5Gb1hEVE15TURjeU9URTFNek14Ck5Gb3djREVpTUNBR0ExVUVBd3daU1c1MFpXd2dVMGRZSUZCRFN5QkRaWEowYVdacFkyRjBaVEVhTUJnR0ExVUUKQ2d3UlNXNTBaV3dnUTI5eWNHOXlZWFJwYjI0eEZEQVNCZ05WQkFjTUMxTmhiblJoSUVOc1lYSmhNUXN3Q1FZRApWUVFJREFKRFFURUxNQWtHQTFVRUJoTUNWVk13V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVFuClA2bUNzUmhHaFUzVDlrSHpCaG1SUHNKM1d2NkxPSzluUFBUY1pxVis2QjlDSDJJdDZCZ0U3VkFMeUlpMGdIemEKYmhzeE5FM2ZKc045NWhaaUFXcmJvNElERERDQ0F3Z3dId1lEVlIwakJCZ3dGb0FVbFc5ZHpiMGI0ZWxBU2NuVQo5RFBPQVZjTDNsUXdhd1lEVlIwZkJHUXdZakJnb0Y2Z1hJWmFhSFIwY0hNNkx5OWhjR2t1ZEhKMWMzUmxaSE5sCmNuWnBZMlZ6TG1sdWRHVnNMbU52YlM5elozZ3ZZMlZ5ZEdsbWFXTmhkR2x2Ymk5Mk5DOXdZMnRqY213L1kyRTkKY0d4aGRHWnZjbTBtWlc1amIyUnBibWM5WkdWeU1CMEdBMVVkRGdRV0JCUXZrTU1jN25RT1k3OTlXM2tBcTJuSQo5bW1LZVRBT0JnTlZIUThCQWY4RUJBTUNCc0F3REFZRFZSMFRBUUgvQkFJd0FEQ0NBamtHQ1NxR1NJYjRUUUVOCkFRU0NBaW93Z2dJbU1CNEdDaXFHU0liNFRRRU5BUUVFRUtUMVh3NS82WG1WTDdROWRhVS85WXN3Z2dGakJnb3EKaGtpRytFMEJEUUVDTUlJQlV6QVFCZ3NxaGtpRytFMEJEUUVDQVFJQkF6QVFCZ3NxaGtpRytFMEJEUUVDQWdJQgpBekFRQmdzcWhraUcrRTBCRFFFQ0F3SUJBakFRQmdzcWhraUcrRTBCRFFFQ0JBSUJBakFRQmdzcWhraUcrRTBCCkRRRUNCUUlCQkRBUUJnc3Foa2lHK0UwQkRRRUNCZ0lCQVRBUUJnc3Foa2lHK0UwQkRRRUNCd0lCQURBUUJnc3EKaGtpRytFMEJEUUVDQ0FJQkJUQVFCZ3NxaGtpRytFMEJEUUVDQ1FJQkFEQVFCZ3NxaGtpRytFMEJEUUVDQ2dJQgpBREFRQmdzcWhraUcrRTBCRFFFQ0N3SUJBREFRQmdzcWhraUcrRTBCRFFFQ0RBSUJBREFRQmdzcWhraUcrRTBCCkRRRUNEUUlCQURBUUJnc3Foa2lHK0UwQkRRRUNEZ0lCQURBUUJnc3Foa2lHK0UwQkRRRUNEd0lCQURBUUJnc3EKaGtpRytFMEJEUUVDRUFJQkFEQVFCZ3NxaGtpRytFMEJEUUVDRVFJQkRUQWZCZ3NxaGtpRytFMEJEUUVDRWdRUQpBd01DQWdRQkFBVUFBQUFBQUFBQUFEQVFCZ29xaGtpRytFMEJEUUVEQkFJQUFEQVVCZ29xaGtpRytFMEJEUUVFCkJBYVF3RzhBQUFBd0R3WUtLb1pJaHZoTkFRMEJCUW9CQVRBZUJnb3Foa2lHK0UwQkRRRUdCQkRjMmREb09seDgKNG0rT09kRzVjKzBkTUVRR0NpcUdTSWI0VFFFTkFRY3dOakFRQmdzcWhraUcrRTBCRFFFSEFRRUIvekFRQmdzcQpoa2lHK0UwQkRRRUhBZ0VCQURBUUJnc3Foa2lHK0UwQkRRRUhBd0VCL3pBS0JnZ3Foa2pPUFFRREFnTkpBREJHCkFpRUFwemRPNEx4amFKVHlVc3pIQ3B3aXVDL05ISzBmV2JpcGR5TlFuMGZmRWYwQ0lRRHRVeU41ZmJNbjlUUHIKWG93R1Y0Y2lIVHJkUEJOZVN2K3JEeEZNTDdVVktBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQ2xqQ0NBajJnQXdJQkFnSVZBSlZ2WGMyOUcrSHBRRW5KMVBRenpnRlhDOTVVTUFvR0NDcUdTTTQ5QkFNQwpNR2d4R2pBWUJnTlZCQU1NRVVsdWRHVnNJRk5IV0NCU2IyOTBJRU5CTVJvd0dBWURWUVFLREJGSmJuUmxiQ0JECmIzSndiM0poZEdsdmJqRVVNQklHQTFVRUJ3d0xVMkZ1ZEdFZ1EyeGhjbUV4Q3pBSkJnTlZCQWdNQWtOQk1Rc3cKQ1FZRFZRUUdFd0pWVXpBZUZ3MHhPREExTWpFeE1EVXdNVEJhRncwek16QTFNakV4TURVd01UQmFNSEF4SWpBZwpCZ05WQkFNTUdVbHVkR1ZzSUZOSFdDQlFRMHNnVUd4aGRHWnZjbTBnUTBFeEdqQVlCZ05WQkFvTUVVbHVkR1ZzCklFTnZjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXgKQ3pBSkJnTlZCQVlUQWxWVE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU5TQi83dDIxbFhTTwoyQ3V6cHh3NzRlSkI3MkV5REdnVzVyWEN0eDJ0VlRMcTZoS2s2eitVaVJaQ25xUjdwc092Z3FGZVN4bG1UbEpsCmVUbWkyV1l6M3FPQnV6Q0J1REFmQmdOVkhTTUVHREFXZ0JRaVpReldXcDAwaWZPRHRKVlN2MUFiT1NjR3JEQlMKQmdOVkhSOEVTekJKTUVlZ1JhQkRoa0ZvZEhSd2N6b3ZMMk5sY25ScFptbGpZWFJsY3k1MGNuVnpkR1ZrYzJWeQpkbWxqWlhNdWFXNTBaV3d1WTI5dEwwbHVkR1ZzVTBkWVVtOXZkRU5CTG1SbGNqQWRCZ05WSFE0RUZnUVVsVzlkCnpiMGI0ZWxBU2NuVTlEUE9BVmNMM2xRd0RnWURWUjBQQVFIL0JBUURBZ0VHTUJJR0ExVWRFd0VCL3dRSU1BWUIKQWY4Q0FRQXdDZ1lJS29aSXpqMEVBd0lEUndBd1JBSWdYc1ZraTB3K2k2VllHVzNVRi8yMnVhWGUwWUpEajFVZQpuQStUakQxYWk1Y0NJQ1liMVNBbUQ1eGtmVFZwdm80VW95aVNZeHJEV0xtVVI0Q0k5Tkt5ZlBOKwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDanpDQ0FqU2dBd0lCQWdJVUltVU0xbHFkTkluemc3U1ZVcjlRR3prbkJxd3dDZ1lJS29aSXpqMEVBd0l3CmFERWFNQmdHQTFVRUF3d1JTVzUwWld3Z1UwZFlJRkp2YjNRZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnYKY25CdmNtRjBhVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4Q3pBSgpCZ05WQkFZVEFsVlRNQjRYRFRFNE1EVXlNVEV3TkRVeE1Gb1hEVFE1TVRJek1USXpOVGsxT1Zvd2FERWFNQmdHCkExVUVBd3dSU1c1MFpXd2dVMGRZSUZKdmIzUWdRMEV4R2pBWUJnTlZCQW9NRVVsdWRHVnNJRU52Y25CdmNtRjAKYVc5dU1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVUVDQXdDUTBFeEN6QUpCZ05WQkFZVApBbFZUTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFQzZuRXdNRElZWk9qL2lQV3NDemFFS2k3CjFPaU9TTFJGaFdHamJuQlZKZlZua1k0dTNJamtEWVlMME14TzRtcXN5WWpsQmFsVFZZeEZQMnNKQks1emxLT0IKdXpDQnVEQWZCZ05WSFNNRUdEQVdnQlFpWlF6V1dwMDBpZk9EdEpWU3YxQWJPU2NHckRCU0JnTlZIUjhFU3pCSgpNRWVnUmFCRGhrRm9kSFJ3Y3pvdkwyTmxjblJwWm1sallYUmxjeTUwY25WemRHVmtjMlZ5ZG1salpYTXVhVzUwClpXd3VZMjl0TDBsdWRHVnNVMGRZVW05dmRFTkJMbVJsY2pBZEJnTlZIUTRFRmdRVUltVU0xbHFkTkluemc3U1YKVXI5UUd6a25CcXd3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUV3Q2dZSQpLb1pJemowRUF3SURTUUF3UmdJaEFPVy81UWtSK1M5Q2lTRGNOb293THVQUkxzV0dmL1lpN0dTWDk0Qmd3VHdnCkFpRUE0SjBsckhvTXMrWG81by9zWDZPOVFXeEhSQXZaVUdPZFJRN2N2cVJYYXFJPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","hcl_report_base64":"SENMQQIAAABaCQAAAgAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAAAAAAAAAAAAAAwMZGwT_AAUAAAAAAAAAAEB73O4ihAAL1Fq3YJOLBeFadfZagSvRh378KKR_plJRdg0_lzrFanQ73FOJV8ioAk0EF89TAb_qtJkcf-PQqX8vuQr5d0gmOU2-DKrvVG4VHWCx7tELBMBIwOniiJl_Gr7HT144wmd5zTW6UINWARezcB0-_vIpFW7C7FnsrogOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGo1RO-ajyGFbRpEQvwrhKfdSit715Hy11JkCim5iEjF_wEDAAAAAAAHAQMAAAAAAAAAAAAAAAAASbZvqkUdGeu9vok3G42vK2WqOYTskBEDQ-ni7sEWrwiFD6IOOxqpqHTXemU4DufmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA5xgGAAAAAAASvbwWCe8Gbbep7Hsm11CTRvTKRuhGJ0CWyyWTmx5xGUQGHKGaMMZ0Px5ZkUju5FEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJoEAAABAAAABAAAAAEAAACGBAAAeyJrZXlzIjpbeyJraWQiOiJIQ0xBa1B1YiIsImtleV9vcHMiOlsic2lnbiJdLCJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsIm4iOiJwM3g2SUFBQTY4MFViZ3AzdU5tTF93Nm1FeTJjaUd2bkFaVHFwM2tueDZGQmtieTMtZFQ2RlhXVl9NYmM3RUk4RHNQRTk1WURnT2szVEJjZktkNmxBdUw0QTdoeVBZdzc3c1dJV1dySnlBTE9FUnNmQTJiUC1hNzQyVjQ5cFJrWXRYWFI4c1NuYWNuS2Rfd0hNZ0NpVzZFNXJoUUZXTzRINUEybW51TV9xcnhocHRlQ1BidmxvN2NiTFNWOXBHTEtNbnV0RUJDYzBITndLSnZ6ZWQ5WG15cGpWWUJJTTdSbXdoNmw0bk44VzFkY0ZOby1fTnhobTV6YXU4bXo5ZktoTlFMSXpPaWkzWk95TWE0dnYtUzNJYmZoTVBUMDZqMnllbUVXWUNTbGxqQU9paGxTYllteXQtT0k3ZHJUdTZjV0tpQmNYanJKa1ZWMVFKcUdhOWRzNHcifSx7ImtpZCI6IkhDTEVrUHViIiwia2V5X29wcyI6WyJlbmNyeXB0Il0sImt0eSI6IlJTQSIsImUiOiJBUUFCIiwibiI6Im9WakUyQUFBRFVmSUlLajJtNjB0dXp2M1NJbDdBVXE2aElTeExfYmlrYWdIeUpTSzJTaWVidVJka25oSWE5MTZSNk1hdlAtdUU0TjRJaXhCMHliZlZ5TGg1YThzcVBNNHFqMnYxN2o3dXp4QWJtTldkTVJvTjRKZHZKNWpOY0FJMUs4ajF5M0pkWGkzZ0d0aWJWTkVuU3RoQ2ZsYzNPdDg1WXZiUlpfYVc5dV95S3hJQUwxWTFWQVE2WnFTaUxPM1B6Q0hUc09BZml2N3B3QUUtb3R5YjVmcFF1bFBxWFVVOGV6a0hSYmFtNUlyYnZCT18wS0FDdmhMaEFvdVB3a2YtREFhVW5uc01kT1ZQZkI1enZtMGJGZnZKTVBRTWNydUE4dVktZk1vbWZGY0tHWlphVXZ2ekNZa2tqd1N6Zmo2NDVLcTd6bUEtNkR4RnV1b2E4enNzdyJ9XSwidm0tY29uZmlndXJhdGlvbiI6eyJyb290LWNlcnQtdGh1bWJwcmludCI6IiIsImNvbnNvbGUtZW5hYmxlZCI6dHJ1ZSwic2VjdXJlLWJvb3QiOmZhbHNlLCJ0cG0tZW5hYmxlZCI6dHJ1ZSwidHBtLXBlcnNpc3RlZCI6dHJ1ZSwidm1VbmlxdWVJZCI6ImJkZDQzOTA0LWRiZjgtNDMzNy04YjkxLTNhZGJhOTJjNWViZCJ9LCJ1c2VyLWRhdGEiOiIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCJ9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","tpm_attestation":{"ak_certificate_pem":"-----BEGIN CERTIFICATE-----\nMIID7TCCAtWgAwIBAgIQZGTaH3CY2Bt8ETaN4Mt8HzANBgkqhkiG9w0BAQsFADAl\nMSMwIQYDVQQDExpHbG9iYWwgVmlydHVhbCBUUE0gQ0EgLSAwMzAeFw0yNTEyMDEw\nMDAwMDBaFw0yNjExMzAwMDAwMDBaMDgxNjA0BgNVBAMTLTM1M2M2ZDlhNzBiYy5D\nb25maWRlbnRpYWxWTS5BenVyZS53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAKd8eiAAAOvNFG4Kd7jZi/8OphMtnIhr5wGU6qd5J8eh\nQZG8t/nU+hV1lfzG3OxCPA7DxPeWA4DpN0wXHynepQLi+AO4cj2MO+7FiFlqycgC\nzhEbHwNmz/mu+NlePaUZGLV10fLEp2nJynf8BzIAoluhOa4UBVjuB+QNpp7jP6q8\nYabXgj275aO3Gy0lfaRiyjJ7rRAQnNBzcCib83nfV5sqY1WASDO0ZsIepeJzfFtX\nXBTaPvzcYZuc2rvJs/XyoTUCyMzoot2TsjGuL7/ktyG34TD09Oo9snphFmAkpZYw\nDooZUm2JsrfjiO3a07unFiogXF46yZFVdUCahmvXbOMCAwEAAaOCAQQwggEAMA4G\nA1UdDwEB/wQEAwIHgDAYBgNVHSAEETAPMA0GCysGAQQBgjdsgUgCMBwGA1UdJQQV\nMBMGCisGAQQBgjcKAwwGBWeBBQgDMB0GA1UdDgQWBBRqgwVlBrzgn9J7BOoGoSDO\n36kjVDAaBgorBgEEAYI3DQIDBAwWCjYuMi45MjAwLjIwWgYJKwYBBAGCNxUUBE0w\nSwIBBQwPQU1TMjUxMDYxOTA5MDAxDBpXT1JLR1JPVVBcQU1TMjUxMDYxOTA5MDAx\nJAwZVnRwbU1hbmFnZW1lbnRTZXJ2aWNlLmV4ZTAfBgNVHSMEGDAWgBRnCYb4+YFe\nk635yWTnFAramcsKLTANBgkqhkiG9w0BAQsFAAOCAQEAKP34NvDPbHhuNjkDqE4/\nmLyy87rDIhICcgg0eDtDGfCGcJENFGuKngtpQeJjEnY3czvZzCBlVO/iO0W6DbGi\nzqqHRcJsAyPtxUUZi84Gt7xvWtr206oHBFuk4cpUJsPunQQan2bsiO5T4YE7pqhU\nob+i49exg/IgHxLiG+w+/C23vVhLg0GM0zBqgAxuOG1ebLerkb2Fy/pHzzVNuW+g\n6XoUz3efvWC2ZXVV+4bU4TxRKjcJ544uYRTKnF3d3KKRQmuJ5ucvGySW+ofN3+Jo\n6PqvHowc0yAF1b1xzEcMhhtz1Wr5Jlv6yXfJ89WulltMxU+Hkf2SU+pKtz0wpPZ+\nWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAA==\n-----END CERTIFICATE-----\n","quote":{"signature":[135,59,50,25,70,64,229,176,28,41,162,94,237,111,83,172,175,95,193,175,187,237,230,200,179,197,131,184,209,16,107,116,168,110,47,199,140,111,223,4,108,181,42,241,70,190,88,160,195,104,249,161,250,7,175,161,30,75,90,63,237,114,102,198,182,0,204,174,119,194,243,184,124,56,2,18,221,200,103,232,156,29,0,207,160,26,216,154,208,18,153,92,97,188,36,147,220,35,39,201,210,118,252,170,60,43,15,134,84,77,23,188,121,113,19,178,249,159,22,128,167,142,179,240,70,246,106,114,183,14,130,235,3,72,120,240,82,210,250,105,178,161,125,199,173,175,5,49,51,117,146,76,175,34,4,18,91,37,189,173,156,248,44,237,115,254,71,215,220,224,130,30,100,31,189,21,7,156,33,253,30,0,199,59,142,80,47,219,5,124,133,252,239,194,105,246,181,83,110,185,30,103,8,122,181,66,117,58,83,78,60,96,167,100,50,82,127,56,219,94,80,62,65,224,146,24,83,243,116,102,27,224,213,122,94,174,102,124,145,114,125,169,192,201,184,137,187,180,255,85,194,214,201,148,46,59],"message":[255,84,67,71,128,24,0,34,0,11,176,196,237,28,251,197,97,211,73,25,195,246,137,118,108,234,140,194,246,203,163,159,152,132,197,213,135,46,152,40,142,215,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,176,163,127,0,0,0,2,0,0,0,0,1,32,32,3,18,0,18,0,3,0,0,0,1,0,11,3,255,255,255,0,32,73,235,12,37,110,154,84,47,86,198,201,8,64,241,53,217,188,196,121,140,27,5,162,10,40,110,110,222,74,249,168,118],"pcrs":[[86,31,111,47,249,11,244,110,95,1,184,215,193,191,150,12,45,100,182,72,51,37,241,141,120,33,124,132,99,15,211,83],[61,69,140,254,85,204,3,234,31,68,63,21,98,190,236,141,245,28,117,225,74,159,207,154,114,52,161,63,25,142,121,105],[189,192,76,193,11,79,205,110,159,121,26,105,91,230,132,199,199,242,175,241,156,196,82,235,102,58,28,53,82,47,75,28],[61,69,140,254,85,204,3,234,31,68,63,21,98,190,236,141,245,28,117,225,74,159,207,154,114,52,161,63,25,142,121,105],[196,162,90,109,119,4,98,159,99,219,132,210,14,168,219,14,156,224,2,178,128,27,233,163,64,9,31,231,172,88,134,153],[94,18,234,167,32,238,182,179,211,0,70,66,80,242,205,229,18,48,16,198,193,183,6,131,184,20,41,112,3,12,244,221],[180,90,56,59,226,129,211,3,171,159,183,227,211,194,92,114,209,57,251,5,37,19,45,58,244,93,121,15,213,151,11,190],[18,77,175,71,180,214,113,121,167,125,195,193,188,202,25,138,225,238,29,9,74,42,135,153,116,132,46,68,171,152,187,6],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[159,74,87,117,18,44,164,112,62,19,90,154,230,4,30,222,173,0,100,38,46,57,157,241,28,168,81,130,176,241,84,29],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[171,215,198,149,255,219,96,129,233,150,54,238,1,109,19,34,145,156,104,208,73,182,152,179,153,210,42,226,21,161,33,191],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]},"event_log":[],"instance_info":null}} \ No newline at end of file diff --git a/attestation/test-assets/azure_failed_dcap_quote_10.bin b/attestation/test-assets/azure_failed_dcap_quote_10.bin deleted file mode 100644 index 2dec55d5d448b8721e513dea91ebe565ab3a5c7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5006 zcmeHKe~=qh9S^WJW2q>3_hP(kVl+F>dT4vvM2qi>VDHoYsB zmVe!uOg8Vm@B99EpU?Yzv&^%^bAxC2+_`nef9T%$!*>y@cHMpb@)dtPm$>?hZCm8q zcOJ~_{pzzX zKfm+Lnw_VA?W_mJue|W#hh|@Kic{kU{(6k@$^AInU4Gz#le=N#b`+FedEb5 z-mvTJ7YXm`@+FO3V>jRM-l5i(7cbs?=ljpxc;0JIJon4i-7kIc^8PpXo%ZWzAHVd9 zM-T5`mfLpyzhC<2t|i*dw?43O-_n)$U2}*h?k#`N_! zy?5`p=^y&zu{ZPoVlUcu&(kk6+Y@zl%Mah7lJC5G`h(xO@hi(cERJGqZ0)+G|H1V5 zn9u6DbqD6Yf3#!kliRw7`cdt%SJ$rIu%6x&xoykK%is2Izw_Rm-yq*V(YCK`yX?B= zU3Z+%iGl4O(r=HQb=_*??@#UCZ+vOb<>Tr@KR=QEC!Js7S@DUsFt;68v;LcVo~YjT zhG+A-RfnH?{)z+JUq6HW>88hDSmU{WzDytK|9j!*!TsLPHO8-e z_Wb1J*Y|kA%IDwObnWWQig#D;AAjibUAZrKjHaVDk`|yap0xtp2Vg&hwGaH z!OR;lV%KOuyoe=p>2ODoC7UsIq)Ac)fmu~g2T5IlD9^EdU1j0|sB*xUVh9@8w7VU zLFZYBls-h+OcY0!oz^Lq%&JUIfaY8TrY+AKNL09QaN)k5k*D)ipvNMh45Kmx+9#It z4Y|xSVq4Ed%YxL#q3ejiIr0cZku;JQEDN-z33gfqDm0B&xoRbn5)Ywi&bmnhkej4L?_zC_^9VFwFpu5TbE?O*>-alaNUZySLdUNY&Eef|Donfnp6P zMk7UpQ8EEEBkr$Bc5b-11UbppEoe5`Ni)M|bGe928WCYK-Vc`zuG%R?qCUef*Rm0@ zMi>pZvYHdG4*?Xfi`~2ucCvo6i^ux~u2#>bMGT}`H(v=;A|1AMYSuF9_JmF`VZu0y zvU)ZhwDJ@_fw~dSa#~-2q{v$LJ1myDJC@wiBor{YnBK*Bw) zh%^O3X^L?%4%@&+V35BGq{svWybavCSXGWzFcOX<;oGQ<4Z^1QLnS+jLK%xWI^m zknUQ=tbewYOcSJ#XmI^Xe4@~b3XHS>iH0pM#zO=n6i&>Y)@ThPz{E6IT(k(V2L`dD zH2C%1w5ds+4TfJSb3Q zwIo?qjE*n{ATp6z!J+%5sZgBtlbv=u9SJJROx-KRbYdW0jEEKs+F<6R#g497E^(=& zVi(oA8G{OQ-pI7XG@`zwPDcFa27chKR`fqc;8wFENWr36LL12(;~Ziej;HVgOOSvQZz^GZSka-W00^;mQTx zm1FFvhHr-=Ym>bM0zScFdICz>f(mnZ%n_Vp$L3|47;4eU>-2o81kUf2bb4NaBj#VceZ>l0^=|)QqO}7(Wv&9ybUahXyqBWwZ)+^L;+AeYGa z(pLnALm+KJsgjkPbb6X3E2RXQjcQ8Q2l5HU;ARk121Sg>Q;gz3Os}FT=O8Lq*=8Xk z+lJHZ#woF8H00@Qy=LJ?pl0-gq|wkE+!$32tYt(2Ph>MfCpT;}Iyx1ejgv#+b6bv7 zJ=`r|AjRw0*aC&2Bn24Olm^mEjB4+w^dh%olF8&yr(8ZV+#JXXjLTPB;sxA&5m?-C zrE%+I9;r5i8$cx6z?K1TX4+b{LfYQSq^5Iee~O);s7@|ZB=sn=e5oSQ0AAHXzFZ|} z&^)c@eF~_fV6R$Iwdrm%kZSfTir$++>3BUQ2WUPl#`>kC==}uTwH%kb$~<>dd_5)j zYOR9EHykshXsMa7#5vUlY}pI*vWXlz+Ogpd??}To?C_%9ykA<>oX&&Z#XN3MPQE#v z2fd5=IqHozr*2c4>I*7kizw9-ShqQqf`ZCB?nhLsz69<~=OZWFcK1|5pO2h4nZ9~7 z^x>tUtHhwM{uq3vCmW0{AYRWVtcgl8-KL!!6RU&>U!syw;xb!Kb5_0qwP;CeRP{i| z&s$Zb>v2-(B?9$UyRTa{n5(Ip-eZ$gI|^e#rxr^<;#BxLV9y*~iBsY0C|wEsx8S7s zx)7zrC`>;tUx##M2CydPZpQ&%70hATNW*|g)Gq#SRjxzdDQ z32{m$9KhYXYMTRb4n)b?Or$Bay_sgPInmBcCc;v>7m-0Xo8l4$Sqd55mYm78_^bX0 HXFdM~?FVd; diff --git a/attestation/test-assets/dcap-quote-collateral-00.json b/attestation/test-assets/dcap-quote-collateral-00.json deleted file mode 100644 index eb8c7b0..0000000 --- a/attestation/test-assets/dcap-quote-collateral-00.json +++ /dev/null @@ -1 +0,0 @@ -{"pck_crl_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","root_ca_crl":"308201203081c8020101300a06082a8648ce3d0403023068311a301806035504030c11496e74656c2053475820526f6f74204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3235303332303131323135375a170d3236303430333131323135375aa02f302d300a0603551d140403020101301f0603551d2304183016801422650cd65a9d3489f383b49552bf501b392706ac300a06082a8648ce3d0403020347003044022030c9fce1438da0a94e4fffdd46c9650e393be6e5a7862d4e4e73527932d04af302206539efe3f734c3d7df20d9dfc4630e1c7ff0439a0f8ece101f15b5eaff9b4f33","pck_crl":"30820bd830820b7d020101300a06082a8648ce3d04030230703122302006035504030c19496e74656c205347582050434b20506c6174666f726d204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3236303132373039343633325a170d3236303232363039343633325a30820aa9303302146fc34e5023e728923435d61aa4b83c618166ad35170d3236303132373039343633325a300c300a0603551d1504030a01013034021500efae6e9715fca13b87e333e8261ed6d990a926ad170d3236303132373039343633325a300c300a0603551d1504030a01013034021500fd608648629cba73078b4d492f4b3ea741ad08cd170d3236303132373039343633325a300c300a0603551d1504030a010130340215008af924184e1d5afddd73c3d63a12f5e8b5737e56170d3236303132373039343633325a300c300a0603551d1504030a01013034021500b1257978cfa9ccdd0759abf8c5ca72fae3a78a9b170d3236303132373039343633325a300c300a0603551d1504030a01013033021474fea614a972be0e2843f2059835811ed872f9b3170d3236303132373039343633325a300c300a0603551d1504030a01013034021500f9c4ef56b3ab48d577e108baedf4bf88014214b9170d3236303132373039343633325a300c300a0603551d1504030a010130330214071de0778f9e5fc4f2878f30d6b07c9a30e6b30b170d3236303132373039343633325a300c300a0603551d1504030a01013034021500cde2424f972cea94ff239937f4d80c25029dd60b170d3236303132373039343633325a300c300a0603551d1504030a0101303302146c3319e5109b64507d3cf1132ce00349ef527319170d3236303132373039343633325a300c300a0603551d1504030a01013034021500df08d756b66a7497f43b5bb58ada04d3f4f7a937170d3236303132373039343633325a300c300a0603551d1504030a01013033021428af485b6cf67e409a39d5cb5aee4598f7a8fa7b170d3236303132373039343633325a300c300a0603551d1504030a01013034021500fb8b2daec092cada8aa9bc4ff2f1c20d0346668c170d3236303132373039343633325a300c300a0603551d1504030a01013034021500cd4850ac52bdcc69a6a6f058c8bc57bbd0b5f864170d3236303132373039343633325a300c300a0603551d1504030a01013034021500994dd3666f5275fb805f95dd02bd50cb2679d8ad170d3236303132373039343633325a300c300a0603551d1504030a0101303302140702136900252274d9035eedf5457462fad0ef4c170d3236303132373039343633325a300c300a0603551d1504030a01013033021461f2bf73e39b4e04aa27d801bd73d24319b5bf80170d3236303132373039343633325a300c300a0603551d1504030a0101303302143992be851b96902eff38959e6c2eff1b0651a4b5170d3236303132373039343633325a300c300a0603551d1504030a0101303302140fda43a00b68ea79b7c2deaeac0b498bdfb2af90170d3236303132373039343633325a300c300a0603551d1504030a010130330214639f139a5040fdcff191e8a4fb1bf086ed603971170d3236303132373039343633325a300c300a0603551d1504030a01013034021500959d533f9249dc1e513544cdc830bf19b7f1f301170d3236303132373039343633325a300c300a0603551d1504030a0101303302147ae37748a9f912f4c63ba7ab07c593ce1d1d1181170d3236303132373039343633325a300c300a0603551d1504030a01013033021413884b33269938c195aa170fca75da177538df0b170d3236303132373039343633325a300c300a0603551d1504030a0101303402150085d3c9381b77a7e04d119c9e5ad6749ff3ffab87170d3236303132373039343633325a300c300a0603551d1504030a0101303402150093887ca4411e7a923bd1fed2819b2949f201b5b4170d3236303132373039343633325a300c300a0603551d1504030a0101303302142498dc6283930996fd8bf23a37acbe26a3bed457170d3236303132373039343633325a300c300a0603551d1504030a010130340215008a66f1a749488667689cc3903ac54c662b712e73170d3236303132373039343633325a300c300a0603551d1504030a01013034021500afc13610bdd36cb7985d106481a880d3a01fda07170d3236303132373039343633325a300c300a0603551d1504030a01013034021500efe04b2c33d036aac96ca673bf1e9a47b64d5cbb170d3236303132373039343633325a300c300a0603551d1504030a0101303402150083d9ac8d8bb509d1c6c809ad712e8430559ed7f3170d3236303132373039343633325a300c300a0603551d1504030a0101303302147931fd50b5071c1bbfc5b7b6ded8b45b9d8b8529170d3236303132373039343633325a300c300a0603551d1504030a0101303302141fa20e2970bde5d57f7b8ddf8339484e1f1d0823170d3236303132373039343633325a300c300a0603551d1504030a0101303302141e87b2c3b32d8d23e411cef34197b95af0c8adf5170d3236303132373039343633325a300c300a0603551d1504030a010130340215009afd2ee90a473550a167d996911437c7502d1f09170d3236303132373039343633325a300c300a0603551d1504030a0101303302144481b0f11728a13b696d3ea9c770a0b15ec58dda170d3236303132373039343633325a300c300a0603551d1504030a01013034021500a7859f57982ef0e67d37bc8ef2ef5ac835ff1aa9170d3236303132373039343633325a300c300a0603551d1504030a010130340215009d67753b81e47090aea763fbec4c4549bcdb9933170d3236303132373039343633325a300c300a0603551d1504030a01013033021434bfbb7a1d9c568147e118b614f7b76ed3ef68df170d3236303132373039343633325a300c300a0603551d1504030a0101303302142c3cc6fe9279db1516d5ce39f2a898cda5a175e1170d3236303132373039343633325a300c300a0603551d1504030a010130330214717948687509234be979e4b7dce6f31bef64b68c170d3236303132373039343633325a300c300a0603551d1504030a010130340215009d76ef2c39c136e8658b6e7396b1d7445a27631f170d3236303132373039343633325a300c300a0603551d1504030a01013034021500c3e025fca995f36f59b48467939e3e34e6361a6f170d3236303132373039343633325a300c300a0603551d1504030a010130340215008c5f6b3257da05b17429e2e61ba965d67330606a170d3236303132373039343633325a300c300a0603551d1504030a01013034021500a17c51722ec1e0c3278fe8bdf052059cbec4e648170d3236303132373039343633325a300c300a0603551d1504030a01013033021434ba4fd76bde5309210cf1dd1ffb494c638a9157170d3236303132373039343633325a300c300a0603551d1504030a010130330214043e04919daae13443248395094d2a2eacfc76fe170d3236303132373039343633325a300c300a0603551d1504030a01013033021447fc577d2d094cbdf270715ed6848a93855ad34b170d3236303132373039343633325a300c300a0603551d1504030a0101303302147d62a2f5e6f386e469653fffff045d0a8178e8e7170d3236303132373039343633325a300c300a0603551d1504030a01013034021500c4ed45fe026bb6a47eaec35ea80b7ef407ce062c170d3236303132373039343633325a300c300a0603551d1504030a01013034021500cf9831077a3ca4f1a2c56867bf55b18eccbeffd8170d3236303132373039343633325a300c300a0603551d1504030a0101303302146c2b81d7ea2e436720ce29f1d0b1ccb7a218600f170d3236303132373039343633325a300c300a0603551d1504030a0101a02f302d300a0603551d140403020101301f0603551d23041830168014956f5dcdbd1be1e94049c9d4f433ce01570bde54300a06082a8648ce3d0403020349003046022100b58bf25ca17aafe54062524903e4f480b101d4303b9be589cd4f76d5478049ce0221009850f5e20354fd25ea145944ae8b1583a664e9279f4d350a843a8a8d5d5f00eb","tcb_info_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","tcb_info":"{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2026-01-27T09:01:45Z\",\"nextUpdate\":\"2026-02-26T09:01:45Z\",\"fmspc\":\"00806F050000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":18,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":8,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":8,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":4,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":8,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":7,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":6,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":6,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\",\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\",\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\",\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]}]}","tcb_info_signature":"a1ac227ba058227872c0467fe2efe6b75cc92c0da91ea486cfabfebc1ea38b14ff7e00a5e976dcdec3ecd16bcc81e7ddb61563b3169115fcafbf4e473c85402f","qe_identity_issuer_chain":"-----BEGIN CERTIFICATE-----\nMIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh\nAKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n","qe_identity":"{\"id\":\"TD_QE\",\"version\":2,\"issueDate\":\"2026-01-27T09:49:59Z\",\"nextUpdate\":\"2026-02-26T09:49:59Z\",\"tcbEvaluationDataNumber\":18,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-11-13T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]}","qe_identity_signature":"7bf989964612ae6d4732b461760b0fe5c461e101e429baa5dab9c53026b0e5905b2792f5c724dc4924658d311484f69da5e7053730e56dabe506a24d18014da6"} diff --git a/attestation/test-assets/dcap-tdx-1766059550570652607 b/attestation/test-assets/dcap-tdx-1766059550570652607 deleted file mode 100644 index 9ea4affbe9f3a10973304d6b2fca90e21df50f40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8000 zcmeHKdz2eh8Q(%%_6+i-MTAOGDacZGl1+9u6oGr^mC0r%nVDpgN#Q^;$xbqvyf%+X zhH|t$JjK$()3Q9IRICM*w@_+vcs3_F znSA$t_j~=m`};DzW515Y9j({Z!$UngZuGCd20Q4!YrjA9fD!Q?U!BuB_xSzjedpbI zMWScLuU8PK-&J1n%Gt9Q`pkcJJbI*i^DWEpuf6u}OMgq#-`IJBF|_o#s_VS@dnixt z$D#K2w>xGwwQjqRzx1;6i;sW(kx#$-KDW~-Pk-W+f!{s;;g!z6?|f$Khwm-Cqj=cC ze?9r|;IQMdzLPG#W^$(f_q%5#w_dd2<)?qS?)8tK*%DYVYv`0zHa>mc9gqIyu-i8A z!#BUas5<|HxetljTEnQEcJ;JBJuvO6KmKO*48c04AKq)6|Hi8)#XbGcR(FE(8uf?+4!`rkL;tblke|#r zddr#hIS;Qpe>HWMJWt)|n?>zT(moF7?bgTK?6?w7%h?jn9U+4;}xD#rMzML4UUN?oZSUo<`Mt@{CV4 z{EbCRUj5O$#7&i}0@po1`&N1QjAhSa7j_s!2aX;~3S{?k( zN`3g77oYve_WIgyubuP2q60tOylHXw!p^nc%TGP)_4OxQaRGnbPlMC$KK1tdZo1=@ zoj0sG?fAPcXSN>u{^M_aa^##Rhc9N28$NdHdEauaFE6%cc2LNR&d$$|ng00*to9-e zvqtv3J@UPI<*ElZ;Onnluw3#R%F302jjk;{JGNi847=$0&I_}@|FR=D-hA?+!Zpi| zVtCi8e-YdEKV;D?^@E4ky{4Y^)TsxDe*VOl>3`Mr{q{ce2~G7o4qE*0bAEeP^qrMg zxxz=>e$)@V+p;fT{q7pL{YFsRf5wDLZNeRL=zzfTKVO3D2j0?0kat~w%v-^R_eE>L z1xsgbTp5~Q=Ffd@`8zLdcdiD1_=vjY-J3Qoc*yy)nTzi^_pK8*y|-k=+_tkOew@*9 z&cPiW^X(U;7?z()P-2LsSptNprWE5?mg*-70{T)KFj)vRRtB7&=JZ%urb`k<)yuN4 zR}FUY(L$q9HOsT|?p(}}#8W+}d`M15&aC?nSu5<@YvB=C_!TU;>B5wgsgkq`($ zO)aIfdLSsU5Ng`UGY6r`699-fR_m=RG9Prf`|Djkr5?}KYTA$kTA(=ShT&MA8_GFz zss7%W<}Ug&oVT|cZloLq=++0AV4vl}%#z<96(p4|Fd1D;#{&=EInW3A$cRo7`b?aM?f-a ziHyg|6CP7>R&+IIb}LTGgQ>ewmWxH)dcuh+kW)P|Ms9Erw@Z~IH6a3_lyiY1?C-Hk zsV=L?#wD7F43d~T0Lut!0lQpYp&x?5e#*u;ECZ7S&GW#(3Hcf&2msq#eQ-1v_N2&A=WZ zP!m|N6)3w378o3x3rZ6NbR%i#EkFPiuZDCOuM2Z^IPa|cM zG?jsYLX1t<(mW7w2!(=Oh13`&210_35SgN@lI_DPyrofO#WcBYouh;?NK{RJd{w*% zp|E=daP2wp0u8mn_@sG(*;E+VeIp4Z(0DH(A%%eq9E=X7;=L)gD&`7G7okh8kd)}j zDLrbw?swBs$AHRPEaj9@_BD~uySn54SkV<1GZCqZ1-qSksJr6OJaW#GrLL-{i|kD( zHP~-{4{MSa#gpR+t-12WWJegf-MG%(WapD>QPt^Ty1Ye!%KIEa!Ll?uN_gDi@npwn zZREvqySS@Gc2dIW!O`UoIk8|e_KhJ310VGgoQ3W28S z4?AhZoCrY9dRoo3^O=UY4jqcv0<-A?oyt(APe!*xiZ=0jfCLUsr|KLTHn|XtBbmin zd&)*>8f$UUhz5mBOt2!6B93PU17yV~OEm{b z1SFLiBB9hwqF3yvBn$dDDy4~WNT#!NA?X!O)hg8dPTo-SVlkF8bTkMUYQv4IdD%jP zQC3AtWpev-4j(Enc5-g!491_Tp?s|4GBo}K1SGdr~NJ@Q( zjQDe5(M7NxexNZJIX0QOy505GrJ;nd=3KoO{Yv!aDU%~vB^J=T zGr>riu;SD}rVn!jG6Bgi(&-4JC-PAC4a)hf;;QzrdX`iaKhD(yu3V|yP;>*vjgYL= z>7cXhg9C2M7zjXYU;4G#JtOUk?MuJ5w=0JJ7EG#N$D$N#hw0w-YpY$UCakfM+p*cN z66#@5W78lI>2?cQu}kt08HrT+Lc#P`gQCA2VFtUEOdlgfJuWo8hfEETGX-2e+!*o} zxN=vt;4XBRqrCx-5UG1bP>Y3`KvER?)LKc5#!KvfNAwt3Tz{r5YE zzx!l{e)pSi_pF;9-Yx?%^5xH07(efTrYkRPm|6DOzF)`a2fD(_nIm_fAH8GYPsFa% ztCyS@GmoP$+;!o%5BA<8d~{;$nfKQn`uO11_Lj~go1NvrlFg4E-0gD$n?3gf_{J@Z z^CwS!x_*aqFDkzN(7`QN_VI7+){AeA5Wl#q7Oyy_ZhLUF`2FaC(J|!9^ScMTR-ZU< z>z$W|E+2K?(C}3y;Q0&A>*(PE2o^PiIrUTR8{%v#pQ3lGj&}zaU&VtCE0r(u}0&ak7j^zg=ja{XXUxq=67IY4*`PXtg8pbMk? zB#z^<#dZcnPnu})HXc=@wPvl3;jMNi4lrsgWtTYDFAY+WNgonzLCeHIx}7Krm3V_= zVYP}h6}W+CQHpG`J~PfTIlJrk%(&QdI};eHRUNPHr}-|cctDF}l zFyk`422E%ct!#NBpvM|oQNkc9l1%X&KMui31QNVjM(1tA(^3t7P|SkSL5bxQyMVfx zI)yN4RjE07KU(5-4CCNtUh|Ez3FkUg(d#&>7zf*iM8z-@EcjBMKva%``KVRH#)}x- z(z9*Arww$n0pM7!6rNu5m(GxX?~JTVwr{%s&>WRfqecnG2d&A9%huaMtpign#7L4# zrElP1&KHcV!fH)0lVTaHFQP6&fayL1xka_jwuC~RNvBCJTjVuGO!(uvnFG3AE#+3^ zB+&x8Nu!q#TXE6E2121(1KqmR<4W}|-Kj+zJ%MHm!xn0*wDRtE@_ z)(yH$SQV%mhx3r4W4fuEv0SMyAsQ_;d$nSQj@05M+v0q!+$^RGeYQU7XhNMb@`X5t zSQHq8>s3<03XU1cr3TixQ=}PIM=Y%?kO{42S-RNhgCs8k!3QOravNaRr7Mw&^M zEEn@gt<7a>zUY9KOG3ShuSeTR*R0f_DuyyLk_N#v3$et;eh5zsU}AoUQcE8Y*nYJx|30XNT4-GmONVq#30v|ysoLuEj3G-vh662 z`)B>0#_EdY$=O+2$=#19D^em2@^;h30_~=b7UK63a${u QME>Iuo}Tli{V%7#0~De6@&Et; diff --git a/attestation/test-assets/measurements.json b/attestation/test-assets/measurements.json deleted file mode 100644 index 7a9097e..0000000 --- a/attestation/test-assets/measurements.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "measurement_id": "azure-tdx-example-01", - "attestation_type": "azure-tdx", - "measurements": { - "4": { - "expected": "ea92ff762767eae6316794f1641c485d4846bc2b9df2eab6ba7f630ce6f4d66f" - }, - "9": { - "expected": "c9f429296634072d1063a03fb287bed0b2d177b0a504755ad9194cffd90b2489" - }, - "11": { - "expected": "efa43e0beff151b0f251c4abf48152382b1452b4414dbd737b4127de05ca31f7" - } - } - }, - { - "measurement_id": "cvm-image-azure-tdx.rootfs-20241107200854.wic.vhd", - "attestation_type": "azure-tdx", - "measurements": { - "4": { - "expected": "1b8cd655f5ebdf50bedabfb5db6b896a0a7c56de54f318103a2de1e7cea57b6b" - }, - "9": { - "expected": "992465f922102234c196f596fdaba86ea16eaa4c264dc425ec26bc2d1c364472" - } - } - }, - { - "measurement_id": "dcap-tdx-example", - "attestation_type": "dcap-tdx", - "measurements": { - "0": { - "expected": "47a1cc074b914df8596bad0ed13d50d561ad1effc7f7cc530ab86da7ea49ffc03e57e7da829f8cba9c629c3970505323" - }, - "1": { - "expected": "da6e07866635cb34a9ffcdc26ec6622f289e625c42c39b320f29cdf1dc84390b4f89dd0b073be52ac38ca7b0a0f375bb" - }, - "2": { - "expected": "a7157e7c5f932e9babac9209d4527ec9ed837b8e335a931517677fa746db51ee56062e3324e266e3f39ec26a516f4f71" - }, - "3": { - "expected": "e63560e50830e22fbc9b06cdce8afe784bf111e4251256cf104050f1347cd4ad9f30da408475066575145da0b098a124" - }, - "4": { - "expected": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" - } - } - } -] diff --git a/attestation/test-assets/measurements_2.json b/attestation/test-assets/measurements_2.json deleted file mode 100644 index bffc2b7..0000000 --- a/attestation/test-assets/measurements_2.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - { - "attestation_type": "dcap-tdx" - } -] diff --git a/attested-tls/Cargo.toml b/attested-tls/Cargo.toml index f7a722d..38a810e 100644 --- a/attested-tls/Cargo.toml +++ b/attested-tls/Cargo.toml @@ -9,9 +9,7 @@ keywords = ["attested-TLS", "CVM", "TDX"] [dependencies] tokio = { version = "1.48.0", features = ["full"] } -tokio-rustls = { version = "0.26.4", default-features = false, features = [ - "ring", -] } +tokio-rustls = { version = "0.26.4", default-features = false } sha2 = "0.10.9" x509-parser = "0.18.0" thiserror = "2.0.17" @@ -20,7 +18,7 @@ http = "1.3.1" serde_json = "1.0.145" tracing = "0.1.41" parity-scale-codec = "3.7.5" -attestation = { path = "../attestation" } +attestation = { git = "https://github.com/flashbots/attested-tls", branch = "peg/add-attestation-crate" } # Used for websocket support tokio-tungstenite = { version = "0.28.0", optional = true } @@ -42,7 +40,7 @@ rcgen = { version = "0.14.5", optional = true } [dev-dependencies] rcgen = "0.14.5" tempfile = "3.23.0" -attestation = { path = "../attestation", features = ["test-helpers", "mock"] } +attestation = { git = "https://github.com/flashbots/attested-tls", branch = "peg/add-attestation-crate", features = ["mock"] } [features] default = ["ws", "rpc"] @@ -67,6 +65,6 @@ rpc = [ ] # Exposes helper functions for testing - do not enable in production as this allows dangerous configuration -test-helpers = ["rcgen", "attestation/test-helpers"] +test-helpers = ["rcgen", "attestation/mock"] mock = ["attestation/mock"] diff --git a/attested-tls/src/test_helpers.rs b/attested-tls/src/test_helpers.rs index 4cd8ec7..9b218a3 100644 --- a/attested-tls/src/test_helpers.rs +++ b/attested-tls/src/test_helpers.rs @@ -8,7 +8,7 @@ use tokio_rustls::rustls::{ use crate::SUPPORTED_ALPN_PROTOCOL_VERSIONS; -pub use attestation::test_helpers::mock_dcap_measurements; +pub use attestation::measurements::mock_dcap_measurements; /// Helper to generate a self-signed certificate for testing pub fn generate_certificate_chain( From 4eb719ce073939629052a3f92e31525acd3e3078 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 6 Mar 2026 09:44:09 +0100 Subject: [PATCH 2/2] Rm awaits after updating attestation crate --- Cargo.lock | 2 +- attested-tls/src/lib.rs | 1 - src/lib.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2aa5c0..3329273 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -506,7 +506,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attestation" version = "0.0.1" -source = "git+https://github.com/flashbots/attested-tls?branch=peg%2Fadd-attestation-crate#f330b2ff9913a6dd6c25f17c2a289058c5a32c8d" +source = "git+https://github.com/flashbots/attested-tls?branch=peg%2Fadd-attestation-crate#4ebc03703510e65fd1317736b8887fc388860481" dependencies = [ "anyhow", "az-tdx-vtpm", diff --git a/attested-tls/src/lib.rs b/attested-tls/src/lib.rs index 7578b3a..9b1eafa 100644 --- a/attested-tls/src/lib.rs +++ b/attested-tls/src/lib.rs @@ -740,7 +740,6 @@ mod tests { "# .to_vec(), ) - .await .unwrap(); let attestation_verifier = AttestationVerifier { diff --git a/src/lib.rs b/src/lib.rs index 58e0ec9..7d44e5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1214,7 +1214,6 @@ mod tests { "# .to_vec(), ) - .await .unwrap(); let attestation_verifier = AttestationVerifier {