Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collateral handling for DCAP #1134

Merged
merged 39 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
e0c4f54
First version that manages to register a quoting enclave
Niederb Dec 6, 2022
f48cde3
Move collateral to attestation-handler
Niederb Dec 6, 2022
072aeeb
Work on collateral handling
Niederb Dec 6, 2022
6130fb8
Use the real collateral data for quoting enclave
Niederb Dec 6, 2022
ddabfbd
Make the dump-ra CLI command work
Niederb Dec 7, 2022
57e1548
Work towards register_tcb_info
Niederb Dec 13, 2022
af8e855
Add all the boilerplate code to register TCB info
Niederb Dec 13, 2022
72a2605
Reduce code duplication for extrinsic encoding
Niederb Dec 13, 2022
9f5077d
Reduce code duplication for extrinsic sending
Niederb Dec 13, 2022
831090a
Extract method for collateral
Niederb Dec 13, 2022
6fc0edd
Remove duplicated code
Niederb Dec 14, 2022
bcbde65
Fix clippy issues
Niederb Jan 3, 2023
13034d7
Fix compilation error in teeracle
Niederb Jan 3, 2023
66ac9a3
Return certificate and dcap quote
Niederb Jan 3, 2023
26e2ac3
Cleanup
Niederb Jan 3, 2023
4ae6f43
Switch to updated docker image
Niederb Jan 4, 2023
2b1667c
Disable DCAP for now
Niederb Jan 4, 2023
4f1ac0b
Register collateral only for DCAP
Niederb Jan 5, 2023
4f02a5a
Register collateral only for DCAP
Niederb Jan 5, 2023
0e58658
Cleanup
Niederb Jan 5, 2023
f2aae17
Update core-primitives/attestation-handler/src/attestation_handler.rs
Niederb Jan 9, 2023
837e4e8
Update enclave-runtime/src/attestation.rs
Niederb Jan 9, 2023
3513c8a
Extract shared logic into separate method
Niederb Jan 9, 2023
bd57bcd
Improve documentation
Niederb Jan 9, 2023
7519e93
Extract DCAP logic into separate function
Niederb Jan 9, 2023
2fcdf53
Get rid of two unwrap() calls
Niederb Jan 9, 2023
cb3d476
Move getting the call_ids into the shared function
Niederb Jan 9, 2023
b467d50
Use the correct Error for metadata
Niederb Jan 9, 2023
27413f1
Add type alias for Fmspc
Niederb Jan 9, 2023
48c508e
Improve separate_json_data_and_signature and add unit test
Niederb Jan 10, 2023
fb4ed84
Fix clippy issues
Niederb Jan 10, 2023
fa5a887
Incorporate review feedback
Niederb Jan 16, 2023
c23738d
Fix unsafe
Niederb Jan 18, 2023
85ae349
Switch implementation of separate_json_data_and_signature
Niederb Jan 18, 2023
9beacf8
Make clippy happy
Niederb Jan 18, 2023
2b870ea
Add missing `use`
Niederb Jan 19, 2023
52b4525
Add missing feature `preserve_order` to `serde_json_sgx`
Niederb Jan 19, 2023
6cbd250
Add compiler flag for std case
Niederb Jan 23, 2023
90c466d
Make separate_json_data_and_signature robust to potential C-style nul…
Niederb Jan 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions build.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions core-primitives/attestation-handler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
OverOrion marked this conversation as resolved.
Show resolved Hide resolved
thiserror = { version = "1.0", optional = true }
webpki = { version = "0.21", optional = true }

Expand All @@ -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 }
Expand All @@ -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" }
Expand Down
25 changes: 14 additions & 11 deletions core-primitives/attestation-handler/src/attestation_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>>;

/// 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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -284,7 +287,7 @@ where

let _ = ecc_handle.close();

Ok((key_der, cert_der))
Ok((cert_der, qe_quote))
}
}

Expand Down Expand Up @@ -640,7 +643,8 @@ where
.map_err(|e| EnclaveError::Other(e.into()))
}

pub fn ecdsa_quote_verification(&self, quote: Vec<u8>) -> SgxResult<Vec<u8>> {
/// Returns Ok if the verification of the quote by the quote verification enclave (QVE) was successful
pub fn ecdsa_quote_verification(&self, quote: Vec<u8>) -> SgxResult<()> {
OverOrion marked this conversation as resolved.
Show resolved Hide resolved
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() };
Expand Down Expand Up @@ -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(
Expand Down
158 changes: 158 additions & 0 deletions core-primitives/attestation-handler/src/collateral.rs
Original file line number Diff line number Diff line change
@@ -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};

OverOrion marked this conversation as resolved.
Show resolved Hide resolved
/// 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<u8>,
pub root_ca_crl: Vec<u8>,
pub pck_crl: Vec<u8>,
pub tcb_info_issuer_chain: Vec<u8>,
pub tcb_info: Vec<u8>,
pub qe_identity_issuer_chain: Vec<u8>,
pub qe_identity: Vec<u8>,
}

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<u8>)> {
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,
clangenb marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Returns the tcb_info split into two parts: json_data and signature
pub fn get_quoting_enclave_split(&self) -> Option<(String, Vec<u8>)> {
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());
}
}
3 changes: 3 additions & 0 deletions core-primitives/attestation-handler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
1 change: 1 addition & 0 deletions core-primitives/enclave-api/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
27 changes: 26 additions & 1 deletion core-primitives/enclave-api/ffi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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" {

Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand Down
Loading