rewrote ioctl layer, updated scripts

This commit is contained in:
Valentyn Faychuk 2024-09-08 02:56:25 +03:00
parent 365fb6499b
commit 924a443998
Signed by: valy
GPG Key ID: F1AB995E20FEADC5
17 changed files with 2480 additions and 55 deletions

1
.gitignore vendored

@ -3,3 +3,4 @@ target
Cargo.lock Cargo.lock
client_instance client_instance
server_instance server_instance
lib

@ -26,6 +26,9 @@ hyper = "1.4.1"
hyper-util = "0.1.7" hyper-util = "0.1.7"
hyper-rustls = { version = "0.27", features = ["http2"] } hyper-rustls = { version = "0.27", features = ["http2"] }
prost = "0.13" prost = "0.13"
#cfg-if = "1.0"
base64 = "0.22"
lazy_static = "1.5"
[dependencies.tonic] [dependencies.tonic]
version = "0.12" version = "0.12"
@ -59,10 +62,10 @@ version = "0.11"
version = "1" version = "1"
features = ["full"] features = ["full"]
[dev-dependencies.cargo-husky] #[dev-dependencies.cargo-husky]
version = "1" #version = "1"
default-features = false #default-features = false
features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"] #features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"]
[build-dependencies] [build-dependencies]
tonic-build = "0.12" tonic-build = "0.12"

80
Occlum.json Normal file

@ -0,0 +1,80 @@
{
"resource_limits": {
"kernel_space_heap_size": "32MB",
"kernel_space_stack_size": "1MB",
"user_space_size": "300MB",
"max_num_of_threads": 32
},
"process": {
"default_stack_size": "4MB",
"default_heap_size": "32MB",
"default_mmap_size": "100MB"
},
"entry_points": [
"/bin"
],
"env": {
"default": [
"OCCLUM=yes"
],
"untrusted": [
"EXAMPLE"
]
},
"metadata": {
"product_id": 0,
"version_number": 0,
"debuggable": false,
"enable_kss": false,
"family_id": {
"high": "0x0",
"low": "0x0"
},
"ext_prod_id": {
"high": "0x0",
"low": "0x0"
}
},
"feature": {
"amx": 0,
"pkru": 0,
"enable_edmm": false,
"enable_posix_shm": false
},
"mount": [
{
"target": "/",
"type": "unionfs",
"options": {
"layers": [
{
"target": "/",
"type": "sefs",
"source": "./build/mount/__ROOT",
"options": {
"MAC": ""
}
},
{
"target": "/",
"type": "sefs",
"source": "./run/mount/__ROOT"
}
]
}
},
{
"target": "/host",
"type": "hostfs",
"source": "."
},
{
"target": "/proc",
"type": "procfs"
},
{
"target": "/dev",
"type": "devfs"
}
]
}

@ -1,4 +1,9 @@
fn main() { fn main() {
// TODO: should be conditional on the target platform (musl vs glibc)
println!("cargo:rustc-link-search=/opt/occlum/toolchains/dcap_lib/musl");
// Cargo will automatically know it must look for `libocclum_dcap.a`
println!("cargo:rustc-link-lib=occlum_dcap");
tonic_build::configure() tonic_build::configure()
.build_server(true) .build_server(true)
.compile(&["examples/echo.proto"], &["examples"]) .compile(&["examples/echo.proto"], &["examples"])

@ -3,16 +3,17 @@ set -e
SCRIPT=$0 SCRIPT=$0
EXAMPLE=$1 EXAMPLE=$1
EXEC=$2
if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then
echo "usage: $SCRIPT https|grpcs" echo "usage: $SCRIPT https|grpcs [--run]"
exit 1 exit 1
fi fi
FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "reqwest,occlum"; else echo "tonic,occlum"; fi) FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "reqwest,occlum"; else echo "tonic,occlum"; fi)
occlum-cargo build --example mratls_"${EXAMPLE}"_client --features="$FEATURES" occlum-cargo build --release --example mratls_"${EXAMPLE}"_client --features="$FEATURES"
strip target/x86_64-unknown-linux-musl/debug/examples/mratls_"${EXAMPLE}"_client strip target/x86_64-unknown-linux-musl/release/examples/mratls_"${EXAMPLE}"_client
cat > client.yaml <<EOF cat > client.yaml <<EOF
includes: includes:
@ -21,13 +22,17 @@ targets:
- target: /bin - target: /bin
copy: copy:
- files: - files:
- ../target/x86_64-unknown-linux-musl/debug/examples/mratls_${EXAMPLE}_client - ../target/x86_64-unknown-linux-musl/release/examples/mratls_${EXAMPLE}_client
EOF EOF
rm -rf client_instance && mkdir client_instance && cd client_instance rm -rf client_instance && mkdir client_instance && cd client_instance
occlum init && rm -rf image occlum init && rm -rf image
cp ../Occlum.json ./
copy_bom -f ../client.yaml --root image --include-dir /opt/occlum/etc/template copy_bom -f ../client.yaml --root image --include-dir /opt/occlum/etc/template
occlum build --sign-key ../examples/signing_key.pem --enable-edmm Y # TODO: "--enable-edmm Y" must be only for platforms that support SGX2
occlum package --debug client.tar.gz occlum build --sign-key ../examples/signing_key.pem
occlum package client.tar.gz
occlum run /bin/mratls_${EXAMPLE}_client if [ "$EXEC" == "--run" ]; then
occlum run /bin/mratls_${EXAMPLE}_client
fi

@ -3,16 +3,17 @@ set -e
SCRIPT=$0 SCRIPT=$0
EXAMPLE=$1 EXAMPLE=$1
EXEC=$2
if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then
echo "usage: $SCRIPT https|grpcs" echo "usage: $SCRIPT https|grpcs [--run]"
exit 1 exit 1
fi fi
FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "actix-web,occlum"; else echo "tonic,occlum"; fi) FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "actix-web,occlum"; else echo "tonic,occlum"; fi)
occlum-cargo build --example mratls_"${EXAMPLE}"_server --features="$FEATURES" occlum-cargo build --release --example mratls_"${EXAMPLE}"_server --features="$FEATURES"
strip target/x86_64-unknown-linux-musl/debug/examples/mratls_"${EXAMPLE}"_server strip target/x86_64-unknown-linux-musl/release/examples/mratls_"${EXAMPLE}"_server
cat > server.yaml <<EOF cat > server.yaml <<EOF
includes: includes:
@ -21,13 +22,17 @@ targets:
- target: /bin - target: /bin
copy: copy:
- files: - files:
- ../target/x86_64-unknown-linux-musl/debug/examples/mratls_${EXAMPLE}_server - ../target/x86_64-unknown-linux-musl/release/examples/mratls_${EXAMPLE}_server
EOF EOF
rm -rf server_instance && mkdir server_instance && cd server_instance rm -rf server_instance && mkdir server_instance && cd server_instance
occlum init && rm -rf image occlum init && rm -rf image
cp ../Occlum.json ./
copy_bom -f ../server.yaml --root image --include-dir /opt/occlum/etc/template copy_bom -f ../server.yaml --root image --include-dir /opt/occlum/etc/template
occlum build --sign-key ../examples/signing_key.pem --enable-edmm Y # TODO: "--enable-edmm Y" must be only for platforms that support SGX2
occlum package --debug server.tar.gz occlum build --sign-key ../examples/signing_key.pem
occlum package server.tar.gz
occlum run /bin/mratls_${EXAMPLE}_server if [ "$EXEC" == "--run" ]; then
occlum run /bin/mratls_${EXAMPLE}_server
fi

@ -6,7 +6,6 @@ use hyper::Uri;
use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor}; use hyper_util::{client::legacy::connect::HttpConnector, rt::TokioExecutor};
use occlum_ratls::prelude::*; use occlum_ratls::prelude::*;
use occlum_ratls::RaTlsConfigBuilder; use occlum_ratls::RaTlsConfigBuilder;
use occlum_sgx::SGXMeasurement;
use pb::{echo_client::EchoClient, EchoRequest}; use pb::{echo_client::EchoClient, EchoRequest};
use tokio_rustls::rustls::ClientConfig; use tokio_rustls::rustls::ClientConfig;
@ -18,9 +17,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut mrsigner = [0u8; 32]; let mut mrsigner = [0u8; 32];
hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed"); hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed");
let config = RaTlsConfig::new().allow_instance_measurement( let config = RaTlsConfig::new()
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner]));
);
let tls = ClientConfig::from_ratls_config(config) let tls = ClientConfig::from_ratls_config(config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?;

@ -33,9 +33,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut mrsigner = [0u8; 32]; let mut mrsigner = [0u8; 32];
hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed"); hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed");
let config = RaTlsConfig::new().allow_instance_measurement( let config = RaTlsConfig::new()
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner]));
);
let mut tls = ServerConfig::from_ratls_config(config) let mut tls = ServerConfig::from_ratls_config(config)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?; .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e)))?;

@ -9,11 +9,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut mrsigner = [0u8; 32]; let mut mrsigner = [0u8; 32];
hex::decode_to_slice(mrsigner_hex, &mut mrsigner)?; hex::decode_to_slice(mrsigner_hex, &mut mrsigner)?;
let client = ClientBuilder::new() let client =
.use_ratls(RaTlsConfig::new().allow_instance_measurement( ClientBuilder::new()
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), .use_ratls(RaTlsConfig::new().allow_instance_measurement(
)) InstanceMeasurement::new().with_mrsigners(vec![mrsigner]),
.build()?; ))
.build()?;
let res = client.get("https://127.0.0.1:8000").send().await?; let res = client.get("https://127.0.0.1:8000").send().await?;
let data = res.text().await?; let data = res.text().await?;

@ -19,7 +19,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.bind_ratls( .bind_ratls(
SocketAddr::from(([127, 0, 0, 1], 8000)), SocketAddr::from(([127, 0, 0, 1], 8000)),
RaTlsConfig::new().allow_instance_measurement( RaTlsConfig::new().allow_instance_measurement(
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]), InstanceMeasurement::new().with_mrsigners(vec![mrsigner]),
), ),
) )
.unwrap() .unwrap()

1988
src/bindings.rs Normal file

File diff suppressed because it is too large Load Diff

@ -1,13 +1,12 @@
use crate::{RaTlsConfigBuilder, RaTlsError}; use crate::{RaTlsConfigBuilder, RaTlsError};
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
use occlum_sgx::SGXQuote; use crate::quote::Quote;
// FIXME: this only suppresses the warnings
#[allow(unused_imports)]
pub use occlum_sgx::SGXMeasurement;
use rustls::{ClientConfig, ServerConfig}; use rustls::{ClientConfig, ServerConfig};
pub type Measurement = [u8; 32];
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct RaTlsConfig { pub struct RaTlsConfig {
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
@ -17,8 +16,8 @@ pub struct RaTlsConfig {
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct InstanceMeasurement { pub struct InstanceMeasurement {
pub(crate) mrsigners: Option<Vec<SGXMeasurement>>, pub(crate) mrsigners: Option<Vec<Measurement>>,
pub(crate) mrenclaves: Option<Vec<SGXMeasurement>>, pub(crate) mrenclaves: Option<Vec<Measurement>>,
pub(crate) product_ids: Option<Vec<u16>>, pub(crate) product_ids: Option<Vec<u16>>,
pub(crate) versions: Option<Vec<u16>>, pub(crate) versions: Option<Vec<u16>>,
} }
@ -29,14 +28,14 @@ impl InstanceMeasurement {
Self::default() Self::default()
} }
pub fn with_mrsigners(self, mrsigners: Vec<SGXMeasurement>) -> Self { pub fn with_mrsigners(self, mrsigners: Vec<Measurement>) -> Self {
Self { Self {
mrsigners: Some(mrsigners), mrsigners: Some(mrsigners),
..self ..self
} }
} }
pub fn with_mrenclaves(self, mrenclaves: Vec<SGXMeasurement>) -> Self { pub fn with_mrenclaves(self, mrenclaves: Vec<Measurement>) -> Self {
Self { Self {
mrenclaves: Some(mrenclaves), mrenclaves: Some(mrenclaves),
..self ..self
@ -57,18 +56,18 @@ impl InstanceMeasurement {
} }
} }
pub(crate) fn check_quote_measurements(&self, quote: &SGXQuote) -> bool { pub(crate) fn check_quote_measurements(&self, quote: &Quote) -> bool {
let mut result = false; let mut result = false;
if let Some(mrsigners) = &self.mrsigners { if let Some(mrsigners) = &self.mrsigners {
result = true; result = true;
let value = quote.mrsigner(); let value = quote.mrsigner().into();
if !mrsigners.contains(&value) { if !mrsigners.contains(&value) {
return false; return false;
} }
} }
if let Some(mrenclaves) = &self.mrenclaves { if let Some(mrenclaves) = &self.mrenclaves {
result = true; result = true;
let value = quote.mrenclave(); let value = quote.mrenclave().into();
if !mrenclaves.contains(&value) { if !mrenclaves.contains(&value) {
return false; return false;
} }
@ -76,7 +75,7 @@ impl InstanceMeasurement {
if let Some(product_ids) = &self.product_ids { if let Some(product_ids) = &self.product_ids {
result = true; result = true;
let value = quote.product_id(); let value = quote.product_id().into();
if !product_ids.contains(&value) { if !product_ids.contains(&value) {
return false; return false;
} }
@ -84,7 +83,7 @@ impl InstanceMeasurement {
if let Some(versions) = &self.versions { if let Some(versions) = &self.versions {
result = true; result = true;
let value = quote.version(); let value = quote.version().into();
if !versions.contains(&value) { if !versions.contains(&value) {
return false; return false;
} }
@ -106,14 +105,14 @@ impl RaTlsConfig {
} }
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
pub(crate) fn is_allowed_quote(&self, quote: &SGXQuote) -> Result<(), RaTlsError> { pub(crate) fn is_allowed_quote(&self, quote: &Quote) -> Result<(), RaTlsError> {
match self match self
.allowed_instances .allowed_instances
.iter() .iter()
.any(|im| im.check_quote_measurements(quote)) .any(|im| im.check_quote_measurements(quote))
{ {
true => Ok(()), true => Ok(()),
false => Err(RaTlsError::QuoteVerifyError(format!( false => Err(RaTlsError::QuoteError(format!(
"{:?} is not allowed", "{:?} is not allowed",
quote quote
))), ))),

@ -3,7 +3,8 @@ use std::{error::Error, fmt::Display};
#[derive(Debug)] #[derive(Debug)]
pub enum RaTlsError { pub enum RaTlsError {
CertificateBuildError(String), CertificateBuildError(String),
QuoteVerifyError(String), QuoteError(String),
DcapError(String),
} }
impl Display for RaTlsError { impl Display for RaTlsError {
@ -12,7 +13,8 @@ impl Display for RaTlsError {
RaTlsError::CertificateBuildError(ref message) => { RaTlsError::CertificateBuildError(ref message) => {
write!(f, "CertificateBuildError: {}", message) write!(f, "CertificateBuildError: {}", message)
} }
RaTlsError::QuoteVerifyError(ref message) => write!(f, "QuoteVerifyError: {}", message), RaTlsError::QuoteError(ref message) => write!(f, "QuoteVerifyError: {}", message),
RaTlsError::DcapError(ref message) => write!(f, "DcapError: {}", message),
} }
} }
} }

@ -1,13 +1,17 @@
mod racert;
mod client; mod client;
mod config; mod config;
mod error; mod error;
mod http; mod http;
mod racert;
mod server; mod server;
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
mod utils; mod utils;
#[cfg(feature = "occlum")]
mod bindings;
pub mod prelude; pub mod prelude;
#[cfg(feature = "occlum")]
mod quote;
//mod sscert; //mod sscert;
pub use crate::config::RaTlsConfig; pub use crate::config::RaTlsConfig;

@ -1,8 +1,7 @@
pub use crate::RaTlsConfig; pub use crate::RaTlsConfig;
pub use crate::SGXMeasurement;
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
pub use crate::InstanceMeasurement; pub use crate::config::InstanceMeasurement;
#[cfg(feature = "reqwest")] #[cfg(feature = "reqwest")]
pub use crate::reqwest::ReqwestUseRatls; pub use crate::reqwest::ReqwestUseRatls;

334
src/quote.rs Normal file

@ -0,0 +1,334 @@
use crate::bindings::*;
use crate::error::RaTlsError;
use lazy_static::lazy_static;
use log::{trace, warn};
use std::fmt::Debug;
use std::ops::Deref;
use std::sync::Mutex;
use std::time::Instant;
pub struct Quote {
buf: Vec<u8>,
report_body: *const sgx_report_body_t,
}
impl TryFrom<Vec<u8>> for Quote {
type Error = RaTlsError;
fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> {
let report_body_offset = size_of::<QuoteHeader>();
let report_body_size = size_of::<sgx_report_body_t>();
if buf.len() < report_body_offset + report_body_size {
let minimal = report_body_offset + report_body_size;
let actual = buf.len();
return Err(RaTlsError::QuoteError(format!(
"Failed to parse DCAP quote, min {minimal}, act {actual}"
)));
}
let report_body = buf.as_slice()[report_body_offset..].as_ptr() as *const sgx_report_body_t;
Ok(Self { buf, report_body })
}
}
#[repr(C)]
struct QuoteHeader {
pub version: u16,
pub att_key_type: u16,
pub att_key_data_0: u32,
pub qe_svn: u16,
pub pce_svn: u16,
pub vendor_id: [u8; 16],
pub user_data: [u8; 20],
}
impl TryFrom<&[u8]> for Quote {
type Error = RaTlsError;
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
buf.to_vec().try_into()
}
}
impl TryFrom<ReportData> for Quote {
type Error = RaTlsError;
fn try_from(value: ReportData) -> Result<Self, Self::Error> {
Self::from_report_data(value)
}
}
impl Deref for Quote {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.buf.as_ref()
}
}
impl Quote {
pub fn from_report_data(data: ReportData) -> Result<Self, RaTlsError> {
IOCTL_CLIENT
.lock()
.unwrap()
.generate_quote(data)?
.try_into()
}
pub fn from_slice(slice: &[u8]) -> Result<Self, RaTlsError> {
slice.try_into()
}
pub fn as_slice(&self) -> &[u8] {
self
}
pub fn verify(&self) -> Result<VerifyResult, RaTlsError> {
IOCTL_CLIENT.lock().unwrap().verify_quote(self.buf.as_ref())
}
pub fn isv_family_id(&self) -> sgx_isvfamily_id_t {
unsafe { (*self.report_body).isv_family_id }
}
pub fn isv_ext_prod_id(&self) -> sgx_isvext_prod_id_t {
unsafe { (*self.report_body).isv_ext_prod_id }
}
pub fn config_id(&self) -> sgx_config_id_t {
unsafe { (*self.report_body).config_id }
}
pub fn mrenclave(&self) -> sgx_measurement_t {
unsafe { (*self.report_body).mr_enclave }
}
pub fn mrsigner(&self) -> sgx_measurement_t {
unsafe { (*self.report_body).mr_signer }
}
pub fn product_id(&self) -> sgx_prod_id_t {
unsafe { (*self.report_body).isv_prod_id }
}
pub fn version(&self) -> sgx_isv_svn_t {
unsafe { (*self.report_body).isv_svn }
}
pub fn report_data(&self) -> ReportData {
unsafe { (*self.report_body).report_data.into() }
}
}
impl Debug for Quote {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SGXQuote")
.field("mrenclave", &self.mrenclave())
.field("mrsigner", &self.mrsigner())
.field("report_body", &self.report_data())
.field("product_id", &self.product_id())
.field("version", &self.version())
.field("family_id", &self.isv_family_id())
.field("ext_prod_id", &self.isv_ext_prod_id())
.field("config_id", &self.config_id())
.finish()
}
}
lazy_static! {
pub static ref IOCTL_CLIENT: Mutex<IoctlClient> = {
let client = IoctlClient::new();
Mutex::new(client)
};
}
pub struct IoctlClient {
fd: HandleType,
quote_size: Option<u32>,
supplemental_size: Option<u32>,
}
// Needed to numb the compiler
unsafe impl Send for IoctlClient {}
impl IoctlClient {
fn new() -> Self {
Self {
fd: std::ptr::null_mut(),
quote_size: None,
supplemental_size: None,
}
}
fn handle(&mut self) -> Result<HandleType, RaTlsError> {
if self.fd.is_null() {
let handle = unsafe { dcap_quote_open() };
if self.fd.is_null() {
return Err(RaTlsError::DcapError(
"Failed to open DCAP quote device".to_string(),
));
}
self.fd = handle;
}
Ok(self.fd)
}
fn get_quote_size(&mut self) -> Result<u32, RaTlsError> {
if self.quote_size.is_none() {
let size = unsafe { dcap_get_quote_size(self.fd) };
trace!("DCAP quote size is {}", size);
self.quote_size = Some(size);
}
Ok(*self.quote_size.as_ref().unwrap())
}
fn get_supplemental_data_size(&mut self) -> Result<u32, RaTlsError> {
if self.supplemental_size.is_none() {
let size = unsafe { dcap_get_supplemental_data_size(self.handle()?) };
trace!("DCAP supplemental data size is {}", size);
self.quote_size = Some(size);
}
Ok(*self.supplemental_size.as_ref().unwrap())
}
pub fn generate_quote(&mut self, report_data: ReportData) -> Result<Vec<u8>, RaTlsError> {
let instant = Instant::now();
let quote_buf = self.generate_quote_inner(report_data)?;
trace!("Generated quote in {:?}ms", instant.elapsed().as_millis());
Ok(quote_buf)
}
fn generate_quote_inner(&mut self, report_data: ReportData) -> Result<Vec<u8>, RaTlsError> {
let quote_size = self.get_quote_size()?;
let mut quote_buf: Vec<u8> = vec![0; quote_size as usize];
let instant = Instant::now();
let ret_code = unsafe {
dcap_generate_quote(self.handle()?, quote_buf.as_mut_ptr(), &report_data.into())
};
trace!("Generated quote in {:?}ms", instant.elapsed().as_millis());
if ret_code < 0 {
return Err(RaTlsError::DcapError(
"Failed to generate DCAP quote".to_string(),
));
}
Ok(quote_buf)
}
pub fn verify_quote(&mut self, quote_buf: &[u8]) -> Result<VerifyResult, RaTlsError> {
let instant = Instant::now();
let result = self.verify_quote_inner(quote_buf)?;
trace!("Verified quote in {:?}ms", instant.elapsed().as_millis());
if result.is_negligible() {
if !result.is_ok() {
warn!("DCAP quote verification returned: {:?}", result);
}
return Ok(result);
}
Err(RaTlsError::QuoteError(format!(
"DCAP quote verification returned: {:?}",
result
)))
}
fn verify_quote_inner(&mut self, quote_buf: &[u8]) -> Result<VerifyResult, RaTlsError> {
let supplemental_data_size = self.get_supplemental_data_size()?;
let mut status = 1;
let mut result = SGX_QL_QV_RESULT_UNSPECIFIED;
let mut suppl_buf: Vec<u8> = vec![0; supplemental_data_size as usize];
let ret_code = unsafe {
dcap_verify_quote(
self.handle()?,
quote_buf.as_ptr(),
quote_buf.len() as u32,
&mut status,
&mut result,
supplemental_data_size,
suppl_buf.as_mut_ptr(),
)
};
if ret_code < 0 {
return Err(RaTlsError::DcapError(
"Failed to verify DCAP quote".to_string(),
));
}
Ok(result.into())
}
}
impl Drop for IoctlClient {
fn drop(&mut self) {
unsafe {
if !self.fd.is_null() {
dcap_quote_close(self.fd);
}
}
}
}
type HandleType = *mut ::std::os::raw::c_void;
pub type ReportData = [u8; 64];
#[derive(Debug)]
pub enum VerifyResult {
Ok,
ConfigNeeded,
OutOfDate,
OutOfDateConfigNeeded,
InvalidSignature,
Revoked,
Unspecified,
SwHardeningNeeded,
ConfigAndSwHardeningNeeded,
}
impl From<sgx_ql_qv_result_t> for VerifyResult {
fn from(result: sgx_ql_qv_result_t) -> Self {
match result {
SGX_QL_QV_RESULT_OK => VerifyResult::Ok,
SGX_QL_QV_RESULT_CONFIG_NEEDED => VerifyResult::ConfigNeeded,
SGX_QL_QV_RESULT_OUT_OF_DATE => VerifyResult::OutOfDate,
SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => VerifyResult::OutOfDateConfigNeeded,
SGX_QL_QV_RESULT_INVALID_SIGNATURE => VerifyResult::InvalidSignature,
SGX_QL_QV_RESULT_REVOKED => VerifyResult::Revoked,
SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => VerifyResult::SwHardeningNeeded,
SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => {
VerifyResult::ConfigAndSwHardeningNeeded
}
//SGX_QL_QV_RESULT_UNSPECIFIED => QuoteVerifyResult::Unspecified,
_ => VerifyResult::Unspecified,
}
}
}
impl VerifyResult {
pub fn is_ok(&self) -> bool {
match self {
VerifyResult::Ok => true,
_ => false,
}
}
pub fn is_negligible(&self) -> bool {
match self {
VerifyResult::Ok => true,
VerifyResult::ConfigNeeded => true,
VerifyResult::OutOfDate => true,
VerifyResult::OutOfDateConfigNeeded => true,
VerifyResult::SwHardeningNeeded => true,
VerifyResult::ConfigAndSwHardeningNeeded => true,
_ => false,
}
}
}

@ -6,7 +6,9 @@ use crate::{error::RaTlsError, RaTlsConfig};
use log::error; use log::error;
#[cfg(feature = "occlum")] #[cfg(feature = "occlum")]
use occlum_sgx::SGXQuote; use crate::quote::Quote;
//#[cfg(feature = "occlum")]
//use occlum_sgx::SGXQuote;
use rcgen::{CertificateParams, CustomExtension, DistinguishedName, KeyPair}; use rcgen::{CertificateParams, CustomExtension, DistinguishedName, KeyPair};
use rustls::crypto::aws_lc_rs::sign::any_supported_type; use rustls::crypto::aws_lc_rs::sign::any_supported_type;
use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}; use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
@ -77,7 +79,7 @@ impl RaTlsCertificateBuilder {
fn get_quote(&self, key_pair: &KeyPair) -> Result<Vec<u8>, Box<dyn Error>> { fn get_quote(&self, key_pair: &KeyPair) -> Result<Vec<u8>, Box<dyn Error>> {
let public_key = key_pair.public_key_raw().to_vec(); let public_key = key_pair.public_key_raw().to_vec();
let report_data = hash_sha512(public_key); let report_data = hash_sha512(public_key);
let quote = SGXQuote::from_report_data(&report_data)?; let quote = Quote::from_report_data(report_data.into())?;
Ok(quote.as_slice().to_vec()) Ok(quote.as_slice().to_vec())
} }
@ -123,7 +125,7 @@ impl RaTlsCertificate for CertificateDer<'_> {
let report_oid = Oid::from(&REPORT_OID).unwrap(); let report_oid = Oid::from(&REPORT_OID).unwrap();
if let Ok(Some(report)) = x509.get_extension_unique(&report_oid) { if let Ok(Some(report)) = x509.get_extension_unique(&report_oid) {
let quote = SGXQuote::from_slice(report.value)?; let quote = Quote::from_slice(report.value)?;
// ECDSA quote verification using SGX DCAP driver // ECDSA quote verification using SGX DCAP driver
quote.verify()?; quote.verify()?;
@ -134,7 +136,7 @@ impl RaTlsCertificate for CertificateDer<'_> {
_ => return Err("Unexpected public key type".into()), _ => return Err("Unexpected public key type".into()),
}; };
let report_data = &*quote.report_data(); let report_data = quote.report_data();
if hash_sha512(public_key) != report_data { if hash_sha512(public_key) != report_data {
return Err("Invalid quote report data".into()); return Err("Invalid quote report data".into());