rewrote ioctl layer, updated scripts
This commit is contained in:
parent
365fb6499b
commit
924a443998
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ target
|
||||
Cargo.lock
|
||||
client_instance
|
||||
server_instance
|
||||
lib
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -26,6 +26,9 @@ hyper = "1.4.1"
|
||||
hyper-util = "0.1.7"
|
||||
hyper-rustls = { version = "0.27", features = ["http2"] }
|
||||
prost = "0.13"
|
||||
#cfg-if = "1.0"
|
||||
base64 = "0.22"
|
||||
lazy_static = "1.5"
|
||||
|
||||
[dependencies.tonic]
|
||||
version = "0.12"
|
||||
@ -59,10 +62,10 @@ version = "0.11"
|
||||
version = "1"
|
||||
features = ["full"]
|
||||
|
||||
[dev-dependencies.cargo-husky]
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"]
|
||||
#[dev-dependencies.cargo-husky]
|
||||
#version = "1"
|
||||
#default-features = false
|
||||
#features = ["precommit-hook", "run-cargo-test", "run-cargo-clippy"]
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.12"
|
||||
|
80
Occlum.json
Normal file
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"
|
||||
}
|
||||
]
|
||||
}
|
5
build.rs
5
build.rs
@ -1,4 +1,9 @@
|
||||
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()
|
||||
.build_server(true)
|
||||
.compile(&["examples/echo.proto"], &["examples"])
|
||||
|
@ -3,16 +3,17 @@ set -e
|
||||
|
||||
SCRIPT=$0
|
||||
EXAMPLE=$1
|
||||
EXEC=$2
|
||||
|
||||
if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then
|
||||
echo "usage: $SCRIPT https|grpcs"
|
||||
echo "usage: $SCRIPT https|grpcs [--run]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "reqwest,occlum"; else echo "tonic,occlum"; fi)
|
||||
|
||||
occlum-cargo build --example mratls_"${EXAMPLE}"_client --features="$FEATURES"
|
||||
strip target/x86_64-unknown-linux-musl/debug/examples/mratls_"${EXAMPLE}"_client
|
||||
occlum-cargo build --release --example mratls_"${EXAMPLE}"_client --features="$FEATURES"
|
||||
strip target/x86_64-unknown-linux-musl/release/examples/mratls_"${EXAMPLE}"_client
|
||||
|
||||
cat > client.yaml <<EOF
|
||||
includes:
|
||||
@ -21,13 +22,17 @@ targets:
|
||||
- target: /bin
|
||||
copy:
|
||||
- files:
|
||||
- ../target/x86_64-unknown-linux-musl/debug/examples/mratls_${EXAMPLE}_client
|
||||
- ../target/x86_64-unknown-linux-musl/release/examples/mratls_${EXAMPLE}_client
|
||||
EOF
|
||||
|
||||
rm -rf client_instance && mkdir client_instance && cd client_instance
|
||||
occlum init && rm -rf image
|
||||
cp ../Occlum.json ./
|
||||
copy_bom -f ../client.yaml --root image --include-dir /opt/occlum/etc/template
|
||||
occlum build --sign-key ../examples/signing_key.pem --enable-edmm Y
|
||||
occlum package --debug client.tar.gz
|
||||
# TODO: "--enable-edmm Y" must be only for platforms that support SGX2
|
||||
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
|
||||
EXAMPLE=$1
|
||||
EXEC=$2
|
||||
|
||||
if [ $# -eq 0 ] || [ "$EXAMPLE" != "https" ] && [ "$EXAMPLE" != "grpcs" ]; then
|
||||
echo "usage: $SCRIPT https|grpcs"
|
||||
echo "usage: $SCRIPT https|grpcs [--run]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FEATURES=$(if [ "$EXAMPLE" == "https" ]; then echo "actix-web,occlum"; else echo "tonic,occlum"; fi)
|
||||
|
||||
occlum-cargo build --example mratls_"${EXAMPLE}"_server --features="$FEATURES"
|
||||
strip target/x86_64-unknown-linux-musl/debug/examples/mratls_"${EXAMPLE}"_server
|
||||
occlum-cargo build --release --example mratls_"${EXAMPLE}"_server --features="$FEATURES"
|
||||
strip target/x86_64-unknown-linux-musl/release/examples/mratls_"${EXAMPLE}"_server
|
||||
|
||||
cat > server.yaml <<EOF
|
||||
includes:
|
||||
@ -21,13 +22,17 @@ targets:
|
||||
- target: /bin
|
||||
copy:
|
||||
- files:
|
||||
- ../target/x86_64-unknown-linux-musl/debug/examples/mratls_${EXAMPLE}_server
|
||||
- ../target/x86_64-unknown-linux-musl/release/examples/mratls_${EXAMPLE}_server
|
||||
EOF
|
||||
|
||||
rm -rf server_instance && mkdir server_instance && cd server_instance
|
||||
occlum init && rm -rf image
|
||||
cp ../Occlum.json ./
|
||||
copy_bom -f ../server.yaml --root image --include-dir /opt/occlum/etc/template
|
||||
occlum build --sign-key ../examples/signing_key.pem --enable-edmm Y
|
||||
occlum package --debug server.tar.gz
|
||||
# TODO: "--enable-edmm Y" must be only for platforms that support SGX2
|
||||
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 occlum_ratls::prelude::*;
|
||||
use occlum_ratls::RaTlsConfigBuilder;
|
||||
use occlum_sgx::SGXMeasurement;
|
||||
use pb::{echo_client::EchoClient, EchoRequest};
|
||||
use tokio_rustls::rustls::ClientConfig;
|
||||
|
||||
@ -18,9 +17,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut mrsigner = [0u8; 32];
|
||||
hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed");
|
||||
|
||||
let config = RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]),
|
||||
);
|
||||
let config = RaTlsConfig::new()
|
||||
.allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner]));
|
||||
|
||||
let tls = ClientConfig::from_ratls_config(config)
|
||||
.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];
|
||||
hex::decode_to_slice(mrsigner_hex, &mut mrsigner).expect("mrsigner decoding failed");
|
||||
|
||||
let config = RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]),
|
||||
);
|
||||
let config = RaTlsConfig::new()
|
||||
.allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(vec![mrsigner]));
|
||||
|
||||
let mut tls = ServerConfig::from_ratls_config(config)
|
||||
.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];
|
||||
hex::decode_to_slice(mrsigner_hex, &mut mrsigner)?;
|
||||
|
||||
let client = ClientBuilder::new()
|
||||
.use_ratls(RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]),
|
||||
))
|
||||
.build()?;
|
||||
let client =
|
||||
ClientBuilder::new()
|
||||
.use_ratls(RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![mrsigner]),
|
||||
))
|
||||
.build()?;
|
||||
let res = client.get("https://127.0.0.1:8000").send().await?;
|
||||
let data = res.text().await?;
|
||||
|
||||
|
@ -19,7 +19,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.bind_ratls(
|
||||
SocketAddr::from(([127, 0, 0, 1], 8000)),
|
||||
RaTlsConfig::new().allow_instance_measurement(
|
||||
InstanceMeasurement::new().with_mrsigners(vec![SGXMeasurement::new(mrsigner)]),
|
||||
InstanceMeasurement::new().with_mrsigners(vec![mrsigner]),
|
||||
),
|
||||
)
|
||||
.unwrap()
|
||||
|
1988
src/bindings.rs
Normal file
1988
src/bindings.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,12 @@
|
||||
use crate::{RaTlsConfigBuilder, RaTlsError};
|
||||
|
||||
#[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};
|
||||
|
||||
pub type Measurement = [u8; 32];
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct RaTlsConfig {
|
||||
#[cfg(feature = "occlum")]
|
||||
@ -17,8 +16,8 @@ pub struct RaTlsConfig {
|
||||
#[cfg(feature = "occlum")]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct InstanceMeasurement {
|
||||
pub(crate) mrsigners: Option<Vec<SGXMeasurement>>,
|
||||
pub(crate) mrenclaves: Option<Vec<SGXMeasurement>>,
|
||||
pub(crate) mrsigners: Option<Vec<Measurement>>,
|
||||
pub(crate) mrenclaves: Option<Vec<Measurement>>,
|
||||
pub(crate) product_ids: Option<Vec<u16>>,
|
||||
pub(crate) versions: Option<Vec<u16>>,
|
||||
}
|
||||
@ -29,14 +28,14 @@ impl InstanceMeasurement {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn with_mrsigners(self, mrsigners: Vec<SGXMeasurement>) -> Self {
|
||||
pub fn with_mrsigners(self, mrsigners: Vec<Measurement>) -> Self {
|
||||
Self {
|
||||
mrsigners: Some(mrsigners),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_mrenclaves(self, mrenclaves: Vec<SGXMeasurement>) -> Self {
|
||||
pub fn with_mrenclaves(self, mrenclaves: Vec<Measurement>) -> Self {
|
||||
Self {
|
||||
mrenclaves: Some(mrenclaves),
|
||||
..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;
|
||||
if let Some(mrsigners) = &self.mrsigners {
|
||||
result = true;
|
||||
let value = quote.mrsigner();
|
||||
let value = quote.mrsigner().into();
|
||||
if !mrsigners.contains(&value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(mrenclaves) = &self.mrenclaves {
|
||||
result = true;
|
||||
let value = quote.mrenclave();
|
||||
let value = quote.mrenclave().into();
|
||||
if !mrenclaves.contains(&value) {
|
||||
return false;
|
||||
}
|
||||
@ -76,7 +75,7 @@ impl InstanceMeasurement {
|
||||
|
||||
if let Some(product_ids) = &self.product_ids {
|
||||
result = true;
|
||||
let value = quote.product_id();
|
||||
let value = quote.product_id().into();
|
||||
if !product_ids.contains(&value) {
|
||||
return false;
|
||||
}
|
||||
@ -84,7 +83,7 @@ impl InstanceMeasurement {
|
||||
|
||||
if let Some(versions) = &self.versions {
|
||||
result = true;
|
||||
let value = quote.version();
|
||||
let value = quote.version().into();
|
||||
if !versions.contains(&value) {
|
||||
return false;
|
||||
}
|
||||
@ -106,14 +105,14 @@ impl RaTlsConfig {
|
||||
}
|
||||
|
||||
#[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
|
||||
.allowed_instances
|
||||
.iter()
|
||||
.any(|im| im.check_quote_measurements(quote))
|
||||
{
|
||||
true => Ok(()),
|
||||
false => Err(RaTlsError::QuoteVerifyError(format!(
|
||||
false => Err(RaTlsError::QuoteError(format!(
|
||||
"{:?} is not allowed",
|
||||
quote
|
||||
))),
|
||||
|
@ -3,7 +3,8 @@ use std::{error::Error, fmt::Display};
|
||||
#[derive(Debug)]
|
||||
pub enum RaTlsError {
|
||||
CertificateBuildError(String),
|
||||
QuoteVerifyError(String),
|
||||
QuoteError(String),
|
||||
DcapError(String),
|
||||
}
|
||||
|
||||
impl Display for RaTlsError {
|
||||
@ -12,7 +13,8 @@ impl Display for RaTlsError {
|
||||
RaTlsError::CertificateBuildError(ref 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 config;
|
||||
mod error;
|
||||
mod http;
|
||||
mod racert;
|
||||
mod server;
|
||||
#[cfg(feature = "occlum")]
|
||||
mod utils;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
mod bindings;
|
||||
pub mod prelude;
|
||||
#[cfg(feature = "occlum")]
|
||||
mod quote;
|
||||
//mod sscert;
|
||||
|
||||
pub use crate::config::RaTlsConfig;
|
||||
|
@ -1,8 +1,7 @@
|
||||
pub use crate::RaTlsConfig;
|
||||
pub use crate::SGXMeasurement;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub use crate::InstanceMeasurement;
|
||||
pub use crate::config::InstanceMeasurement;
|
||||
|
||||
#[cfg(feature = "reqwest")]
|
||||
pub use crate::reqwest::ReqwestUseRatls;
|
||||
|
334
src/quote.rs
Normal file
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;
|
||||
|
||||
#[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 rustls::crypto::aws_lc_rs::sign::any_supported_type;
|
||||
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>> {
|
||||
let public_key = key_pair.public_key_raw().to_vec();
|
||||
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())
|
||||
}
|
||||
@ -123,7 +125,7 @@ impl RaTlsCertificate for CertificateDer<'_> {
|
||||
let report_oid = Oid::from(&REPORT_OID).unwrap();
|
||||
|
||||
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
|
||||
quote.verify()?;
|
||||
@ -134,7 +136,7 @@ impl RaTlsCertificate for CertificateDer<'_> {
|
||||
_ => 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 {
|
||||
return Err("Invalid quote report data".into());
|
||||
|
Loading…
Reference in New Issue
Block a user