From 39624bc3e87eeae71ca274fcac8e09f71edc8655 Mon Sep 17 00:00:00 2001 From: Thomas Niederberger <781000+Niederb@users.noreply.github.com> Date: Thu, 26 Jan 2023 11:41:02 +0100 Subject: [PATCH] Collateral handling for DCAP (#1134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First version that manages to register a quoting enclave * Move collateral to attestation-handler * Work on collateral handling * Use the real collateral data for quoting enclave * Make the dump-ra CLI command work * Work towards register_tcb_info * Add all the boilerplate code to register TCB info * Reduce code duplication for extrinsic encoding * Reduce code duplication for extrinsic sending * Extract method for collateral * Remove duplicated code * Fix clippy issues * Fix compilation error in teeracle * Return certificate and dcap quote * Cleanup * Switch to updated docker image * Disable DCAP for now * Register collateral only for DCAP * Register collateral only for DCAP * Cleanup * Update core-primitives/attestation-handler/src/attestation_handler.rs Co-authored-by: Szilárd Parrag * Update enclave-runtime/src/attestation.rs Co-authored-by: Szilárd Parrag * Extract shared logic into separate method * Improve documentation * Extract DCAP logic into separate function * Get rid of two unwrap() calls * Move getting the call_ids into the shared function * Use the correct Error for metadata * Add type alias for Fmspc * Improve separate_json_data_and_signature and add unit test * Fix clippy issues * Incorporate review feedback * Fix unsafe * Switch implementation of separate_json_data_and_signature * Make clippy happy * Add missing `use` * Add missing feature `preserve_order` to `serde_json_sgx` * Add compiler flag for std case * Make separate_json_data_and_signature robust to potential C-style null terminators Co-authored-by: Szilárd Parrag --- .github/workflows/build_and_test.yml | 2 +- Dockerfile | 2 +- build.Dockerfile | 4 +- .../attestation-handler/Cargo.toml | 5 +- .../src/attestation_handler.rs | 25 +-- .../attestation-handler/src/collateral.rs | 158 +++++++++++++++++ .../attestation-handler/src/lib.rs | 3 + core-primitives/enclave-api/build.rs | 1 + core-primitives/enclave-api/ffi/src/lib.rs | 27 ++- .../enclave-api/src/remote_attestation.rs | 89 +++++++++- .../node-api/metadata/src/metadata_mocks.rs | 26 ++- .../node-api/metadata/src/pallet_teerex.rs | 22 ++- core-primitives/settings/src/lib.rs | 2 +- core-primitives/utils/src/hex.rs | 6 +- enclave-runtime/Cargo.lock | 17 ++ enclave-runtime/Enclave.edl | 12 ++ enclave-runtime/src/attestation.rs | 167 ++++++++++++++++-- enclave-runtime/src/tls_ra/authentication.rs | 6 +- service/build.rs | 1 + service/src/account_funding.rs | 4 +- service/src/main.rs | 66 +++++-- service/src/teeracle/mod.rs | 7 +- 22 files changed, 578 insertions(+), 74 deletions(-) create mode 100644 core-primitives/attestation-handler/src/collateral.rs diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 4a57697c19..44e5e71d4b 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -94,7 +94,7 @@ jobs: clippy: runs-on: ubuntu-latest - container: "integritee/integritee-dev:0.1.10" + container: "integritee/integritee-dev:0.1.11" steps: - uses: actions/checkout@v3 - name: init rust diff --git a/Dockerfile b/Dockerfile index e82301687e..b32444efac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM integritee/integritee-dev:0.1.10 +FROM integritee/integritee-dev:0.1.11 LABEL maintainer="zoltan@integritee.network" # By default we warp the service diff --git a/build.Dockerfile b/build.Dockerfile index 26ba8c2402..b8523c4c49 100644 --- a/build.Dockerfile +++ b/build.Dockerfile @@ -17,7 +17,7 @@ ### Builder Stage ################################################## -FROM integritee/integritee-dev:0.1.10 AS builder +FROM integritee/integritee-dev:0.1.11 AS builder LABEL maintainer="zoltan@integritee.network" # set environment variables @@ -49,7 +49,7 @@ RUN cargo test --release # A builder stage that uses sccache to speed up local builds with docker # Installation and setup of sccache should be moved to the integritee-dev image, so we don't # always need to compile and install sccache on CI (where we have no caching so far). -FROM integritee/integritee-dev:0.1.10 AS cached-builder +FROM integritee/integritee-dev:0.1.11 AS cached-builder LABEL maintainer="zoltan@integritee.network" # set environment variables diff --git a/core-primitives/attestation-handler/Cargo.toml b/core-primitives/attestation-handler/Cargo.toml index f5d474f3b4..4568cb9304 100644 --- a/core-primitives/attestation-handler/Cargo.toml +++ b/core-primitives/attestation-handler/Cargo.toml @@ -17,7 +17,7 @@ log = { version = "0.4", default-features = false } base64 = { version = "0.13", features = ["alloc"], optional = true } chrono = { version = "0.4.19", features = ["alloc"], optional = true } rustls = { version = "0.19", optional = true } -serde_json = { version = "1.0", optional = true } +serde_json = { version = "1.0", features = ["preserve_order"], optional = true } thiserror = { version = "1.0", optional = true } webpki = { version = "0.21", optional = true } @@ -26,7 +26,7 @@ base64_sgx = { package = "base64", rev = "sgx_1.1.3", git = "https://github.com/ chrono_sgx = { package = "chrono", git = "https://github.com/mesalock-linux/chrono-sgx", optional = true } num-bigint = { optional = true, git = "https://github.com/mesalock-linux/num-bigint-sgx" } rustls_sgx = { package = "rustls", rev = "sgx_1.1.3", features = ["dangerous_configuration"], git = "https://github.com/mesalock-linux/rustls", optional = true } -serde_json_sgx = { package = "serde_json", tag = "sgx_1.1.3", git = "https://github.com/mesalock-linux/serde-json-sgx", optional = true } +serde_json_sgx = { package = "serde_json", tag = "sgx_1.1.3", features = ["preserve_order"], git = "https://github.com/mesalock-linux/serde-json-sgx", optional = true } thiserror_sgx = { package = "thiserror", git = "https://github.com/mesalock-linux/thiserror-sgx", tag = "sgx_1.1.3", optional = true } webpki-roots = { git = "https://github.com/mesalock-linux/webpki-roots", branch = "mesalock_sgx" } webpki_sgx = { package = "webpki", git = "https://github.com/mesalock-linux/webpki", branch = "mesalock_sgx", optional = true } @@ -50,7 +50,6 @@ itp-types = { path = "../types", default-features = false } # integritee httparse = { default-features = false, git = "https://github.com/integritee-network/httparse-sgx", branch = "sgx-experimental" } - # substrate deps sp-core = { default-features = false, features = ["full_crypto"], git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.36" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.36" } diff --git a/core-primitives/attestation-handler/src/attestation_handler.rs b/core-primitives/attestation-handler/src/attestation_handler.rs index 8bb00fc20d..7e6023dd8d 100644 --- a/core-primitives/attestation-handler/src/attestation_handler.rs +++ b/core-primitives/attestation-handler/src/attestation_handler.rs @@ -78,11 +78,14 @@ pub const REPORT_SUFFIX: &str = "/sgx/dev/attestation/v4/report"; /// Trait to provide an abstraction to the attestation logic pub trait AttestationHandler { - /// Generates an encoded remote attestation certificate. + /// Generates an encoded remote attestation certificate. Returns DER encoded certificate. /// If skip_ra is set, it will not perform a remote attestation via IAS /// but instead generate a mock certificate. fn generate_ias_ra_cert(&self, skip_ra: bool) -> EnclaveResult>; + /// Returns the DER encoded certificate and the raw DCAP quote. + /// If skip_ra is set, it will not perform a remote attestation via IAS + /// but instead generate a mock certificate. fn generate_dcap_ra_cert( &self, quoting_enclave_target_info: &sgx_target_info_t, @@ -170,13 +173,13 @@ where quoting_enclave_target_info: &sgx_target_info_t, quote_size: u32, ) -> EnclaveResult<()> { - let (_key_der, cert_der) = + let (_cert_der, dcap_quote) = match self.generate_dcap_ra_cert(quoting_enclave_target_info, quote_size, false) { Ok(r) => r, Err(e) => return Err(e), }; - if let Err(err) = io::write(&cert_der, RA_DUMP_CERT_DER_FILE) { + if let Err(err) = io::write(&dcap_quote, RA_DUMP_CERT_DER_FILE) { error!( " [Enclave] failed to write RA file ({}), status: {:?}", RA_DUMP_CERT_DER_FILE, err @@ -254,7 +257,7 @@ where let (prv_k, pub_k) = ecc_handle.create_key_pair()?; info!("Enclave Attestation] Generated ephemeral ECDSA keypair:"); - let payload = if !skip_ra { + let qe_quote = if !skip_ra { let qe_quote = match self.retrieve_qe_dcap_quote( &chain_signer.public().0, quoting_enclave_target_info, @@ -266,15 +269,15 @@ where return Err(e.into()) }, }; - // Verify the quote via qve enclave - self.ecdsa_quote_verification(qe_quote)? + qe_quote } else { Default::default() }; // generate an ECC certificate debug!("[Enclave] Generate ECC Certificate"); - let (key_der, cert_der) = match cert::gen_ecc_cert(&payload, &prv_k, &pub_k, &ecc_handle) { + let (_key_der, cert_der) = match cert::gen_ecc_cert(&qe_quote, &prv_k, &pub_k, &ecc_handle) + { Ok(r) => r, Err(e) => { error!("[Enclave] gen_ecc_cert failed: {:?}", e); @@ -284,7 +287,7 @@ where let _ = ecc_handle.close(); - Ok((key_der, cert_der)) + Ok((cert_der, qe_quote)) } } @@ -640,7 +643,8 @@ where .map_err(|e| EnclaveError::Other(e.into())) } - pub fn ecdsa_quote_verification(&self, quote: Vec) -> SgxResult> { + /// Returns Ok if the verification of the quote by the quote verification enclave (QVE) was successful + pub fn ecdsa_quote_verification(&self, quote: Vec) -> SgxResult<()> { let mut app_enclave_target_info: sgx_target_info_t = unsafe { std::mem::zeroed() }; let quote_collateral: sgx_ql_qve_collateral_t = unsafe { std::mem::zeroed() }; let mut qve_report_info: sgx_ql_qe_report_info_t = unsafe { std::mem::zeroed() }; @@ -724,8 +728,7 @@ where return Err(sgx_status_t::SGX_ERROR_UNEXPECTED) } - // TODO. What to send to our teerex pallet? - Ok(vec![]) + Ok(()) } pub fn retrieve_qe_dcap_quote( diff --git a/core-primitives/attestation-handler/src/collateral.rs b/core-primitives/attestation-handler/src/collateral.rs new file mode 100644 index 0000000000..a4713c5c94 --- /dev/null +++ b/core-primitives/attestation-handler/src/collateral.rs @@ -0,0 +1,158 @@ +/* + Copyright 2022 Integritee AG and Supercomputing Systems AG + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +#[cfg(all(not(feature = "std"), feature = "sgx"))] +use crate::sgx_reexport_prelude::serde_json; +use sgx_types::sgx_ql_qve_collateral_t; +use std::{io::Write, string::String, vec::Vec}; + +/// This is a rust-ified version of the type sgx_ql_qve_collateral_t. +/// See Appendix A.3 in the document +/// "Intel® Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: ECDSA Quote Library API" +/// https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_ECDSA_QuoteLibReference_DCAP_API.pdf +pub struct SgxQlQveCollateral { + pub version: u32, // version = 1. PCK Cert chain is in the Quote. + /* intel DCAP 1.13 */ + pub tee_type: u32, // 0x00000000: SGX or 0x00000081: TDX + pub pck_crl_issuer_chain: Vec, + pub root_ca_crl: Vec, + pub pck_crl: Vec, + pub tcb_info_issuer_chain: Vec, + pub tcb_info: Vec, + pub qe_identity_issuer_chain: Vec, + pub qe_identity: Vec, +} + +impl SgxQlQveCollateral { + /// # Safety + /// + /// The caller is in charge of ensuring that `c` is properly initialized and all + /// its members have a value that is not nullptr + pub unsafe fn from_c_type(c: &sgx_ql_qve_collateral_t) -> Self { + let pck_crl_issuer_chain = std::slice::from_raw_parts( + c.pck_crl_issuer_chain as *const u8, + c.pck_crl_issuer_chain_size as usize, + ) + .to_vec(); + let root_ca_crl = + std::slice::from_raw_parts(c.root_ca_crl as *const u8, c.root_ca_crl_size as usize) + .to_vec(); + let pck_crl = + std::slice::from_raw_parts(c.pck_crl as *const u8, c.pck_crl_size as usize).to_vec(); + let tcb_info_issuer_chain = std::slice::from_raw_parts( + c.tcb_info_issuer_chain as *const u8, + c.tcb_info_issuer_chain_size as usize, + ) + .to_vec(); + let tcb_info = + std::slice::from_raw_parts(c.tcb_info as *const u8, c.tcb_info_size as usize).to_vec(); + let qe_identity_issuer_chain = std::slice::from_raw_parts( + c.qe_identity_issuer_chain as *const u8, + c.qe_identity_issuer_chain_size as usize, + ) + .to_vec(); + let qe_identity = + std::slice::from_raw_parts(c.qe_identity as *const u8, c.qe_identity_size as usize) + .to_vec(); + SgxQlQveCollateral { + version: c.version, + tee_type: c.tee_type, + pck_crl_issuer_chain, + root_ca_crl, + pck_crl, + tcb_info_issuer_chain, + tcb_info, + qe_identity_issuer_chain, + qe_identity, + } + } + + pub fn dump_to_disk(&self) { + Self::write_data_to_disk("pck_crl_issuer_chain", &self.pck_crl_issuer_chain); + Self::write_data_to_disk("root_ca_crl", &self.root_ca_crl); + Self::write_data_to_disk("pck_crl", &self.pck_crl); + Self::write_data_to_disk("tcb_info_issuer_chain", &self.tcb_info_issuer_chain); + Self::write_data_to_disk("tcb_info", &self.tcb_info); + Self::write_data_to_disk("qe_identity_issuer_chain", &self.qe_identity_issuer_chain); + Self::write_data_to_disk("qe_identity", &self.qe_identity); + } + + /// Returns the tcb_info split into two parts: json_data and signature + pub fn get_tcb_info_split(&self) -> Option<(String, Vec)> { + let (json_data, signature) = + Self::separate_json_data_and_signature("tcbInfo", &self.tcb_info)?; + match hex::decode(signature) { + Ok(hex_signature) => Some((json_data, hex_signature)), + Err(_) => None, + } + } + + /// Returns the tcb_info split into two parts: json_data and signature + pub fn get_quoting_enclave_split(&self) -> Option<(String, Vec)> { + let (json_data, signature) = + Self::separate_json_data_and_signature("enclaveIdentity", &self.qe_identity)?; + match hex::decode(signature) { + Ok(hex_signature) => Some((json_data, hex_signature)), + Err(_) => None, + } + } + + /// Separates the actual data part from the signature for an Intel collateral in JSON format + /// Returns the data part and signature as a pair + fn separate_json_data_and_signature(data_name: &str, data: &[u8]) -> Option<(String, String)> { + let json = String::from_utf8_lossy(data); + // Remove potential C-style null terminators + let json = json.trim_matches(char::from(0)); + let value: serde_json::Value = serde_json::from_str(json).ok()?; + if value[data_name].is_null() || value["signature"].is_null() { + return None + } + let data_json = serde_json::to_string(&value[data_name]).ok()?; + let signature = serde_json::to_string(&value["signature"]).ok()?; + // We want the signature without leading/ending " + let signature = signature.replace('\"', ""); + Some((data_json, signature)) + } + + fn write_data_to_disk(filename: &str, contents: &[u8]) { + let mut file = std::fs::File::create(filename).unwrap(); + file.write_all(contents).unwrap(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn separate_json_data_and_signature() { + // A bit more complex json to ensure the ordering stays the same + let json = br#"{"tcbInfo":{"id":"SGX","version":3,"issueDate":"2022-11-17T12:45:32Z"},"signature":"71746f2"}"#; + let (data, signature) = + SgxQlQveCollateral::separate_json_data_and_signature("tcbInfo", json).unwrap(); + assert_eq!(data, r#"{"id":"SGX","version":3,"issueDate":"2022-11-17T12:45:32Z"}"#); + assert_eq!(signature, "71746f2"); + + let json = br#"{"tcbInfo":{not_a_valid_json},"nosignature":"thesignature"}"#; + assert!(SgxQlQveCollateral::separate_json_data_and_signature("tcbInfo", json).is_none()); + + let json = br#"{"tcbInfo":{"id":"SGX"},"nosignature":"thesignature"}"#; + assert!(SgxQlQveCollateral::separate_json_data_and_signature("tcbInfo", json).is_none()); + + let json = br#"{"tcbInfo":{"id":"SGX"},"signature":""#; + assert!(SgxQlQveCollateral::separate_json_data_and_signature("tcbInfo", json).is_none()); + } +} diff --git a/core-primitives/attestation-handler/src/lib.rs b/core-primitives/attestation-handler/src/lib.rs index fb787dd395..651aeca924 100644 --- a/core-primitives/attestation-handler/src/lib.rs +++ b/core-primitives/attestation-handler/src/lib.rs @@ -39,11 +39,14 @@ pub mod sgx_reexport_prelude { #[cfg(all(not(feature = "std"), feature = "sgx"))] pub mod attestation_handler; +pub mod collateral; + pub mod cert; pub mod error; #[cfg(all(not(feature = "std"), feature = "sgx"))] pub use attestation_handler::{AttestationHandler, IntelAttestationHandler, DEV_HOSTNAME}; +pub use collateral::SgxQlQveCollateral; pub use error::{Error, Result}; diff --git a/core-primitives/enclave-api/build.rs b/core-primitives/enclave-api/build.rs index 5b181fe3d2..1c20ea4c84 100644 --- a/core-primitives/enclave-api/build.rs +++ b/core-primitives/enclave-api/build.rs @@ -20,4 +20,5 @@ fn main() { // ln -s libsgx_dcap_ql.so.1 libsgx_dcap_ql.so println!("cargo:rustc-link-lib=dylib=sgx_dcap_ql"); println!("cargo:rustc-link-lib=dylib=sgx_dcap_quoteverify"); + println!("cargo:rustc-link-lib=dylib=dcap_quoteprov"); } diff --git a/core-primitives/enclave-api/ffi/src/lib.rs b/core-primitives/enclave-api/ffi/src/lib.rs index d8dc4d66c2..5dcf464324 100644 --- a/core-primitives/enclave-api/ffi/src/lib.rs +++ b/core-primitives/enclave-api/ffi/src/lib.rs @@ -1,6 +1,9 @@ ///! FFI's that call into the enclave. These functions need to be added to the /// enclave edl file and be implemented within the enclave. -use sgx_types::{c_int, sgx_enclave_id_t, sgx_quote_sign_type_t, sgx_status_t, sgx_target_info_t}; +use sgx_types::{ + c_int, sgx_enclave_id_t, sgx_ql_qve_collateral_t, sgx_quote_sign_type_t, sgx_status_t, + sgx_target_info_t, +}; extern "C" { @@ -112,6 +115,22 @@ extern "C" { quote_size: u32, ) -> sgx_status_t; + pub fn generate_register_quoting_enclave_extrinsic( + eid: sgx_enclave_id_t, + retval: *mut sgx_status_t, + collateral: *const sgx_ql_qve_collateral_t, + unchecked_extrinsic: *mut u8, + unchecked_extrinsic_size: u32, + ) -> sgx_status_t; + + pub fn generate_register_tcb_info_extrinsic( + eid: sgx_enclave_id_t, + retval: *mut sgx_status_t, + collateral: *const sgx_ql_qve_collateral_t, + unchecked_extrinsic: *mut u8, + unchecked_extrinsic_size: u32, + ) -> sgx_status_t; + pub fn dump_ias_ra_cert_to_disk( eid: sgx_enclave_id_t, retval: *mut sgx_status_t, @@ -124,6 +143,12 @@ extern "C" { quote_size: u32, ) -> sgx_status_t; + pub fn dump_dcap_collateral_to_disk( + eid: sgx_enclave_id_t, + retval: *mut sgx_status_t, + collateral: *const sgx_ql_qve_collateral_t, + ) -> sgx_status_t; + pub fn test_main_entrance(eid: sgx_enclave_id_t, retval: *mut sgx_status_t) -> sgx_status_t; pub fn call_rpc_methods( diff --git a/core-primitives/enclave-api/src/remote_attestation.rs b/core-primitives/enclave-api/src/remote_attestation.rs index 5005c570a1..92cb68a0e0 100644 --- a/core-primitives/enclave-api/src/remote_attestation.rs +++ b/core-primitives/enclave-api/src/remote_attestation.rs @@ -33,6 +33,8 @@ const ID_ENCLAVE: &str = "libsgx_id_enclave.signed.so.1"; const LIBDCAP_QUOTEPROV: &str = "libdcap_quoteprov.so.1"; const QVE_ENCLAVE: &str = "libsgx_qve.signed.so.1"; +type Fmspc = [u8; 6]; + /// Struct that unites all relevant data reported by the QVE pub struct QveReport { pub supplemental_data: Vec, @@ -47,15 +49,23 @@ pub trait RemoteAttestation { fn generate_dcap_ra_extrinsic(&self, w_url: &str, skip_ra: bool) -> EnclaveResult>; + fn generate_register_quoting_enclave_extrinsic(&self, fmspc: Fmspc) -> EnclaveResult>; + + fn generate_register_tcb_info_extrinsic(&self, fmspc: Fmspc) -> EnclaveResult>; + fn dump_ias_ra_cert_to_disk(&self) -> EnclaveResult<()>; fn dump_dcap_ra_cert_to_disk(&self) -> EnclaveResult<()>; + fn dump_dcap_collateral_to_disk(&self, fmspc: Fmspc) -> EnclaveResult<()>; + fn set_ql_qe_enclave_paths(&self) -> EnclaveResult<()>; fn qe_get_target_info(&self) -> EnclaveResult; fn qe_get_quote_size(&self) -> EnclaveResult; + + fn get_dcap_collateral(&self, fmspc: Fmspc) -> EnclaveResult<*const sgx_ql_qve_collateral_t>; } /// call-backs that are made from inside the enclave (using o-call), to e-calls again inside the enclave @@ -168,6 +178,52 @@ impl RemoteAttestation for Enclave { Ok(unchecked_extrinsic) } + fn generate_register_quoting_enclave_extrinsic(&self, fmspc: Fmspc) -> EnclaveResult> { + let mut retval = sgx_status_t::SGX_SUCCESS; + let mut unchecked_extrinsic: Vec = vec![0u8; EXTRINSIC_MAX_SIZE]; + + let collateral_ptr = self.get_dcap_collateral(fmspc)?; + + let result = unsafe { + ffi::generate_register_quoting_enclave_extrinsic( + self.eid, + &mut retval, + collateral_ptr, + unchecked_extrinsic.as_mut_ptr(), + unchecked_extrinsic.len() as u32, + ) + }; + let free_status = unsafe { sgx_ql_free_quote_verification_collateral(collateral_ptr) }; + ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval)); + ensure!(free_status == sgx_quote3_error_t::SGX_QL_SUCCESS, Error::SgxQuote(free_status)); + + Ok(unchecked_extrinsic) + } + + fn generate_register_tcb_info_extrinsic(&self, fmspc: Fmspc) -> EnclaveResult> { + let mut retval = sgx_status_t::SGX_SUCCESS; + let mut unchecked_extrinsic: Vec = vec![0u8; EXTRINSIC_MAX_SIZE]; + + let collateral_ptr = self.get_dcap_collateral(fmspc)?; + + let result = unsafe { + ffi::generate_register_tcb_info_extrinsic( + self.eid, + &mut retval, + collateral_ptr, + unchecked_extrinsic.as_mut_ptr(), + unchecked_extrinsic.len() as u32, + ) + }; + let free_status = unsafe { sgx_ql_free_quote_verification_collateral(collateral_ptr) }; + ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(retval)); + ensure!(free_status == sgx_quote3_error_t::SGX_QL_SUCCESS, Error::SgxQuote(free_status)); + + Ok(unchecked_extrinsic) + } + fn dump_ias_ra_cert_to_disk(&self) -> EnclaveResult<()> { let mut retval = sgx_status_t::SGX_SUCCESS; @@ -229,6 +285,38 @@ impl RemoteAttestation for Enclave { Ok(quote_size) } + + fn dump_dcap_collateral_to_disk(&self, fmspc: Fmspc) -> EnclaveResult<()> { + let mut retval = sgx_status_t::SGX_SUCCESS; + let collateral_ptr = self.get_dcap_collateral(fmspc)?; + let result = + unsafe { ffi::dump_dcap_collateral_to_disk(self.eid, &mut retval, collateral_ptr) }; + let free_status = unsafe { sgx_ql_free_quote_verification_collateral(collateral_ptr) }; + ensure!(result == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(retval == sgx_status_t::SGX_SUCCESS, Error::Sgx(result)); + ensure!(free_status == sgx_quote3_error_t::SGX_QL_SUCCESS, Error::SgxQuote(free_status)); + Ok(()) + } + + fn get_dcap_collateral(&self, fmspc: Fmspc) -> EnclaveResult<*const sgx_ql_qve_collateral_t> { + let pck_ra = b"processor\x00"; + + // SAFETY: Just get a nullptr for the FFI to overwrite later + let mut collateral_ptr: *mut sgx_ql_qve_collateral_t = unsafe { std::mem::zeroed() }; + + let collateral_ptr_ptr: *mut *mut sgx_ql_qve_collateral_t = &mut collateral_ptr; + // SAFETY: All parameters are properly initialized so the FFI call should be fine + let sgx_status = unsafe { + sgx_ql_get_quote_verification_collateral( + fmspc.as_ptr(), + fmspc.len() as uint16_t, //fmspc len is fixed in the function signature + pck_ra.as_ptr() as _, + collateral_ptr_ptr, + ) + }; + ensure!(sgx_status == sgx_quote3_error_t::SGX_QL_SUCCESS, Error::SgxQuote(sgx_status)); + Ok(collateral_ptr) + } } impl RemoteAttestationCallBacks for Enclave { @@ -299,7 +387,6 @@ impl RemoteAttestationCallBacks for Enclave { fn get_dcap_quote(&self, report: sgx_report_t, quote_size: u32) -> EnclaveResult> { let mut quote_vec: Vec = vec![0; quote_size as usize]; - let qe3_ret = unsafe { sgx_qe_get_quote(&report, quote_size, quote_vec.as_mut_ptr() as _) }; ensure!(qe3_ret == sgx_quote3_error_t::SGX_QL_SUCCESS, Error::SgxQuote(qe3_ret)); diff --git a/core-primitives/node-api/metadata/src/metadata_mocks.rs b/core-primitives/node-api/metadata/src/metadata_mocks.rs index 7fe6d4245b..aa6188c5e4 100644 --- a/core-primitives/node-api/metadata/src/metadata_mocks.rs +++ b/core-primitives/node-api/metadata/src/metadata_mocks.rs @@ -23,8 +23,11 @@ use codec::{Decode, Encode}; #[derive(Default, Encode, Decode, Debug, Clone)] pub struct NodeMetadataMock { teerex_module: u8, - register_enclave: u8, + register_ias_enclave: u8, + register_dcap_enclave: u8, unregister_enclave: u8, + register_quoting_enclave: u8, + register_tcb_info: u8, call_worker: u8, processed_parentchain_block: u8, shield_funds: u8, @@ -39,8 +42,11 @@ impl NodeMetadataMock { pub fn new() -> Self { NodeMetadataMock { teerex_module: 50u8, - register_enclave: 0u8, + register_ias_enclave: 0u8, + register_dcap_enclave: 6, unregister_enclave: 1u8, + register_quoting_enclave: 7, + register_tcb_info: 8, call_worker: 2u8, processed_parentchain_block: 3u8, shield_funds: 4u8, @@ -54,14 +60,26 @@ impl NodeMetadataMock { } impl TeerexCallIndexes for NodeMetadataMock { - fn register_enclave_call_indexes(&self) -> Result<[u8; 2]> { - Ok([self.teerex_module, self.register_enclave]) + fn register_ias_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teerex_module, self.register_ias_enclave]) + } + + fn register_dcap_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teerex_module, self.register_dcap_enclave]) } fn unregister_enclave_call_indexes(&self) -> Result<[u8; 2]> { Ok([self.teerex_module, self.unregister_enclave]) } + fn register_quoting_enclave_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teerex_module, self.register_quoting_enclave]) + } + + fn register_tcb_info_call_indexes(&self) -> Result<[u8; 2]> { + Ok([self.teerex_module, self.register_tcb_info]) + } + fn call_worker_call_indexes(&self) -> Result<[u8; 2]> { Ok([self.teerex_module, self.call_worker]) } diff --git a/core-primitives/node-api/metadata/src/pallet_teerex.rs b/core-primitives/node-api/metadata/src/pallet_teerex.rs index 0dfad40691..cb07b342fc 100644 --- a/core-primitives/node-api/metadata/src/pallet_teerex.rs +++ b/core-primitives/node-api/metadata/src/pallet_teerex.rs @@ -21,10 +21,16 @@ use sp_core::storage::StorageKey; const TEEREX: &str = "Teerex"; pub trait TeerexCallIndexes { - fn register_enclave_call_indexes(&self) -> Result<[u8; 2]>; + fn register_ias_enclave_call_indexes(&self) -> Result<[u8; 2]>; + + fn register_dcap_enclave_call_indexes(&self) -> Result<[u8; 2]>; fn unregister_enclave_call_indexes(&self) -> Result<[u8; 2]>; + fn register_quoting_enclave_call_indexes(&self) -> Result<[u8; 2]>; + + fn register_tcb_info_call_indexes(&self) -> Result<[u8; 2]>; + fn call_worker_call_indexes(&self) -> Result<[u8; 2]>; fn confirm_processed_parentchain_block_call_indexes(&self) -> Result<[u8; 2]>; @@ -41,10 +47,22 @@ pub trait TeerexStorageKey { } impl TeerexCallIndexes for NodeMetadata { - fn register_enclave_call_indexes(&self) -> Result<[u8; 2]> { + fn register_ias_enclave_call_indexes(&self) -> Result<[u8; 2]> { self.call_indexes(TEEREX, "register_enclave") } + fn register_dcap_enclave_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEREX, "register_dcap_enclave") + } + + fn register_quoting_enclave_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEREX, "register_quoting_enclave") + } + + fn register_tcb_info_call_indexes(&self) -> Result<[u8; 2]> { + self.call_indexes(TEEREX, "register_tcb_info") + } + fn unregister_enclave_call_indexes(&self) -> Result<[u8; 2]> { self.call_indexes(TEEREX, "unregister_enclave") } diff --git a/core-primitives/settings/src/lib.rs b/core-primitives/settings/src/lib.rs index dc24f46129..1bfa54a1d0 100644 --- a/core-primitives/settings/src/lib.rs +++ b/core-primitives/settings/src/lib.rs @@ -71,7 +71,7 @@ pub mod files { /// Settings concerning the worker pub mod worker { // the maximum size of any extrinsic that the enclave will ever generate in B - pub const EXTRINSIC_MAX_SIZE: usize = 5500; + pub const EXTRINSIC_MAX_SIZE: usize = 13_000; // the maximum size of the header pub const HEADER_MAX_SIZE: usize = 200; // maximum size of shielding key diff --git a/core-primitives/utils/src/hex.rs b/core-primitives/utils/src/hex.rs index c68ce00a29..6f3c63e68c 100644 --- a/core-primitives/utils/src/hex.rs +++ b/core-primitives/utils/src/hex.rs @@ -28,7 +28,7 @@ pub trait ToHexPrefixed { impl ToHexPrefixed for T { fn to_hex(&self) -> String { - hex_encode(self.encode()) + hex_encode(&self.encode()) } } @@ -49,7 +49,7 @@ impl FromHexPrefixed for T { } /// Hex encodes given data and preappends a "0x". -pub fn hex_encode(data: Vec) -> String { +pub fn hex_encode(data: &[u8]) -> String { let mut hex_str = hex::encode(data); hex_str.insert_str(0, "0x"); hex_str @@ -73,7 +73,7 @@ mod tests { fn hex_encode_decode_works() { let data = "Hello World!".to_string(); - let hex_encoded_data = hex_encode(data.encode()); + let hex_encoded_data = hex_encode(&data.encode()); let decoded_data = String::decode(&mut decode_hex(hex_encoded_data).unwrap().as_slice()).unwrap(); diff --git a/enclave-runtime/Cargo.lock b/enclave-runtime/Cargo.lock index 098ed74b6b..e31d754be2 100644 --- a/enclave-runtime/Cargo.lock +++ b/enclave-runtime/Cargo.lock @@ -1265,6 +1265,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29fba9abe4742d586dfd0c06ae4f7e73a1c2d86b856933509b269d82cdf06e18" +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" + [[package]] name = "hashbrown" version = "0.12.3" @@ -1384,6 +1390,16 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "indexmap" +version = "1.6.1" +source = "git+https://github.com/mesalock-linux/indexmap-sgx#19f52458ba64dd7349a5d3a62227619a17e4db85" +dependencies = [ + "autocfg 1.1.0", + "hashbrown 0.9.1", + "sgx_tstd", +] + [[package]] name = "integer-sqrt" version = "0.1.5" @@ -3504,6 +3520,7 @@ name = "serde_json" version = "1.0.60" source = "git+https://github.com/mesalock-linux/serde-json-sgx?tag=sgx_1.1.3#380893814ad2a057758d825bab798aa117f7362a" dependencies = [ + "indexmap", "itoa 0.4.5", "ryu", "serde 1.0.118 (git+https://github.com/mesalock-linux/serde-sgx)", diff --git a/enclave-runtime/Enclave.edl b/enclave-runtime/Enclave.edl index 6808ff284d..dffd2dd139 100644 --- a/enclave-runtime/Enclave.edl +++ b/enclave-runtime/Enclave.edl @@ -97,6 +97,16 @@ enclave { uint32_t quote_size ); + public sgx_status_t generate_register_quoting_enclave_extrinsic( + [in] const sgx_ql_qve_collateral_t *p_quote_collateral, + [out, size=unchecked_extrinsic_size] uint8_t* unchecked_extrinsic, uint32_t unchecked_extrinsic_size + ); + + public sgx_status_t generate_register_tcb_info_extrinsic( + [in] const sgx_ql_qve_collateral_t *p_quote_collateral, + [out, size=unchecked_extrinsic_size] uint8_t* unchecked_extrinsic, uint32_t unchecked_extrinsic_size + ); + public sgx_status_t update_market_data_xt( [in, size=crypto_currency_size] uint8_t* crypto_currency, uint32_t crypto_currency_size, [in, size=fiat_currency_size] uint8_t* fiat_currency, uint32_t fiat_currency_size, @@ -113,6 +123,8 @@ enclave { public sgx_status_t dump_dcap_ra_cert_to_disk([in] const sgx_target_info_t* quoting_enclave_target_info, uint32_t quote_size); + public sgx_status_t dump_dcap_collateral_to_disk([in] const sgx_ql_qve_collateral_t *p_quote_collateral); + public sgx_status_t run_state_provisioning_server(int fd, sgx_quote_sign_type_t quote_type, int skip_ra); public sgx_status_t request_state_provisioning( int fd, diff --git a/enclave-runtime/src/attestation.rs b/enclave-runtime/src/attestation.rs index f24c6063a5..116885c9fd 100644 --- a/enclave-runtime/src/attestation.rs +++ b/enclave-runtime/src/attestation.rs @@ -36,13 +36,15 @@ use crate::{ Error as EnclaveError, Result as EnclaveResult, }; use codec::{Decode, Encode}; -use itp_attestation_handler::AttestationHandler; +use itp_attestation_handler::{AttestationHandler, SgxQlQveCollateral}; use itp_component_container::ComponentGetter; use itp_extrinsics_factory::CreateExtrinsics; use itp_node_api::metadata::{ pallet_teerex::TeerexCallIndexes, provider::{AccessNodeMetadata, Error as MetadataProviderError}, + Error as MetadataError, }; +use itp_node_api_metadata::NodeMetadata; use itp_settings::worker::MR_ENCLAVE_SIZE; use itp_types::OpaqueCall; use itp_utils::write_slice_and_whitespace_pad; @@ -129,34 +131,66 @@ pub unsafe extern "C" fn generate_ias_ra_extrinsic( #[no_mangle] pub unsafe extern "C" fn generate_dcap_ra_extrinsic( - _w_url: *const u8, - _w_url_size: u32, - _unchecked_extrinsic: *mut u8, - _unchecked_extrinsic_size: u32, - _skip_ra: c_int, + w_url: *const u8, + w_url_size: u32, + unchecked_extrinsic: *mut u8, + unchecked_extrinsic_size: u32, + skip_ra: c_int, quoting_enclave_target_info: &sgx_target_info_t, quote_size: u32, ) -> sgx_status_t { - let attestation_handler = match GLOBAL_ATTESTATION_HANDLER_COMPONENT.get() { - Ok(r) => r, - Err(e) => { - error!("Component get failure: {:?}", e); - return sgx_status_t::SGX_ERROR_UNEXPECTED - }, - }; + if w_url.is_null() || unchecked_extrinsic.is_null() { + return sgx_status_t::SGX_ERROR_INVALID_PARAMETER + } + let mut url_slice = slice::from_raw_parts(w_url, w_url_size as usize); + let url = String::decode(&mut url_slice).expect("Could not decode url slice to a valid String"); + let extrinsic_slice = + slice::from_raw_parts_mut(unchecked_extrinsic, unchecked_extrinsic_size as usize); - let (_key_der, _cert_der) = match attestation_handler.generate_dcap_ra_cert( + let extrinsic = match generate_dcap_ra_extrinsic_internal( + url, + skip_ra == 1, quoting_enclave_target_info, quote_size, - false, ) { - Ok(r) => r, + Ok(xt) => xt, Err(e) => return e.into(), }; - // TODO Need to send this to the teerex pallet (something similar to perform_ra_internal) + + if let Err(e) = write_slice_and_whitespace_pad(extrinsic_slice, extrinsic.encode()) { + return EnclaveError::Other(Box::new(e)).into() + }; sgx_status_t::SGX_SUCCESS } +fn generate_dcap_ra_extrinsic_internal( + url: String, + skip_ra: bool, + quoting_enclave_target_info: &sgx_target_info_t, + quote_size: u32, +) -> EnclaveResult { + let attestation_handler = GLOBAL_ATTESTATION_HANDLER_COMPONENT.get()?; + + let (_cert_der, dcap_quote) = attestation_handler.generate_dcap_ra_cert( + quoting_enclave_target_info, + quote_size, + skip_ra, + )?; + + // TODO Need to send this to the teerex pallet (something similar to perform_ra_internal) + let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + let node_metadata_repo = get_node_metadata_repository_from_solo_or_parachain()?; + + let call_ids = node_metadata_repo + .get_from_metadata(|m| m.register_dcap_enclave_call_indexes())? + .map_err(MetadataProviderError::MetadataError)?; + info!(" [Enclave] Compose register enclave call DCAP IDs: {:?}", call_ids); + let call = OpaqueCall::from_tuple(&(call_ids, dcap_quote, url)); + + let extrinsic = extrinsics_factory.create_extrinsics(&[call], None)?; + Ok(extrinsic[0].clone()) +} + fn generate_ias_ra_extrinsic_internal( url: String, skip_ra: bool, @@ -169,7 +203,7 @@ fn generate_ias_ra_extrinsic_internal( info!(" [Enclave] Compose register enclave call"); let call_ids = node_metadata_repo - .get_from_metadata(|m| m.register_enclave_call_indexes())? + .get_from_metadata(|m| m.register_ias_enclave_call_indexes())? .map_err(MetadataProviderError::MetadataError)?; let call = OpaqueCall::from_tuple(&(call_ids, cert_der, url)); @@ -179,6 +213,94 @@ fn generate_ias_ra_extrinsic_internal( Ok(extrinsics[0].clone()) } +#[no_mangle] +pub unsafe extern "C" fn generate_register_quoting_enclave_extrinsic( + collateral: *const sgx_ql_qve_collateral_t, + unchecked_extrinsic: *mut u8, + unchecked_extrinsic_size: u32, +) -> sgx_status_t { + if unchecked_extrinsic.is_null() || collateral.is_null() { + return sgx_status_t::SGX_ERROR_INVALID_PARAMETER + } + let extrinsic_slice = + slice::from_raw_parts_mut(unchecked_extrinsic, unchecked_extrinsic_size as usize); + let collateral = SgxQlQveCollateral::from_c_type(&*collateral); + let collateral_data = match collateral.get_quoting_enclave_split() { + Some(d) => d, + None => return sgx_status_t::SGX_ERROR_INVALID_PARAMETER, + }; + + let call_index_getter = |m: &NodeMetadata| m.register_quoting_enclave_call_indexes(); + let extrinsic = generate_generic_register_collateral_extrinsic( + call_index_getter, + extrinsic_slice, + &collateral_data.0, + &collateral_data.1, + &collateral.qe_identity_issuer_chain, + ); + match extrinsic { + Ok(_) => sgx_status_t::SGX_SUCCESS, + Err(e) => e.into(), + } +} + +#[no_mangle] +pub unsafe extern "C" fn generate_register_tcb_info_extrinsic( + collateral: *const sgx_ql_qve_collateral_t, + unchecked_extrinsic: *mut u8, + unchecked_extrinsic_size: u32, +) -> sgx_status_t { + if unchecked_extrinsic.is_null() || collateral.is_null() { + return sgx_status_t::SGX_ERROR_INVALID_PARAMETER + } + let extrinsic_slice = + slice::from_raw_parts_mut(unchecked_extrinsic, unchecked_extrinsic_size as usize); + let collateral = SgxQlQveCollateral::from_c_type(&*collateral); + let collateral_data = match collateral.get_tcb_info_split() { + Some(d) => d, + None => return sgx_status_t::SGX_ERROR_INVALID_PARAMETER, + }; + + let call_index_getter = |m: &NodeMetadata| m.register_tcb_info_call_indexes(); + let extrinsic = generate_generic_register_collateral_extrinsic( + call_index_getter, + extrinsic_slice, + &collateral_data.0, + &collateral_data.1, + &collateral.tcb_info_issuer_chain, + ); + match extrinsic { + Ok(_) => sgx_status_t::SGX_SUCCESS, + Err(e) => e.into(), + } +} + +pub fn generate_generic_register_collateral_extrinsic( + getter: F, + extrinsic_slice: &mut [u8], + collateral_data: &str, + data_signature: &[u8], + issuer_chain: &[u8], +) -> EnclaveResult<()> +where + F: Fn(&NodeMetadata) -> Result<[u8; 2], MetadataError>, +{ + let extrinsics_factory = get_extrinsic_factory_from_solo_or_parachain()?; + + let node_metadata_repo = get_node_metadata_repository_from_solo_or_parachain()?; + let call_ids = node_metadata_repo + .get_from_metadata(getter)? + .map_err(MetadataProviderError::MetadataError)?; + info!(" [Enclave] Compose register collateral call: {:?}", call_ids); + let call = OpaqueCall::from_tuple(&(call_ids, collateral_data, data_signature, issuer_chain)); + + let extrinsic = extrinsics_factory.create_extrinsics(&[call], None)?[0].clone(); + if let Err(e) = write_slice_and_whitespace_pad(extrinsic_slice, extrinsic.encode()) { + return EnclaveError::Other(Box::new(e)).into() + }; + Ok(()) +} + #[no_mangle] pub extern "C" fn dump_ias_ra_cert_to_disk() -> sgx_status_t { let attestation_handler = match GLOBAL_ATTESTATION_HANDLER_COMPONENT.get() { @@ -211,3 +333,12 @@ pub unsafe extern "C" fn dump_dcap_ra_cert_to_disk( Err(e) => e.into(), } } + +#[no_mangle] +pub unsafe extern "C" fn dump_dcap_collateral_to_disk( + collateral: *const sgx_ql_qve_collateral_t, +) -> sgx_status_t { + let collateral = SgxQlQveCollateral::from_c_type(&*collateral); + collateral.dump_to_disk(); + sgx_status_t::SGX_SUCCESS +} diff --git a/enclave-runtime/src/tls_ra/authentication.rs b/enclave-runtime/src/tls_ra/authentication.rs index 3cae981bac..5df275b539 100644 --- a/enclave-runtime/src/tls_ra/authentication.rs +++ b/enclave-runtime/src/tls_ra/authentication.rs @@ -48,17 +48,17 @@ where fn verify_client_cert( &self, - _certs: &[rustls::Certificate], + certs: &[rustls::Certificate], _sni: Option<&DNSName>, ) -> Result { - debug!("client cert: {:?}", _certs); + debug!("client cert: {:?}", certs); // This call will automatically verify cert is properly signed if self.skip_ra { warn!("Skip verifying ra-report"); return Ok(rustls::ClientCertVerified::assertion()) } - match cert::verify_mra_cert(&_certs[0].0, &self.attestation_ocall) { + match cert::verify_mra_cert(&certs[0].0, &self.attestation_ocall) { Ok(()) => Ok(rustls::ClientCertVerified::assertion()), Err(sgx_status_t::SGX_ERROR_UPDATE_NEEDED) => if self.outdated_ok { diff --git a/service/build.rs b/service/build.rs index 01874c908e..8f18978c62 100644 --- a/service/build.rs +++ b/service/build.rs @@ -46,6 +46,7 @@ fn main() { // ln -s libsgx_dcap_ql.so.1 libsgx_dcap_ql.so println!("cargo:rustc-link-lib=dylib=sgx_dcap_ql"); println!("cargo:rustc-link-lib=dylib=sgx_dcap_quoteverify"); + println!("cargo:rustc-link-lib=dylib=dcap_quoteprov"); match is_sim.as_ref() { "SW" => { println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"); diff --git a/service/src/account_funding.rs b/service/src/account_funding.rs index 787e74cbf1..586c4f1ff1 100644 --- a/service/src/account_funding.rs +++ b/service/src/account_funding.rs @@ -54,7 +54,7 @@ impl EnclaveAccountInfoProvider { pub fn setup_account_funding( api: &ParentchainApi, accountid: &AccountId32, - extrinsic_prefix: String, + extrinsic_prefix: &str, is_development_mode: bool, ) -> ServiceResult<()> { // Account funds @@ -63,7 +63,7 @@ pub fn setup_account_funding( ensure_account_has_funds(api, accountid)?; } else { // Production mode, there is no faucet. - let registration_fees = enclave_registration_fees(api, &extrinsic_prefix)?; + let registration_fees = enclave_registration_fees(api, extrinsic_prefix)?; info!("Registration fees = {:?}", registration_fees); let free_balance = api.get_free_balance(accountid)?; info!("TEE's free balance = {:?}", free_balance); diff --git a/service/src/main.rs b/service/src/main.rs index 5decc203cb..742937344d 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -63,6 +63,7 @@ use itp_settings::{ files::SIDECHAIN_STORAGE_PATH, worker_mode::{ProvideWorkerMode, WorkerMode, WorkerModeProvider}, }; +use itp_utils::hex::hex_encode; use its_peer_fetch::{ block_fetch_client::BlockFetcher, untrusted_peer_fetch::UntrustedPeerFetcher, }; @@ -222,7 +223,14 @@ fn main() { #[cfg(not(feature = "dcap"))] enclave.dump_ias_ra_cert_to_disk().unwrap(); #[cfg(feature = "dcap")] - enclave.dump_dcap_ra_cert_to_disk().unwrap(); + { + // Hard coded 6-byte FMSPC that represents the state of devsgx03 + // TODO: either fetch this value from a list of pre-configured FMSPC values or + // extract the information out of the RA certificate + let fmspc = [00u8, 0x90, 0x6E, 0xA1, 00, 00]; + enclave.dump_dcap_collateral_to_disk(fmspc).unwrap(); + enclave.dump_dcap_ra_cert_to_disk().unwrap(); + } } else if matches.is_present("mrenclave") { println!("{}", enclave.get_mrenclave().unwrap().encode().to_base58()); } else if let Some(sub_matches) = matches.subcommand_matches("init-shard") { @@ -415,6 +423,9 @@ fn start_worker( ) .expect("Could not set the node metadata in the enclave"); + #[cfg(feature = "dcap")] + register_collateral(&node_api, &*enclave, &tee_accountid, is_development_mode); + // ------------------------------------------------------------------------ // Perform a remote attestation and get an unchecked extrinsic back. let trusted_url = config.trusted_worker_url_external(); @@ -429,22 +440,8 @@ fn start_worker( let uxt = enclave.generate_ias_ra_extrinsic(&trusted_url, skip_ra).unwrap(); #[cfg(feature = "dcap")] let uxt = enclave.generate_dcap_ra_extrinsic(&trusted_url, skip_ra).unwrap(); - - let mut xthex = hex::encode(uxt); - xthex.insert_str(0, "0x"); - - // Account funds - if let Err(x) = - setup_account_funding(&node_api, &tee_accountid, xthex.clone(), is_development_mode) - { - error!("Starting worker failed: {:?}", x); - // Return without registering the enclave. This will fail and the transaction will be banned for 30min. - return - } - - println!("[>] Register the enclave (send the extrinsic)"); - let register_enclave_xt_hash = node_api.send_extrinsic(xthex, XtStatus::Finalized).unwrap(); - println!("[<] Extrinsic got finalized. Hash: {:?}\n", register_enclave_xt_hash); + let register_enclave_xt_hash = + send_extrinsic(&uxt, &node_api, &tee_accountid, is_development_mode); let register_enclave_xt_header = node_api.get_header(register_enclave_xt_hash).unwrap().unwrap(); @@ -697,6 +694,41 @@ fn print_events(events: Events, _sender: Sender) { } } +#[cfg(feature = "dcap")] +fn register_collateral( + api: &ParentchainApi, + enclave: &dyn RemoteAttestation, + accountid: &AccountId32, + is_development_mode: bool, +) { + let fmspc = [00u8, 0x90, 0x6E, 0xA1, 00, 00]; + let uxt = enclave.generate_register_quoting_enclave_extrinsic(fmspc).unwrap(); + send_extrinsic(&uxt, api, accountid, is_development_mode); + + let uxt = enclave.generate_register_tcb_info_extrinsic(fmspc).unwrap(); + send_extrinsic(&uxt, api, accountid, is_development_mode); +} + +fn send_extrinsic( + extrinsic: &[u8], + api: &ParentchainApi, + accountid: &AccountId32, + is_development_mode: bool, +) -> Option { + let xthex = hex_encode(extrinsic); + // Account funds + if let Err(x) = setup_account_funding(api, accountid, &xthex, is_development_mode) { + error!("Starting worker failed: {:?}", x); + // Return without registering the enclave. This will fail and the transaction will be banned for 30min. + return None + } + + println!("[>] Register the TCB info (send the extrinsic)"); + let register_qe_xt_hash = api.send_extrinsic(xthex, XtStatus::Finalized).unwrap(); + println!("[<] Extrinsic got finalized. Hash: {:?}\n", register_qe_xt_hash); + register_qe_xt_hash +} + /// Subscribe to the node API finalized heads stream and trigger a parent chain sync /// upon receiving a new header. fn subscribe_to_parentchain_new_headers( diff --git a/service/src/teeracle/mod.rs b/service/src/teeracle/mod.rs index 15c3637a4a..e39a247985 100644 --- a/service/src/teeracle/mod.rs +++ b/service/src/teeracle/mod.rs @@ -20,6 +20,7 @@ use codec::{Decode, Encode}; use itp_enclave_api::teeracle_api::TeeracleApi; use itp_node_api::api_client::ParentchainApi; use itp_settings::teeracle::DEFAULT_MARKET_DATA_UPDATE_INTERVAL; +use itp_utils::hex::hex_encode; use log::*; use sp_runtime::OpaqueExtrinsic; use std::time::Duration; @@ -75,8 +76,7 @@ fn execute_weather_update( extrinsics.into_iter().for_each(|call| { let node_api_clone = node_api.clone(); tokio_handle.spawn(async move { - let mut hex_encoded_extrinsic = hex::encode(call.encode()); - hex_encoded_extrinsic.insert_str(0, "0x"); + let hex_encoded_extrinsic = hex_encode(&call.encode()); debug!("Hex encoded extrinsic to be sent: {}", hex_encoded_extrinsic); println!("[>] Update oracle (send the extrinsic)"); let extrinsic_hash = @@ -123,8 +123,7 @@ fn execute_update_market( for call in extrinsics.into_iter() { let node_api_clone = node_api.clone(); tokio_handle.spawn(async move { - let mut hex_encoded_extrinsic = hex::encode(call.encode()); - hex_encoded_extrinsic.insert_str(0, "0x"); + let hex_encoded_extrinsic = hex_encode(&call.encode()); debug!("Hex encoded extrinsic to be sent: {}", hex_encoded_extrinsic); println!("[>] Update the exchange rate (send the extrinsic)");