diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..58644be --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,42 @@ +name: Test + +on: [push, pull_request] + +jobs: + build_and_test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y pkg-config libtss2-dev + + - name: Set up Rust + uses: dtolnay/rust-toolchain@nightly + with: + toolchain: nightly + components: rustfmt, clippy + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Check formatting + run: cargo fmt --all -- --check + + - name: Run cargo clippy + run: cargo clippy --workspace --features azure -- -D warnings + + - name: Run cargo test + run: cargo test --workspace --features azure --all-targets -- --test-threads=1 diff --git a/Cargo.lock b/Cargo.lock index 06bca7b..612867a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,9 +3,3817 @@ version = 4 [[package]] -name = "attested-tls" +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "asn1-rs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "asn1_der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4858a9d740c5007a9069007c3b4e91152d0506f13c1b31dd49051fd537656156" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "attestation" version = "0.0.1" +dependencies = [ + "anyhow", + "az-tdx-vtpm", + "base64 0.22.1", + "configfs-tsm", + "dcap-qvl", + "hex", + "http", + "num-bigint", + "once_cell", + "openssl", + "parity-scale-codec", + "pem-rfc7468", + "rand_core 0.6.4", + "reqwest", + "rustls-webpki", + "serde", + "serde_json", + "tdx-quote", + "tempfile", + "thiserror 2.0.18", + "time", + "tokio", + "tokio-rustls", + "tracing", + "tss-esapi", + "x509-parser", +] [[package]] -name = "nested-tls" +name = "attested-tls" version = "0.0.1" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "az-cvm-vtpm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3d0900c6757c9674b05b0479236458297026e25fb505186dc8d7735091a21c" +dependencies = [ + "bincode 1.3.3", + "jsonwebkey", + "memoffset", + "openssl", + "serde", + "serde-big-array", + "serde_json", + "sev", + "sha2", + "thiserror 2.0.18", + "tss-esapi", + "zerocopy", +] + +[[package]] +name = "az-tdx-vtpm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04849677b3c0704d4593d89940cde0dc0caad2202bf9fb29352e153782b91ff8" +dependencies = [ + "az-cvm-vtpm", + "base64-url", + "bincode 1.3.3", + "serde", + "serde_json", + "thiserror 2.0.18", + "ureq", + "zerocopy", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-url" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5b428e9fb429c6fda7316e9b006f993e6b4c33005e4659339fb5214479dddec" +dependencies = [ + "base64 0.22.1", +] + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + +[[package]] +name = "bitfield" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21ba6517c6b0f2bf08be60e187ab64b038438f22dd755614d8fe4d4098c46419" +dependencies = [ + "bitfield-macros", +] + +[[package]] +name = "bitfield-macros" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f48d6ace212fdf1b45fd6b566bb40808415344642b76c3224c07c8df9da81e97" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "codicon" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12170080f3533d6f09a19f81596f836854d0fa4867dc32c8172b8474b4e9de61" + +[[package]] +name = "configfs-tsm" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187437900921c8172f33316ad51a3267df588e99a2aebfa5ca1a2ed44df9e703" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "dcap-qvl" +version = "0.3.12" +source = "git+https://github.com/flashbots/dcap-qvl.git?branch=peg%2Fazure-outdated-tcp-override#465c1c231a335db4c6acfb828e815ca1c9ffe2bf" +dependencies = [ + "anyhow", + "asn1_der", + "base64 0.22.1", + "borsh", + "byteorder", + "chrono", + "const-oid", + "dcap-qvl-webpki", + "der", + "derive_more 2.1.1", + "futures", + "hex", + "log", + "p256", + "parity-scale-codec", + "pem", + "reqwest", + "ring", + "rustls-pki-types", + "scale-info", + "serde", + "serde-human-bytes", + "serde_json", + "sha2", + "signature", + "tracing", + "urlencoding", + "wasm-bindgen-futures", + "x509-cert", +] + +[[package]] +name = "dcap-qvl-webpki" +version = "0.103.4+dcap.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0af040afe66c4f26ca05f308482d98bd75a35a80a227d877c2e28c9947a9fa6" +dependencies = [ + "ecdsa", + "ed25519-dalek", + "p256", + "p384", + "ring", + "rsa", + "rustls-pki-types", + "sha2", + "signature", + "untrusted", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2", + "subtle", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flagset" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hickory-proto" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.9.2", + "ring", + "thiserror 2.0.18", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "moka", + "once_cell", + "parking_lot", + "rand 0.9.2", + "resolv-conf", + "smallvec", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname-validator" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "iocuddle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8972d5be69940353d5347a1344cb375d9b457d6809b428b05bb1ca2fb9ce007" + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.10", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebkey" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c57c852b14147e2bd58c14fde40398864453403ef632b1101db130282ee6e2cc" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "generic-array", + "num-bigint", + "serde", + "serde_json", + "thiserror 1.0.69", + "yasna", + "zeroize", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "mbox" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d142aeadbc4e8c679fc6d93fbe7efe1c021fa7d80629e615915b519e3bc6de" +dependencies = [ + "libc", + "stable_deref_trait", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moka" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b" +dependencies = [ + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "nested-tls" +version = "0.0.1" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "oid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c19903c598813dba001b53beeae59bb77ad4892c5c1b9b3500ce4293a0d06c2" +dependencies = [ + "serde", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-src" +version = "300.5.5+3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "picky-asn1" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "295eea0f33c16be21e2a98b908fdd4d73c04dd48c8480991b76dbcf0cb58b212" +dependencies = [ + "oid", + "serde", + "serde_bytes", +] + +[[package]] +name = "picky-asn1-der" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df7873a9e36d42dadb393bea5e211fe83d793c172afad5fb4ec846ec582793f" +dependencies = [ + "picky-asn1", + "serde", + "serde_bytes", +] + +[[package]] +name = "picky-asn1-x509" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5f20f71a68499ff32310f418a6fad8816eac1a2859ed3f0c5c741389dd6208" +dependencies = [ + "base64 0.21.7", + "oid", + "picky-asn1", + "picky-asn1-der", + "serde", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rdrand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92195228612ac8eed47adbc2ed0f04e513a4ccb98175b6f2bd04d963b533655" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "hickory-resolver", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "resolv-conf" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scale-info" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more 1.0.0", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-human-bytes" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a091af6294712930d01e375cce513e4ac416f823e033e8991ec4e5d6e6ef4c0" +dependencies = [ + "base64 0.13.1", + "hex", + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "indexmap", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sev" +version = "6.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420c6c161b5d6883d8195584a802b114af6c884ed56d937d994e30f7f81d54ec" +dependencies = [ + "base64 0.22.1", + "bincode 2.0.1", + "bitfield 0.19.4", + "bitflags 2.11.0", + "byteorder", + "codicon", + "dirs", + "hex", + "iocuddle", + "lazy_static", + "libc", + "openssl", + "rdrand", + "serde", + "serde-big-array", + "serde_bytes", + "static_assertions", + "uuid", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tdx-quote" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a2b5801f4d44185197dffb3a63147bb227e19987b5b93628269625676ab1635" +dependencies = [ + "nom", + "p256", + "pem", + "sha2", + "spki", + "x509-verify", +] + +[[package]] +name = "tempfile" +version = "3.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" +dependencies = [ + "fastrand", + "getrandom 0.4.2", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2 0.6.2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.4+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tss-esapi" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ea9ccde878b029392ac97b5be1f470173d06ea41d18ad0bb3c92794c16a0f2" +dependencies = [ + "bitfield 0.14.0", + "enumflags2", + "getrandom 0.2.17", + "hostname-validator", + "log", + "mbox", + "num-derive", + "num-traits", + "oid", + "picky-asn1", + "picky-asn1-x509", + "regex", + "serde", + "tss-esapi-sys", + "zeroize", +] + +[[package]] +name = "tss-esapi-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535cd192581c2ec4d5f82e670b1d3fbba6a23ccce8c85de387642051d7cad5b5" +dependencies = [ + "pkg-config", + "target-lexicon", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64 0.22.1", + "log", + "once_cell", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "spki", +] + +[[package]] +name = "x509-ocsp" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e54e695a31f0fecb826cf59ae2093c941d7ef932a1f8508185dd23b29ce2e2e" +dependencies = [ + "const-oid", + "der", + "spki", + "x509-cert", +] + +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "x509-verify" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43a49bf845cd2f3aff9603a4276409dbf2b8fa4454d3e9501bf5b0028342964" +dependencies = [ + "const-oid", + "der", + "ecdsa", + "ed25519-dalek", + "k256", + "p256", + "p384", + "p521", + "sha2", + "signature", + "spki", + "x509-cert", + "x509-ocsp", +] + +[[package]] +name = "yasna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75" +dependencies = [ + "num-bigint", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index a420236..9a9cc3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,13 @@ resolver = "3" members = [ "crates/attested-tls", "crates/nested-tls", + "crates/attestation", ] +[workspace.dependencies] +tokio = "1.48.0" +tokio-rustls = { version = "0.26.4", default-features = false } + [workspace.lints.rust] unreachable_pub = "deny" diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml new file mode 100644 index 0000000..b04ae03 --- /dev/null +++ b/crates/attestation/Cargo.toml @@ -0,0 +1,58 @@ +[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" +keywords = ["attestation", "CVM", "TDX"] + +[dependencies] +tokio = { workspace = true, features = ["fs"] } +tokio-rustls = { workspace = true, default-features = false } +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" +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 } +openssl = { version = "0.10.75", 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"] } +tokio-rustls = { workspace = true, default-features = true } + +[features] +default = [] + +# Adds support for Microsoft Azure attestation generation and verification +azure = ["tss-esapi", "az-tdx-vtpm", "openssl"] + +# Allows mock quotes used in tests and exposes related functions for testing +mock = ["tdx-quote"] + +[lints] +workspace = true diff --git a/crates/attestation/README.md b/crates/attestation/README.md new file mode 100644 index 0000000..277aeb3 --- /dev/null +++ b/crates/attestation/README.md @@ -0,0 +1,129 @@ +# attestation + +Attestation generation and verification for confidential VMs, plus measurement policy handling. + +This crate provides: +- Attestation type detection (`none`, `dcap-tdx`, `gcp-tdx`, and `azure-tdx` when enabled) +- Attestation generation and verification for DCAP and (optionally) Azure +- Parsing and evaluation of measurement policies + +## Feature flags + +### `azure` + +Enables Microsoft Azure vTPM attestation support (generation and verification), through `tss-esapi`. + +This feature requires [tpm2](https://tpm2-software.github.io) and `openssl` to be installed. On Debian-based systems tpm2 is provided by [`libtss2-dev`](https://packages.debian.org/trixie/libtss2-dev), and on nix `tpm2-tss`. This dependency is currently not packaged for MacOS, meaning currently it is not possible to compile or run with the `azure` feature on MacOS. + +This feature is disabled by default. Note that without this feature, verification of azure attestations is not possible and azure attestations will be rejected with an error. + +### `mock` + +Enables mock quote support via `tdx-quote` for tests and development on non-TDX hardware. Do not use in production. Disabled by default. + +## Attestation Types + +These are the attestation type names used in the measurements file. + +- `none` - No attestation provided +- `gcp-tdx` - DCAP TDX on Google Cloud Platform +- `azure-tdx` - TDX on Azure, with vTPM attestation +- `qemu-tdx` - TDX on Qemu (no cloud platform) +- `dcap-tdx` - DCAP TDX (platform not specified) + +Local attestation types can be automatically detected. This works by initially attempting an Azure attestation, and if it fails attempting a DCAP attestation, and if that fails assume no CVM attestation. On detecting DCAP, a call to the Google Cloud metadata API is used to detect whether we are on Google Cloud. + +In the case of attestation types `dcap-tdx`, `gcp-tdx`, and `qemu-tdx`, a standard DCAP attestation is generated using the `configfs-tsm` linux filesystem interface. This means that the binary must be run with access to `/sys/kernel/config/tsm/report` which on many systems requires sudo. + +Alternatively, an external 'attestation provider service' URL can be provided which outsources the attestation generation to another process. + +When verifying DCAP attestations, the Intel PCS is used to retrieve collateral unless a PCCS URL is provided via a command line argument. If outdated TCB is used, the quote will fail to verify. For special cases where outdated TCB should be allowed, a custom override function can be passed when verifying which may modify collateral before it is validated against the TCB. + +## Measurements File + +Accepted measurements for the remote party can be specified in a JSON file containing an array of objects, each of which specifies an accepted attestation type and set of measurements. + +This aims to match the formatting used by `cvm-reverse-proxy`. + +These objects have the following fields: +- `measurement_id` - a name used to describe the entry. For example the name and version of the CVM OS image that these measurements correspond to. +- `attestation_type` - a string containing one of the attestation types (confidential computing platforms) described below. +- `measurements` - an object with fields referring to the five measurement registers. Field names are the same as for the measurement headers (see below). + +Each measurement register entry supports two mutually exclusive fields: +- `expected_any` - **(recommended)** an array of hex-encoded measurement values. The attestation is accepted if the actual measurement matches **any** value in the list (OR semantics). +- `expected` - **(deprecated)** a single hex-encoded measurement value. Retained for backwards compatibility but `expected_any` should be preferred. + +Example using `expected_any` (recommended): + +```JSON +[ + { + "measurement_id": "dcap-tdx-example", + "attestation_type": "dcap-tdx", + "measurements": { + "0": { + "expected_any": [ + "47a1cc074b914df8596bad0ed13d50d561ad1effc7f7cc530ab86da7ea49ffc03e57e7da829f8cba9c629c3970505323" + ] + }, + "1": { + "expected_any": [ + "da6e07866635cb34a9ffcdc26ec6622f289e625c42c39b320f29cdf1dc84390b4f89dd0b073be52ac38ca7b0a0f375bb" + ] + }, + "2": { + "expected_any": [ + "a7157e7c5f932e9babac9209d4527ec9ed837b8e335a931517677fa746db51ee56062e3324e266e3f39ec26a516f4f71" + ] + }, + "3": { + "expected_any": [ + "e63560e50830e22fbc9b06cdce8afe784bf111e4251256cf104050f1347cd4ad9f30da408475066575145da0b098a124" + ] + }, + "4": { + "expected_any": [ + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ] + } + } + } +] +``` + +The `expected_any` field is useful when multiple measurement values should be accepted for a register (e.g., for different versions of the firmware): + +```JSON +{ + "0": { + "expected_any": [ + "47a1cc074b914df8596bad0ed13d50d561ad1effc7f7cc530ab86da7ea49ffc03e57e7da829f8cba9c629c3970505323", + "abc123def456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + ] + } +} +``` + +
+Legacy format using deprecated expected field + +The `expected` field is deprecated but still supported for backwards compatibility: + +```JSON +[ + { + "measurement_id": "dcap-tdx-example", + "attestation_type": "dcap-tdx", + "measurements": { + "0": { + "expected": "47a1cc074b914df8596bad0ed13d50d561ad1effc7f7cc530ab86da7ea49ffc03e57e7da829f8cba9c629c3970505323" + } + } + } +] +``` + +
+ +The only mandatory field is `attestation_type`. If an attestation type is specified, but no measurements, *any* measurements will be accepted for this attestation type. The measurements can still be checked up-stream by the source client or target service using header injection described below. But it is then up to these external programs to reject unacceptable measurements. diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs new file mode 100644 index 0000000..9fc5c32 --- /dev/null +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -0,0 +1,207 @@ +//! Generation and verification of AK certificates from the vTPM +use std::time::Duration; + +use once_cell::sync::Lazy; +use tokio_rustls::rustls::pki_types::{CertificateDer, TrustAnchor, UnixTime}; +use webpki::EndEntityCert; + +use crate::azure::{MaaError, nv_index}; + +/// 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(crate) 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(crate) 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/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs new file mode 100644 index 0000000..7d3a7ab --- /dev/null +++ b/crates/attestation/src/azure/mod.rs @@ -0,0 +1,438 @@ +//! 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 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 Ok(x509_parser::public_key::PublicKey::RSA(rsa_from_cert)) = spki.parsed() else { + 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 super::*; + use crate::measurements::MeasurementPolicy; + + 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()).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/crates/attestation/src/azure/nv_index.rs b/crates/attestation/src/azure/nv_index.rs new file mode 100644 index 0000000..074d03b --- /dev/null +++ b/crates/attestation/src/azure/nv_index.rs @@ -0,0 +1,21 @@ +use tss_esapi::{ + Context, + handles::NvIndexTpmHandle, + interface_types::{resource_handles::NvAuth, session_handles::AuthSession}, + tcti_ldr::{DeviceConfig, TctiNameConf}, +}; + +pub(crate) 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(crate) 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/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs new file mode 100644 index 0000000..bf29dcd --- /dev/null +++ b/crates/attestation/src/dcap.rs @@ -0,0 +1,256 @@ +//! Data Center Attestation Primitives (DCAP) evidence generation and +//! verification +use configfs_tsm::QuoteGenerationError; +use dcap_qvl::{ + QuoteCollateralV3, + collateral::get_collateral_for_fmspc, + quote::{Quote, Report}, + tcb_info::TcbInfo, +}; +use thiserror::Error; + +use crate::{AttestationError, measurements::MultiMeasurements}; + +/// 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 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::dangerous_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 super::*; + use crate::measurements::MeasurementPolicy; + #[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()).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/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs new file mode 100644 index 0000000..df5c5ae --- /dev/null +++ b/crates/attestation/src/lib.rs @@ -0,0 +1,541 @@ +//! CVM attestation generation and verification + +#[cfg(feature = "azure")] +pub mod azure; +pub mod dcap; +pub mod measurements; + +use std::{ + fmt::{self, Display, Formatter}, + net::IpAddr, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use measurements::MultiMeasurements; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{dcap::DcapVerificationError, measurements::MeasurementPolicy}; + +/// Used in attestation type detection to check if we are on GCP +const GCP_METADATA_API: &str = + "http://metadata.google.internal/computeMetadata/v1/project/project-id"; + +/// An attestation payload together with its type +#[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]).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)?, + }) + } + } + + /// Generate attestation evidence bytes based on attestation type, with + /// given input data + 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)?) + } + #[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), + } + } + + /// 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 = "mock"))] + 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 tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpListener, + }; + + use super::*; + + 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/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs new file mode 100644 index 0000000..b93030d --- /dev/null +++ b/crates/attestation/src/measurements.rs @@ -0,0 +1,798 @@ +//! Measurements and policy for enforcing them when validating a remote +//! attestation +use std::{collections::HashMap, fmt, fmt::Formatter, path::PathBuf}; + +use dcap_qvl::quote::Report; +use http::{HeaderValue, header::InvalidHeaderValue}; +use serde::Deserialize; +use thiserror::Error; + +use crate::{AttestationError, AttestationType, dcap::DcapVerificationError}; + +/// 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, +} + +/// For converting from the format used in headers +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()) + } +} + +/// All-zero measurment values used in some tests +#[cfg(any(test, feature = "mock"))] +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]), + ])) +} + +/// 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()) + } 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) + } + + /// Parse from JSON + pub 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 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()).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()).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()); + 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()); + 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()); + 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()).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/crates/attestation/test-assets/azure-collateral.json b/crates/attestation/test-assets/azure-collateral.json new file mode 100644 index 0000000..bd64f8a --- /dev/null +++ b/crates/attestation/test-assets/azure-collateral.json @@ -0,0 +1 @@ +{"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/crates/attestation/test-assets/azure-collateral02.json b/crates/attestation/test-assets/azure-collateral02.json new file mode 100644 index 0000000..57f251c --- /dev/null +++ b/crates/attestation/test-assets/azure-collateral02.json @@ -0,0 +1 @@ +{"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/crates/attestation/test-assets/azure-tdx-1764662251380464271 b/crates/attestation/test-assets/azure-tdx-1764662251380464271 new file mode 100644 index 0000000..fce573d --- /dev/null +++ b/crates/attestation/test-assets/azure-tdx-1764662251380464271 @@ -0,0 +1 @@ +{"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/crates/attestation/test-assets/azure_failed_dcap_quote_10.bin b/crates/attestation/test-assets/azure_failed_dcap_quote_10.bin new file mode 100644 index 0000000..2dec55d Binary files /dev/null and b/crates/attestation/test-assets/azure_failed_dcap_quote_10.bin differ diff --git a/crates/attestation/test-assets/dcap-quote-collateral-00.json b/crates/attestation/test-assets/dcap-quote-collateral-00.json new file mode 100644 index 0000000..eb8c7b0 --- /dev/null +++ b/crates/attestation/test-assets/dcap-quote-collateral-00.json @@ -0,0 +1 @@ +{"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/crates/attestation/test-assets/dcap-tdx-1766059550570652607 b/crates/attestation/test-assets/dcap-tdx-1766059550570652607 new file mode 100644 index 0000000..9ea4aff Binary files /dev/null and b/crates/attestation/test-assets/dcap-tdx-1766059550570652607 differ diff --git a/crates/attestation/test-assets/hclreport.bin b/crates/attestation/test-assets/hclreport.bin new file mode 100644 index 0000000..ff9494a Binary files /dev/null and b/crates/attestation/test-assets/hclreport.bin differ diff --git a/crates/attestation/test-assets/measurements.json b/crates/attestation/test-assets/measurements.json new file mode 100644 index 0000000..7a9097e --- /dev/null +++ b/crates/attestation/test-assets/measurements.json @@ -0,0 +1,50 @@ +[ + { + "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/crates/attestation/test-assets/measurements_2.json b/crates/attestation/test-assets/measurements_2.json new file mode 100644 index 0000000..bffc2b7 --- /dev/null +++ b/crates/attestation/test-assets/measurements_2.json @@ -0,0 +1,5 @@ +[ + { + "attestation_type": "dcap-tdx" + } +] diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index e69de29..8b13789 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -0,0 +1 @@ + diff --git a/crates/nested-tls/src/lib.rs b/crates/nested-tls/src/lib.rs index e69de29..8b13789 100644 --- a/crates/nested-tls/src/lib.rs +++ b/crates/nested-tls/src/lib.rs @@ -0,0 +1 @@ + diff --git a/readme.md b/readme.md index cf1926c..2cadb85 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,9 @@ # attested-tls Primitives for attested tls channels. + +Provided crates: + +- [`attested-tls`](./crates/attested-tls) - WIP - provides attested TLS via X509 Certificate extensions and a custom certificate verifier +- [`nested-tls`](./crates/nested-tls) - WIP - provides two TLS sessions, such that that outer session can be used for a CA signed certificate and the inner session for attestation +- [`attestation`](./crates/attestation) - provides attestation generation, verification and measurement handling diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..a3fe682 --- /dev/null +++ b/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + nativeBuildInputs = with pkgs; [ + pkg-config + ]; + + buildInputs = with pkgs;[ + tpm2-tss + openssl + ]; +}