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
|
Cargo.lock
|
||||||
client_instance
|
client_instance
|
||||||
server_instance
|
server_instance
|
||||||
|
lib
|
||||||
|
11
Cargo.toml
11
Cargo.toml
@ -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
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() {
|
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
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
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());
|
||||||
|
Loading…
Reference in New Issue
Block a user