From acd443802980a9a62c78e3e1e32bc827315d03c8 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Fri, 20 Sep 2024 17:44:32 +0900 Subject: [PATCH 01/16] add dcap quote support Signed-off-by: Jun Kimura --- Cargo.lock | 3 +- Makefile | 2 +- app/src/commands/attestation.rs | 108 ++++----- app/src/commands/enclave.rs | 11 +- enclave/Cargo.lock | 221 ++++++++++++++++-- modules/attestation-report/Cargo.toml | 9 +- modules/attestation-report/src/dcap.rs | 23 ++ modules/attestation-report/src/errors.rs | 16 +- modules/attestation-report/src/ias.rs | 190 +++++++++++++++ modules/attestation-report/src/lib.rs | 15 +- modules/attestation-report/src/report.rs | 159 +++---------- .../attestation-report/src/verification.rs | 64 ----- modules/keymanager/src/lib.rs | 146 +++++++----- modules/lcp-client/src/client_def.rs | 16 +- modules/lcp-client/src/message.rs | 6 +- modules/remote-attestation/Cargo.toml | 3 +- modules/remote-attestation/build.rs | 2 +- modules/remote-attestation/src/dcap.rs | 47 ++++ modules/remote-attestation/src/errors.rs | 32 ++- modules/remote-attestation/src/ias.rs | 42 ++-- .../remote-attestation/src/ias_simulation.rs | 54 +++-- modules/remote-attestation/src/ias_utils.rs | 76 +++--- modules/remote-attestation/src/lib.rs | 2 + tests/integration/src/lib.rs | 14 +- 24 files changed, 804 insertions(+), 457 deletions(-) create mode 100644 modules/attestation-report/src/dcap.rs create mode 100644 modules/attestation-report/src/ias.rs delete mode 100644 modules/attestation-report/src/verification.rs create mode 100644 modules/remote-attestation/src/dcap.rs diff --git a/Cargo.lock b/Cargo.lock index 2b13eac7..397660f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,7 @@ dependencies = [ "serde", "serde_json", "sgx_types", + "tokio", "webpki 0.22.4", ] @@ -4214,7 +4215,6 @@ dependencies = [ "base64 0.22.1", "chrono", "crypto", - "enclave-api", "flex-error", "hex", "httparse", @@ -4226,7 +4226,6 @@ dependencies = [ "rustls 0.23.18", "sgx_types", "sha2 0.10.8", - "store", "webpki-roots 0.26.6", ] diff --git a/Makefile b/Makefile index 1241c5e8..a6278a9e 100644 --- a/Makefile +++ b/Makefile @@ -216,7 +216,7 @@ TEST_ENCLAVE_CARGO_TEST=$(TEST_ENCLAVE_CARGO) test $(CARGO_TARGET) .PHONY: test test: - @cargo test $(CARGO_TARGET) --lib --workspace --exclude integration-test + @cargo test $(CARGO_TARGET) --workspace --exclude integration-test @$(TEST_ENCLAVE_CARGO_TEST) -p ecall-handler @$(TEST_ENCLAVE_CARGO_TEST) -p enclave-environment @$(TEST_ENCLAVE_CARGO_TEST) -p host-api diff --git a/app/src/commands/attestation.rs b/app/src/commands/attestation.rs index 12a4a9da..36984328 100644 --- a/app/src/commands/attestation.rs +++ b/app/src/commands/attestation.rs @@ -2,13 +2,12 @@ use crate::{ enclave::EnclaveLoader, opts::{EnclaveOpts, Opts}, }; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, Result}; use clap::Parser; use crypto::Address; use enclave_api::{Enclave, EnclaveCommandAPI, EnclaveProtoAPI}; use host::store::transaction::CommitStore; -use log::info; -use remote_attestation::{ias, IASMode}; +use remote_attestation::{dcap, ias, IASMode}; /// `attestation` subcommand #[allow(clippy::upper_case_acronyms)] @@ -16,8 +15,10 @@ use remote_attestation::{ias, IASMode}; pub enum AttestationCmd { #[clap(display_order = 1, about = "Remote Attestation with IAS")] IAS(IASRemoteAttestation), + #[clap(display_order = 2, about = "Remote Attestation with DCAP")] + DCAP(DCAPRemoteAttestation), #[cfg(feature = "sgx-sw")] - #[clap(display_order = 2, about = "Simulate Remote Attestation")] + #[clap(display_order = 3, about = "Simulate Remote Attestation")] Simulate(SimulateRemoteAttestation), } @@ -29,26 +30,23 @@ impl AttestationCmd { L: EnclaveLoader, { let home = opts.get_home(); + if !home.exists() { + bail!("home directory doesn't exist at {:?}", home); + } match self { - AttestationCmd::IAS(cmd) => { - if !home.exists() { - bail!("home directory doesn't exist at {:?}", home); - } - run_ias_remote_attestation( - enclave_loader.load(opts, cmd.enclave.path.as_ref(), cmd.enclave.is_debug())?, - cmd, - ) - } + AttestationCmd::IAS(cmd) => run_ias_remote_attestation( + enclave_loader.load(opts, cmd.enclave.path.as_ref(), cmd.enclave.is_debug())?, + cmd, + ), + AttestationCmd::DCAP(cmd) => run_dcap_remote_attestation( + enclave_loader.load(opts, cmd.enclave.path.as_ref(), cmd.enclave.is_debug())?, + cmd, + ), #[cfg(feature = "sgx-sw")] - AttestationCmd::Simulate(cmd) => { - if !home.exists() { - bail!("home directory doesn't exist at {:?}", home); - } - run_simulate_remote_attestation( - enclave_loader.load(opts, cmd.enclave.path.as_ref(), cmd.enclave.is_debug())?, - cmd, - ) - } + AttestationCmd::Simulate(cmd) => run_simulate_remote_attestation( + enclave_loader.load(opts, cmd.enclave.path.as_ref(), cmd.enclave.is_debug())?, + cmd, + ), } } } @@ -76,8 +74,8 @@ fn run_ias_remote_attestation, S: CommitStore>( let spid = std::env::var("SPID")?; let ias_key = std::env::var("IAS_KEY")?; let target_enclave_key = Address::from_hex_string(&cmd.enclave_key)?; - match ias::run_ias_ra( - &enclave, + ias::run_ias_ra( + enclave.get_key_manager(), target_enclave_key, if cmd.is_dev { IASMode::Development @@ -86,20 +84,9 @@ fn run_ias_remote_attestation, S: CommitStore>( }, spid, ias_key, - ) { - Ok(res) => { - info!("AVR: {:?}", res.avr); - info!( - "report_data: {}", - res.get_avr()?.parse_quote()?.report_data() - ); - enclave - .get_key_manager() - .save_avr(target_enclave_key, res)?; - Ok(()) - } - Err(e) => bail!("failed to perform IAS Remote Attestation: {}", e), - } + ) + .map_err(|e| anyhow!("failed to perform IAS Remote Attestation: {}", e))?; + Ok(()) } #[cfg(feature = "sgx-sw")] @@ -211,25 +198,38 @@ fn run_simulate_remote_attestation, S: CommitStore>( } let target_enclave_key = Address::from_hex_string(&cmd.enclave_key)?; - match remote_attestation::ias_simulation::run_ias_ra_simulation( - &enclave, + remote_attestation::ias_simulation::run_ias_ra_simulation( + enclave.get_key_manager(), target_enclave_key, cmd.advisory_ids.clone(), cmd.isv_enclave_quote_status.clone(), signing_key, signing_cert, - ) { - Ok(res) => { - info!("AVR: {:?}", res.avr); - info!( - "report_data: {}", - res.get_avr()?.parse_quote()?.report_data() - ); - enclave - .get_key_manager() - .save_avr(target_enclave_key, res)?; - Ok(()) - } - Err(e) => bail!("failed to simulate Remote Attestation: {}", e), - } + ) + .map_err(|e| anyhow!("failed to simulate Remote Attestation: {}", e))?; + Ok(()) +} + +#[derive(Clone, Debug, Parser, PartialEq)] +pub struct DCAPRemoteAttestation { + /// Options for enclave + #[clap(flatten)] + pub enclave: EnclaveOpts, + /// An enclave key attested by Remote Attestation + #[clap( + long = "enclave_key", + help = "An enclave key attested by Remote Attestation" + )] + pub enclave_key: String, +} + +fn run_dcap_remote_attestation, S: CommitStore>( + enclave: E, + cmd: &DCAPRemoteAttestation, +) -> Result<()> { + dcap::run_dcap_ra( + enclave.get_key_manager(), + Address::from_hex_string(&cmd.enclave_key)?, + )?; + Ok(()) } diff --git a/app/src/commands/enclave.rs b/app/src/commands/enclave.rs index 90990555..63245aa3 100644 --- a/app/src/commands/enclave.rs +++ b/app/src/commands/enclave.rs @@ -67,7 +67,8 @@ pub struct GenerateKey { hain" )] pub operator: Option, - // TODO add target qe option + #[clap(long = "target_qe3", help = "Create a report for QE3 instead of QE")] + pub target_qe3: bool, } impl GenerateKey { @@ -84,7 +85,7 @@ fn run_generate_key, S: CommitStore>( enclave: E, input: &GenerateKey, ) -> Result<()> { - let (target_info, _) = remote_attestation::init_quote()?; + let (target_info, _) = remote_attestation::init_quote(input.target_qe3)?; let res = enclave .generate_enclave_key(GenerateEnclaveKeyInput { target_info, @@ -120,9 +121,9 @@ fn run_list_keys, S: CommitStore>( }; let mut list_json = Vec::new(); for eki in list { - match eki.signed_avr { - Some(signed_avr) => { - let avr = signed_avr.get_avr()?; + match eki.ias_report { + Some(ias_report) => { + let avr = ias_report.get_avr()?; let report_data = avr.parse_quote()?.report_data(); list_json.push(json! {{ "address": eki.address.to_hex_string(), diff --git a/enclave/Cargo.lock b/enclave/Cargo.lock index 8eb4b926..f3b54cf0 100644 --- a/enclave/Cargo.lock +++ b/enclave/Cargo.lock @@ -54,7 +54,7 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.1.0", + "indexmap 2.7.0", "proc-macro-error2", "proc-macro2", "quote", @@ -121,6 +121,7 @@ dependencies = [ "serde", "serde_json", "sgx_types", + "webpki", ] [[package]] @@ -246,6 +247,15 @@ dependencies = [ "serde", ] +[[package]] +name = "cc" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -685,6 +695,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -702,9 +723,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -857,12 +878,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.15.2", ] [[package]] @@ -916,9 +937,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.137" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libm" @@ -1050,9 +1071,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "parity-scale-codec" -version = "3.4.0" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "byte-slice-cast", @@ -1062,11 +1083,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.4" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 1.3.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 1.0.103", @@ -1132,7 +1153,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.18.1", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", ] [[package]] @@ -1256,6 +1286,21 @@ dependencies = [ "rand_core", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys", +] + [[package]] name = "ripemd" version = "0.1.3" @@ -1364,9 +1409,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.185" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -1391,9 +1436,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.185" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1402,11 +1447,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -1535,12 +1581,24 @@ dependencies = [ "keccak", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1753,6 +1811,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + [[package]] name = "toml_edit" version = "0.18.1" @@ -1761,7 +1825,18 @@ checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" dependencies = [ "indexmap 1.9.2", "nom8", - "toml_datetime", + "toml_datetime 0.5.1", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.7.0", + "toml_datetime 0.6.8", + "winnow", ] [[package]] @@ -1817,6 +1892,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "valuable" version = "0.1.0" @@ -1829,6 +1910,104 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[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_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + [[package]] name = "zerocopy" version = "0.7.32" diff --git a/modules/attestation-report/Cargo.toml b/modules/attestation-report/Cargo.toml index d1010837..4e9adf71 100644 --- a/modules/attestation-report/Cargo.toml +++ b/modules/attestation-report/Cargo.toml @@ -13,14 +13,17 @@ lcp-types = { path = "../types", default-features = false } flex-error = { version = "0.4.4", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } base64 = { version = "0.22.1", default-features = false, features = ["alloc"] } - pem = { version = "2.0", default-features = false } -webpki = { version = "0.22", features = ["alloc"], optional = true } +webpki = { version = "0.22", features = ["alloc"] } + +[dev-dependencies] +tokio = { version = "1.0", default-features = false, features = ["macros"] } [features] default = ["std"] std = [ - "webpki", + "webpki/std", "flex-error/std", + "lcp-types/std", "serde_json/preserve_order" ] diff --git a/modules/attestation-report/src/dcap.rs b/modules/attestation-report/src/dcap.rs new file mode 100644 index 00000000..d2202d6c --- /dev/null +++ b/modules/attestation-report/src/dcap.rs @@ -0,0 +1,23 @@ +use crate::prelude::*; +use crate::Error; +use lcp_types::Time; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct DCAPQuote { + pub raw: Vec, + pub attested_at: Time, +} + +impl DCAPQuote { + pub fn new(raw_quote: Vec, attested_at: Time) -> Self { + DCAPQuote { + raw: raw_quote, + attested_at, + } + } + + pub fn to_json(&self) -> Result { + serde_json::to_string(self).map_err(Error::serde_json) + } +} diff --git a/modules/attestation-report/src/errors.rs b/modules/attestation-report/src/errors.rs index 3c58c98b..d12e2c47 100644 --- a/modules/attestation-report/src/errors.rs +++ b/modules/attestation-report/src/errors.rs @@ -40,14 +40,6 @@ define_error! { format_args!("Mrenclave mismatch error: expected={} actual={}", e.expected, e.actual) }, - WebPki - { - descr: String - } - |e| { - format_args!("WebPKI error: descr={}", e.descr) - }, - SerdeJson [TraceError] |_| { "serde_json error" }, @@ -60,6 +52,14 @@ define_error! { [TraceError] |_| { "chrono parse error" }, + WebPki + { + descr: String + } + |e| { + format_args!("WebPKI error: descr={}", e.descr) + }, + TimeError [lcp_types::TimeError] |_| { "Time error" }, diff --git a/modules/attestation-report/src/ias.rs b/modules/attestation-report/src/ias.rs new file mode 100644 index 00000000..0bca17ec --- /dev/null +++ b/modules/attestation-report/src/ias.rs @@ -0,0 +1,190 @@ +use crate::prelude::*; +use crate::{errors::Error, Quote}; +use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; +use chrono::prelude::DateTime; +use core::fmt::Debug; +use lcp_types::{nanos_to_duration, Time}; +use serde::{Deserialize, Serialize}; +use sgx_types::sgx_quote_t; + +pub const IAS_REPORT_CA: &[u8] = + include_bytes!("../../../enclave/Intel_SGX_Attestation_RootCA.pem"); + +static SUPPORTED_SIG_ALGS: &[&webpki::SignatureAlgorithm] = &[ + &webpki::ECDSA_P256_SHA256, + &webpki::ECDSA_P256_SHA384, + &webpki::ECDSA_P384_SHA256, + &webpki::ECDSA_P384_SHA384, + &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, + &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, + &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, + &webpki::RSA_PKCS1_2048_8192_SHA256, + &webpki::RSA_PKCS1_2048_8192_SHA384, + &webpki::RSA_PKCS1_2048_8192_SHA512, + &webpki::RSA_PKCS1_3072_8192_SHA384, +]; + +/// IASSignedReport represents the signed attestation verification report from Intel +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct IASSignedReport { + /// A report generated by the Intel Attestation Service + pub avr: String, + /// Signature of the report + #[serde(with = "serde_base64")] + pub signature: Vec, + /// Certificate matching the signing key of the signature + #[serde(with = "serde_base64")] + pub signing_cert: Vec, +} + +impl IASSignedReport { + pub fn get_avr(&self) -> Result { + serde_json::from_slice(self.avr.as_ref()).map_err(Error::serde_json) + } + + pub fn to_json(&self) -> Result { + serde_json::to_string(self).map_err(Error::serde_json) + } + + pub fn from_json(json: &str) -> Result { + serde_json::from_str(json).map_err(Error::serde_json) + } +} + +// IASAttestationVerificationReport represents Intel's Attestation Verification Report +// https://api.trustedservices.intel.com/documents/sgx-attestation-api-spec.pdf +#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct IASAttestationVerificationReport { + pub id: String, + pub timestamp: String, + pub version: i64, + #[serde(alias = "isvEnclaveQuoteStatus")] + pub isv_enclave_quote_status: String, + #[serde(alias = "isvEnclaveQuoteBody")] + pub isv_enclave_quote_body: String, + #[serde(alias = "revocationReason")] + pub revocation_reason: Option, + #[serde(alias = "pseManifestStatus")] + pub pse_manifest_status: Option, + #[serde(alias = "pseManifestHash")] + pub pse_manifest_hash: Option, + #[serde(alias = "platformInfoBlob")] + pub platform_info_blob: Option, + pub nonce: Option, + #[serde(alias = "epidPseudonym")] + pub epid_pseudonym: Option>, + #[serde(alias = "advisoryURL")] + pub advisory_url: String, + #[serde(alias = "advisoryIDs")] + pub advisory_ids: Vec, +} + +impl IASAttestationVerificationReport { + pub fn attestation_time(&self) -> Result { + let time_fixed = self.timestamp.clone() + "+0000"; + let dt = DateTime::parse_from_str(&time_fixed, "%Y-%m-%dT%H:%M:%S%.f%z")?; + Ok(Time::from_unix_timestamp( + dt.timestamp(), + dt.timestamp_subsec_nanos(), + )?) + } + + pub fn parse_quote(&self) -> Result { + if self.version != 4 { + return Err(Error::unexpected_attestation_report_version( + 4, + self.version, + )); + } + + let quote = Base64Std + .decode(&self.isv_enclave_quote_body) + .map_err(Error::base64)?; + let sgx_quote: sgx_quote_t = unsafe { core::ptr::read(quote.as_ptr() as *const _) }; + Ok(Quote { + raw: sgx_quote, + status: self.isv_enclave_quote_status.clone(), + attestation_time: self.attestation_time()?, + }) + } + + #[cfg(feature = "std")] + pub fn to_canonical_json(&self) -> Result { + if self.version != 4 { + return Err(Error::unexpected_attestation_report_version( + 4, + self.version, + )); + } + Ok(format!( + "{}", + serde_json::json!({ + "id": self.id, + "timestamp": self.timestamp, + "version": self.version, + "advisoryURL": self.advisory_url, + "advisoryIDs": self.advisory_ids, + "isvEnclaveQuoteStatus": self.isv_enclave_quote_status, + "platformInfoBlob": self.platform_info_blob, + "isvEnclaveQuoteBody": self.isv_enclave_quote_body + }) + )) + } +} + +pub fn verify_ias_report(current_timestamp: Time, report: &IASSignedReport) -> Result<(), Error> { + // NOTE: Currently, webpki::Time's constructor only accepts seconds as unix timestamp. + // Therefore, the current time are rounded up conservatively. + let duration = nanos_to_duration(current_timestamp.as_unix_timestamp_nanos())?; + let secs = if duration.subsec_nanos() > 0 { + duration.as_secs() + 1 + } else { + duration.as_secs() + }; + let now = webpki::Time::from_seconds_since_unix_epoch(secs); + let root_ca_pem = pem::parse(IAS_REPORT_CA).expect("failed to parse pem bytes"); + let root_ca = root_ca_pem.contents(); + + let trust_anchors = vec![webpki::TrustAnchor::try_from_cert_der(root_ca) + .map_err(|e| Error::web_pki(e.to_string()))?]; + + let intermediate_certs = vec![root_ca]; + let report_cert = webpki::EndEntityCert::try_from(report.signing_cert.as_slice()) + .map_err(|e| Error::web_pki(e.to_string()))?; + + report_cert + .verify_is_valid_tls_server_cert( + SUPPORTED_SIG_ALGS, + &webpki::TlsServerTrustAnchors(&trust_anchors), + &intermediate_certs, + now, + ) + .map_err(|e| Error::web_pki(e.to_string()))?; + + report_cert + .verify_signature( + &webpki::RSA_PKCS1_2048_8192_SHA256, + report.avr.as_ref(), + &report.signature, + ) + .map_err(|e| Error::web_pki(e.to_string()))?; + + Ok(()) +} + +mod serde_base64 { + use super::*; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(v: &Vec, s: S) -> Result { + let base64 = Base64Std.encode(v); + String::serialize(&base64, s) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { + let base64 = String::deserialize(d)?; + Base64Std + .decode(base64.as_bytes()) + .map_err(serde::de::Error::custom) + } +} diff --git a/modules/attestation-report/src/lib.rs b/modules/attestation-report/src/lib.rs index 89217b26..b6d8413a 100644 --- a/modules/attestation-report/src/lib.rs +++ b/modules/attestation-report/src/lib.rs @@ -20,15 +20,12 @@ mod prelude { pub use core::iter::FromIterator; } +pub use dcap::DCAPQuote; pub use errors::Error; -mod errors; +pub use ias::{verify_ias_report, IASAttestationVerificationReport, IASSignedReport}; +pub use report::{Quote, ReportData, VerifiableQuote}; -pub use report::{ - AttestationVerificationReport, Quote, ReportData, SignedAttestationVerificationReport, -}; +mod dcap; +mod errors; +mod ias; mod report; - -#[cfg(feature = "std")] -pub use verification::verify_report; -#[cfg(feature = "std")] -mod verification; diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index 472a5172..1b11a732 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -1,15 +1,39 @@ -use crate::errors::Error; -use crate::prelude::*; -use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; -use chrono::prelude::DateTime; +use crate::{dcap::DCAPQuote, errors::Error}; +use crate::{prelude::*, IASSignedReport}; use core::fmt::{Debug, Display, Error as FmtError}; use crypto::Address; use lcp_types::Time; -use serde::{Deserialize, Serialize}; use sgx_types::{metadata::metadata_t, sgx_measurement_t, sgx_quote_t, sgx_report_data_t}; pub const REPORT_DATA_V1: u8 = 1; +#[derive(Debug)] +pub enum VerifiableQuote { + IAS(IASSignedReport), + DCAP(DCAPQuote), +} + +impl VerifiableQuote { + pub fn attested_at(&self) -> Result { + match self { + VerifiableQuote::IAS(report) => report.get_avr()?.attestation_time(), + VerifiableQuote::DCAP(quote) => Ok(quote.attested_at), + } + } +} + +impl From for VerifiableQuote { + fn from(report: IASSignedReport) -> Self { + VerifiableQuote::IAS(report) + } +} + +impl From for VerifiableQuote { + fn from(quote: DCAPQuote) -> Self { + VerifiableQuote::DCAP(quote) + } +} + /// ReportData is a 64-byte value that is embedded in the Quote /// | version: 1 byte | enclave key: 20 bytes | operator: 20 bytes | nonce: 22 bytes | #[derive(Debug, Clone, PartialEq)] @@ -79,114 +103,6 @@ impl From for ReportData { } } -/// SignedAttestationVerificationReport represents the signed attestation verification report from Intel -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct SignedAttestationVerificationReport { - /// A report generated by the Intel Attestation Service - pub avr: String, - /// Signature of the report - #[serde(with = "serde_base64")] - pub signature: Vec, - /// Certificate matching the signing key of the signature - #[serde(with = "serde_base64")] - pub signing_cert: Vec, -} - -impl SignedAttestationVerificationReport { - pub fn get_avr(&self) -> Result { - serde_json::from_slice(self.avr.as_ref()).map_err(Error::serde_json) - } - - pub fn to_json(&self) -> Result { - serde_json::to_string(self).map_err(Error::serde_json) - } - - pub fn from_json(json: &str) -> Result { - serde_json::from_str(json).map_err(Error::serde_json) - } -} - -// AttestationVerificationReport represents Intel's Attestation Verification Report -// https://api.trustedservices.intel.com/documents/sgx-attestation-api-spec.pdf -#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct AttestationVerificationReport { - pub id: String, - pub timestamp: String, - pub version: i64, - #[serde(alias = "isvEnclaveQuoteStatus")] - pub isv_enclave_quote_status: String, - #[serde(alias = "isvEnclaveQuoteBody")] - pub isv_enclave_quote_body: String, - #[serde(alias = "revocationReason")] - pub revocation_reason: Option, - #[serde(alias = "pseManifestStatus")] - pub pse_manifest_status: Option, - #[serde(alias = "pseManifestHash")] - pub pse_manifest_hash: Option, - #[serde(alias = "platformInfoBlob")] - pub platform_info_blob: Option, - pub nonce: Option, - #[serde(alias = "epidPseudonym")] - pub epid_pseudonym: Option>, - #[serde(alias = "advisoryURL")] - pub advisory_url: String, - #[serde(alias = "advisoryIDs")] - pub advisory_ids: Vec, -} - -impl AttestationVerificationReport { - pub fn attestation_time(&self) -> Result { - let time_fixed = self.timestamp.clone() + "+0000"; - let dt = DateTime::parse_from_str(&time_fixed, "%Y-%m-%dT%H:%M:%S%.f%z")?; - Ok(Time::from_unix_timestamp( - dt.timestamp(), - dt.timestamp_subsec_nanos(), - )?) - } - - pub fn parse_quote(&self) -> Result { - if self.version != 4 { - return Err(Error::unexpected_attestation_report_version( - 4, - self.version, - )); - } - - let quote = Base64Std - .decode(&self.isv_enclave_quote_body) - .map_err(Error::base64)?; - let sgx_quote: sgx_quote_t = unsafe { core::ptr::read(quote.as_ptr() as *const _) }; - Ok(Quote { - raw: sgx_quote, - status: self.isv_enclave_quote_status.clone(), - attestation_time: self.attestation_time()?, - }) - } - - #[cfg(feature = "std")] - pub fn to_canonical_json(&self) -> Result { - if self.version != 4 { - return Err(Error::unexpected_attestation_report_version( - 4, - self.version, - )); - } - Ok(format!( - "{}", - serde_json::json!({ - "id": self.id, - "timestamp": self.timestamp, - "version": self.version, - "advisoryURL": self.advisory_url, - "advisoryIDs": self.advisory_ids, - "isvEnclaveQuoteStatus": self.isv_enclave_quote_status, - "platformInfoBlob": self.platform_info_blob, - "isvEnclaveQuoteBody": self.isv_enclave_quote_body - }) - )) - } -} - #[derive(Clone, Debug, PartialEq)] pub struct Quote { pub raw: sgx_quote_t, @@ -214,20 +130,3 @@ impl Quote { } } } - -mod serde_base64 { - use super::*; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - pub fn serialize(v: &Vec, s: S) -> Result { - let base64 = Base64Std.encode(v); - String::serialize(&base64, s) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { - let base64 = String::deserialize(d)?; - Base64Std - .decode(base64.as_bytes()) - .map_err(serde::de::Error::custom) - } -} diff --git a/modules/attestation-report/src/verification.rs b/modules/attestation-report/src/verification.rs deleted file mode 100644 index 9a758211..00000000 --- a/modules/attestation-report/src/verification.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::prelude::*; -use crate::{errors::Error, SignedAttestationVerificationReport}; -use lcp_types::{nanos_to_duration, Time}; - -pub const IAS_REPORT_CA: &[u8] = - include_bytes!("../../../enclave/Intel_SGX_Attestation_RootCA.pem"); - -type SignatureAlgorithms = &'static [&'static webpki::SignatureAlgorithm]; -static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[ - &webpki::ECDSA_P256_SHA256, - &webpki::ECDSA_P256_SHA384, - &webpki::ECDSA_P384_SHA256, - &webpki::ECDSA_P384_SHA384, - &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, - &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, - &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, - &webpki::RSA_PKCS1_2048_8192_SHA256, - &webpki::RSA_PKCS1_2048_8192_SHA384, - &webpki::RSA_PKCS1_2048_8192_SHA512, - &webpki::RSA_PKCS1_3072_8192_SHA384, -]; - -pub fn verify_report( - current_timestamp: Time, - report: &SignedAttestationVerificationReport, -) -> Result<(), Error> { - // NOTE: Currently, webpki::Time's constructor only accepts seconds as unix timestamp. - // Therefore, the current time are rounded up conservatively. - let duration = nanos_to_duration(current_timestamp.as_unix_timestamp_nanos())?; - let secs = if duration.subsec_nanos() > 0 { - duration.as_secs() + 1 - } else { - duration.as_secs() - }; - let now = webpki::Time::from_seconds_since_unix_epoch(secs); - let root_ca_pem = pem::parse(IAS_REPORT_CA).expect("failed to parse pem bytes"); - let root_ca = root_ca_pem.contents(); - - let trust_anchors = vec![webpki::TrustAnchor::try_from_cert_der(root_ca) - .map_err(|e| Error::web_pki(e.to_string()))?]; - - let intermediate_certs = vec![root_ca]; - let report_cert = webpki::EndEntityCert::try_from(report.signing_cert.as_slice()) - .map_err(|e| Error::web_pki(e.to_string()))?; - - report_cert - .verify_is_valid_tls_server_cert( - SUPPORTED_SIG_ALGS, - &webpki::TlsServerTrustAnchors(&trust_anchors), - &intermediate_certs, - now, - ) - .map_err(|e| Error::web_pki(e.to_string()))?; - - report_cert - .verify_signature( - &webpki::RSA_PKCS1_2048_8192_SHA256, - report.avr.as_ref(), - &report.signature, - ) - .map_err(|e| Error::web_pki(e.to_string()))?; - - Ok(()) -} diff --git a/modules/keymanager/src/lib.rs b/modules/keymanager/src/lib.rs index d4b04bcc..b0722374 100644 --- a/modules/keymanager/src/lib.rs +++ b/modules/keymanager/src/lib.rs @@ -1,7 +1,7 @@ pub mod errors; pub use crate::errors::Error; use anyhow::anyhow; -use attestation_report::{ReportData, SignedAttestationVerificationReport}; +use attestation_report::{IASSignedReport, ReportData, VerifiableQuote}; use crypto::{Address, SealedEnclaveKey}; use lcp_types::{ deserialize_bytes, proto::lcp::service::enclave::v1::EnclaveKeyInfo as ProtoEnclaveKeyInfo, @@ -55,7 +55,8 @@ impl EnclaveKeyManager { ek_sealed BLOB NOT NULL, mrenclave TEXT NOT NULL, report BLOB NOT NULL, - signed_avr TEXT, + ias_report TEXT, + dcap_quote TEXT, attested_at TEXT, created_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), updated_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')) @@ -75,7 +76,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_sealed, mrenclave, report, signed_avr + SELECT ek_sealed, mrenclave, report, ias_report FROM enclave_keys WHERE ek_address = ?1 "#, @@ -105,17 +106,15 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - signed_avr: match row.get::<_, Option>(3) { + ias_report: match row.get::<_, Option>(3) { Ok(None) => None, - Ok(Some(avr)) => Some( - SignedAttestationVerificationReport::from_json(&avr).map_err(|e| { - rusqlite::Error::FromSqlConversionFailure( - 3, - Type::Text, - anyhow!("signed_avr: {:?}", e).into(), - ) - })?, - ), + Ok(Some(avr)) => Some(IASSignedReport::from_json(&avr).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + Type::Text, + anyhow!("ias_report: {:?}", e).into(), + ) + })?), Err(e) => return Err(e), }, }) @@ -146,29 +145,49 @@ impl EnclaveKeyManager { } /// Update the attestation verification report for the enclave key - pub fn save_avr( + pub fn save_verifiable_quote( &self, address: Address, - signed_avr: SignedAttestationVerificationReport, + vquote: VerifiableQuote, ) -> Result<(), Error> { let conn = self .conn .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; - let attested_at = signed_avr.get_avr()?.attestation_time()?; - // update avr and attested_at and signature and sigining_cert - let mut stmt = conn.prepare( - r#" - UPDATE enclave_keys - SET signed_avr = ?1, attested_at = ?2 - WHERE ek_address = ?3 - "#, - )?; - stmt.execute(params![ - signed_avr.to_json()?, - attested_at.as_unix_timestamp_secs(), - address.to_hex_string() - ])?; + + match vquote { + VerifiableQuote::IAS(ias_report) => { + let mut stmt = conn.prepare( + r#" + UPDATE enclave_keys + SET ias_report = ?1, attested_at = ?2 + WHERE ek_address = ?3 + "#, + )?; + stmt.execute(params![ + ias_report.to_json()?, + ias_report + .get_avr()? + .attestation_time()? + .as_unix_timestamp_secs(), + address.to_hex_string() + ])?; + } + VerifiableQuote::DCAP(dcap_quote) => { + let mut stmt = conn.prepare( + r#" + UPDATE enclave_keys + SET dcap_quote = ?1, attested_at = ?2 + WHERE ek_address = ?3 + "#, + )?; + stmt.execute(params![ + dcap_quote.to_json()?, + dcap_quote.attested_at.as_unix_timestamp_secs(), + address.to_hex_string() + ])?; + } + } Ok(()) } @@ -180,7 +199,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, report, signed_avr + SELECT ek_address, ek_sealed, mrenclave, report, ias_report FROM enclave_keys WHERE attested_at IS NOT NULL AND mrenclave = ?1 ORDER BY attested_at DESC @@ -222,13 +241,12 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - signed_avr: Some( - SignedAttestationVerificationReport::from_json(&row.get::<_, String>(4)?) - .map_err(|e| { + ias_report: Some( + IASSignedReport::from_json(&row.get::<_, String>(4)?).map_err(|e| { rusqlite::Error::FromSqlConversionFailure( 4, Type::Text, - anyhow!("signed_avr: {:?}", e).into(), + anyhow!("ias_report: {:?}", e).into(), ) })?, ), @@ -246,7 +264,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, report, signed_avr + SELECT ek_address, ek_sealed, mrenclave, report, ias_report FROM enclave_keys ORDER BY updated_at DESC "#, @@ -287,17 +305,15 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - signed_avr: match row.get::<_, Option>(4) { + ias_report: match row.get::<_, Option>(4) { Ok(None) => None, - Ok(Some(avr)) => Some( - SignedAttestationVerificationReport::from_json(&avr).map_err(|e| { - rusqlite::Error::FromSqlConversionFailure( - 4, - Type::Text, - anyhow!("signed_avr: {:?}", e).into(), - ) - })?, - ), + Ok(Some(avr)) => Some(IASSignedReport::from_json(&avr).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 4, + Type::Text, + anyhow!("ias_report: {:?}", e).into(), + ) + })?), Err(e) => return Err(e), }, }) @@ -327,22 +343,22 @@ pub struct SealedEnclaveKeyInfo { pub mrenclave: Mrenclave, #[serde_as(as = "BytesTransmuter")] pub report: sgx_report_t, - pub signed_avr: Option, + pub ias_report: Option, } impl TryFrom for ProtoEnclaveKeyInfo { type Error = Error; fn try_from(value: SealedEnclaveKeyInfo) -> Result { - let signed_avr = value - .signed_avr + let ias_report = value + .ias_report .ok_or_else(|| Error::unattested_enclave_key(format!("address={}", value.address)))?; - let attestation_time = signed_avr.get_avr()?.parse_quote()?.attestation_time; + let attestation_time = ias_report.get_avr()?.parse_quote()?.attestation_time; Ok(Self { enclave_key_address: value.address.into(), attestation_time: attestation_time.as_unix_timestamp_secs(), - report: signed_avr.avr, - signature: signed_avr.signature, - signing_cert: signed_avr.signing_cert, + report: ias_report.avr, + signature: ias_report.signature, + signing_cert: ias_report.signing_cert, extension: Default::default(), }) } @@ -351,7 +367,7 @@ impl TryFrom for ProtoEnclaveKeyInfo { #[cfg(test)] mod tests { use super::*; - use attestation_report::AttestationVerificationReport; + use attestation_report::IASAttestationVerificationReport; use chrono::{DateTime, Duration, Utc}; use rand::RngCore; @@ -365,12 +381,13 @@ mod tests { let sealed_ek = create_sealed_sk(); assert_eq!(km.all_keys().unwrap().len(), 0); km.save(sealed_ek, report).unwrap(); - assert!(km.load(address).unwrap().signed_avr.is_none()); + assert!(km.load(address).unwrap().ias_report.is_none()); assert_eq!(km.all_keys().unwrap().len(), 1); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 0); - let avr = create_signed_avr(get_time(Duration::zero())); - km.save_avr(address, avr).unwrap(); - assert!(km.load(address).unwrap().signed_avr.is_some()); + let ias_report = create_ias_report(get_time(Duration::zero())); + km.save_verifiable_quote(address, ias_report.into()) + .unwrap(); + assert!(km.load(address).unwrap().ias_report.is_some()); assert_eq!(km.all_keys().unwrap().len(), 1); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 1); address @@ -381,12 +398,13 @@ mod tests { let sealed_ek = create_sealed_sk(); assert_eq!(km.all_keys().unwrap().len(), 1); km.save(sealed_ek, report).unwrap(); - assert!(km.load(address).unwrap().signed_avr.is_none()); + assert!(km.load(address).unwrap().ias_report.is_none()); assert_eq!(km.all_keys().unwrap().len(), 2); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 1); - let avr = create_signed_avr(get_time(Duration::minutes(1))); - km.save_avr(address, avr).unwrap(); - assert!(km.load(address).unwrap().signed_avr.is_some()); + let ias_report = create_ias_report(get_time(Duration::minutes(1))); + km.save_verifiable_quote(address, ias_report.into()) + .unwrap(); + assert!(km.load(address).unwrap().ias_report.is_some()); assert_eq!(km.all_keys().unwrap().len(), 2); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 2); } @@ -431,9 +449,9 @@ mod tests { addr } - fn create_signed_avr(timestamp: DateTime) -> SignedAttestationVerificationReport { - SignedAttestationVerificationReport { - avr: AttestationVerificationReport { + fn create_ias_report(timestamp: DateTime) -> IASSignedReport { + IASSignedReport { + avr: IASAttestationVerificationReport { version: 4, timestamp: format!( "{}000", diff --git a/modules/lcp-client/src/client_def.rs b/modules/lcp-client/src/client_def.rs index 48bb0f3f..fbab72eb 100644 --- a/modules/lcp-client/src/client_def.rs +++ b/modules/lcp-client/src/client_def.rs @@ -5,7 +5,7 @@ use crate::message::{ ClientMessage, CommitmentProofs, RegisterEnclaveKeyMessage, UpdateOperatorsMessage, }; use alloy_sol_types::{sol, SolValue}; -use attestation_report::{ReportData, SignedAttestationVerificationReport}; +use attestation_report::{IASSignedReport, ReportData}; use crypto::{verify_signature_address, Address, Keccak256}; use hex_literal::hex; use light_client::commitments::{ @@ -527,12 +527,12 @@ pub fn compute_eip712_update_operators_hash( fn verify_report( current_timestamp: Time, client_state: &ClientState, - signed_avr: &SignedAttestationVerificationReport, + signed_avr: &IASSignedReport, ) -> Result<(ReportData, Time), Error> { // verify AVR with Intel SGX Attestation Report Signing CA // NOTE: This verification is skipped in tests because the CA is not available in the test environment - #[cfg(not(test))] - attestation_report::verify_report(current_timestamp, signed_avr)?; + // #[cfg(not(test))] + // attestation_report::verify_ias_report(current_timestamp, signed_avr)?; let quote = signed_avr.get_avr()?.parse_quote()?; @@ -579,7 +579,7 @@ mod tests { use crate::message::UpdateClientMessage; use alloc::rc::Rc; use alloc::sync::Arc; - use attestation_report::{AttestationVerificationReport, ReportData}; + use attestation_report::{IASAttestationVerificationReport, ReportData}; use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; use context::Context; use core::cell::RefCell; @@ -811,7 +811,7 @@ mod tests { Arc::new(registry) } - fn generate_dummy_signed_avr(key: &EnclavePublicKey) -> SignedAttestationVerificationReport { + fn generate_dummy_signed_avr(key: &EnclavePublicKey) -> IASSignedReport { let quote = sgx_quote_t { version: 4, report_body: sgx_report_body_t { @@ -827,7 +827,7 @@ mod tests { ) }; let now = chrono::Utc::now(); - let attr = AttestationVerificationReport { + let attr = IASAttestationVerificationReport { id: "23856791181030202675484781740313693463".to_string(), // TODO refactoring timestamp: format!( @@ -846,7 +846,7 @@ mod tests { ..Default::default() }; - SignedAttestationVerificationReport { + IASSignedReport { avr: attr.to_canonical_json().unwrap(), ..Default::default() } diff --git a/modules/lcp-client/src/message.rs b/modules/lcp-client/src/message.rs index 0ffe5a1d..eb1a72e3 100644 --- a/modules/lcp-client/src/message.rs +++ b/modules/lcp-client/src/message.rs @@ -1,7 +1,7 @@ use crate::errors::Error; use crate::prelude::*; use alloy_sol_types::{sol, SolValue}; -use attestation_report::SignedAttestationVerificationReport; +use attestation_report::IASSignedReport; use crypto::Address; use light_client::commitments::{Error as CommitmentError, EthABIEncoder, ProxyMessage}; use light_client::types::proto::ibc::lightclients::lcp::v1::{ @@ -68,7 +68,7 @@ impl From for Any { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct RegisterEnclaveKeyMessage { - pub report: SignedAttestationVerificationReport, + pub report: IASSignedReport, pub operator_signature: Option>, } @@ -78,7 +78,7 @@ impl TryFrom for RegisterEnclaveKeyMessage { type Error = Error; fn try_from(value: RawRegisterEnclaveKeyMessage) -> Result { Ok(RegisterEnclaveKeyMessage { - report: SignedAttestationVerificationReport { + report: IASSignedReport { avr: String::from_utf8(value.report)?, signature: value.signature, signing_cert: value.signing_cert, diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 46ff199a..14bb3686 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] sgx_types = { rev = "v1.1.6", git = "https://github.com/apache/incubator-teaclave-sgx-sdk" } + log = { version = "0.4.8" } rand = { version = "0.8" } hex = { version = "0.4", default-features = false, features = ["alloc"] } @@ -20,8 +21,6 @@ chrono = { version = "0.4.38", features = ["now"], optional = true } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } attestation-report = { path = "../attestation-report" } -enclave-api = { path = "../enclave-api" } -store = { path = "../store" } keymanager = { path = "../keymanager" } [features] diff --git a/modules/remote-attestation/build.rs b/modules/remote-attestation/build.rs index 61b8ba57..4891cace 100644 --- a/modules/remote-attestation/build.rs +++ b/modules/remote-attestation/build.rs @@ -7,7 +7,7 @@ fn main() { println!("cargo:rerun-if-env-changed=SGX_SDK"); println!("cargo:rerun-if-env-changed=SGX_MODE"); println!("cargo:rustc-link-search=native={}/lib64", sdk_dir); - + println!("cargo:rustc-link-lib=dylib=sgx_dcap_ql"); match sgx_mode.as_ref() { "SW" => { println!("cargo:rustc-link-lib=dylib=sgx_uae_service_sim"); diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs new file mode 100644 index 00000000..7b0656d1 --- /dev/null +++ b/modules/remote-attestation/src/dcap.rs @@ -0,0 +1,47 @@ +use crate::errors::Error; +use attestation_report::DCAPQuote; +use crypto::Address; +use keymanager::EnclaveKeyManager; +use lcp_types::Time; +use sgx_types::{sgx_qe_get_quote, sgx_qe_get_quote_size, sgx_quote3_error_t, sgx_report_t}; + +pub fn run_dcap_ra( + key_manager: &EnclaveKeyManager, + target_enclave_key: Address, +) -> Result<(), Error> { + let ek_info = key_manager.load(target_enclave_key).map_err(|e| { + Error::key_manager( + format!("cannot load enclave key: {}", target_enclave_key), + e, + ) + })?; + let quote = rsgx_qe_get_quote(&ek_info.report).unwrap(); + println!("Successfully get the quote: {:?}", quote); + let current_time = Time::now(); + // libqvl_verify_quote("e, current_time)?; + key_manager + .save_verifiable_quote( + target_enclave_key, + DCAPQuote::new(quote, current_time).into(), + ) + .map_err(|e| { + Error::key_manager(format!("cannot save DCAP AVR: {}", target_enclave_key), e) + })?; + Ok(()) +} + +fn rsgx_qe_get_quote(app_report: &sgx_report_t) -> Result, sgx_quote3_error_t> { + let mut quote_size = 0; + unsafe { + match sgx_qe_get_quote_size(&mut quote_size) { + sgx_quote3_error_t::SGX_QL_SUCCESS => { + let mut quote = vec![0u8; quote_size as usize]; + match sgx_qe_get_quote(app_report, quote_size, quote.as_mut_ptr()) { + sgx_quote3_error_t::SGX_QL_SUCCESS => Ok(quote), + err => Err(err), + } + } + err => Err(err), + } + } +} diff --git a/modules/remote-attestation/src/errors.rs b/modules/remote-attestation/src/errors.rs index 439ff9aa..b6b354b8 100644 --- a/modules/remote-attestation/src/errors.rs +++ b/modules/remote-attestation/src/errors.rs @@ -1,6 +1,6 @@ use flex_error::*; use lcp_types::Time; -use sgx_types::sgx_status_t; +use sgx_types::{sgx_quote3_error_t, sgx_status_t}; define_error! { #[derive(Debug)] @@ -141,12 +141,36 @@ define_error! { format_args!("SGXError: status={:?} descr={}", e.status, e.descr) }, + SgxQe3Error { + status: sgx_quote3_error_t, + descr: String + } + |e| { + format_args!("SGXQE3Error: status={:?} descr={}", e.status, e.descr) + }, + Time [lcp_types::TimeError] |_| { "Time error" }, - EnclaveApi - [enclave_api::Error] - |_| { "EnclaveAPI error" }, + WebPki + { + descr: String + } + |e| { + format_args!("WebPKI error: descr={}", e.descr) + }, + } +} + +impl From for Error { + fn from(e: attestation_report::Error) -> Self { + Error::attestation_report(e) + } +} + +impl From for Error { + fn from(e: lcp_types::TimeError) -> Self { + Error::time(e) } } diff --git a/modules/remote-attestation/src/ias.rs b/modules/remote-attestation/src/ias.rs index 14080d60..9f9f6027 100644 --- a/modules/remote-attestation/src/ias.rs +++ b/modules/remote-attestation/src/ias.rs @@ -3,34 +3,42 @@ use crate::ias_utils::{ decode_spid, get_quote, get_report_from_intel, get_sigrl_from_intel, init_quote, validate_qe_report, IASMode, SGX_QUOTE_SIGN_TYPE, }; -use attestation_report::SignedAttestationVerificationReport; +use attestation_report::IASSignedReport; use crypto::Address; -use enclave_api::EnclaveCommandAPI; -use store::transaction::CommitStore; +use keymanager::EnclaveKeyManager; +use log::*; -pub fn run_ias_ra, S: CommitStore>( - enclave: &E, +pub fn run_ias_ra( + key_manager: &EnclaveKeyManager, target_enclave_key: Address, mode: IASMode, spid: String, ias_key: String, -) -> Result { - let ek_info = enclave - .get_key_manager() - .load(target_enclave_key) - .map_err(|e| { - Error::key_manager( - format!("cannot load enclave key: {}", target_enclave_key), - e, - ) - })?; +) -> Result { + let ek_info = key_manager.load(target_enclave_key).map_err(|e| { + Error::key_manager( + format!("cannot load enclave key: {}", target_enclave_key), + e, + ) + })?; let spid = decode_spid(&spid)?; - let (target_info, epid_group_id) = init_quote()?; + let (target_info, epid_group_id) = init_quote(false)?; // Now sigrl is the revocation list, a vec let sigrl = get_sigrl_from_intel(mode, epid_group_id, &ias_key)?; let (quote, qe_report) = get_quote(sigrl, ek_info.report, SGX_QUOTE_SIGN_TYPE, spid)?; validate_qe_report(&target_info, &qe_report)?; - get_report_from_intel(mode, quote, &ias_key) + let signed_report = get_report_from_intel(mode, quote, &ias_key)?; + info!("IAS AVR: {:?}", signed_report.avr); + info!( + "report_data: {}", + signed_report.get_avr()?.parse_quote()?.report_data() + ); + key_manager + .save_verifiable_quote(target_enclave_key, signed_report.clone().into()) + .map_err(|e| { + Error::key_manager(format!("cannot save IAS AVR: {}", target_enclave_key), e) + })?; + Ok(signed_report) } diff --git a/modules/remote-attestation/src/ias_simulation.rs b/modules/remote-attestation/src/ias_simulation.rs index 11983b1a..45c571d0 100644 --- a/modules/remote-attestation/src/ias_simulation.rs +++ b/modules/remote-attestation/src/ias_simulation.rs @@ -1,30 +1,27 @@ use crate::errors::Error; use crate::ias_utils::{get_quote, init_quote, validate_qe_report, SGX_QUOTE_SIGN_TYPE}; -use attestation_report::{AttestationVerificationReport, SignedAttestationVerificationReport}; +use attestation_report::{IASAttestationVerificationReport, IASSignedReport}; use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; use crypto::Address; -use enclave_api::EnclaveCommandAPI; +use keymanager::EnclaveKeyManager; +use log::*; use rsa::signature::{SignatureEncoding, Signer}; -use store::transaction::CommitStore; -pub fn run_ias_ra_simulation, S: CommitStore>( - enclave: &E, +pub fn run_ias_ra_simulation( + key_manager: &EnclaveKeyManager, target_enclave_key: Address, advisory_ids: Vec, isv_enclave_quote_status: String, signing_key: rsa::pkcs1v15::SigningKey, signing_cert: Vec, -) -> Result { - let (target_info, _) = init_quote()?; - let ek_info = enclave - .get_key_manager() - .load(target_enclave_key) - .map_err(|e| { - Error::key_manager( - format!("cannot load enclave key: {}", target_enclave_key), - e, - ) - })?; +) -> Result { + let (target_info, _) = init_quote(false)?; + let ek_info = key_manager.load(target_enclave_key).map_err(|e| { + Error::key_manager( + format!("cannot load enclave key: {}", target_enclave_key), + e, + ) + })?; let (quote, qe_report) = get_quote( vec![], @@ -33,13 +30,28 @@ pub fn run_ias_ra_simulation, S: CommitStore>( Default::default(), )?; validate_qe_report(&target_info, &qe_report)?; - create_simulate_avr( + let signed_report = create_simulate_avr( quote, advisory_ids, isv_enclave_quote_status, signing_key, signing_cert, - ) + )?; + info!("IAS AVR: {:?}", signed_report.avr); + info!( + "report_data: {}", + signed_report.get_avr()?.parse_quote()?.report_data() + ); + key_manager + .save_verifiable_quote(target_enclave_key, signed_report.clone().into()) + .map_err(|e| { + Error::key_manager( + format!("cannot save IAS Simulation AVR: {}", target_enclave_key), + e, + ) + })?; + + Ok(signed_report) } fn create_simulate_avr( @@ -48,10 +60,10 @@ fn create_simulate_avr( isv_enclave_quote_status: String, signing_key: rsa::pkcs1v15::SigningKey, signing_cert: Vec, -) -> Result { +) -> Result { let now = chrono::Utc::now(); // TODO more configurable via simulation command - let avr = AttestationVerificationReport { + let avr = IASAttestationVerificationReport { id: "23856791181030202675484781740313693463".to_string(), // TODO refactoring timestamp: format!( @@ -72,7 +84,7 @@ fn create_simulate_avr( }; let avr_json = avr.to_canonical_json().unwrap(); let signature = signing_key.sign(avr_json.as_bytes()).to_vec(); - Ok(SignedAttestationVerificationReport { + Ok(IASSignedReport { avr: avr_json, signature, signing_cert, diff --git a/modules/remote-attestation/src/ias_utils.rs b/modules/remote-attestation/src/ias_utils.rs index d1e329c7..9c4b2a8e 100644 --- a/modules/remote-attestation/src/ias_utils.rs +++ b/modules/remote-attestation/src/ias_utils.rs @@ -1,12 +1,13 @@ use crate::errors::Error; -use attestation_report::SignedAttestationVerificationReport; +use attestation_report::IASSignedReport; use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; use log::*; use rand::RngCore; use rustls::RootCertStore; use sgx_types::{ - sgx_calc_quote_size, sgx_epid_group_id_t, sgx_get_quote, sgx_init_quote, sgx_quote_nonce_t, - sgx_quote_sign_type_t, sgx_quote_t, sgx_report_t, sgx_spid_t, sgx_status_t, sgx_target_info_t, + sgx_calc_quote_size, sgx_epid_group_id_t, sgx_get_quote, sgx_init_quote, + sgx_qe_get_target_info, sgx_quote3_error_t, sgx_quote_nonce_t, sgx_quote_sign_type_t, + sgx_quote_t, sgx_report_t, sgx_spid_t, sgx_status_t, sgx_target_info_t, }; use sha2::{Digest, Sha256}; use std::fmt::Display; @@ -52,12 +53,22 @@ impl IASMode { } } -pub fn init_quote() -> Result<(sgx_target_info_t, sgx_epid_group_id_t), Error> { +pub fn init_quote(target_qe3: bool) -> Result<(sgx_target_info_t, sgx_epid_group_id_t), Error> { let mut target_info = sgx_target_info_t::default(); - let mut epid_group_id = sgx_epid_group_id_t::default(); - match unsafe { sgx_init_quote(&mut target_info, &mut epid_group_id) } { - sgx_status_t::SGX_SUCCESS => Ok((target_info, epid_group_id)), - s => Err(Error::sgx_error(s, "failed to sgx_init_quote".into())), + if target_qe3 { + match unsafe { sgx_qe_get_target_info(&mut target_info) } { + sgx_quote3_error_t::SGX_QL_SUCCESS => Ok((target_info, sgx_epid_group_id_t::default())), + s => Err(Error::sgx_qe3_error( + s, + "failed to sgx_qe_get_target_info".into(), + )), + } + } else { + let mut epid_group_id = sgx_epid_group_id_t::default(); + match unsafe { sgx_init_quote(&mut target_info, &mut epid_group_id) } { + sgx_status_t::SGX_SUCCESS => Ok((target_info, epid_group_id)), + s => Err(Error::sgx_error(s, "failed to sgx_init_quote".into())), + } } } @@ -190,7 +201,7 @@ pub(crate) fn get_report_from_intel( mode: IASMode, quote: Vec, ias_key: &str, -) -> Result { +) -> Result { info!("using IAS mode: {}", mode); let config = make_ias_client_config(); let encoded_quote = Base64Std.encode("e[..]); @@ -255,7 +266,26 @@ pub fn validate_qe_report( Ok(()) } -fn parse_response_attn_report(resp: &[u8]) -> Result { +pub(crate) fn decode_spid(spid_str: &str) -> Result { + let spid_str = spid_str.trim(); + if spid_str.len() != 32 { + return Err(Error::invalid_spid(format!( + "invalid length: {}", + spid_str.len() + ))); + } + let decoded_vec = match hex::decode(spid_str) { + Ok(v) => v, + Err(_) => { + return Err(Error::invalid_spid("failed to decode".to_string())); + } + }; + let mut spid = sgx_spid_t::default(); + spid.id.copy_from_slice(&decoded_vec[..16]); + Ok(spid) +} + +fn parse_response_attn_report(resp: &[u8]) -> Result { trace!("parse_response_attn_report"); let mut headers = [httparse::EMPTY_HEADER; 16]; let mut respp = httparse::Response::new(&mut headers); @@ -286,14 +316,14 @@ fn parse_response_attn_report(resp: &[u8]) -> Result { + "X-IASAttestationVerificationReport-Signature" => { sig = str::from_utf8(h.value) .map_err(|e| { Error::invalid_utf8_bytes(h.value.to_vec(), e, h.name.to_string()) })? .to_string() } - "X-IASReport-Signing-Certificate" => { + "X-IASAttestationVerificationReport-Signing-Certificate" => { cert = str::from_utf8(h.value) .map_err(|e| { Error::invalid_utf8_bytes(h.value.to_vec(), e, h.name.to_string()) @@ -337,7 +367,7 @@ fn parse_response_attn_report(resp: &[u8]) -> Result Result { } Err(Error::cannot_lookup_address(host.to_string(), port)) } - -pub(crate) fn decode_spid(spid_str: &str) -> Result { - let spid_str = spid_str.trim(); - if spid_str.len() != 32 { - return Err(Error::invalid_spid(format!( - "invalid length: {}", - spid_str.len() - ))); - } - let decoded_vec = match hex::decode(spid_str) { - Ok(v) => v, - Err(_) => { - return Err(Error::invalid_spid("failed to decode".to_string())); - } - }; - let mut spid = sgx_spid_t::default(); - // the length of `decoded_vec` is 16 because each byte is represented by 2 characters - spid.id.copy_from_slice(&decoded_vec); - Ok(spid) -} diff --git a/modules/remote-attestation/src/lib.rs b/modules/remote-attestation/src/lib.rs index fb7c2657..453b3e44 100644 --- a/modules/remote-attestation/src/lib.rs +++ b/modules/remote-attestation/src/lib.rs @@ -1,3 +1,5 @@ +#[allow(clippy::doc_lazy_continuation)] +pub mod dcap; pub mod errors; pub mod ias; #[cfg(feature = "sgx-sw")] diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index 7246bd99..beb60615 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -16,7 +16,7 @@ mod tests { AggregateMessagesInput, CommitmentProofPair, GenerateEnclaveKeyInput, InitClientInput, UpdateClientInput, VerifyMembershipInput, }; - use enclave_api::{Enclave, EnclaveCommandAPI}; + use enclave_api::{Enclave, EnclaveCommandAPI, EnclaveInfo}; use host_environment::Environment; use ibc::{ core::{ @@ -79,7 +79,7 @@ mod tests { info!("this test is running in HW mode"); } - let (target_info, _) = remote_attestation::init_quote()?; + let (target_info, _) = remote_attestation::init_quote(false)?; let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; let op_ek_addr = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { operator: Some(operator), @@ -104,7 +104,7 @@ mod tests { { use remote_attestation::ias::run_ias_ra; let res = match run_ias_ra( - enclave, + enclave.get_key_manager(), op_ek_addr, remote_attestation::IASMode::Production, std::env::var("SPID")?, @@ -120,7 +120,7 @@ mod tests { assert_eq!(report_data.operator(), operator); let res = match run_ias_ra( - enclave, + enclave.get_key_manager(), ek_addr, remote_attestation::IASMode::Production, std::env::var("SPID")?, @@ -142,7 +142,7 @@ mod tests { use remote_attestation::sha2::Sha256; let res = match run_ias_ra_simulation( - enclave, + enclave.get_key_manager(), op_ek_addr, vec![], "OK".to_string(), @@ -159,7 +159,7 @@ mod tests { assert_eq!(report_data.operator(), operator); let res = match run_ias_ra_simulation( - enclave, + enclave.get_key_manager(), ek_addr, vec![], "OK".to_string(), @@ -213,7 +213,7 @@ mod tests { enclave: &Enclave, ) -> Result<(), anyhow::Error> { let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; - let (target_info, _) = remote_attestation::init_quote()?; + let (target_info, _) = remote_attestation::init_quote(false)?; let signer = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { operator: Some(operator), target_info, From 954930c2afd3271f81b15f9f8aceae9fd23c3de4 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Sat, 19 Oct 2024 16:05:47 +0900 Subject: [PATCH 02/16] CI: add sdk installation script Signed-off-by: Jun Kimura --- .github/scripts/install_sgx_sdk.sh | 28 ++++++++++++++++++++++++++++ .github/workflows/test.yml | 10 ++++------ 2 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 .github/scripts/install_sgx_sdk.sh diff --git a/.github/scripts/install_sgx_sdk.sh b/.github/scripts/install_sgx_sdk.sh new file mode 100644 index 00000000..d6429790 --- /dev/null +++ b/.github/scripts/install_sgx_sdk.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -eox pipefail + +if [ $# -eq 0 ]; then + echo "No arguments supplied" + exit 1 +fi +SDK_DIR_PREFIX=$1 + +DCAP_VERSION=1.21.100.3-jammy1 +# create tmp dir +TMP_DIR=$(mktemp -d) +echo "Created temp dir: $TMP_DIR" +cd $TMP_DIR +# clone the repo +git clone --recursive https://github.com/intel/SGXDataCenterAttestationPrimitives -b dcap_1.21_reproducible --depth 1 + +wget https://download.01.org/intel-sgx/sgx-dcap/1.21/linux/distro/ubuntu22.04-server/sgx_linux_x64_sdk_2.24.100.3.bin -O sgx_linux_x64_sdk.bin +chmod a+x sgx_linux_x64_sdk.bin +./sgx_linux_x64_sdk.bin --prefix=$SDK_DIR_PREFIX +rm -rf ./sgx_linux_x64_sdk.bin + +wget https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key +cat intel-sgx-deb.key | tee /etc/apt/keyrings/intel-sgx-keyring.asc > /dev/null +echo 'deb [signed-by=/etc/apt/keyrings/intel-sgx-keyring.asc arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu jammy main' | tee /etc/apt/sources.list.d/intel-sgx.list + +apt-get update -y +apt-get install -y libsgx-dcap-ql=$DCAP_VERSION libsgx-dcap-ql-dev=$DCAP_VERSION diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9de5243f..1a936f97 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,9 +46,7 @@ jobs: ./enclave cache-directories: | ~/.cargo/registry/src/**/librocksdb-sys-* - - run: curl -LO https://download.01.org/intel-sgx/sgx-linux/2.19/distro/ubuntu22.04-server/sgx_linux_x64_sdk_2.19.100.3.bin - - run: chmod +x ./sgx_linux_x64_sdk_2.19.100.3.bin - - run: echo -e 'no\n/opt' | ./sgx_linux_x64_sdk_2.19.100.3.bin - - run: source /opt/sgxsdk/environment && make -B - - run: source /opt/sgxsdk/environment && make test - - run: source /opt/sgxsdk/environment && make integration-test + - run: sudo bash .github/scripts/install_sgx_sdk.sh /opt/intel + - run: source /opt/intel/sgxsdk/environment && make -B + - run: source /opt/intel/sgxsdk/environment && make test + - run: source /opt/intel/sgxsdk/environment && make integration-test From 8b0330b86e34a385e95f776413419f45c7199d12 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Fri, 13 Dec 2024 11:42:08 +0900 Subject: [PATCH 03/16] WIP Signed-off-by: Jun Kimura --- Cargo.lock | 636 +++++++++++++++++++++-- modules/attestation-report/src/dcap.rs | 6 + modules/attestation-report/src/ias.rs | 18 +- modules/attestation-report/src/lib.rs | 18 + modules/attestation-report/src/report.rs | 3 +- modules/keymanager/src/lib.rs | 42 +- modules/remote-attestation/Cargo.toml | 1 + modules/remote-attestation/src/dcap.rs | 1 - 8 files changed, 670 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 397660f3..e9999ad8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ dependencies = [ "once_cell", "regex", "secrecy", - "semver", + "semver 1.0.23", "serde", "termcolor", "toml", @@ -110,23 +110,56 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +[[package]] +name = "alloy-json-abi" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84c506bf264110fa7e90d9924f742f40ef53c6572ea56a0b0bd714a567ed389" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + [[package]] name = "alloy-primitives" version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425" dependencies = [ + "alloy-rlp", "bytes", "cfg-if 1.0.0", "const-hex", "derive_more 1.0.0", + "foldhash", + "hashbrown 0.15.1", "hex-literal", + "indexmap 2.6.0", "itoa", + "k256 0.13.4", + "keccak-asm", "paste", + "proptest", + "rand 0.8.5", "ruint", + "rustc-hash 2.1.0", + "serde", + "sha3", "tiny-keccak", ] +[[package]] +name = "alloy-rlp" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" +dependencies = [ + "arrayvec", + "bytes", +] + [[package]] name = "alloy-sol-macro" version = "0.8.12" @@ -174,15 +207,27 @@ dependencies = [ "syn-solidity", ] +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce13ff37285b0870d0a0746992a4ae48efaf34b766ae4c2640fa15e5305f8e73" +dependencies = [ + "serde", + "winnow", +] + [[package]] name = "alloy-sol-types" version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6520d427d4a8eb7aa803d852d7a52ceb0c519e784c292f64bb339e636918cf27" dependencies = [ + "alloy-json-abi", "alloy-primitives", "alloy-sol-macro", "const-hex", + "serde", ] [[package]] @@ -261,6 +306,130 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -279,6 +448,45 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -357,6 +565,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.88", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -456,6 +675,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" +[[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" @@ -511,7 +736,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.88", ] @@ -533,7 +758,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", "syn 2.0.88", "which", @@ -775,7 +1000,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver", + "semver 1.0.23", "serde", "serde_json", ] @@ -1157,6 +1382,18 @@ dependencies = [ "zeroize", ] +[[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" @@ -1260,6 +1497,29 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "dcap-rs" +version = "0.1.0" +source = "git+https://github.com/bluele/dcap-rs?rev=a9f807fc18983302edcd670df47b445d33f9c0aa#a9f807fc18983302edcd670df47b445d33f9c0aa" +dependencies = [ + "alloy-sol-types", + "chrono", + "hex", + "p256", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3", + "time", + "x509-parser", +] + [[package]] name = "deflate" version = "1.0.0" @@ -1290,12 +1550,37 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "derivation-path" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -1446,11 +1731,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der 0.6.1", - "elliptic-curve", - "rfc6979", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", "signature 1.6.4", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.9", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki", +] + [[package]] name = "ed25519" version = "1.5.3" @@ -1513,15 +1812,35 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", "der 0.6.1", "digest 0.10.7", - "ff", + "ff 0.12.1", "generic-array", - "group", + "group 0.12.1", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "pem-rfc7468", + "pkcs8", "rand_core 0.6.4", - "sec1", + "sec1 0.7.3", "subtle", "zeroize", ] @@ -1665,6 +1984,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.12.1" @@ -1675,6 +2005,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "filetime" version = "0.2.25" @@ -1716,6 +2056,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1843,6 +2189,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1902,7 +2249,18 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] @@ -1991,6 +2349,10 @@ name = "hashbrown" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "foldhash", + "serde", +] [[package]] name = "hashlink" @@ -2066,6 +2428,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hex-literal" @@ -2415,7 +2780,7 @@ dependencies = [ "retry", "ripemd", "secp256k1", - "semver", + "semver 1.0.23", "serde", "serde_derive", "serde_json", @@ -2427,7 +2792,7 @@ dependencies = [ "tendermint-light-client", "tendermint-light-client-verifier 0.28.0", "tendermint-rpc", - "thiserror", + "thiserror 1.0.69", "tiny-bip39", "tiny-keccak", "tokio", @@ -2562,7 +2927,7 @@ dependencies = [ "itertools 0.10.5", "prost", "rand 0.8.5", - "semver", + "semver 1.0.23", "serde", "serde_json", "serde_yaml", @@ -2789,6 +3154,7 @@ checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown 0.15.1", + "serde", ] [[package]] @@ -2886,8 +3252,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" dependencies = [ "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.8", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", "sha2 0.10.8", ] @@ -2900,6 +3279,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + [[package]] name = "keymanager" version = "0.1.0" @@ -3312,12 +3701,12 @@ dependencies = [ "once_cell", "parking_lot", "quanta", - "rustc_version", + "rustc_version 0.4.1", "scheduled-thread-pool", "skeptic", "smallvec", "tagptr", - "thiserror", + "thiserror 1.0.69", "triomphe", "uuid 1.11.0", ] @@ -3496,6 +3885,15 @@ dependencies = [ "sgx_types", ] +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.20.2" @@ -3569,7 +3967,7 @@ dependencies = [ "js-sys", "once_cell", "pin-project-lite", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3589,7 +3987,7 @@ dependencies = [ "opentelemetry_api", "percent-encoding", "rand 0.8.5", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3635,6 +4033,18 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2 0.10.8", +] + [[package]] name = "parity-scale-codec" version = "3.7.0" @@ -3757,6 +4167,17 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror 2.0.6", + "ucd-trie", +] + [[package]] name = "pin-project" version = "1.1.7" @@ -3835,6 +4256,15 @@ dependencies = [ "syn 2.0.88", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -3945,7 +4375,7 @@ dependencies = [ "memchr", "parking_lot", "protobuf", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4076,6 +4506,7 @@ dependencies = [ "libc", "rand_chacha 0.3.1", "rand_core 0.6.4", + "serde", ] [[package]] @@ -4160,7 +4591,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4215,6 +4646,7 @@ dependencies = [ "base64 0.22.1", "chrono", "crypto", + "dcap-rs", "flex-error", "hex", "httparse", @@ -4282,11 +4714,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac 0.12.1", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -4337,6 +4779,16 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -4397,8 +4849,18 @@ version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", "proptest", "rand 0.8.5", + "rlp", "ruint-macro", "serde", "valuable", @@ -4437,19 +4899,43 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc-hex" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver", + "semver 1.0.23", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", ] [[package]] @@ -4762,13 +5248,27 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", + "base16ct 0.1.1", "der 0.6.1", "generic-array", "subtle", "zeroize", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.9", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.24.3" @@ -4823,6 +5323,15 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.23" @@ -4832,6 +5341,15 @@ dependencies = [ "serde", ] +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.215" @@ -5102,6 +5620,16 @@ dependencies = [ "keccak", ] +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if 1.0.0", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -5430,7 +5958,7 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256", + "k256 0.11.6", "num-traits", "once_cell", "prost", @@ -5615,7 +6143,7 @@ dependencies = [ "subtle-encoding", "tendermint 0.28.0", "tendermint-config", - "thiserror", + "thiserror 1.0.69", "time", "tokio", "tracing", @@ -5661,7 +6189,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl 2.0.6", ] [[package]] @@ -5675,6 +6212,17 @@ dependencies = [ "syn 2.0.88", ] +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.88", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -5700,6 +6248,7 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ + "itoa", "libc", "num_threads", "serde", @@ -5733,9 +6282,9 @@ dependencies = [ "once_cell", "pbkdf2", "rand 0.8.5", - "rustc-hash", + "rustc-hash 1.1.0", "sha2 0.10.8", - "thiserror", + "thiserror 1.0.69", "unicode-normalization", "wasm-bindgen", "zeroize", @@ -6148,7 +6697,7 @@ dependencies = [ "rand 0.8.5", "rustls 0.20.9", "sha-1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", "webpki 0.22.4", @@ -6169,6 +6718,12 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uint" version = "0.9.5" @@ -6707,6 +7262,23 @@ dependencies = [ "tap", ] +[[package]] +name = "x509-parser" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + [[package]] name = "yansi" version = "1.0.1" diff --git a/modules/attestation-report/src/dcap.rs b/modules/attestation-report/src/dcap.rs index d2202d6c..92f5e9ec 100644 --- a/modules/attestation-report/src/dcap.rs +++ b/modules/attestation-report/src/dcap.rs @@ -1,10 +1,12 @@ use crate::prelude::*; +use crate::serde_base64; use crate::Error; use lcp_types::Time; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] pub struct DCAPQuote { + #[serde(with = "serde_base64")] pub raw: Vec, pub attested_at: Time, } @@ -20,4 +22,8 @@ impl DCAPQuote { pub fn to_json(&self) -> Result { serde_json::to_string(self).map_err(Error::serde_json) } + + pub fn from_json(json: &str) -> Result { + serde_json::from_str(json).map_err(Error::serde_json) + } } diff --git a/modules/attestation-report/src/ias.rs b/modules/attestation-report/src/ias.rs index 0bca17ec..b0f2a0a6 100644 --- a/modules/attestation-report/src/ias.rs +++ b/modules/attestation-report/src/ias.rs @@ -1,4 +1,5 @@ use crate::prelude::*; +use crate::serde_base64; use crate::{errors::Error, Quote}; use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; use chrono::prelude::DateTime; @@ -171,20 +172,3 @@ pub fn verify_ias_report(current_timestamp: Time, report: &IASSignedReport) -> R Ok(()) } - -mod serde_base64 { - use super::*; - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - - pub fn serialize(v: &Vec, s: S) -> Result { - let base64 = Base64Std.encode(v); - String::serialize(&base64, s) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { - let base64 = String::deserialize(d)?; - Base64Std - .decode(base64.as_bytes()) - .map_err(serde::de::Error::custom) - } -} diff --git a/modules/attestation-report/src/lib.rs b/modules/attestation-report/src/lib.rs index b6d8413a..67503339 100644 --- a/modules/attestation-report/src/lib.rs +++ b/modules/attestation-report/src/lib.rs @@ -25,6 +25,24 @@ pub use errors::Error; pub use ias::{verify_ias_report, IASAttestationVerificationReport, IASSignedReport}; pub use report::{Quote, ReportData, VerifiableQuote}; +pub(crate) mod serde_base64 { + use crate::prelude::*; + use base64::{engine::general_purpose::STANDARD as Base64Std, Engine}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(v: &Vec, s: S) -> Result { + let base64 = Base64Std.encode(v); + String::serialize(&base64, s) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { + let base64 = String::deserialize(d)?; + Base64Std + .decode(base64.as_bytes()) + .map_err(serde::de::Error::custom) + } +} + mod dcap; mod errors; mod ias; diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index 1b11a732..6f50d76a 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -3,11 +3,12 @@ use crate::{prelude::*, IASSignedReport}; use core::fmt::{Debug, Display, Error as FmtError}; use crypto::Address; use lcp_types::Time; +use serde::{Deserialize, Serialize}; use sgx_types::{metadata::metadata_t, sgx_measurement_t, sgx_quote_t, sgx_report_data_t}; pub const REPORT_DATA_V1: u8 = 1; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub enum VerifiableQuote { IAS(IASSignedReport), DCAP(DCAPQuote), diff --git a/modules/keymanager/src/lib.rs b/modules/keymanager/src/lib.rs index b0722374..6fe21c1d 100644 --- a/modules/keymanager/src/lib.rs +++ b/modules/keymanager/src/lib.rs @@ -1,7 +1,7 @@ pub mod errors; pub use crate::errors::Error; use anyhow::anyhow; -use attestation_report::{IASSignedReport, ReportData, VerifiableQuote}; +use attestation_report::{DCAPQuote, IASSignedReport, ReportData, VerifiableQuote}; use crypto::{Address, SealedEnclaveKey}; use lcp_types::{ deserialize_bytes, proto::lcp::service::enclave::v1::EnclaveKeyInfo as ProtoEnclaveKeyInfo, @@ -76,7 +76,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_sealed, mrenclave, report, ias_report + SELECT ek_sealed, mrenclave, report, ias_report, dcap_quote FROM enclave_keys WHERE ek_address = ?1 "#, @@ -117,6 +117,17 @@ impl EnclaveKeyManager { })?), Err(e) => return Err(e), }, + dcap_quote: match row.get::<_, Option>(4) { + Ok(None) => None, + Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 4, + Type::Text, + anyhow!("dcap_quote: {:?}", e).into(), + ) + })?), + Err(e) => return Err(e), + }, }) })?; Ok(key_info) @@ -199,7 +210,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, report, ias_report + SELECT ek_address, ek_sealed, mrenclave, report, ias_report, dcap_quote FROM enclave_keys WHERE attested_at IS NOT NULL AND mrenclave = ?1 ORDER BY attested_at DESC @@ -250,6 +261,17 @@ impl EnclaveKeyManager { ) })?, ), + dcap_quote: match row.get::<_, Option>(5) { + Ok(None) => None, + Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 5, + Type::Text, + anyhow!("dcap_quote: {:?}", e).into(), + ) + })?), + Err(e) => return Err(e), + }, }) })? .collect::, _>>()?; @@ -264,7 +286,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, report, ias_report + SELECT ek_address, ek_sealed, mrenclave, report, ias_report, dcap_quote FROM enclave_keys ORDER BY updated_at DESC "#, @@ -316,6 +338,17 @@ impl EnclaveKeyManager { })?), Err(e) => return Err(e), }, + dcap_quote: match row.get::<_, Option>(5) { + Ok(None) => None, + Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 5, + Type::Text, + anyhow!("dcap_quote: {:?}", e).into(), + ) + })?), + Err(e) => return Err(e), + }, }) })? .collect::, _>>()?; @@ -344,6 +377,7 @@ pub struct SealedEnclaveKeyInfo { #[serde_as(as = "BytesTransmuter")] pub report: sgx_report_t, pub ias_report: Option, + pub dcap_quote: Option, } impl TryFrom for ProtoEnclaveKeyInfo { diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 14bb3686..cb57f669 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -17,6 +17,7 @@ flex-error = { version = "0.4.4" } sha2 = { version = "0.10.6", features = ["oid"] } rsa = { version = "0.9.2", features = ["pem"], optional = true } chrono = { version = "0.4.38", features = ["now"], optional = true } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "a9f807fc18983302edcd670df47b445d33f9c0aa" } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index 7b0656d1..fd590cf8 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -18,7 +18,6 @@ pub fn run_dcap_ra( let quote = rsgx_qe_get_quote(&ek_info.report).unwrap(); println!("Successfully get the quote: {:?}", quote); let current_time = Time::now(); - // libqvl_verify_quote("e, current_time)?; key_manager .save_verifiable_quote( target_enclave_key, From bf7055651decc4d78e617ed4fc98893bce7dfa26 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 14:55:34 +0900 Subject: [PATCH 04/16] passed with a9f807fc18983302edcd670df47b445d33f9c0aa Signed-off-by: Jun Kimura --- Cargo.lock | 481 ++++++++++++++++++++++--- modules/remote-attestation/Cargo.toml | 14 +- modules/remote-attestation/src/dcap.rs | 147 +++++++- 3 files changed, 598 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9999ad8..0bec0f83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -546,7 +546,7 @@ dependencies = [ "flex-error", "hex", "lcp-types", - "pem", + "pem 2.0.1", "serde", "serde_json", "sgx_types", @@ -620,9 +620,9 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", "itoa", "matchit", "memchr", @@ -631,7 +631,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower", "tower-layer", "tower-service", @@ -646,8 +646,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "mime", "rustversion", "tower-layer", @@ -1037,6 +1037,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[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.38" @@ -1506,7 +1512,6 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dcap-rs" version = "0.1.0" -source = "git+https://github.com/bluele/dcap-rs?rev=a9f807fc18983302edcd670df47b445d33f9c0aa#a9f807fc18983302edcd670df47b445d33f9c0aa" dependencies = [ "alloy-sol-types", "chrono", @@ -1879,6 +1884,18 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.88", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -2305,7 +2322,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.6.0", "slab", "tokio", @@ -2381,7 +2398,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -2393,7 +2410,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.12", ] [[package]] @@ -2438,6 +2455,51 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hickory-proto" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand 0.8.5", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" +dependencies = [ + "cfg-if 1.0.0", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand 0.8.5", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + [[package]] name = "hmac" version = "0.8.1" @@ -2497,6 +2559,17 @@ dependencies = [ "store", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -2508,6 +2581,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -2515,7 +2599,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.2.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2558,8 +2665,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -2571,6 +2678,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-proxy" version = "0.9.1" @@ -2580,8 +2706,8 @@ dependencies = [ "bytes", "futures", "headers", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.31", "hyper-rustls 0.22.1", "rustls-native-certs 0.5.0", "tokio", @@ -2598,7 +2724,7 @@ checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" dependencies = [ "ct-logs", "futures-util", - "hyper", + "hyper 0.14.31", "log", "rustls 0.19.1", "rustls-native-certs 0.5.0", @@ -2615,25 +2741,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.31", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.2.0", + "hyper 1.5.1", + "hyper-util", + "rustls 0.23.18", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.1", + "tower-service", + "webpki-roots 0.26.6", +] + [[package]] name = "hyper-timeout" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.31", "pin-project-lite", "tokio", "tokio-io-timeout", ] +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.2.0", + "http-body 1.0.1", + "hyper 1.5.1", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -2697,10 +2860,10 @@ dependencies = [ "async-trait", "flex-error", "futures", - "http", + "http 0.2.12", "ibc-proto 0.24.1", "ibc-relayer-types", - "reqwest", + "reqwest 0.11.27", "serde", "serde_json", "tendermint-rpc", @@ -2765,7 +2928,7 @@ dependencies = [ "generic-array", "hdpath", "hex", - "http", + "http 0.2.12", "humantime", "humantime-serde", "ibc-proto 0.24.1", @@ -2821,7 +2984,7 @@ dependencies = [ "flex-error", "futures", "hdpath", - "http", + "http 0.2.12", "humantime", "ibc-chain-registry", "ibc-relayer", @@ -2919,7 +3082,7 @@ dependencies = [ "flex-error", "hdpath", "hex", - "http", + "http 0.2.12", "ibc-proto 0.24.1", "ibc-relayer", "ibc-relayer-cli", @@ -3191,6 +3354,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.10.1" @@ -3555,6 +3730,12 @@ dependencies = [ "store", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3583,6 +3764,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "lz4-sys" version = "1.11.1+lz4-1.10.0" @@ -3602,6 +3792,12 @@ dependencies = [ "libc", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -4152,6 +4348,15 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -4469,6 +4674,58 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.0", + "rustls 0.23.18", + "socket2", + "thiserror 2.0.6", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring 0.17.8", + "rustc-hash 2.1.0", + "rustls 0.23.18", + "rustls-pki-types", + "slab", + "thiserror 2.0.6", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.37" @@ -4653,11 +4910,15 @@ dependencies = [ "keymanager", "lcp-types", "log", + "pem 3.0.4", "rand 0.8.5", + "reqwest 0.12.9", "rsa", "rustls 0.23.18", "sgx_types", "sha2 0.10.8", + "tokio", + "urlencoding", "webpki-roots 0.26.6", ] @@ -4673,9 +4934,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", "hyper-rustls 0.24.2", "ipnet", "js-sys", @@ -4685,11 +4946,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-rustls 0.24.1", @@ -4702,6 +4963,60 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "hickory-resolver", + "http 1.2.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.1", + "hyper-rustls 0.27.3", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.18", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.26.6", + "windows-registry", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "retry" version = "2.0.0" @@ -4997,6 +5312,7 @@ dependencies = [ "aws-lc-rs", "log", "once_cell", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle", @@ -5022,7 +5338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "schannel", "security-framework", ] @@ -5036,11 +5352,23 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -5878,6 +6206,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[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.12.6" @@ -6130,8 +6467,8 @@ dependencies = [ "flex-error", "futures", "getrandom 0.2.15", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.31", "hyper-proxy", "hyper-rustls 0.22.1", "peg", @@ -6407,6 +6744,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls 0.23.18", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.16" @@ -6471,16 +6818,16 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", "hyper-timeout", "percent-encoding", "pin-project", "prost", "prost-derive", "rustls-native-certs 0.6.3", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "tokio", "tokio-rustls 0.23.4", "tokio-stream", @@ -6505,9 +6852,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", "hyper-timeout", "percent-encoding", "pin-project", @@ -6691,7 +7038,7 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes", - "http", + "http 0.2.12", "httparse", "log", "rand 0.8.5", @@ -6804,6 +7151,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" @@ -6978,6 +7331,16 @@ dependencies = [ "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" version = "0.21.4" @@ -7034,6 +7397,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -7074,6 +7443,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index cb57f669..c34f6d2e 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -14,16 +14,28 @@ httparse = { version = "1.3", default-features = false } rustls = { version = "0.23" } webpki-roots = { version = "0.26" } flex-error = { version = "0.4.4" } +pem = { version = "3", default-features = false } sha2 = { version = "0.10.6", features = ["oid"] } rsa = { version = "0.9.2", features = ["pem"], optional = true } chrono = { version = "0.4.38", features = ["now"], optional = true } -dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "a9f807fc18983302edcd670df47b445d33f9c0aa" } +reqwest = { version = "0.12.9", default-features = false, features = [ + "rustls-tls", + "blocking", + "hickory-dns", +] } +urlencoding = { version = "2" } + +# dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "a9f807fc18983302edcd670df47b445d33f9c0aa" } +dcap-rs = { path = "/home/jun/repos/github.com/bluele/dcap-rs" } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } attestation-report = { path = "../attestation-report" } keymanager = { path = "../keymanager" } +[dev-dependencies] +tokio = { version = "1", features = ["macros"] } + [features] default = [] sgx-sw = ["rsa", "chrono"] diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index fd590cf8..849751cf 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -1,10 +1,18 @@ use crate::errors::Error; use attestation_report::DCAPQuote; use crypto::Address; +use dcap_rs::types::collaterals::IntelCollateral; +use dcap_rs::types::quotes::version_3::QuoteV3; +use dcap_rs::utils::cert::{extract_sgx_extension, parse_certchain, parse_pem}; use keymanager::EnclaveKeyManager; use lcp_types::Time; use sgx_types::{sgx_qe_get_quote, sgx_qe_get_quote_size, sgx_quote3_error_t, sgx_report_t}; +const INTEL_ROOT_CA: &'static [u8] = + include_bytes!("../assets/Intel_SGX_Provisioning_Certification_RootCA.der"); +// TODO This is not root of trust, so we should get it via network +const INTEL_ROOT_CA_CRL: &'static [u8] = include_bytes!("../assets/IntelSGXRootCA.der"); + pub fn run_dcap_ra( key_manager: &EnclaveKeyManager, target_enclave_key: Address, @@ -15,13 +23,14 @@ pub fn run_dcap_ra( e, ) })?; - let quote = rsgx_qe_get_quote(&ek_info.report).unwrap(); + let raw_quote = rsgx_qe_get_quote(&ek_info.report).unwrap(); + let quote = QuoteV3::from_bytes(&raw_quote); println!("Successfully get the quote: {:?}", quote); let current_time = Time::now(); key_manager .save_verifiable_quote( target_enclave_key, - DCAPQuote::new(quote, current_time).into(), + DCAPQuote::new(raw_quote, current_time).into(), ) .map_err(|e| { Error::key_manager(format!("cannot save DCAP AVR: {}", target_enclave_key), e) @@ -44,3 +53,137 @@ fn rsgx_qe_get_quote(app_report: &sgx_report_t) -> Result, sgx_quote3_er } } } + +pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { + let base_url = format!("{}/sgx/certification/v4", pccs_url.trim_end_matches('/')); + let v3_base_url = format!("{}/sgx/certification/v3", pccs_url.trim_end_matches('/')); + assert_eq!( + quote.signature.qe_cert_data.cert_data_type, 5, + "QE Cert Type must be 5" + ); + let certchain_pems = parse_pem("e.signature.qe_cert_data.cert_data).unwrap(); + let certchain = parse_certchain(&certchain_pems); + + // get the pck certificate, and check whether issuer common name is valid + let pck_cert = &certchain[0]; + // let pck_cert_issuer = &certchain[1]; + + // get the SGX extension + let sgx_extensions = extract_sgx_extension(&pck_cert); + let fmspc = hex::encode_upper(sgx_extensions.fmspc); + + let builder = reqwest::Client::builder(); + let client = builder.build().unwrap(); + + let mut collateral = IntelCollateral::new(); + // used? + let tcb_info_issuer_chain; + let raw_tcb_info; + { + println!( + "Getting TCB info from {}", + format!("{v3_base_url}/tcb?fmspc={fmspc}") + ); + let res = client + .get(format!("{v3_base_url}/tcb?fmspc={fmspc}")) + .send() + .await + .unwrap(); + tcb_info_issuer_chain = get_header(&res, "SGX-TCB-Info-Issuer-Chain").unwrap(); + raw_tcb_info = res.text().await.unwrap(); + collateral.set_tcbinfo_bytes(raw_tcb_info.as_bytes()); + } + + // let qe_identity_issuer_chain; + { + let response = client + .get(format!("{base_url}/qe/identity")) + .send() + .await + .unwrap(); + // qe_identity_issuer_chain = get_header(&response, "SGX-Enclave-Identity-Issuer-Chain").unwrap(); + let raw_qe_identity = response.text().await.unwrap(); + collateral.set_qeidentity_bytes(raw_qe_identity.as_bytes()); + } + collateral.set_intel_root_ca_der(INTEL_ROOT_CA); + + let tcb_info_issuer_chain = extract_raw_certs(tcb_info_issuer_chain.as_bytes()).unwrap(); + collateral.set_sgx_tcb_signing_der(&tcb_info_issuer_chain[0]); + + collateral.set_sgx_intel_root_ca_crl_der(INTEL_ROOT_CA_CRL); + + { + let res = client + .get(format!("{base_url}/pckcrl?ca=processor&encoding=der")) + .send() + .await + .unwrap(); + let crl = res.bytes().await.unwrap(); + collateral.set_sgx_processor_crl_der(&crl); + } + { + let res = client + .get(format!("{base_url}/pckcrl?ca=platform&encoding=der")) + .send() + .await + .unwrap(); + let crl = res.bytes().await.unwrap(); + collateral.set_sgx_platform_crl_der(&crl); + } + + collateral +} + +fn get_header(resposne: &reqwest::Response, name: &str) -> Result { + let value = resposne + .headers() + .get(name) + .ok_or(format!("Missing {name}"))? + .to_str() + .unwrap(); + let value = urlencoding::decode(value).unwrap(); + Ok(value.into_owned()) +} + +fn extract_raw_certs(cert_chain: &[u8]) -> Result>, Error> { + Ok(pem::parse_many(cert_chain) + // .map_err(|_| Error::CodecError)? + .unwrap() + .iter() + .map(|i| i.contents().to_vec()) + .collect()) +} + +#[cfg(test)] +mod tests { + use std::time::SystemTime; + + use dcap_rs::utils::quotes::version_3::verify_quote_dcapv3; + + use super::*; + + #[test] + fn test_quote() { + QuoteV3::from_bytes(&get_test_quote()); + } + + #[tokio::test] + async fn test_dcap_collateral() { + let quote = get_test_quote(); + let quote = QuoteV3::from_bytes("e); + let collateral = get_collateral("https://api.trustedservices.intel.com/", "e).await; + let output = verify_quote_dcapv3( + "e, + &collateral, + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + ); + println!("{:?}", output); + } + + fn get_test_quote() -> Vec { + hex::decode("03000200000000000a001000939a7233f79c4ca9940a0db3957f0607b5fe5d7f613d2d40b066b320879bd14d0000000015150b07ff800e000000000000000000000000000000000000000000000000000000000000000000000000000000000005000000000000000700000000000000fe5a6a5bb9128e406517a8bea2d44eb9e238ca581f6a74c11d1437a0e9a6fb12000000000000000000000000000000000000000000000000000000000000000083d719e77deaca1470f6baf62a4d774303c899db69020f9c70ee1dfc08c7ce9e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000146a5b0a1d467d9dcf154e0b396cf5f44abcfd922000000000000000000000000000000000000000000000000000000000000000000000000000000000000004810000034868d98c393c8e4e470f545383c036336055e5bc04fbff926768b1235c95ab7c369ccf6733fbefd74ee7bd95f60a07bc16e6cad7f35355e3193520ecbf82d934b1526520dd11db5efc9504fa42d048e37ba38c90c8873e7c62f72e86794797bcf8586b9e5c10d0866a95331548da898ae0adf78e428128324151ee558cfc71215150b07ff800e00000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000070000000000000096b347a64e5a045e27369c26e6dcda51fd7c850e9b3a3a79e718f43261dee1e400000000000000000000000000000000000000000000000000000000000000008c4f5775d796503e96137f77c68a829a0056ac8ded70140b081b094490c57bff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000017b0dc79c3dc5ff39b3f67346eef41f1ecd63e0a5259a9102eaace1f0aca06ec00000000000000000000000000000000000000000000000000000000000000005ebe66d69491408b1c5948a56b7209b932051148415b68ca371d91ffa4e83e81408e877ac580c5f848a22c849fa4334221695eb4567de369757b949fe086ba7b2000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f0500e00d00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949456a7a4343424453674177494241674956414a34674a3835554b6b7a613873504a4847676e4f4b6d5451426e754d416f4743437147534d343942414d430a4d484578497a416842674e5642414d4d476b6c756447567349464e48574342515130736755484a765932567a6332397949454e424d526f77474159445651514b0a4442464a626e526c6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e560a4241674d416b4e424d517377435159445651514745774a56557a4165467730794e4445794d5445774e44457a4e544e614677307a4d5445794d5445774e44457a0a4e544e614d484178496a416742674e5642414d4d47556c756447567349464e4857434251513073675132567964476c6d61574e6864475578476a415942674e560a42416f4d45556c756447567349454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b470a413155454341774351304578437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741450a516a537877644d662b2b3578645553717478343769335952633970504a475434304642774e306e5335557a43314233524b63544875514c3135796b357a4c766c0a5535707a7563552f2b6d674a4e6f55774b6e784942364f434171677767674b6b4d42384741315564497751594d426141464e446f71747031312f6b75535265590a504873555a644456386c6c4e4d477747413155644877526c4d474d77596142666f463247573268306448427a4f693876595842704c6e527964584e305a57527a0a5a584a3261574e6c63793570626e526c6243356a62323076633264344c324e6c636e52705a6d6c6a5958527062323476646a517663474e7259334a7350324e680a5058427962324e6c63334e7663695a6c626d4e765a476c755a7a316b5a584977485159445652304f42425945464f7632356e4f67634c754f693644424b3037470a4d4f5161315a53494d41344741315564447745422f775145417749477744414d42674e5648524d4241663845416a41414d4949423141594a4b6f5a496876684e0a415130424249494278544343416345774867594b4b6f5a496876684e41513042415151514459697469663748386e4277566732482b38504f476a4343415751470a43697147534962345451454e41514977676746554d42414743797147534962345451454e41514942416745564d42414743797147534962345451454e415149430a416745564d42414743797147534962345451454e41514944416745434d42414743797147534962345451454e41514945416745454d42414743797147534962340a5451454e41514946416745424d42454743797147534962345451454e41514947416749416744415142677371686b69472b4530424451454342774942446a41510a42677371686b69472b45304244514543434149424144415142677371686b69472b45304244514543435149424144415142677371686b69472b453042445145430a436749424144415142677371686b69472b45304244514543437749424144415142677371686b69472b45304244514543444149424144415142677371686b69470a2b45304244514543445149424144415142677371686b69472b45304244514543446749424144415142677371686b69472b4530424451454344774942414441510a42677371686b69472b45304244514543454149424144415142677371686b69472b45304244514543455149424454416642677371686b69472b453042445145430a4567515146525543424147414467414141414141414141414144415142676f71686b69472b45304244514544424149414144415542676f71686b69472b4530420a44514545424159416b473756414141774477594b4b6f5a496876684e4151304242516f424144414b42676771686b6a4f5051514441674e4a41444247416945410a326d327a6e44316a3867426453344c74707051445a763246436252686f5a6a46386d474857555637534b34434951447a415847355945585142796d6f4f2b704f0a327a50443978436d2f4f4f794a4f673537574a412f34566f33413d3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436d444343416a36674177494241674956414e446f71747031312f6b7553526559504873555a644456386c6c4e4d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484578497a41680a42674e5642414d4d476b6c756447567349464e48574342515130736755484a765932567a6332397949454e424d526f77474159445651514b4442464a626e526c0a6243424462334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e420a4d517377435159445651514745774a56557a425a4d424d4742797147534d34394167454743437147534d34394177454841304941424c39712b4e4d7032494f670a74646c31626b2f75575a352b5447516d38614369387a373866732b664b435133642b75447a586e56544154325a68444369667949754a77764e33774e427039690a484253534d4a4d4a72424f6a6762737767626777487759445652306a42426777466f4155496d554d316c71644e496e7a6737535655723951477a6b6e427177770a556759445652306642457377535442486f45576751345a426148523063484d364c79396a5a584a3061575a70593246305a584d7564484a316333526c5a484e6c0a636e5a705932567a4c6d6c75644756734c6d4e766253394a626e526c62464e4857464a76623352445153356b5a584977485159445652304f42425945464e446f0a71747031312f6b7553526559504873555a644456386c6c4e4d41344741315564447745422f77514541774942426a415342674e5648524d4241663845434441470a4151482f416745414d416f4743437147534d343942414d43413067414d4555434951434a6754627456714f795a316d336a716941584d365159613672357357530a34792f4737793875494a4778647749675271507642534b7a7a516167424c517135733541373070646f6961524a387a2f3075447a344e675639316b3d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a00").unwrap() + } +} From d6a98a85c666d67d5a2830e4e5cfc26c653248c4 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 16:25:13 +0900 Subject: [PATCH 05/16] WIP: passed with API v4 Signed-off-by: Jun Kimura --- Cargo.lock | 1 + modules/remote-attestation/Cargo.toml | 3 +-- modules/remote-attestation/src/dcap.rs | 27 ++++++++++++-------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0bec0f83..c3253604 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1512,6 +1512,7 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dcap-rs" version = "0.1.0" +source = "git+https://github.com/bluele/dcap-rs?rev=43f60654515fb3000ebdc11ac80e1af9caba1ff9#43f60654515fb3000ebdc11ac80e1af9caba1ff9" dependencies = [ "alloy-sol-types", "chrono", diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index c34f6d2e..13facd3c 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -25,8 +25,7 @@ reqwest = { version = "0.12.9", default-features = false, features = [ ] } urlencoding = { version = "2" } -# dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "a9f807fc18983302edcd670df47b445d33f9c0aa" } -dcap-rs = { path = "/home/jun/repos/github.com/bluele/dcap-rs" } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "43f60654515fb3000ebdc11ac80e1af9caba1ff9" } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index 849751cf..f5a2e8e4 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -56,7 +56,6 @@ fn rsgx_qe_get_quote(app_report: &sgx_report_t) -> Result, sgx_quote3_er pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { let base_url = format!("{}/sgx/certification/v4", pccs_url.trim_end_matches('/')); - let v3_base_url = format!("{}/sgx/certification/v3", pccs_url.trim_end_matches('/')); assert_eq!( quote.signature.qe_cert_data.cert_data_type, 5, "QE Cert Type must be 5" @@ -66,7 +65,6 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral // get the pck certificate, and check whether issuer common name is valid let pck_cert = &certchain[0]; - // let pck_cert_issuer = &certchain[1]; // get the SGX extension let sgx_extensions = extract_sgx_extension(&pck_cert); @@ -76,22 +74,24 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral let client = builder.build().unwrap(); let mut collateral = IntelCollateral::new(); - // used? - let tcb_info_issuer_chain; - let raw_tcb_info; { println!( "Getting TCB info from {}", - format!("{v3_base_url}/tcb?fmspc={fmspc}") + format!("{base_url}/tcb?fmspc={fmspc}") ); let res = client - .get(format!("{v3_base_url}/tcb?fmspc={fmspc}")) + .get(format!("{base_url}/tcb?fmspc={fmspc}")) .send() .await .unwrap(); - tcb_info_issuer_chain = get_header(&res, "SGX-TCB-Info-Issuer-Chain").unwrap(); - raw_tcb_info = res.text().await.unwrap(); - collateral.set_tcbinfo_bytes(raw_tcb_info.as_bytes()); + let issuer_chain = extract_raw_certs( + get_header(&res, "TCB-Info-Issuer-Chain") + .unwrap() + .as_bytes(), + ) + .unwrap(); + collateral.set_sgx_tcb_signing_der(&issuer_chain[0]); + collateral.set_tcbinfo_bytes(res.bytes().await.unwrap().as_ref()); } // let qe_identity_issuer_chain; @@ -107,9 +107,6 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral } collateral.set_intel_root_ca_der(INTEL_ROOT_CA); - let tcb_info_issuer_chain = extract_raw_certs(tcb_info_issuer_chain.as_bytes()).unwrap(); - collateral.set_sgx_tcb_signing_der(&tcb_info_issuer_chain[0]); - collateral.set_sgx_intel_root_ca_crl_der(INTEL_ROOT_CA_CRL); { @@ -134,8 +131,8 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral collateral } -fn get_header(resposne: &reqwest::Response, name: &str) -> Result { - let value = resposne +fn get_header(res: &reqwest::Response, name: &str) -> Result { + let value = res .headers() .get(name) .ok_or(format!("Missing {name}"))? From 3039d788bfc8b79400f2d739a604b99e2c12f60f Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 16:39:08 +0900 Subject: [PATCH 06/16] OK Signed-off-by: Jun Kimura --- modules/remote-attestation/src/dcap.rs | 38 ++++++++++++-------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index f5a2e8e4..032d2adc 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -6,12 +6,11 @@ use dcap_rs::types::quotes::version_3::QuoteV3; use dcap_rs::utils::cert::{extract_sgx_extension, parse_certchain, parse_pem}; use keymanager::EnclaveKeyManager; use lcp_types::Time; +use log::*; use sgx_types::{sgx_qe_get_quote, sgx_qe_get_quote_size, sgx_quote3_error_t, sgx_report_t}; const INTEL_ROOT_CA: &'static [u8] = include_bytes!("../assets/Intel_SGX_Provisioning_Certification_RootCA.der"); -// TODO This is not root of trust, so we should get it via network -const INTEL_ROOT_CA_CRL: &'static [u8] = include_bytes!("../assets/IntelSGXRootCA.der"); pub fn run_dcap_ra( key_manager: &EnclaveKeyManager, @@ -26,6 +25,7 @@ pub fn run_dcap_ra( let raw_quote = rsgx_qe_get_quote(&ek_info.report).unwrap(); let quote = QuoteV3::from_bytes(&raw_quote); println!("Successfully get the quote: {:?}", quote); + let current_time = Time::now(); key_manager .save_verifiable_quote( @@ -54,8 +54,9 @@ fn rsgx_qe_get_quote(app_report: &sgx_report_t) -> Result, sgx_quote3_er } } -pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { +async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { let base_url = format!("{}/sgx/certification/v4", pccs_url.trim_end_matches('/')); + info!("base_url: {}", base_url); assert_eq!( quote.signature.qe_cert_data.cert_data_type, 5, "QE Cert Type must be 5" @@ -70,15 +71,9 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral let sgx_extensions = extract_sgx_extension(&pck_cert); let fmspc = hex::encode_upper(sgx_extensions.fmspc); - let builder = reqwest::Client::builder(); - let client = builder.build().unwrap(); - + let client = reqwest::Client::new(); let mut collateral = IntelCollateral::new(); { - println!( - "Getting TCB info from {}", - format!("{base_url}/tcb?fmspc={fmspc}") - ); let res = client .get(format!("{base_url}/tcb?fmspc={fmspc}")) .send() @@ -94,20 +89,25 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral collateral.set_tcbinfo_bytes(res.bytes().await.unwrap().as_ref()); } - // let qe_identity_issuer_chain; { - let response = client + let res = client .get(format!("{base_url}/qe/identity")) .send() .await .unwrap(); - // qe_identity_issuer_chain = get_header(&response, "SGX-Enclave-Identity-Issuer-Chain").unwrap(); - let raw_qe_identity = response.text().await.unwrap(); - collateral.set_qeidentity_bytes(raw_qe_identity.as_bytes()); + collateral.set_qeidentity_bytes(res.bytes().await.unwrap().as_ref()); } collateral.set_intel_root_ca_der(INTEL_ROOT_CA); - collateral.set_sgx_intel_root_ca_crl_der(INTEL_ROOT_CA_CRL); + { + let res = client + .get("https://certificates.trustedservices.intel.com/IntelSGXRootCA.der") + .send() + .await + .unwrap(); + let crl = res.bytes().await.unwrap(); + collateral.set_sgx_intel_root_ca_crl_der(&crl); + } { let res = client @@ -115,8 +115,7 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral .send() .await .unwrap(); - let crl = res.bytes().await.unwrap(); - collateral.set_sgx_processor_crl_der(&crl); + collateral.set_sgx_processor_crl_der(res.bytes().await.unwrap().as_ref()); } { let res = client @@ -124,8 +123,7 @@ pub async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral .send() .await .unwrap(); - let crl = res.bytes().await.unwrap(); - collateral.set_sgx_platform_crl_der(&crl); + collateral.set_sgx_platform_crl_der(res.bytes().await.unwrap().as_ref()); } collateral From 9e14ac550725ca6e21368e4f07885ed2c47fe902 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 16:55:09 +0900 Subject: [PATCH 07/16] OK Signed-off-by: Jun Kimura --- Cargo.lock | 1 - modules/remote-attestation/Cargo.toml | 3 - modules/remote-attestation/src/dcap.rs | 96 ++++++++++++++------------ 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3253604..6bbe7018 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4918,7 +4918,6 @@ dependencies = [ "rustls 0.23.18", "sgx_types", "sha2 0.10.8", - "tokio", "urlencoding", "webpki-roots 0.26.6", ] diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 13facd3c..07dc1107 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -32,9 +32,6 @@ crypto = { path = "../crypto", default-features = false } attestation-report = { path = "../attestation-report" } keymanager = { path = "../keymanager" } -[dev-dependencies] -tokio = { version = "1", features = ["macros"] } - [features] default = [] sgx-sw = ["rsa", "chrono"] diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index 032d2adc..7c5f3eaa 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -1,15 +1,18 @@ +use std::time::SystemTime; + use crate::errors::Error; use attestation_report::DCAPQuote; use crypto::Address; use dcap_rs::types::collaterals::IntelCollateral; use dcap_rs::types::quotes::version_3::QuoteV3; use dcap_rs::utils::cert::{extract_sgx_extension, parse_certchain, parse_pem}; +use dcap_rs::utils::quotes::version_3::verify_quote_dcapv3; use keymanager::EnclaveKeyManager; use lcp_types::Time; use log::*; use sgx_types::{sgx_qe_get_quote, sgx_qe_get_quote_size, sgx_quote3_error_t, sgx_report_t}; -const INTEL_ROOT_CA: &'static [u8] = +const INTEL_ROOT_CA: &[u8] = include_bytes!("../assets/Intel_SGX_Provisioning_Certification_RootCA.der"); pub fn run_dcap_ra( @@ -23,8 +26,24 @@ pub fn run_dcap_ra( ) })?; let raw_quote = rsgx_qe_get_quote(&ek_info.report).unwrap(); + info!("Successfully get the quote: {}", hex::encode(&raw_quote)); + let quote = QuoteV3::from_bytes(&raw_quote); - println!("Successfully get the quote: {:?}", quote); + + let collateral = get_collateral( + "https://api.trustedservices.intel.com/", + "https://certificates.trustedservices.intel.com/", + "e, + ); + let output = verify_quote_dcapv3( + "e, + &collateral, + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + ); + info!("DCAP RA output: {:?}", output); let current_time = Time::now(); key_manager @@ -54,7 +73,7 @@ fn rsgx_qe_get_quote(app_report: &sgx_report_t) -> Result, sgx_quote3_er } } -async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { +fn get_collateral(pccs_url: &str, certs_service_url: &str, quote: &QuoteV3) -> IntelCollateral { let base_url = format!("{}/sgx/certification/v4", pccs_url.trim_end_matches('/')); info!("base_url: {}", base_url); assert_eq!( @@ -63,22 +82,18 @@ async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { ); let certchain_pems = parse_pem("e.signature.qe_cert_data.cert_data).unwrap(); let certchain = parse_certchain(&certchain_pems); + assert_eq!(certchain.len(), 3, "QE Cert chain must have 3 certs"); // get the pck certificate, and check whether issuer common name is valid let pck_cert = &certchain[0]; // get the SGX extension - let sgx_extensions = extract_sgx_extension(&pck_cert); + let sgx_extensions = extract_sgx_extension(pck_cert); let fmspc = hex::encode_upper(sgx_extensions.fmspc); - let client = reqwest::Client::new(); let mut collateral = IntelCollateral::new(); { - let res = client - .get(format!("{base_url}/tcb?fmspc={fmspc}")) - .send() - .await - .unwrap(); + let res = reqwest::blocking::get(format!("{base_url}/tcb?fmspc={fmspc}")).unwrap(); let issuer_chain = extract_raw_certs( get_header(&res, "TCB-Info-Issuer-Chain") .unwrap() @@ -86,50 +101,39 @@ async fn get_collateral(pccs_url: &str, quote: &QuoteV3) -> IntelCollateral { ) .unwrap(); collateral.set_sgx_tcb_signing_der(&issuer_chain[0]); - collateral.set_tcbinfo_bytes(res.bytes().await.unwrap().as_ref()); + collateral.set_tcbinfo_bytes(res.bytes().unwrap().as_ref()); } { - let res = client - .get(format!("{base_url}/qe/identity")) - .send() - .await - .unwrap(); - collateral.set_qeidentity_bytes(res.bytes().await.unwrap().as_ref()); + let res = reqwest::blocking::get(format!("{base_url}/qe/identity")).unwrap(); + collateral.set_qeidentity_bytes(res.bytes().unwrap().as_ref()); } collateral.set_intel_root_ca_der(INTEL_ROOT_CA); { - let res = client - .get("https://certificates.trustedservices.intel.com/IntelSGXRootCA.der") - .send() - .await - .unwrap(); - let crl = res.bytes().await.unwrap(); - collateral.set_sgx_intel_root_ca_crl_der(&crl); + let res = reqwest::blocking::get(format!( + "{}/IntelSGXRootCA.der", + certs_service_url.trim_end_matches('/') + )) + .unwrap(); + collateral.set_sgx_intel_root_ca_crl_der(res.bytes().unwrap().as_ref()); } { - let res = client - .get(format!("{base_url}/pckcrl?ca=processor&encoding=der")) - .send() - .await - .unwrap(); - collateral.set_sgx_processor_crl_der(res.bytes().await.unwrap().as_ref()); + let res = + reqwest::blocking::get(format!("{base_url}/pckcrl?ca=processor&encoding=der")).unwrap(); + collateral.set_sgx_processor_crl_der(res.bytes().unwrap().as_ref()); } { - let res = client - .get(format!("{base_url}/pckcrl?ca=platform&encoding=der")) - .send() - .await - .unwrap(); - collateral.set_sgx_platform_crl_der(res.bytes().await.unwrap().as_ref()); + let res = + reqwest::blocking::get(format!("{base_url}/pckcrl?ca=platform&encoding=der")).unwrap(); + collateral.set_sgx_platform_crl_der(res.bytes().unwrap().as_ref()); } collateral } -fn get_header(res: &reqwest::Response, name: &str) -> Result { +fn get_header(res: &reqwest::blocking::Response, name: &str) -> Result { let value = res .headers() .get(name) @@ -151,22 +155,24 @@ fn extract_raw_certs(cert_chain: &[u8]) -> Result>, Error> { #[cfg(test)] mod tests { - use std::time::SystemTime; - - use dcap_rs::utils::quotes::version_3::verify_quote_dcapv3; - use super::*; + use dcap_rs::{constants::SGX_TEE_TYPE, utils::quotes::version_3::verify_quote_dcapv3}; + use std::time::SystemTime; #[test] fn test_quote() { QuoteV3::from_bytes(&get_test_quote()); } - #[tokio::test] - async fn test_dcap_collateral() { + #[test] + fn test_dcap_collateral() { let quote = get_test_quote(); let quote = QuoteV3::from_bytes("e); - let collateral = get_collateral("https://api.trustedservices.intel.com/", "e).await; + let collateral = get_collateral( + "https://api.trustedservices.intel.com/", + "https://certificates.trustedservices.intel.com/", + "e, + ); let output = verify_quote_dcapv3( "e, &collateral, @@ -175,7 +181,7 @@ mod tests { .unwrap() .as_secs(), ); - println!("{:?}", output); + assert_eq!(output.tee_type, SGX_TEE_TYPE); } fn get_test_quote() -> Vec { From 5c84dadd27f10218d2b74836d83f85eaa993a636 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 17:04:08 +0900 Subject: [PATCH 08/16] add DCAP root CA Signed-off-by: Jun Kimura --- ...ntel_SGX_Provisioning_Certification_RootCA.der | Bin 0 -> 659 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 modules/remote-attestation/assets/Intel_SGX_Provisioning_Certification_RootCA.der diff --git a/modules/remote-attestation/assets/Intel_SGX_Provisioning_Certification_RootCA.der b/modules/remote-attestation/assets/Intel_SGX_Provisioning_Certification_RootCA.der new file mode 100644 index 0000000000000000000000000000000000000000..768806c673709fb71537020abbabad2b1dc23773 GIT binary patch literal 659 zcmXqLV(K?&Vlr94%*4pVB%+kcb1iDFN$2P0EmMQ`2S{70v#l}UV&l+i^EhYA!pvll zVJKxF!NwfQ!ptM+nOBmUqY&&Kp%9dxU!vgb2$SQ2$vNj2733EsmSpDV8HyMPf%LKS za0e&ml_V-S=Oh*-8gd(OfM-Ch~kvMtrKjmv1bZ!Z(*nQf5%loS+O>FXz_7L{bCWhN(hi5#{Wtmy%j!APX{+k420HyOn$(X?{k= z|17|0XJi9Mo~$s4&tbp@q?i~PkrM{9Cxd|-lOn^@{ZBasf9gARD%>&aGSGW`QSWG5 z{WqmIDbv3SH3&@mV{?50sw!g B#yS81 literal 0 HcmV?d00001 From e321e12d33722991379dcb0fb59585e2c3d10d75 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 18:13:34 +0900 Subject: [PATCH 09/16] WIP Signed-off-by: Jun Kimura --- Cargo.lock | 3 +- app/src/commands/enclave.rs | 50 +++++++++++------- modules/attestation-report/Cargo.toml | 3 ++ modules/attestation-report/src/dcap.rs | 65 +++++++++++++++++++++++- modules/attestation-report/src/errors.rs | 8 --- modules/attestation-report/src/report.rs | 2 +- modules/remote-attestation/Cargo.toml | 2 +- modules/remote-attestation/src/dcap.rs | 11 ++-- 8 files changed, 110 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bbe7018..e27614ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -543,6 +543,7 @@ dependencies = [ "base64 0.22.1", "chrono", "crypto", + "dcap-rs", "flex-error", "hex", "lcp-types", @@ -1512,7 +1513,7 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dcap-rs" version = "0.1.0" -source = "git+https://github.com/bluele/dcap-rs?rev=43f60654515fb3000ebdc11ac80e1af9caba1ff9#43f60654515fb3000ebdc11ac80e1af9caba1ff9" +source = "git+https://github.com/bluele/dcap-rs?rev=71fe1e02f151a28bf5661b01dba5096730564840#71fe1e02f151a28bf5661b01dba5096730564840" dependencies = [ "alloy-sol-types", "chrono", diff --git a/app/src/commands/enclave.rs b/app/src/commands/enclave.rs index 63245aa3..8798fa6a 100644 --- a/app/src/commands/enclave.rs +++ b/app/src/commands/enclave.rs @@ -121,25 +121,37 @@ fn run_list_keys, S: CommitStore>( }; let mut list_json = Vec::new(); for eki in list { - match eki.ias_report { - Some(ias_report) => { - let avr = ias_report.get_avr()?; - let report_data = avr.parse_quote()?.report_data(); - list_json.push(json! {{ - "address": eki.address.to_hex_string(), - "attested": true, - "report_data": report_data.to_string(), - "isv_enclave_quote_status": avr.isv_enclave_quote_status, - "advisory_ids": avr.advisory_ids, - "attested_at": avr.timestamp - }}); - } - None => { - list_json.push(json! {{ - "address": eki.address.to_hex_string(), - "attested": false, - }}); - } + let ias_attested = eki.ias_report.is_some(); + let dcap_attested = eki.dcap_quote.is_some(); + + if ias_attested { + let avr = eki.ias_report.as_ref().unwrap().get_avr()?; + let report_data = avr.parse_quote()?.report_data(); + list_json.push(json! {{ + "type": "ias", + "address": eki.address.to_hex_string(), + "attested": true, + "report_data": report_data.to_string(), + "isv_enclave_quote_status": avr.isv_enclave_quote_status, + "advisory_ids": avr.advisory_ids, + "attested_at": avr.timestamp + }}); + } else if dcap_attested { + let dcap_quote = eki.dcap_quote.as_ref().unwrap(); + list_json.push(json! {{ + "type": "dcap", + "address": eki.address.to_hex_string(), + "attested": true, + "report_data": dcap_quote.report_data().to_string(), + "isv_enclave_quote_status": dcap_quote.tcb_status.to_string(), + "advisory_ids": dcap_quote.advisory_ids, + "attested_at": dcap_quote.attested_at, + }}); + } else { + list_json.push(json! {{ + "address": eki.address.to_hex_string(), + "attested": false, + }}); } } println!("{}", serde_json::to_string(&list_json).unwrap()); diff --git a/modules/attestation-report/Cargo.toml b/modules/attestation-report/Cargo.toml index 4e9adf71..cd85f0cb 100644 --- a/modules/attestation-report/Cargo.toml +++ b/modules/attestation-report/Cargo.toml @@ -16,12 +16,15 @@ base64 = { version = "0.22.1", default-features = false, features = ["alloc"] } pem = { version = "2.0", default-features = false } webpki = { version = "0.22", features = ["alloc"] } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840", optional = true } + [dev-dependencies] tokio = { version = "1.0", default-features = false, features = ["macros"] } [features] default = ["std"] std = [ + "dcap-rs", "webpki/std", "flex-error/std", "lcp-types/std", diff --git a/modules/attestation-report/src/dcap.rs b/modules/attestation-report/src/dcap.rs index 92f5e9ec..92c92769 100644 --- a/modules/attestation-report/src/dcap.rs +++ b/modules/attestation-report/src/dcap.rs @@ -1,6 +1,7 @@ use crate::prelude::*; use crate::serde_base64; use crate::Error; +use crate::ReportData; use lcp_types::Time; use serde::{Deserialize, Serialize}; @@ -8,13 +9,68 @@ use serde::{Deserialize, Serialize}; pub struct DCAPQuote { #[serde(with = "serde_base64")] pub raw: Vec, + pub tcb_status: TcbStatus, + pub advisory_ids: Option>, pub attested_at: Time, } +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum TcbStatus { + OK, + TcbSwHardeningNeeded, + TcbConfigurationAndSwHardeningNeeded, + TcbConfigurationNeeded, + TcbOutOfDate, + TcbOutOfDateConfigurationNeeded, + TcbRevoked, + TcbUnrecognized, +} + +impl TcbStatus { + pub fn from_str(s: &str) -> Self { + return match s { + "UpToDate" => TcbStatus::OK, + "SWHardeningNeeded" => TcbStatus::TcbSwHardeningNeeded, + "ConfigurationAndSWHardeningNeeded" => TcbStatus::TcbConfigurationAndSwHardeningNeeded, + "ConfigurationNeeded" => TcbStatus::TcbConfigurationNeeded, + "OutOfDate" => TcbStatus::TcbOutOfDate, + "OutOfDateConfigurationNeeded" => TcbStatus::TcbOutOfDateConfigurationNeeded, + "Revoked" => TcbStatus::TcbRevoked, + _ => TcbStatus::TcbUnrecognized, + }; + } +} + +impl ToString for TcbStatus { + fn to_string(&self) -> String { + return match self { + TcbStatus::OK => "UpToDate".to_string(), + TcbStatus::TcbSwHardeningNeeded => "SWHardeningNeeded".to_string(), + TcbStatus::TcbConfigurationAndSwHardeningNeeded => { + "ConfigurationAndSWHardeningNeeded".to_string() + } + TcbStatus::TcbConfigurationNeeded => "ConfigurationNeeded".to_string(), + TcbStatus::TcbOutOfDate => "OutOfDate".to_string(), + TcbStatus::TcbOutOfDateConfigurationNeeded => { + "OutOfDateConfigurationNeeded".to_string() + } + TcbStatus::TcbRevoked => "Revoked".to_string(), + TcbStatus::TcbUnrecognized => "Unrecognized".to_string(), + }; + } +} + impl DCAPQuote { - pub fn new(raw_quote: Vec, attested_at: Time) -> Self { + pub fn new( + raw_quote: Vec, + tcb_status: String, + advisory_ids: Option>, + attested_at: Time, + ) -> Self { DCAPQuote { raw: raw_quote, + tcb_status: TcbStatus::from_str(&tcb_status), + advisory_ids, attested_at, } } @@ -26,4 +82,11 @@ impl DCAPQuote { pub fn from_json(json: &str) -> Result { serde_json::from_str(json).map_err(Error::serde_json) } + + #[cfg(feature = "std")] + pub fn report_data(&self) -> ReportData { + use dcap_rs::types::quotes::version_3::QuoteV3; + let quote = QuoteV3::from_bytes(&self.raw); + ReportData(quote.isv_enclave_report.report_data) + } } diff --git a/modules/attestation-report/src/errors.rs b/modules/attestation-report/src/errors.rs index d12e2c47..72f75342 100644 --- a/modules/attestation-report/src/errors.rs +++ b/modules/attestation-report/src/errors.rs @@ -23,14 +23,6 @@ define_error! { format_args!("unexpected report data version: expected={} actual={}", e.expected, e.actual) }, - InvalidReportDataSize - { - size: usize - } - |e| { - format_args!("invalid report data size: size must be >= 20, but got {}", e.size) - }, - MrenclaveMismatch { expected: Mrenclave, diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index 6f50d76a..e963b3f8 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -38,7 +38,7 @@ impl From for VerifiableQuote { /// ReportData is a 64-byte value that is embedded in the Quote /// | version: 1 byte | enclave key: 20 bytes | operator: 20 bytes | nonce: 22 bytes | #[derive(Debug, Clone, PartialEq)] -pub struct ReportData([u8; 64]); +pub struct ReportData(pub(crate) [u8; 64]); impl ReportData { /// Creates a new report data diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 07dc1107..fa1f07cf 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -25,7 +25,7 @@ reqwest = { version = "0.12.9", default-features = false, features = [ ] } urlencoding = { version = "2" } -dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "43f60654515fb3000ebdc11ac80e1af9caba1ff9" } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840" } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index 7c5f3eaa..a99b7119 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -49,7 +49,13 @@ pub fn run_dcap_ra( key_manager .save_verifiable_quote( target_enclave_key, - DCAPQuote::new(raw_quote, current_time).into(), + DCAPQuote::new( + raw_quote, + output.tcb_status.to_string(), + output.advisory_ids, + current_time, + ) + .into(), ) .map_err(|e| { Error::key_manager(format!("cannot save DCAP AVR: {}", target_enclave_key), e) @@ -89,10 +95,9 @@ fn get_collateral(pccs_url: &str, certs_service_url: &str, quote: &QuoteV3) -> I // get the SGX extension let sgx_extensions = extract_sgx_extension(pck_cert); - let fmspc = hex::encode_upper(sgx_extensions.fmspc); - let mut collateral = IntelCollateral::new(); { + let fmspc = hex::encode_upper(sgx_extensions.fmspc); let res = reqwest::blocking::get(format!("{base_url}/tcb?fmspc={fmspc}")).unwrap(); let issuer_chain = extract_raw_certs( get_header(&res, "TCB-Info-Issuer-Chain") From 7d073366a819a453fdc12c02d76ccc252e7e252b Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 18:30:26 +0900 Subject: [PATCH 10/16] OK Signed-off-by: Jun Kimura --- app/src/commands/enclave.rs | 6 +-- modules/attestation-report/src/dcap.rs | 55 ++------------------------ 2 files changed, 7 insertions(+), 54 deletions(-) diff --git a/app/src/commands/enclave.rs b/app/src/commands/enclave.rs index 8798fa6a..77d90982 100644 --- a/app/src/commands/enclave.rs +++ b/app/src/commands/enclave.rs @@ -142,10 +142,10 @@ fn run_list_keys, S: CommitStore>( "type": "dcap", "address": eki.address.to_hex_string(), "attested": true, - "report_data": dcap_quote.report_data().to_string(), - "isv_enclave_quote_status": dcap_quote.tcb_status.to_string(), + "report_data": dcap_quote.report_data()?.to_string(), + "isv_enclave_quote_status": dcap_quote.tcb_status, "advisory_ids": dcap_quote.advisory_ids, - "attested_at": dcap_quote.attested_at, + "attested_at": dcap_quote.attested_at.to_string(), }}); } else { list_json.push(json! {{ diff --git a/modules/attestation-report/src/dcap.rs b/modules/attestation-report/src/dcap.rs index 92c92769..99e96e43 100644 --- a/modules/attestation-report/src/dcap.rs +++ b/modules/attestation-report/src/dcap.rs @@ -1,7 +1,6 @@ use crate::prelude::*; use crate::serde_base64; use crate::Error; -use crate::ReportData; use lcp_types::Time; use serde::{Deserialize, Serialize}; @@ -9,57 +8,11 @@ use serde::{Deserialize, Serialize}; pub struct DCAPQuote { #[serde(with = "serde_base64")] pub raw: Vec, - pub tcb_status: TcbStatus, + pub tcb_status: String, pub advisory_ids: Option>, pub attested_at: Time, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum TcbStatus { - OK, - TcbSwHardeningNeeded, - TcbConfigurationAndSwHardeningNeeded, - TcbConfigurationNeeded, - TcbOutOfDate, - TcbOutOfDateConfigurationNeeded, - TcbRevoked, - TcbUnrecognized, -} - -impl TcbStatus { - pub fn from_str(s: &str) -> Self { - return match s { - "UpToDate" => TcbStatus::OK, - "SWHardeningNeeded" => TcbStatus::TcbSwHardeningNeeded, - "ConfigurationAndSWHardeningNeeded" => TcbStatus::TcbConfigurationAndSwHardeningNeeded, - "ConfigurationNeeded" => TcbStatus::TcbConfigurationNeeded, - "OutOfDate" => TcbStatus::TcbOutOfDate, - "OutOfDateConfigurationNeeded" => TcbStatus::TcbOutOfDateConfigurationNeeded, - "Revoked" => TcbStatus::TcbRevoked, - _ => TcbStatus::TcbUnrecognized, - }; - } -} - -impl ToString for TcbStatus { - fn to_string(&self) -> String { - return match self { - TcbStatus::OK => "UpToDate".to_string(), - TcbStatus::TcbSwHardeningNeeded => "SWHardeningNeeded".to_string(), - TcbStatus::TcbConfigurationAndSwHardeningNeeded => { - "ConfigurationAndSWHardeningNeeded".to_string() - } - TcbStatus::TcbConfigurationNeeded => "ConfigurationNeeded".to_string(), - TcbStatus::TcbOutOfDate => "OutOfDate".to_string(), - TcbStatus::TcbOutOfDateConfigurationNeeded => { - "OutOfDateConfigurationNeeded".to_string() - } - TcbStatus::TcbRevoked => "Revoked".to_string(), - TcbStatus::TcbUnrecognized => "Unrecognized".to_string(), - }; - } -} - impl DCAPQuote { pub fn new( raw_quote: Vec, @@ -69,7 +22,7 @@ impl DCAPQuote { ) -> Self { DCAPQuote { raw: raw_quote, - tcb_status: TcbStatus::from_str(&tcb_status), + tcb_status, advisory_ids, attested_at, } @@ -84,9 +37,9 @@ impl DCAPQuote { } #[cfg(feature = "std")] - pub fn report_data(&self) -> ReportData { + pub fn report_data(&self) -> Result { use dcap_rs::types::quotes::version_3::QuoteV3; let quote = QuoteV3::from_bytes(&self.raw); - ReportData(quote.isv_enclave_report.report_data) + Ok(crate::ReportData(quote.isv_enclave_report.report_data)) } } From d5ff9339bf1e51a9942f2dfda8161845c6308903 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 19:19:02 +0900 Subject: [PATCH 11/16] fix Signed-off-by: Jun Kimura --- modules/remote-attestation/src/ias_utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/remote-attestation/src/ias_utils.rs b/modules/remote-attestation/src/ias_utils.rs index 9c4b2a8e..be778502 100644 --- a/modules/remote-attestation/src/ias_utils.rs +++ b/modules/remote-attestation/src/ias_utils.rs @@ -316,14 +316,14 @@ fn parse_response_attn_report(resp: &[u8]) -> Result { })?; trace!("content length = {}", len_num); } - "X-IASAttestationVerificationReport-Signature" => { + "X-IASReport-Signature" => { sig = str::from_utf8(h.value) .map_err(|e| { Error::invalid_utf8_bytes(h.value.to_vec(), e, h.name.to_string()) })? .to_string() } - "X-IASAttestationVerificationReport-Signing-Certificate" => { + "X-IASReport-Signing-Certificate" => { cert = str::from_utf8(h.value) .map_err(|e| { Error::invalid_utf8_bytes(h.value.to_vec(), e, h.name.to_string()) From a74ba69fd56431cd8b1c43055d8e754abe8cf98f Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 19:29:17 +0900 Subject: [PATCH 12/16] enable "ring" feature on rustls Signed-off-by: Jun Kimura --- modules/remote-attestation/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index fa1f07cf..72f6f790 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -11,7 +11,7 @@ rand = { version = "0.8" } hex = { version = "0.4", default-features = false, features = ["alloc"] } base64 = { version = "0.22.1", default-features = false, features = ["alloc"] } httparse = { version = "1.3", default-features = false } -rustls = { version = "0.23" } +rustls = { version = "0.23", features = ["ring"] } webpki-roots = { version = "0.26" } flex-error = { version = "0.4.4" } pem = { version = "3", default-features = false } From 5e2fed1c2cb67c6dc7e7d9b9a793fefc8a09ebd2 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 19:40:08 +0900 Subject: [PATCH 13/16] disable-rustls-aws_lc_rs Signed-off-by: Jun Kimura --- Cargo.lock | 96 +-------------------------- modules/remote-attestation/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e27614ce..b0a11cfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -583,33 +583,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "aws-lc-rs" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe7c2840b66236045acd2607d5866e274380afd87ef99d6226e961e2cb47df45" -dependencies = [ - "aws-lc-sys", - "mirai-annotations", - "paste", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad3a619a9de81e1d7de1f1186dcba4506ed661a0e483d84410fdef0ee87b2f96" -dependencies = [ - "bindgen 0.69.5", - "cc", - "cmake", - "dunce", - "fs_extra", - "libc", - "paste", -] - [[package]] name = "axum" version = "0.6.20" @@ -742,29 +715,6 @@ dependencies = [ "syn 2.0.88", ] -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags 2.6.0", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.88", - "which", -] - [[package]] name = "bit-set" version = "0.5.3" @@ -1164,15 +1114,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" -[[package]] -name = "cmake" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" -dependencies = [ - "cc", -] - [[package]] name = "color-eyre" version = "0.6.3" @@ -2099,12 +2040,6 @@ dependencies = [ "autocfg", ] -[[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" @@ -2532,15 +2467,6 @@ dependencies = [ "hmac 0.8.1", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "host" version = "0.1.0" @@ -3628,7 +3554,7 @@ version = "0.11.0+8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" dependencies = [ - "bindgen 0.65.1", + "bindgen", "bzip2-sys", "cc", "glob", @@ -3870,12 +3796,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "mirai-annotations" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" - [[package]] name = "mock-lc" version = "0.1.0" @@ -5310,7 +5230,6 @@ version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ - "aws-lc-rs", "log", "once_cell", "ring 0.17.8", @@ -5387,7 +5306,6 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "aws-lc-rs", "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", @@ -7386,18 +7304,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "widestring" version = "1.1.0" diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index 72f6f790..aa24b79a 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -11,7 +11,7 @@ rand = { version = "0.8" } hex = { version = "0.4", default-features = false, features = ["alloc"] } base64 = { version = "0.22.1", default-features = false, features = ["alloc"] } httparse = { version = "1.3", default-features = false } -rustls = { version = "0.23", features = ["ring"] } +rustls = { version = "0.23", default-features = false, features = ["ring", "logging", "std", "tls12"] } webpki-roots = { version = "0.26" } flex-error = { version = "0.4.4" } pem = { version = "3", default-features = false } From f94e125a6aa8b3324870ccaf5674925c82aa94a1 Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 19:49:32 +0900 Subject: [PATCH 14/16] fix Signed-off-by: Jun Kimura --- modules/keymanager/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/keymanager/src/lib.rs b/modules/keymanager/src/lib.rs index 6fe21c1d..988c82d5 100644 --- a/modules/keymanager/src/lib.rs +++ b/modules/keymanager/src/lib.rs @@ -252,15 +252,17 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - ias_report: Some( - IASSignedReport::from_json(&row.get::<_, String>(4)?).map_err(|e| { + ias_report: match row.get::<_, Option>(4) { + Ok(None) => None, + Ok(Some(avr)) => Some(IASSignedReport::from_json(&avr).map_err(|e| { rusqlite::Error::FromSqlConversionFailure( 4, Type::Text, anyhow!("ias_report: {:?}", e).into(), ) - })?, - ), + })?), + Err(e) => return Err(e), + }, dcap_quote: match row.get::<_, Option>(5) { Ok(None) => None, Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { From c1e32ca1542a632a0f4e6ff5a11979ae06ff6aba Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Mon, 16 Dec 2024 23:56:57 +0900 Subject: [PATCH 15/16] OK Signed-off-by: Jun Kimura --- Cargo.lock | 1 + app/Cargo.toml | 1 + app/src/commands/enclave.rs | 74 +++--- modules/attestation-report/src/errors.rs | 8 + modules/attestation-report/src/ias.rs | 8 - modules/attestation-report/src/lib.rs | 2 +- modules/attestation-report/src/report.rs | 54 +++- modules/enclave-api/src/api/command.rs | 13 +- modules/keymanager/src/lib.rs | 238 +++++++++--------- modules/remote-attestation/src/dcap.rs | 2 +- modules/remote-attestation/src/ias.rs | 2 +- .../remote-attestation/src/ias_simulation.rs | 2 +- .../lcp/service/enclave/v1/query.proto | 18 +- proto/src/descriptor.bin | Bin 100384 -> 100949 bytes proto/src/prost/lcp.service.enclave.v1.rs | 38 ++- tests/integration/src/lib.rs | 33 ++- 16 files changed, 301 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0a11cfe..fde40d95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3431,6 +3431,7 @@ name = "lcp" version = "0.0.1" dependencies = [ "anyhow", + "attestation-report", "clap 4.5.21", "crypto", "dirs", diff --git a/app/Cargo.toml b/app/Cargo.toml index ba9ff87a..be758db2 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -26,6 +26,7 @@ ecall-commands = { path = "../modules/ecall-commands" } crypto = { path = "../modules/crypto" } keymanager = { path = "../modules/keymanager" } remote-attestation = { path = "../modules/remote-attestation" } +attestation-report = { path = "../modules/attestation-report" } [build-dependencies] git2 = "0.19" diff --git a/app/src/commands/enclave.rs b/app/src/commands/enclave.rs index 77d90982..dbe1c7df 100644 --- a/app/src/commands/enclave.rs +++ b/app/src/commands/enclave.rs @@ -3,6 +3,7 @@ use crate::{ opts::{EnclaveOpts, Opts}, }; use anyhow::{anyhow, Result}; +use attestation_report::RAQuote; use clap::Parser; use crypto::Address; use ecall_commands::GenerateEnclaveKeyInput; @@ -87,10 +88,13 @@ fn run_generate_key, S: CommitStore>( ) -> Result<()> { let (target_info, _) = remote_attestation::init_quote(input.target_qe3)?; let res = enclave - .generate_enclave_key(GenerateEnclaveKeyInput { - target_info, - operator: input.get_operator()?, - }) + .generate_enclave_key( + GenerateEnclaveKeyInput { + target_info, + operator: input.get_operator()?, + }, + input.target_qe3, + ) .map_err(|e| anyhow!("failed to generate an enclave key: {:?}", e))?; println!("{}", res.pub_key.as_address()); Ok(()) @@ -121,37 +125,37 @@ fn run_list_keys, S: CommitStore>( }; let mut list_json = Vec::new(); for eki in list { - let ias_attested = eki.ias_report.is_some(); - let dcap_attested = eki.dcap_quote.is_some(); - - if ias_attested { - let avr = eki.ias_report.as_ref().unwrap().get_avr()?; - let report_data = avr.parse_quote()?.report_data(); - list_json.push(json! {{ - "type": "ias", - "address": eki.address.to_hex_string(), - "attested": true, - "report_data": report_data.to_string(), - "isv_enclave_quote_status": avr.isv_enclave_quote_status, - "advisory_ids": avr.advisory_ids, - "attested_at": avr.timestamp - }}); - } else if dcap_attested { - let dcap_quote = eki.dcap_quote.as_ref().unwrap(); - list_json.push(json! {{ - "type": "dcap", - "address": eki.address.to_hex_string(), - "attested": true, - "report_data": dcap_quote.report_data()?.to_string(), - "isv_enclave_quote_status": dcap_quote.tcb_status, - "advisory_ids": dcap_quote.advisory_ids, - "attested_at": dcap_quote.attested_at.to_string(), - }}); - } else { - list_json.push(json! {{ - "address": eki.address.to_hex_string(), - "attested": false, - }}); + match eki.ra_quote { + Some(RAQuote::IAS(report)) => { + let avr = report.get_avr()?; + let report_data = avr.parse_quote()?.report_data(); + list_json.push(json! {{ + "type": "ias", + "address": eki.address.to_hex_string(), + "attested": true, + "report_data": report_data.to_string(), + "isv_enclave_quote_status": avr.isv_enclave_quote_status, + "advisory_ids": avr.advisory_ids, + "attested_at": avr.timestamp + }}); + } + Some(RAQuote::DCAP(quote)) => { + list_json.push(json! {{ + "type": "dcap", + "address": eki.address.to_hex_string(), + "attested": true, + "report_data": quote.report_data()?.to_string(), + "isv_enclave_quote_status": quote.tcb_status, + "advisory_ids": quote.advisory_ids, + "attested_at": quote.attested_at.to_string(), + }}); + } + None => { + list_json.push(json! {{ + "address": eki.address.to_hex_string(), + "attested": false, + }}); + } } } println!("{}", serde_json::to_string(&list_json).unwrap()); diff --git a/modules/attestation-report/src/errors.rs b/modules/attestation-report/src/errors.rs index 72f75342..dfa05e4b 100644 --- a/modules/attestation-report/src/errors.rs +++ b/modules/attestation-report/src/errors.rs @@ -23,6 +23,14 @@ define_error! { format_args!("unexpected report data version: expected={} actual={}", e.expected, e.actual) }, + InvalidRaType + { + ra_type: u32 + } + |e| { + format_args!("Invalid RA type: ra_type={}", e.ra_type) + }, + MrenclaveMismatch { expected: Mrenclave, diff --git a/modules/attestation-report/src/ias.rs b/modules/attestation-report/src/ias.rs index b0f2a0a6..d36a9a9a 100644 --- a/modules/attestation-report/src/ias.rs +++ b/modules/attestation-report/src/ias.rs @@ -42,14 +42,6 @@ impl IASSignedReport { pub fn get_avr(&self) -> Result { serde_json::from_slice(self.avr.as_ref()).map_err(Error::serde_json) } - - pub fn to_json(&self) -> Result { - serde_json::to_string(self).map_err(Error::serde_json) - } - - pub fn from_json(json: &str) -> Result { - serde_json::from_str(json).map_err(Error::serde_json) - } } // IASAttestationVerificationReport represents Intel's Attestation Verification Report diff --git a/modules/attestation-report/src/lib.rs b/modules/attestation-report/src/lib.rs index 67503339..fa84a7c3 100644 --- a/modules/attestation-report/src/lib.rs +++ b/modules/attestation-report/src/lib.rs @@ -23,7 +23,7 @@ mod prelude { pub use dcap::DCAPQuote; pub use errors::Error; pub use ias::{verify_ias_report, IASAttestationVerificationReport, IASSignedReport}; -pub use report::{Quote, ReportData, VerifiableQuote}; +pub use report::{Quote, RAQuote, RAType, ReportData}; pub(crate) mod serde_base64 { use crate::prelude::*; diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index e963b3f8..091008cf 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -9,29 +9,67 @@ use sgx_types::{metadata::metadata_t, sgx_measurement_t, sgx_quote_t, sgx_report pub const REPORT_DATA_V1: u8 = 1; #[derive(Debug, Serialize, Deserialize)] -pub enum VerifiableQuote { +pub enum RAType { + IAS, + DCAP, +} + +impl RAType { + pub fn as_u32(&self) -> u32 { + match self { + Self::IAS => 1, + Self::DCAP => 2, + } + } + pub fn from_u32(v: u32) -> Result { + match v { + 1 => Ok(Self::IAS), + 2 => Ok(Self::DCAP), + _ => Err(Error::invalid_ra_type(v)), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "type")] +pub enum RAQuote { IAS(IASSignedReport), DCAP(DCAPQuote), } -impl VerifiableQuote { +impl RAQuote { + pub fn ra_type(&self) -> RAType { + match self { + RAQuote::IAS(_) => RAType::IAS, + RAQuote::DCAP(_) => RAType::DCAP, + } + } + pub fn attested_at(&self) -> Result { match self { - VerifiableQuote::IAS(report) => report.get_avr()?.attestation_time(), - VerifiableQuote::DCAP(quote) => Ok(quote.attested_at), + RAQuote::IAS(report) => report.get_avr()?.attestation_time(), + RAQuote::DCAP(quote) => Ok(quote.attested_at), } } + + pub fn from_json(json: &str) -> Result { + serde_json::from_str(json).map_err(Error::serde_json) + } + + pub fn to_json(&self) -> Result { + serde_json::to_string(self).map_err(Error::serde_json) + } } -impl From for VerifiableQuote { +impl From for RAQuote { fn from(report: IASSignedReport) -> Self { - VerifiableQuote::IAS(report) + RAQuote::IAS(report) } } -impl From for VerifiableQuote { +impl From for RAQuote { fn from(quote: DCAPQuote) -> Self { - VerifiableQuote::DCAP(quote) + RAQuote::DCAP(quote) } } diff --git a/modules/enclave-api/src/api/command.rs b/modules/enclave-api/src/api/command.rs index bd1ed1b0..d678b438 100644 --- a/modules/enclave-api/src/api/command.rs +++ b/modules/enclave-api/src/api/command.rs @@ -1,4 +1,5 @@ use crate::{EnclavePrimitiveAPI, Result}; +use attestation_report::RAType; use ecall_commands::{ AggregateMessagesInput, AggregateMessagesResponse, Command, CommandResponse, EnclaveManageCommand, EnclaveManageResponse, GenerateEnclaveKeyInput, @@ -14,6 +15,7 @@ pub trait EnclaveCommandAPI: EnclavePrimitiveAPI { fn generate_enclave_key( &self, input: GenerateEnclaveKeyInput, + is_target_qe3: bool, ) -> Result { let res = match self.execute_command( Command::EnclaveManage(EnclaveManageCommand::GenerateEnclaveKey(input)), @@ -22,8 +24,15 @@ pub trait EnclaveCommandAPI: EnclavePrimitiveAPI { CommandResponse::EnclaveManage(EnclaveManageResponse::GenerateEnclaveKey(res)) => res, _ => unreachable!(), }; - self.get_key_manager() - .save(res.sealed_ek.clone(), res.report)?; + self.get_key_manager().save( + res.sealed_ek.clone(), + res.report, + if is_target_qe3 { + RAType::DCAP + } else { + RAType::IAS + }, + )?; Ok(res) } diff --git a/modules/keymanager/src/lib.rs b/modules/keymanager/src/lib.rs index 988c82d5..f857900c 100644 --- a/modules/keymanager/src/lib.rs +++ b/modules/keymanager/src/lib.rs @@ -1,10 +1,14 @@ pub mod errors; pub use crate::errors::Error; use anyhow::anyhow; -use attestation_report::{DCAPQuote, IASSignedReport, ReportData, VerifiableQuote}; +use attestation_report::{RAQuote, RAType, ReportData}; use crypto::{Address, SealedEnclaveKey}; use lcp_types::{ - deserialize_bytes, proto::lcp::service::enclave::v1::EnclaveKeyInfo as ProtoEnclaveKeyInfo, + deserialize_bytes, + proto::lcp::service::enclave::v1::{ + enclave_key_info, DcapEnclaveKeyInfo, EnclaveKeyInfo as ProtoEnclaveKeyInfo, + IasEnclaveKeyInfo, + }, serialize_bytes, BytesTransmuter, Mrenclave, Time, }; use log::*; @@ -55,8 +59,8 @@ impl EnclaveKeyManager { ek_sealed BLOB NOT NULL, mrenclave TEXT NOT NULL, report BLOB NOT NULL, - ias_report TEXT, - dcap_quote TEXT, + ra_type INTEGER NOT NULL, + ra_quote TEXT, attested_at TEXT, created_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')), updated_at TEXT NOT NULL DEFAULT (DATETIME('now', 'localtime')) @@ -76,7 +80,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_sealed, mrenclave, report, ias_report, dcap_quote + SELECT ek_sealed, mrenclave, report, ra_type, ra_quote FROM enclave_keys WHERE ek_address = ?1 "#, @@ -106,24 +110,20 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - ias_report: match row.get::<_, Option>(3) { - Ok(None) => None, - Ok(Some(avr)) => Some(IASSignedReport::from_json(&avr).map_err(|e| { - rusqlite::Error::FromSqlConversionFailure( - 3, - Type::Text, - anyhow!("ias_report: {:?}", e).into(), - ) - })?), - Err(e) => return Err(e), - }, - dcap_quote: match row.get::<_, Option>(4) { + ra_type: RAType::from_u32(row.get::<_, i64>(3)? as u32).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 3, + Type::Integer, + anyhow!("ra_type: {:?}", e).into(), + ) + })?, + ra_quote: match row.get::<_, Option>(4) { Ok(None) => None, - Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { + Ok(Some(ra_quote)) => Some(RAQuote::from_json(&ra_quote).map_err(|e| { rusqlite::Error::FromSqlConversionFailure( 4, Type::Text, - anyhow!("dcap_quote: {:?}", e).into(), + anyhow!("ra_quote: {:?}", e).into(), ) })?), Err(e) => return Err(e), @@ -134,15 +134,20 @@ impl EnclaveKeyManager { } /// Save a sealed enclave key - pub fn save(&self, sealed_ek: SealedEnclaveKey, report: sgx_report_t) -> Result<(), Error> { + pub fn save( + &self, + sealed_ek: SealedEnclaveKey, + report: sgx_report_t, + ra_type: RAType, + ) -> Result<(), Error> { let conn = self .conn .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - INSERT INTO enclave_keys(ek_address, ek_sealed, mrenclave, report) - VALUES (?1, ?2, ?3, ?4) + INSERT INTO enclave_keys(ek_address, ek_sealed, mrenclave, report, ra_type) + VALUES (?1, ?2, ?3, ?4, ?5) "#, )?; let rd = ReportData::from(report.body.report_data); @@ -151,54 +156,29 @@ impl EnclaveKeyManager { sealed_ek.to_vec(), Mrenclave::from(report.body.mr_enclave).to_hex_string(), serialize_bytes(&report), + ra_type.as_u32() ])?; Ok(()) } /// Update the attestation verification report for the enclave key - pub fn save_verifiable_quote( - &self, - address: Address, - vquote: VerifiableQuote, - ) -> Result<(), Error> { + pub fn save_ra_quote(&self, address: Address, vquote: RAQuote) -> Result<(), Error> { let conn = self .conn .lock() .map_err(|e| Error::mutex_lock(e.to_string()))?; - - match vquote { - VerifiableQuote::IAS(ias_report) => { - let mut stmt = conn.prepare( - r#" - UPDATE enclave_keys - SET ias_report = ?1, attested_at = ?2 - WHERE ek_address = ?3 - "#, - )?; - stmt.execute(params![ - ias_report.to_json()?, - ias_report - .get_avr()? - .attestation_time()? - .as_unix_timestamp_secs(), - address.to_hex_string() - ])?; - } - VerifiableQuote::DCAP(dcap_quote) => { - let mut stmt = conn.prepare( - r#" - UPDATE enclave_keys - SET dcap_quote = ?1, attested_at = ?2 - WHERE ek_address = ?3 - "#, - )?; - stmt.execute(params![ - dcap_quote.to_json()?, - dcap_quote.attested_at.as_unix_timestamp_secs(), - address.to_hex_string() - ])?; - } - } + let mut stmt = conn.prepare( + r#" + UPDATE enclave_keys + SET ra_quote = ?1, attested_at = ?2 + WHERE ek_address = ?3 + "#, + )?; + stmt.execute(params![ + vquote.to_json()?, + vquote.attested_at()?.as_unix_timestamp_secs(), + address.to_hex_string() + ])?; Ok(()) } @@ -210,7 +190,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, report, ias_report, dcap_quote + SELECT ek_address, ek_sealed, mrenclave, report, ra_type, ra_quote FROM enclave_keys WHERE attested_at IS NOT NULL AND mrenclave = ?1 ORDER BY attested_at DESC @@ -252,24 +232,20 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - ias_report: match row.get::<_, Option>(4) { - Ok(None) => None, - Ok(Some(avr)) => Some(IASSignedReport::from_json(&avr).map_err(|e| { - rusqlite::Error::FromSqlConversionFailure( - 4, - Type::Text, - anyhow!("ias_report: {:?}", e).into(), - ) - })?), - Err(e) => return Err(e), - }, - dcap_quote: match row.get::<_, Option>(5) { + ra_type: RAType::from_u32(row.get::<_, i64>(4)? as u32).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 4, + Type::Integer, + anyhow!("ra_type: {:?}", e).into(), + ) + })?, + ra_quote: match row.get::<_, Option>(5) { Ok(None) => None, - Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { + Ok(Some(ra_quote)) => Some(RAQuote::from_json(&ra_quote).map_err(|e| { rusqlite::Error::FromSqlConversionFailure( 5, Type::Text, - anyhow!("dcap_quote: {:?}", e).into(), + anyhow!("ra_quote: {:?}", e).into(), ) })?), Err(e) => return Err(e), @@ -288,7 +264,7 @@ impl EnclaveKeyManager { .map_err(|e| Error::mutex_lock(e.to_string()))?; let mut stmt = conn.prepare( r#" - SELECT ek_address, ek_sealed, mrenclave, report, ias_report, dcap_quote + SELECT ek_address, ek_sealed, mrenclave, report, ra_type, ra_quote FROM enclave_keys ORDER BY updated_at DESC "#, @@ -329,24 +305,20 @@ impl EnclaveKeyManager { anyhow!("report: {:?}", e).into(), ) })?, - ias_report: match row.get::<_, Option>(4) { - Ok(None) => None, - Ok(Some(avr)) => Some(IASSignedReport::from_json(&avr).map_err(|e| { - rusqlite::Error::FromSqlConversionFailure( - 4, - Type::Text, - anyhow!("ias_report: {:?}", e).into(), - ) - })?), - Err(e) => return Err(e), - }, - dcap_quote: match row.get::<_, Option>(5) { + ra_type: RAType::from_u32(row.get::<_, i64>(4)? as u32).map_err(|e| { + rusqlite::Error::FromSqlConversionFailure( + 4, + Type::Integer, + anyhow!("ra_type: {:?}", e).into(), + ) + })?, + ra_quote: match row.get::<_, Option>(5) { Ok(None) => None, - Ok(Some(dq)) => Some(DCAPQuote::from_json(&dq).map_err(|e| { + Ok(Some(avr)) => Some(RAQuote::from_json(&avr).map_err(|e| { rusqlite::Error::FromSqlConversionFailure( 5, Type::Text, - anyhow!("dcap_quote: {:?}", e).into(), + anyhow!("ra_quote: {:?}", e).into(), ) })?), Err(e) => return Err(e), @@ -378,32 +350,51 @@ pub struct SealedEnclaveKeyInfo { pub mrenclave: Mrenclave, #[serde_as(as = "BytesTransmuter")] pub report: sgx_report_t, - pub ias_report: Option, - pub dcap_quote: Option, + pub ra_type: RAType, + pub ra_quote: Option, } impl TryFrom for ProtoEnclaveKeyInfo { type Error = Error; fn try_from(value: SealedEnclaveKeyInfo) -> Result { - let ias_report = value - .ias_report - .ok_or_else(|| Error::unattested_enclave_key(format!("address={}", value.address)))?; - let attestation_time = ias_report.get_avr()?.parse_quote()?.attestation_time; - Ok(Self { - enclave_key_address: value.address.into(), - attestation_time: attestation_time.as_unix_timestamp_secs(), - report: ias_report.avr, - signature: ias_report.signature, - signing_cert: ias_report.signing_cert, - extension: Default::default(), - }) + match value.ra_quote { + Some(RAQuote::IAS(report)) => { + let attestation_time = report + .get_avr()? + .attestation_time()? + .as_unix_timestamp_secs(); + Ok(ProtoEnclaveKeyInfo { + key_info: Some(enclave_key_info::KeyInfo::Ias(IasEnclaveKeyInfo { + enclave_key_address: value.address.into(), + attestation_time, + report: report.avr, + signature: report.signature, + signing_cert: report.signing_cert, + })), + }) + } + Some(RAQuote::DCAP(dcap)) => { + let attestation_time = dcap.attested_at.as_unix_timestamp_secs(); + Ok(ProtoEnclaveKeyInfo { + key_info: Some(enclave_key_info::KeyInfo::Dcap(DcapEnclaveKeyInfo { + enclave_key_address: value.address.into(), + quote: dcap.raw, + attestation_time, + })), + }) + } + None => Err(Error::unattested_enclave_key(format!( + "address={}", + value.address + ))), + } } } #[cfg(test)] mod tests { use super::*; - use attestation_report::IASAttestationVerificationReport; + use attestation_report::{IASAttestationVerificationReport, IASSignedReport}; use chrono::{DateTime, Duration, Utc}; use rand::RngCore; @@ -416,14 +407,13 @@ mod tests { let report = create_report(mrenclave, address); let sealed_ek = create_sealed_sk(); assert_eq!(km.all_keys().unwrap().len(), 0); - km.save(sealed_ek, report).unwrap(); - assert!(km.load(address).unwrap().ias_report.is_none()); + km.save(sealed_ek, report, RAType::IAS).unwrap(); + assert!(km.load(address).unwrap().ra_quote.is_none()); assert_eq!(km.all_keys().unwrap().len(), 1); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 0); let ias_report = create_ias_report(get_time(Duration::zero())); - km.save_verifiable_quote(address, ias_report.into()) - .unwrap(); - assert!(km.load(address).unwrap().ias_report.is_some()); + km.save_ra_quote(address, ias_report.into()).unwrap(); + assert!(km.load(address).unwrap().ra_quote.is_some()); assert_eq!(km.all_keys().unwrap().len(), 1); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 1); address @@ -433,14 +423,13 @@ mod tests { let report = create_report(mrenclave, address); let sealed_ek = create_sealed_sk(); assert_eq!(km.all_keys().unwrap().len(), 1); - km.save(sealed_ek, report).unwrap(); - assert!(km.load(address).unwrap().ias_report.is_none()); + km.save(sealed_ek, report, RAType::IAS).unwrap(); + assert!(km.load(address).unwrap().ra_quote.is_none()); assert_eq!(km.all_keys().unwrap().len(), 2); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 1); let ias_report = create_ias_report(get_time(Duration::minutes(1))); - km.save_verifiable_quote(address, ias_report.into()) - .unwrap(); - assert!(km.load(address).unwrap().ias_report.is_some()); + km.save_ra_quote(address, ias_report.into()).unwrap(); + assert!(km.load(address).unwrap().ra_quote.is_some()); assert_eq!(km.all_keys().unwrap().len(), 2); assert_eq!(km.available_keys(mrenclave).unwrap().len(), 2); } @@ -458,6 +447,23 @@ mod tests { ); } + #[test] + fn test_key_info_conversion() { + let km = EnclaveKeyManager::new_in_memory().unwrap(); + let mrenclave = create_mrenclave(); + let sealed_ek = create_sealed_sk(); + let address = create_address(); + let report = create_report(mrenclave, address); + km.save(sealed_ek, report, RAType::IAS).unwrap(); + let key_info = km.load(address).unwrap(); + assert!(ProtoEnclaveKeyInfo::try_from(key_info).is_err()); + let ias_report = create_ias_report(get_time(Duration::minutes(1))); + km.save_ra_quote(address, ias_report.into()).unwrap(); + let key_info = km.load(address).unwrap(); + let res = ProtoEnclaveKeyInfo::try_from(key_info); + assert!(res.is_ok(), "{:?}", res); + } + fn get_time(d: Duration) -> DateTime { Utc::now().checked_sub_signed(d).unwrap() } diff --git a/modules/remote-attestation/src/dcap.rs b/modules/remote-attestation/src/dcap.rs index a99b7119..69ec1f62 100644 --- a/modules/remote-attestation/src/dcap.rs +++ b/modules/remote-attestation/src/dcap.rs @@ -47,7 +47,7 @@ pub fn run_dcap_ra( let current_time = Time::now(); key_manager - .save_verifiable_quote( + .save_ra_quote( target_enclave_key, DCAPQuote::new( raw_quote, diff --git a/modules/remote-attestation/src/ias.rs b/modules/remote-attestation/src/ias.rs index 9f9f6027..644abaea 100644 --- a/modules/remote-attestation/src/ias.rs +++ b/modules/remote-attestation/src/ias.rs @@ -36,7 +36,7 @@ pub fn run_ias_ra( signed_report.get_avr()?.parse_quote()?.report_data() ); key_manager - .save_verifiable_quote(target_enclave_key, signed_report.clone().into()) + .save_ra_quote(target_enclave_key, signed_report.clone().into()) .map_err(|e| { Error::key_manager(format!("cannot save IAS AVR: {}", target_enclave_key), e) })?; diff --git a/modules/remote-attestation/src/ias_simulation.rs b/modules/remote-attestation/src/ias_simulation.rs index 45c571d0..d61125f7 100644 --- a/modules/remote-attestation/src/ias_simulation.rs +++ b/modules/remote-attestation/src/ias_simulation.rs @@ -43,7 +43,7 @@ pub fn run_ias_ra_simulation( signed_report.get_avr()?.parse_quote()?.report_data() ); key_manager - .save_verifiable_quote(target_enclave_key, signed_report.clone().into()) + .save_ra_quote(target_enclave_key, signed_report.clone().into()) .map_err(|e| { Error::key_manager( format!("cannot save IAS Simulation AVR: {}", target_enclave_key), diff --git a/proto/definitions/lcp/service/enclave/v1/query.proto b/proto/definitions/lcp/service/enclave/v1/query.proto index 092ecdc0..6274d4f2 100644 --- a/proto/definitions/lcp/service/enclave/v1/query.proto +++ b/proto/definitions/lcp/service/enclave/v1/query.proto @@ -20,12 +20,24 @@ message QueryAvailableEnclaveKeysResponse { } message EnclaveKeyInfo { + oneof key_info { + IASEnclaveKeyInfo ias = 1; + DCAPEnclaveKeyInfo dcap = 2; + } +} + +message IASEnclaveKeyInfo { bytes enclave_key_address = 1; - uint64 attestation_time = 2; - string report = 3; + string report = 2; + uint64 attestation_time = 3; bytes signature = 4; bytes signing_cert = 5; - bytes extension = 6; +} + +message DCAPEnclaveKeyInfo { + bytes enclave_key_address = 1; + bytes quote = 2; + uint64 attestation_time = 3; } message QueryEnclaveKeyRequest { diff --git a/proto/src/descriptor.bin b/proto/src/descriptor.bin index cf8cc6293b7b6675c19bf344fca160c12eaf50b7..8301150dee4eb2076e56f4b7a544aec56e1f0969 100644 GIT binary patch delta 1144 zcmb7Cy>1gh7`*+t^WG*Q_Try&h<_D3iH+ij9uWtSh-kp1p^B_xO0#Q-UeKYgTH@6q>yl?NlH=oICkN#A%*dsq0ABenk zdwl$K_%gg3P7lV9C+fOnqv3f#>SSx_+VTn`X$3{i5{F!qdrFWUTywMQU4Shfx%sN5g0| z86QQXXJNpwj1N}-_2whOEAr|FK@pY$}L}XyCi?Z=! zI!1*iegLjU8DjthVnrl&K(MR8PN!%3%qq=WB5_p=C{n10{%VS#tE$UZM-{8l!eUVb1Qx|bA9cpU6VApZQ8Z@=!&@~o14qZc} zC!itLCB+S32pRlMU|P2#(tbwt(pxjKH= z#s`33*Tw(>v1`)o%@gj?tT_ZTFnhVAT_E`N L=3iFGlUKh12_1$3 delta 657 zcmYL_J5Iwu5Qe=EFY8SN$wKVS13OAmz$p+d9b6y^l95tCP~rk1A=4mHQXsiP;t)u= z09T-*;}F#Ro9vqM+nMj5+4*`E?=Rx(vz)4T~E-G!6CHLj-#3xdf;jlo~b>%mx=a#4W7~aZXBRXV^?C(y7iU}T35Dx z&2}DioW?clQNKya;q_{d!|O@E3WwKAjPuagug8TO@<$1w_3LpVv_8fuMUlYMV7R@p zT`HC7CXU$~XLML@Rs, +} +/// Nested message and enum types in `EnclaveKeyInfo`. +pub mod enclave_key_info { + #[derive(::serde::Serialize, ::serde::Deserialize)] + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum KeyInfo { + #[prost(message, tag = "1")] + Ias(super::IasEnclaveKeyInfo), + #[prost(message, tag = "2")] + Dcap(super::DcapEnclaveKeyInfo), + } +} +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct IasEnclaveKeyInfo { #[prost(bytes = "vec", tag = "1")] pub enclave_key_address: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "2")] - pub attestation_time: u64, - #[prost(string, tag = "3")] + #[prost(string, tag = "2")] pub report: ::prost::alloc::string::String, + #[prost(uint64, tag = "3")] + pub attestation_time: u64, #[prost(bytes = "vec", tag = "4")] pub signature: ::prost::alloc::vec::Vec, #[prost(bytes = "vec", tag = "5")] pub signing_cert: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "6")] - pub extension: ::prost::alloc::vec::Vec, +} +#[derive(::serde::Serialize, ::serde::Deserialize)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DcapEnclaveKeyInfo { + #[prost(bytes = "vec", tag = "1")] + pub enclave_key_address: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub quote: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "3")] + pub attestation_time: u64, } #[derive(::serde::Serialize, ::serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index beb60615..8addd7c3 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -81,19 +81,25 @@ mod tests { let (target_info, _) = remote_attestation::init_quote(false)?; let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; - let op_ek_addr = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { - operator: Some(operator), - target_info, - }) { + let op_ek_addr = match enclave.generate_enclave_key( + GenerateEnclaveKeyInput { + operator: Some(operator), + target_info, + }, + false, + ) { Ok(res) => res.pub_key.as_address(), Err(e) => { bail!("failed to generate an enclave key: {:?}!", e); } }; - let ek_addr = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { - operator: None, - target_info, - }) { + let ek_addr = match enclave.generate_enclave_key( + GenerateEnclaveKeyInput { + operator: None, + target_info, + }, + false, + ) { Ok(res) => res.pub_key.as_address(), Err(e) => { bail!("failed to generate an enclave key: {:?}!", e); @@ -214,10 +220,13 @@ mod tests { ) -> Result<(), anyhow::Error> { let operator = Address::from_hex_string("0x396e1ccc2f11cd6d2114c2449dad7751357e413e")?; let (target_info, _) = remote_attestation::init_quote(false)?; - let signer = match enclave.generate_enclave_key(GenerateEnclaveKeyInput { - operator: Some(operator), - target_info, - }) { + let signer = match enclave.generate_enclave_key( + GenerateEnclaveKeyInput { + operator: Some(operator), + target_info, + }, + false, + ) { Ok(res) => res.pub_key.as_address(), Err(e) => { bail!("failed to generate an enclave key: {:?}!", e); From e8e9329f09c5459658d9eac423af21f8552ee4fb Mon Sep 17 00:00:00 2001 From: Jun Kimura Date: Wed, 18 Dec 2024 17:29:38 +0900 Subject: [PATCH 16/16] implement `zkdcap_register_enclave_key` for `LCPClient` Signed-off-by: Jun Kimura --- Cargo.lock | 3 +- modules/attestation-report/Cargo.toml | 2 +- modules/attestation-report/src/report.rs | 2 +- modules/lcp-client/Cargo.toml | 1 + modules/lcp-client/src/client_def.rs | 72 +++++++++++++++++- modules/lcp-client/src/dcap.rs | 44 +++++++++++ modules/lcp-client/src/errors.rs | 5 ++ modules/lcp-client/src/lib.rs | 1 + modules/lcp-client/src/message.rs | 43 ++++++++++- modules/remote-attestation/Cargo.toml | 2 +- .../ibc/lightclients/lcp/v1/lcp.proto | 6 ++ proto/src/descriptor.bin | Bin 100949 -> 101266 bytes proto/src/prost/ibc.lightclients.lcp.v1.rs | 10 +++ 13 files changed, 183 insertions(+), 8 deletions(-) create mode 100644 modules/lcp-client/src/dcap.rs diff --git a/Cargo.lock b/Cargo.lock index fde40d95..982c5b3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1454,7 +1454,7 @@ checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dcap-rs" version = "0.1.0" -source = "git+https://github.com/bluele/dcap-rs?rev=71fe1e02f151a28bf5661b01dba5096730564840#71fe1e02f151a28bf5661b01dba5096730564840" +source = "git+https://github.com/bluele/dcap-rs?rev=c3098b6a3c9faa4a884c87db65d0f586000bcf16#c3098b6a3c9faa4a884c87db65d0f586000bcf16" dependencies = [ "alloy-sol-types", "chrono", @@ -3461,6 +3461,7 @@ dependencies = [ "chrono", "context", "crypto", + "dcap-rs", "flex-error", "hex-literal", "ibc", diff --git a/modules/attestation-report/Cargo.toml b/modules/attestation-report/Cargo.toml index cd85f0cb..e1d78584 100644 --- a/modules/attestation-report/Cargo.toml +++ b/modules/attestation-report/Cargo.toml @@ -16,7 +16,7 @@ base64 = { version = "0.22.1", default-features = false, features = ["alloc"] } pem = { version = "2.0", default-features = false } webpki = { version = "0.22", features = ["alloc"] } -dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840", optional = true } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "c3098b6a3c9faa4a884c87db65d0f586000bcf16", optional = true } [dev-dependencies] tokio = { version = "1.0", default-features = false, features = ["macros"] } diff --git a/modules/attestation-report/src/report.rs b/modules/attestation-report/src/report.rs index 091008cf..f96d1f55 100644 --- a/modules/attestation-report/src/report.rs +++ b/modules/attestation-report/src/report.rs @@ -76,7 +76,7 @@ impl From for RAQuote { /// ReportData is a 64-byte value that is embedded in the Quote /// | version: 1 byte | enclave key: 20 bytes | operator: 20 bytes | nonce: 22 bytes | #[derive(Debug, Clone, PartialEq)] -pub struct ReportData(pub(crate) [u8; 64]); +pub struct ReportData(pub [u8; 64]); impl ReportData { /// Creates a new report data diff --git a/modules/lcp-client/Cargo.toml b/modules/lcp-client/Cargo.toml index c47043c1..ee8b63cb 100644 --- a/modules/lcp-client/Cargo.toml +++ b/modules/lcp-client/Cargo.toml @@ -11,6 +11,7 @@ flex-error = { version = "0.4.4", default-features = false } tiny-keccak = { version = "2.0" } hex-literal = { version = "0.4.1" } alloy-sol-types = { version = "0.8", default-features = false } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "c3098b6a3c9faa4a884c87db65d0f586000bcf16" } attestation-report = { path = "../attestation-report", default-features = false } light-client = { path = "../light-client", default-features = false } diff --git a/modules/lcp-client/src/client_def.rs b/modules/lcp-client/src/client_def.rs index fbab72eb..f37d2863 100644 --- a/modules/lcp-client/src/client_def.rs +++ b/modules/lcp-client/src/client_def.rs @@ -3,10 +3,12 @@ use crate::consensus_state::ConsensusState; use crate::errors::Error; use crate::message::{ ClientMessage, CommitmentProofs, RegisterEnclaveKeyMessage, UpdateOperatorsMessage, + ZKDCAPRegisterEnclaveKeyMessage, }; use alloy_sol_types::{sol, SolValue}; use attestation_report::{IASSignedReport, ReportData}; use crypto::{verify_signature_address, Address, Keccak256}; +use dcap_rs::types::quotes::body::QuoteBody; use hex_literal::hex; use light_client::commitments::{ CommitmentPrefix, EthABIEncoder, MisbehaviourProxyMessage, ProxyMessage, @@ -125,6 +127,9 @@ impl LCPClient { ClientMessage::RegisterEnclaveKey(msg) => { self.register_enclave_key(ctx, client_id, client_state, msg) } + ClientMessage::ZKDCAPRegisterEnclaveKey(msg) => { + self.zkdcap_register_enclave_key(ctx, client_id, client_state, msg) + } ClientMessage::UpdateOperators(msg) => { self.update_operators(ctx, client_id, client_state, msg) } @@ -192,7 +197,7 @@ impl LCPClient { assert!(!client_state.frozen); let (report_data, attestation_time) = - verify_report(ctx.host_timestamp(), &client_state, &message.report)?; + verify_ias_report(ctx.host_timestamp(), &client_state, &message.report)?; let operator = if let Some(operator_signature) = message.operator_signature { verify_signature_address( @@ -217,6 +222,50 @@ impl LCPClient { Ok(()) } + fn zkdcap_register_enclave_key( + &self, + ctx: &mut dyn HostClientKeeper, + client_id: ClientId, + client_state: ClientState, + message: ZKDCAPRegisterEnclaveKeyMessage, + ) -> Result<(), Error> { + assert!(!client_state.frozen); + + // TODO + // verify_zkdcap_report(ctx.host_timestamp(), &client_state, &message.commit, &message.proof)?; + + let attestation_time = + Time::from_unix_timestamp(message.commit.attestation_time as i64, 0)?; + let report = if let QuoteBody::SGXQuoteBody(report) = message.commit.output.quote_body { + report + } else { + return Err(Error::unexpected_quote_body()); + }; + let report_data = ReportData(report.report_data); + + let operator = if let Some(operator_signature) = message.operator_signature { + verify_signature_address( + compute_eip712_zkdcap_register_enclave_key(message.commit.hash()).as_ref(), + operator_signature.as_ref(), + )? + } else { + Default::default() + }; + let expected_operator = report_data.operator(); + // check if the operator matches the expected operator in the report data + assert!(expected_operator.is_zero() || operator == expected_operator); + self.set_enclave_operator_info( + ctx, + &client_id, + report_data.enclave_key(), + EKOperatorInfo::new( + (attestation_time + client_state.key_expiration)?.as_unix_timestamp_secs(), + operator, + ), + ); + Ok(()) + } + fn update_operators( &self, ctx: &mut dyn HostClientKeeper, @@ -456,6 +505,23 @@ pub fn compute_eip712_register_enclave_key_hash(avr: &str) -> [u8; 32] { keccak256(&compute_eip712_register_enclave_key(avr)) } +pub fn compute_eip712_zkdcap_register_enclave_key(commit_hash: [u8; 32]) -> Vec { + // 0x1901 | DOMAIN_SEPARATOR_ZKDCAP_REGISTER_ENCLAVE_KEY | keccak256(keccak256("ZKDCAPRegisterEnclaveKey(bytes32 commit_hash)") | commit_hash) + let type_hash = { + let mut h = Keccak::v256(); + h.update(&keccak256(b"ZKDCAPRegisterEnclaveKey(bytes32 commit_hash)")); + h.update(&commit_hash); + let mut result = [0u8; 32]; + h.finalize(result.as_mut()); + result + }; + [0x19, 0x01] + .into_iter() + .chain(LCP_CLIENT_DOMAIN_SEPARATOR) + .chain(type_hash) + .collect() +} + pub fn compute_eip712_update_operators( client_id: ClientId, nonce: u64, @@ -521,10 +587,10 @@ pub fn compute_eip712_update_operators_hash( )) } -// verify_report +// verify_ias_report // - verifies the Attestation Verification Report // - calculate a key expiration with client_state and report's timestamp -fn verify_report( +fn verify_ias_report( current_timestamp: Time, client_state: &ClientState, signed_avr: &IASSignedReport, diff --git a/modules/lcp-client/src/dcap.rs b/modules/lcp-client/src/dcap.rs new file mode 100644 index 00000000..059b0a68 --- /dev/null +++ b/modules/lcp-client/src/dcap.rs @@ -0,0 +1,44 @@ +use dcap_rs::{types::VerifiedOutput, utils::hash::keccak256sum}; + +#[derive(Debug, Clone, PartialEq)] +pub struct DCAPVerifierCommit { + pub output: VerifiedOutput, + pub attestation_time: u64, + pub sgx_intel_root_ca_hash: [u8; 32], +} + +impl DCAPVerifierCommit { + pub fn new(attestation_time: u64, output: VerifiedOutput, sgx_intel_root_ca: &[u8]) -> Self { + Self { + attestation_time, + sgx_intel_root_ca_hash: keccak256sum(sgx_intel_root_ca), + output, + } + } + + pub fn to_bytes(&self) -> Vec { + let mut output = self.output.to_bytes(); + let mut aux: [u8; 40] = [0; 40]; + aux[..8].copy_from_slice(&self.attestation_time.to_be_bytes()); + aux[8..].copy_from_slice(&self.sgx_intel_root_ca_hash); + output.extend_from_slice(aux.as_ref()); + output + } + + pub fn from_bytes(slice: &[u8]) -> Self { + let output = VerifiedOutput::from_bytes(&slice[..slice.len() - 48]); + let mut attestation_time = [0; 8]; + attestation_time.copy_from_slice(&slice[slice.len() - 48..slice.len() - 40]); + let mut sgx_intel_root_ca_hash = [0; 32]; + sgx_intel_root_ca_hash.copy_from_slice(&slice[slice.len() - 40..]); + Self { + output, + attestation_time: u64::from_be_bytes(attestation_time), + sgx_intel_root_ca_hash, + } + } + + pub fn hash(&self) -> [u8; 32] { + keccak256sum(&self.to_bytes()) + } +} diff --git a/modules/lcp-client/src/errors.rs b/modules/lcp-client/src/errors.rs index 773f5245..74800866 100644 --- a/modules/lcp-client/src/errors.rs +++ b/modules/lcp-client/src/errors.rs @@ -19,6 +19,11 @@ define_error! { format_args!("unexpected header type: type_url={}", e.type_url) }, + UnexpectedQuoteBody + |e| { + "unexpected quote body" + }, + ExpiredAvr { current_timestamp: light_client::types::Time, attestation_time: light_client::types::Time, diff --git a/modules/lcp-client/src/lib.rs b/modules/lcp-client/src/lib.rs index 71307da2..ac1c212e 100644 --- a/modules/lcp-client/src/lib.rs +++ b/modules/lcp-client/src/lib.rs @@ -24,5 +24,6 @@ mod prelude { pub mod client_def; pub mod client_state; pub mod consensus_state; +pub mod dcap; pub mod errors; pub mod message; diff --git a/modules/lcp-client/src/message.rs b/modules/lcp-client/src/message.rs index eb1a72e3..6b63e380 100644 --- a/modules/lcp-client/src/message.rs +++ b/modules/lcp-client/src/message.rs @@ -1,27 +1,33 @@ +use crate::dcap::DCAPVerifierCommit; use crate::errors::Error; use crate::prelude::*; use alloy_sol_types::{sol, SolValue}; use attestation_report::IASSignedReport; use crypto::Address; +use dcap_rs::types::VerifiedOutput; use light_client::commitments::{Error as CommitmentError, EthABIEncoder, ProxyMessage}; use light_client::types::proto::ibc::lightclients::lcp::v1::{ RegisterEnclaveKeyMessage as RawRegisterEnclaveKeyMessage, UpdateClientMessage as RawUpdateClientMessage, UpdateOperatorsMessage as RawUpdateOperatorsMessage, + ZkdcapRegisterEnclaveKeyMessage as RawZKDCAPRegisterEnclaveKeyMessage, }; use light_client::types::{proto::protobuf::Protobuf, Any}; use serde::{Deserialize, Serialize}; pub const LCP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL: &str = "/ibc.lightclients.lcp.v1.RegisterEnclaveKeyMessage"; +pub const LCP_ZKDCAP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL: &str = + "/ibc.lightclients.lcp.v1.ZKDCAPRegisterEnclaveKeyMessage"; pub const LCP_UPDATE_CLIENT_MESSAGE_TYPE_URL: &str = "/ibc.lightclients.lcp.v1.UpdateClientMessage"; pub const LCP_UPDATE_OPERATORS_MESSAGE_TYPE_URL: &str = "/ibc.lightclients.lcp.v1.UpdateOperatorsMessage"; #[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[derive(Debug, Clone, PartialEq)] pub enum ClientMessage { RegisterEnclaveKey(RegisterEnclaveKeyMessage), + ZKDCAPRegisterEnclaveKey(ZKDCAPRegisterEnclaveKeyMessage), UpdateClient(UpdateClientMessage), UpdateOperators(UpdateOperatorsMessage), } @@ -54,6 +60,10 @@ impl From for Any { LCP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL.to_string(), h.encode_vec().unwrap(), ), + ClientMessage::ZKDCAPRegisterEnclaveKey(h) => Any::new( + LCP_ZKDCAP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL.to_string(), + h.encode_vec().unwrap(), + ), ClientMessage::UpdateClient(h) => Any::new( LCP_UPDATE_CLIENT_MESSAGE_TYPE_URL.to_string(), h.encode_vec().unwrap(), @@ -100,6 +110,37 @@ impl From for RawRegisterEnclaveKeyMessage { } } +#[derive(Debug, Clone, PartialEq)] +pub struct ZKDCAPRegisterEnclaveKeyMessage { + pub commit: DCAPVerifierCommit, + pub proof: Vec, + pub operator_signature: Option>, +} + +impl Protobuf for ZKDCAPRegisterEnclaveKeyMessage {} + +impl TryFrom for ZKDCAPRegisterEnclaveKeyMessage { + type Error = Error; + fn try_from(value: RawZKDCAPRegisterEnclaveKeyMessage) -> Result { + Ok(ZKDCAPRegisterEnclaveKeyMessage { + commit: DCAPVerifierCommit::from_bytes(&value.commit), + proof: value.proof, + operator_signature: (!value.operator_signature.is_empty()) + .then_some(value.operator_signature), + }) + } +} + +impl From for RawZKDCAPRegisterEnclaveKeyMessage { + fn from(value: ZKDCAPRegisterEnclaveKeyMessage) -> Self { + RawZKDCAPRegisterEnclaveKeyMessage { + commit: value.commit.to_bytes(), + proof: value.proof, + operator_signature: value.operator_signature.unwrap_or_default(), + } + } +} + #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct UpdateClientMessage { pub signatures: Vec>, diff --git a/modules/remote-attestation/Cargo.toml b/modules/remote-attestation/Cargo.toml index aa24b79a..dc63625d 100644 --- a/modules/remote-attestation/Cargo.toml +++ b/modules/remote-attestation/Cargo.toml @@ -25,7 +25,7 @@ reqwest = { version = "0.12.9", default-features = false, features = [ ] } urlencoding = { version = "2" } -dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "71fe1e02f151a28bf5661b01dba5096730564840" } +dcap-rs = { git = "https://github.com/bluele/dcap-rs", rev = "c3098b6a3c9faa4a884c87db65d0f586000bcf16" } lcp-types = { path = "../types" } crypto = { path = "../crypto", default-features = false } diff --git a/proto/definitions/ibc/lightclients/lcp/v1/lcp.proto b/proto/definitions/ibc/lightclients/lcp/v1/lcp.proto index d9e52489..8d3a384c 100644 --- a/proto/definitions/ibc/lightclients/lcp/v1/lcp.proto +++ b/proto/definitions/ibc/lightclients/lcp/v1/lcp.proto @@ -19,6 +19,12 @@ message RegisterEnclaveKeyMessage { bytes operator_signature = 4; } +message ZKDCAPRegisterEnclaveKeyMessage { + bytes commit = 1; + bytes proof = 2; + bytes operator_signature = 3; +} + message UpdateOperatorsMessage { uint64 nonce = 1; repeated bytes new_operators = 2; diff --git a/proto/src/descriptor.bin b/proto/src/descriptor.bin index 8301150dee4eb2076e56f4b7a544aec56e1f0969..2259329c677f4be4077345982c26af9179c3c7d9 100644 GIT binary patch delta 1443 zcmX|>&2G~`6ooTCcI;^>WZI@7NgYGmv}t0eG-{Vf2w0Urb%~HrL8ep!Ql)7nHZ>9; z5UN-pP_{e-QlEq;V1>jRz=AXO9WRg1{f_Tk-|^3{?w5)C<_9}Fy-P~ZDd%uB z96qb@>~Su1r1bDG8SRaSqsK=F`>*!K$D^bs&i|zByYTi5GW-jBn{uMh0rbv(@;=OczflbtC$1T(yj zUZZ#{sOWTi>S~sT!tP}Fkp&o}gN!ci7L>7y3@o~!FBEM!ma8aX49EKJ1E?FM1 zxWGJMv2T0!fW<}6z7~BR6XpX;`vvEN>-%y>in)6otKa*RpnS^2IyAD#Q1y?b@#?>q1B5AXJu_*eS%03lr5wJet?6NxCp3v7zXM*eJ8|EMe^q4IPZeY0zlfVXg z?Ub!7wv3_6h!VC`rCiSnArbdn5-Fra!O)c=C5p!w6e$_1QDb=+nmudepH=CS8ljA- zTOkn0i>c)l3S&QT3UTpyhcQ@Vx?oEH8<%_;Ny3`C=S*={k3%KGf!=d1QR+`49iBUA!=Funv+i z%;~OsFJ3>xZ!35kpwQa1?e1;|I}I}q#Wdw~wKkVk1`21ppZ6jzB{h*Tt23I`sxz9% zn1v~4G?6h|Ectr4P)cLAJcOimh=-7rU$G<)A!!h~N`$1Nm_y1|DCaa{uLW*izmgWX zx$Zj;+4&{P2jA>xyqUJQXg?97O;1;XAT0|A9 zbz^&2L_5{B->uqEb`f*xRCy4{%Xtx@P?-CNPZJ7p`PsS2F#hTvprBqfOs;p&zlb=; c6R-uh0tL3vhmC^*TXec_y?5`gK3qNd4<8Fj=>Px# diff --git a/proto/src/prost/ibc.lightclients.lcp.v1.rs b/proto/src/prost/ibc.lightclients.lcp.v1.rs index 8a24045e..1cda149d 100644 --- a/proto/src/prost/ibc.lightclients.lcp.v1.rs +++ b/proto/src/prost/ibc.lightclients.lcp.v1.rs @@ -20,6 +20,16 @@ pub struct RegisterEnclaveKeyMessage { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] +pub struct ZkdcapRegisterEnclaveKeyMessage { + #[prost(bytes = "vec", tag = "1")] + pub commit: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub proof: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub operator_signature: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] pub struct UpdateOperatorsMessage { #[prost(uint64, tag = "1")] pub nonce: u64,