diff --git a/tools/toolchains/dcap_lib/Cargo.lock b/tools/toolchains/dcap_lib/Cargo.lock new file mode 100644 index 00000000..701cfa9c --- /dev/null +++ b/tools/toolchains/dcap_lib/Cargo.lock @@ -0,0 +1,28 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "libc" +version = "0.2.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" + +[[package]] +name = "occlum_dcap" +version = "0.1.0" +dependencies = [ + "cfg-if", + "libc", + "sgx_types", +] + +[[package]] +name = "sgx_types" +version = "1.1.4" diff --git a/tools/toolchains/dcap_lib/Cargo.toml b/tools/toolchains/dcap_lib/Cargo.toml new file mode 100644 index 00000000..02f60f9d --- /dev/null +++ b/tools/toolchains/dcap_lib/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "occlum_dcap" +version = "0.1.0" +authors = ["Zheng, Qi "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sgx_types = { path = "../../../deps/rust-sgx-sdk/sgx_types" } +libc = "0.2" +cfg-if = "1.0.0" + +[lib] +crate-type = ["cdylib", "rlib", "staticlib"] diff --git a/tools/toolchains/dcap_lib/build.sh b/tools/toolchains/dcap_lib/build.sh new file mode 100755 index 00000000..4c303f88 --- /dev/null +++ b/tools/toolchains/dcap_lib/build.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +INSTALL_DIR=/opt/occlum/toolchains/dcap_lib + +echo "*** Build and install musl-libc dcap ***" +occlum-cargo clean +occlum-cargo build --all-targets --release + +mkdir -p ${INSTALL_DIR}/musl +cp target/x86_64-unknown-linux-musl/release/libocclum_dcap.a ${INSTALL_DIR}/musl/ +cp target/x86_64-unknown-linux-musl/release/libocclum_dcap.so ${INSTALL_DIR}/musl/ +cp target/x86_64-unknown-linux-musl/release/examples/dcap_test ${INSTALL_DIR}/musl/ + +echo "*** Build and install glibc dcap ***" +cargo clean +cargo build --all-targets --release + +mkdir -p ${INSTALL_DIR}/glibc +cp target/release/libocclum_dcap.a ${INSTALL_DIR}/glibc/ +cp target/release/libocclum_dcap.so ${INSTALL_DIR}/glibc/ +cp target/release/examples/dcap_test ${INSTALL_DIR}/glibc/ + +cp -r inc ${INSTALL_DIR}/ diff --git a/tools/toolchains/dcap_lib/examples/dcap_test.rs b/tools/toolchains/dcap_lib/examples/dcap_test.rs new file mode 100644 index 00000000..74987361 --- /dev/null +++ b/tools/toolchains/dcap_lib/examples/dcap_test.rs @@ -0,0 +1,169 @@ +extern crate occlum_dcap; +use std::str; +use std::io::Result; +use std::convert::TryFrom; +use occlum_dcap::*; + +struct DcapDemo { + dcap_quote: DcapQuote, + quote_size: u32, + quote_buf: Vec, + req_data: sgx_report_data_t, + supplemental_size: u32, + suppl_buf: Vec +} + +impl DcapDemo { + pub fn new(report_data: &str) -> Self { + let mut dcap = DcapQuote::new(); + let quote_size = dcap.get_quote_size(); + let supplemental_size = dcap.get_supplemental_data_size(); + let quote_buf: Vec = vec![0; quote_size as usize]; + let suppl_buf: Vec = vec![0; supplemental_size as usize]; + let mut req_data = sgx_report_data_t::default(); + + //fill in the report data array + for (pos, val) in report_data.as_bytes().iter().enumerate() { + req_data.d[pos] = *val; + } + + Self { + dcap_quote: dcap, + quote_size: quote_size, + quote_buf: quote_buf, + req_data: req_data, + supplemental_size: supplemental_size, + suppl_buf: suppl_buf + } + } + + fn dcap_quote_gen(&mut self) -> Result { + self.dcap_quote.generate_quote(self.quote_buf.as_mut_ptr(), &mut self.req_data).unwrap(); + + println!("DCAP generate quote successfully"); + + Ok( 0 ) + } + + // Quote has type `sgx_quote3_t` and is structured as + // pub struct sgx_quote3_t { + // pub header: sgx_quote_header_t, + // pub report_body: sgx_report_body_t, + // pub signature_data_len: uint32_t, + // pub signature_data: [uint8_t; 0], + // } + + fn dcap_quote_get_report_body(&mut self) -> Result<*const sgx_report_body_t> { + let report_body_offset = std::mem::size_of::(); + let report_body: *const sgx_report_body_t + = (self.quote_buf[report_body_offset..]).as_ptr() as _; + + Ok(report_body) + } + + fn dcap_quote_get_report_data(&mut self) -> Result<*const sgx_report_data_t> { + let report_body_ptr = self.dcap_quote_get_report_body().unwrap(); + let report_data_ptr = unsafe { &(*report_body_ptr).report_data }; + + Ok(report_data_ptr) + } + + fn dcap_quote_ver(&mut self) -> Result { + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + let mut status = 1; + + let mut verify_arg = IoctlVerDCAPQuoteArg { + quote_buf: self.quote_buf.as_mut_ptr(), + quote_size: self.quote_size, + collateral_expiration_status: &mut status, + quote_verification_result: &mut quote_verification_result, + supplemental_data_size: self.supplemental_size, + supplemental_data: self.suppl_buf.as_mut_ptr(), + }; + + self.dcap_quote.verify_quote(&mut verify_arg).unwrap(); + println!("DCAP verify quote successfully"); + + Ok( quote_verification_result ) + } + + fn dcap_dump_quote_info(&mut self) { + let report_body_ptr = self.dcap_quote_get_report_body().unwrap(); + + // Dump ISV FAMILY ID + let family_id = unsafe { (*report_body_ptr).isv_family_id }; + let (fam_id_l, fam_id_h) = family_id.split_at(8); + let fam_id_l = <&[u8; 8]>::try_from(fam_id_l).unwrap(); + let fam_id_l = u64::from_le_bytes(*fam_id_l); + let fam_id_h = <&[u8; 8]>::try_from(fam_id_h).unwrap(); + let fam_id_h = u64::from_le_bytes(*fam_id_h); + println!("\nSGX ISV Family ID:"); + println!("\t Low 8 bytes: 0x{:016x?}\t", fam_id_l); + println!("\t high 8 bytes: 0x{:016x?}\t", fam_id_h); + + // Dump ISV EXT Product ID + let prod_id = unsafe { (*report_body_ptr).isv_ext_prod_id }; + let (prod_id_l, prod_id_h) = prod_id.split_at(8); + let prod_id_l = <&[u8; 8]>::try_from(prod_id_l).unwrap(); + let prod_id_l = u64::from_le_bytes(*prod_id_l); + let prod_id_h = <&[u8; 8]>::try_from(prod_id_h).unwrap(); + let prod_id_h = u64::from_le_bytes(*prod_id_h); + println!("\nSGX ISV EXT Product ID:"); + println!("\t Low 8 bytes: 0x{:016x?}\t", prod_id_l); + println!("\t high 8 bytes: 0x{:016x?}\t", prod_id_h); + + // Dump CONFIG ID + let conf_id = unsafe { (*report_body_ptr).config_id }; + println!("\nSGX CONFIG ID:"); + println!("\t{:02x?}", &conf_id[..16]); + println!("\t{:02x?}", &conf_id[16..32]); + println!("\t{:02x?}", &conf_id[32..48]); + println!("\t{:02x?}", &conf_id[48..]); + + // Dump CONFIG SVN + let conf_svn = unsafe { (*report_body_ptr).config_svn }; + println!("\nSGX CONFIG SVN:\t {:04x?}", conf_svn); + } +} + +impl Drop for DcapDemo { + fn drop(&mut self) { + self.dcap_quote.close(); + } +} + +fn main() { + let report_str = "Dcap demo sample"; + let mut dcap_demo = DcapDemo::new(report_str); + + println!("Generate quote with report data : {}", report_str); + dcap_demo.dcap_quote_gen().unwrap(); + + // compare the report data in quote buffer + let report_data_ptr = dcap_demo.dcap_quote_get_report_data().unwrap(); + let string = str::from_utf8( unsafe { &(*report_data_ptr).d } ).unwrap(); + + if report_str == &string[..report_str.len()] { + println!("Report data from Quote: '{}' exactly matches.", string); + } else { + println!("Report data from Quote: '{}' doesn't match !!!", string); + } + + dcap_demo.dcap_dump_quote_info(); + + let result = dcap_demo.dcap_quote_ver().unwrap(); + match result { + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => { + println!("Succeed to verify the quote!"); + }, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED | + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE | + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED | + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED | + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { + println!("WARN: App: Verification completed with Non-terminal result: {:?}", result); + }, + _ => println!("Error: App: Verification completed with Terminal result: {:?}", result), + } + +} diff --git a/tools/toolchains/dcap_lib/inc/occlum_dcap.h b/tools/toolchains/dcap_lib/inc/occlum_dcap.h new file mode 100644 index 00000000..33a2026c --- /dev/null +++ b/tools/toolchains/dcap_lib/inc/occlum_dcap.h @@ -0,0 +1,38 @@ +#ifndef _OCCLUM_DCAP_H +#define _OCCLUM_DCAP_H + +#include +#include + +#include "sgx_report.h" +#include "sgx_qve_header.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void *dcap_quote_open(void); + +uint32_t dcap_get_quote_size(void *handle); + +int32_t dcap_generate_quote(void *handle, uint8_t *quote_buf, const sgx_report_data_t *report_data); + +uint32_t dcap_get_supplemental_data_size(void *handle); + +int32_t dcap_verify_quote(void *handle, + const uint8_t *quote_buf, + uint32_t quote_size, + uint32_t *collateral_expiration_status, + sgx_ql_qv_result_t *quote_verification_result, + uint32_t supplemental_data_size, + uint8_t *supplemental_data); + + +void dcap_quote_close(void *handle); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/tools/toolchains/dcap_lib/src/lib.rs b/tools/toolchains/dcap_lib/src/lib.rs new file mode 100644 index 00000000..abb59c2e --- /dev/null +++ b/tools/toolchains/dcap_lib/src/lib.rs @@ -0,0 +1,105 @@ +mod occlum_dcap; +mod prelude; + +pub use crate::prelude::*; +pub use crate::occlum_dcap::*; + +#[no_mangle] +pub extern "C" fn dcap_quote_open() -> *mut c_void { + Box::into_raw(Box::new(DcapQuote::new())) as *mut c_void +} + +#[no_mangle] +pub extern "C" fn dcap_get_quote_size(handle: *mut c_void) -> u32 { + if handle.is_null() { + return 0 + } + + let dcap = unsafe { + &mut *(handle as *mut DcapQuote) + }; + + dcap.get_quote_size() +} + +#[no_mangle] +pub extern "C" fn dcap_generate_quote( + handle: *mut c_void, + quote_buf: *mut u8, + report_data: *const sgx_report_data_t) -> i32 +{ + if handle.is_null() { + return -1 + } + + let dcap = unsafe { + &mut *(handle as *mut DcapQuote) + }; + + dcap.generate_quote(quote_buf, report_data).unwrap(); + + 0 +} + +#[no_mangle] +pub extern "C" fn dcap_get_supplemental_data_size(handle: *mut c_void) -> u32 { + if handle.is_null() { + return 0 + } + + let dcap = unsafe { + &mut *(handle as *mut DcapQuote) + }; + + dcap.get_supplemental_data_size() +} + +#[no_mangle] +pub extern "C" fn dcap_verify_quote( + handle: *mut c_void, + quote_buf: *const u8, + quote_size: u32, + collateral_expiration_status: *mut u32, + quote_verification_result: *mut sgx_ql_qv_result_t, + supplemental_data_size: u32, + supplemental_data: *mut u8) -> i32 +{ + if handle.is_null() { + return -1 + } + + let dcap = unsafe { + &mut *(handle as *mut DcapQuote) + }; + + let mut verify_arg = IoctlVerDCAPQuoteArg { + quote_buf: quote_buf, + quote_size: quote_size, + collateral_expiration_status: collateral_expiration_status, + quote_verification_result: quote_verification_result, + supplemental_data_size: supplemental_data_size, + supplemental_data: supplemental_data, + }; + + dcap.verify_quote(&mut verify_arg).unwrap(); + + 0 +} + + +#[no_mangle] +pub extern "C" fn dcap_quote_close(handle: *mut c_void) { + if handle.is_null() { + return + } + + let dcap = unsafe { + &mut *(handle as *mut DcapQuote) + }; + + dcap.close(); + + unsafe { + Box::from_raw(handle); + } +} diff --git a/tools/toolchains/dcap_lib/src/occlum_dcap.rs b/tools/toolchains/dcap_lib/src/occlum_dcap.rs new file mode 100644 index 00000000..22ba3158 --- /dev/null +++ b/tools/toolchains/dcap_lib/src/occlum_dcap.rs @@ -0,0 +1,117 @@ +use std::ffi::CString; +use crate::prelude::*; + +const SGXIOC_GET_DCAP_QUOTE_SIZE: u64 = 0x80047307; +const SGXIOC_GEN_DCAP_QUOTE: u64 = 0xc0187308; +const SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE: u64 = 0x80047309; +const SGXIOC_VER_DCAP_QUOTE: u64 = 0xc030730a; + +cfg_if::cfg_if! { + if #[cfg(target_env = "musl")] { + const IOCTL_GET_DCAP_QUOTE_SIZE: i32 = SGXIOC_GET_DCAP_QUOTE_SIZE as i32; + const IOCTL_GEN_DCAP_QUOTE: i32 = SGXIOC_GEN_DCAP_QUOTE as i32; + const IOCTL_GET_DCAP_SUPPLEMENTAL_SIZE: i32 = SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE as i32; + const IOCTL_VER_DCAP_QUOTE: i32 = SGXIOC_VER_DCAP_QUOTE as i32; + } else { + const IOCTL_GET_DCAP_QUOTE_SIZE: u64 = SGXIOC_GET_DCAP_QUOTE_SIZE; + const IOCTL_GEN_DCAP_QUOTE: u64 = SGXIOC_GEN_DCAP_QUOTE; + const IOCTL_GET_DCAP_SUPPLEMENTAL_SIZE: u64 = SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE; + const IOCTL_VER_DCAP_QUOTE: u64 = SGXIOC_VER_DCAP_QUOTE; + } +} + + +// Copy from occlum/src/libos/src/fs/dev_fs/dev_sgx/mod.rs +//#[allow(dead_code)] +#[repr(C)] +pub struct IoctlGenDCAPQuoteArg { + pub report_data: *const sgx_report_data_t, // Input + pub quote_size: *mut u32, // Input/output + pub quote_buf: *mut u8, // Output +} + +// Copy from occlum/src/libos/src/fs/dev_fs/dev_sgx/mod.rs +//#[allow(dead_code)] +#[repr(C)] +pub struct IoctlVerDCAPQuoteArg { + pub quote_buf: *const u8, // Input + pub quote_size: u32, // Input + pub collateral_expiration_status: *mut u32, // Output + pub quote_verification_result: *mut sgx_ql_qv_result_t, // Output + pub supplemental_data_size: u32, // Input (optional) + pub supplemental_data: *mut u8, // Output (optional) +} + +pub struct DcapQuote { + fd: c_int, + quote_size: u32, + supplemental_size: u32, +} + +impl DcapQuote { + pub fn new() -> Self { + let path = CString::new("/dev/sgx").unwrap(); + let fd = unsafe { libc::open(path.as_ptr(), O_RDONLY) }; + if fd > 0 { + Self { + fd: fd, + quote_size: 0, + supplemental_size: 0, + } + } else { + panic!("Open /dev/sgx failed") + } + } + + pub fn get_quote_size(&mut self) -> u32 { + let size: u32 = 0; + let ret = unsafe { libc::ioctl(self.fd, IOCTL_GET_DCAP_QUOTE_SIZE, &size) }; + if ret < 0 { + panic!("IOCTRL IOCTL_GET_DCAP_QUOTE_SIZE failed"); + } else { + self.quote_size = size; + size + } + } + + pub fn generate_quote(&mut self, quote_buf: *mut u8, report_data: *const sgx_report_data_t) -> Result { + let quote_arg: IoctlGenDCAPQuoteArg = IoctlGenDCAPQuoteArg { + report_data: report_data, + quote_size: &mut self.quote_size, + quote_buf: quote_buf, + }; + + let ret = unsafe { libc::ioctl(self.fd, IOCTL_GEN_DCAP_QUOTE, "e_arg) }; + if ret < 0 { + Err("IOCTRL IOCTL_GEN_DCAP_QUOTE failed") + } else { + Ok( 0 ) + } + } + + pub fn get_supplemental_data_size(&mut self) -> u32 { + let size: u32 = 0; + let ret = unsafe { libc::ioctl(self.fd, IOCTL_GET_DCAP_SUPPLEMENTAL_SIZE, &size) }; + if ret < 0 { + panic!("IOCTRL IOCTL_GET_DCAP_SUPPLEMENTAL_SIZE failed"); + } else { + self.supplemental_size = size; + size + } + } + + pub fn verify_quote(&mut self, verify_arg: *mut IoctlVerDCAPQuoteArg) -> Result { + let ret = unsafe { libc::ioctl(self.fd, IOCTL_VER_DCAP_QUOTE, verify_arg) }; + if ret < 0 { + println!("ret = {}", ret); + Err("IOCTRL IOCTL_VER_DCAP_QUOTE failed") + } else { + Ok( 0 ) + } + } + + pub fn close(&mut self) { + unsafe { libc::close(self.fd) }; + } +} + diff --git a/tools/toolchains/dcap_lib/src/prelude.rs b/tools/toolchains/dcap_lib/src/prelude.rs new file mode 100644 index 00000000..e2c828c3 --- /dev/null +++ b/tools/toolchains/dcap_lib/src/prelude.rs @@ -0,0 +1,7 @@ +pub use std::boxed::Box; +pub use libc::{open, ioctl, close, c_void, c_int, O_RDONLY}; + +// Defined in "occlum/deps/rust-sgx-sdk/sgx_types" +pub use sgx_types::{ + sgx_quote_header_t, sgx_report_data_t, sgx_ql_qv_result_t, sgx_report_body_t, sgx_quote3_t +};