refactor
This commit is contained in:
parent
966819d0e6
commit
2cd8fc0e56
35
Cargo.toml
35
Cargo.toml
@ -2,11 +2,11 @@
|
||||
# All rights reserved.
|
||||
|
||||
[package]
|
||||
name = "occlum-ratls"
|
||||
name = "occlum-sgx"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Valentyn Faychuk <faitchouk.valentyn@gmail.com>", "Ivan Chirkin <chirkin.ivan@gmail.com>"]
|
||||
description = "Remote attestation for Intel SGX"
|
||||
authors = ["Valentyn Faychuk <faitchouk.valentyn@gmail.com>"]
|
||||
description = "Intel SGX Occlum interface"
|
||||
license = "MIT OR Apache-2.0"
|
||||
keywords = ["occlum", "rustls", "ratls"]
|
||||
# Inspired by https://github.com/aggregion/occlum-ratls
|
||||
@ -14,7 +14,6 @@ keywords = ["occlum", "rustls", "ratls"]
|
||||
[dependencies]
|
||||
rustls = "0.23"
|
||||
x509-parser = "0.16"
|
||||
#occlum-sgx = "0.1" # get/verify quote
|
||||
ring = "0.17" # hash256
|
||||
rcgen = "0.13"
|
||||
log = "0.4"
|
||||
@ -28,10 +27,6 @@ hyper-rustls = { version = "0.27", features = ["http2"] }
|
||||
prost = "0.13"
|
||||
base64 = "0.22"
|
||||
lazy_static = "1.5"
|
||||
#sgx_tse = { version = "1.1", features = ["capi"] }
|
||||
#sgx_tse = "1.1"
|
||||
#sgx_types = "1.1"
|
||||
#sgx_tseal = "1.1"
|
||||
|
||||
[dependencies.tonic]
|
||||
version = "0.12"
|
||||
@ -57,6 +52,19 @@ default-features = false
|
||||
features = ["__rustls"]
|
||||
optional = true
|
||||
|
||||
[dependencies.pbkdf2]
|
||||
version = "0.12.2"
|
||||
optional = true
|
||||
features = ["hmac"]
|
||||
|
||||
[dependencies.sha2]
|
||||
version = "0.10.8"
|
||||
optional = true
|
||||
|
||||
[dependencies.aes-gcm]
|
||||
version = "0.10.3"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.env_logger]
|
||||
version = "0.11"
|
||||
|
||||
@ -76,26 +84,29 @@ tonic-build = "0.12"
|
||||
default = []
|
||||
# TOOD: rename to testing and reverse uses in the code
|
||||
occlum = []
|
||||
sealing = ["occlum", "dep:pbkdf2", "dep:sha2", "dep:aes-gcm"]
|
||||
reqwest = ["dep:reqwest"]
|
||||
actix-web = ["dep:actix-web", "actix-service", "actix-http"]
|
||||
tonic = ["dep:tonic"]
|
||||
full = ["occlum", "sealing", "reqwest", "actix-web", "tonic"]
|
||||
|
||||
|
||||
[[example]]
|
||||
name = "mratls_https_server"
|
||||
required-features = ["actix-web"]
|
||||
required-features = ["actix-web", "occlum"]
|
||||
|
||||
[[example]]
|
||||
name = "mratls_https_client"
|
||||
required-features = ["reqwest"]
|
||||
required-features = ["reqwest", "occlum"]
|
||||
|
||||
[[example]]
|
||||
name = "mratls_grpcs_server"
|
||||
required-features = ["tonic"]
|
||||
required-features = ["tonic", "occlum"]
|
||||
|
||||
[[example]]
|
||||
name = "mratls_grpcs_client"
|
||||
required-features = ["tonic"]
|
||||
required-features = ["tonic", "occlum"]
|
||||
|
||||
[[example]]
|
||||
name = "sealing"
|
||||
required-features = ["sealing"]
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Occlum SGX Remote Attestation integrated in TLS connection
|
||||
# Occlum SGX Remote Attestation integrated in TLS connection and many more
|
||||
|
||||
The MRSIGNER of the `example/signing_key.pem` is hardcoded in the enclave code:
|
||||
|
||||
@ -60,14 +60,14 @@ Run the occlum image in the docker environment:
|
||||
|
||||
```bash
|
||||
# Notice that there is no SGX device mounted
|
||||
docker run --rm -it -v /path/to/occlum-ratls:/root/occlum-ratls occlum/occlum:latest-ubuntu20.04
|
||||
docker run --rm -it -v /path/to/occlum-sgx:/root/occlum-sgx occlum/occlum:latest-ubuntu20.04
|
||||
# Inside the docker container do env preparation to build the image
|
||||
rustup install stable-x86_64-unknown-linux-gnu
|
||||
rustup default stable
|
||||
rustup target add x86_64-unknown-linux-musl
|
||||
|
||||
# Build the server and the client
|
||||
cd occlum-ratls
|
||||
cd occlum-sgx
|
||||
./build_server.sh grpcs
|
||||
./build_client.sh grpcs
|
||||
```
|
||||
|
11
build.rs
11
build.rs
@ -4,6 +4,7 @@ fn main() {
|
||||
#[cfg(feature = "occlum")]
|
||||
{
|
||||
let target = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
|
||||
|
||||
let dcap_lib_path = match target.as_str() {
|
||||
"musl" => "/opt/occlum/toolchains/dcap_lib/musl",
|
||||
_ => "/opt/occlum/toolchains/dcap_lib/glibc", // gnu, msvc, sgx...
|
||||
@ -21,6 +22,16 @@ fn main() {
|
||||
println!("cargo:rustc-link-search={}", dcap_lib_path);
|
||||
println!("cargo:rustc-link-lib=occlum_dcap");
|
||||
// println!("cargo:rustc-link-lib=static:+whole-archive=occlum_dcap");
|
||||
|
||||
/* ---occlum_utils--- */
|
||||
|
||||
let util_lib_path = match target.as_str() {
|
||||
"musl" => "/opt/occlum/toolchains/utils_lib/musl",
|
||||
_ => "/opt/occlum/toolchains/utils_lib/glibc", // gnu, msvc, sgx...
|
||||
};
|
||||
|
||||
println!("cargo:rustc-link-search={}", util_lib_path);
|
||||
println!("cargo:rustc-link-lib=occlum_utils");
|
||||
}
|
||||
|
||||
#[cfg(feature = "tonic")]
|
||||
|
@ -4,7 +4,7 @@ set -e
|
||||
SCRIPT=$0
|
||||
EXEC=$1
|
||||
|
||||
occlum-cargo build --release --example sealing --features="occlum"
|
||||
occlum-cargo build --release --example sealing --features="sealing"
|
||||
strip target/x86_64-unknown-linux-musl/release/examples/sealing
|
||||
|
||||
cat > sealing.yaml <<EOF
|
||||
@ -19,6 +19,7 @@ targets:
|
||||
copy:
|
||||
- files:
|
||||
- /opt/occlum/toolchains/dcap_lib/musl/libocclum_dcap.so.0.1.0
|
||||
- /opt/occlum/toolchains/utils_lib/musl/libocclum_utils.so.0.1.0
|
||||
EOF
|
||||
|
||||
rm -rf sealing_instance && mkdir sealing_instance && cd sealing_instance
|
||||
|
@ -1,7 +1,51 @@
|
||||
use occlum_ratls::prelude::*;
|
||||
use std::{
|
||||
fs,
|
||||
path::Path,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
const DATA_PATH: &str = "/host/sealed_data";
|
||||
|
||||
fn main() {
|
||||
println!("Example of sealing");
|
||||
let config = SealingConfig::new().unwrap();
|
||||
config.print_sealing_key();
|
||||
let sgx_sealing = SgxSealing::new().unwrap();
|
||||
println!("sealing : {:?}", sgx_sealing);
|
||||
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
|
||||
println!("timestamp: {:?}", ×tamp);
|
||||
|
||||
if !Path::new(DATA_PATH).exists() {
|
||||
// seal data
|
||||
|
||||
let payload = format!("this is sealing paylod; timestamp {}", timestamp)
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
|
||||
seal_and_write_data(sgx_sealing, payload);
|
||||
} else {
|
||||
// unseal data
|
||||
|
||||
let sealed_data = std::fs::read(DATA_PATH).unwrap();
|
||||
unseal_data(sgx_sealing, sealed_data);
|
||||
}
|
||||
}
|
||||
|
||||
fn seal_and_write_data(sgx_sealing: SgxSealing, payload: Vec<u8>) {
|
||||
let sealed_data = sgx_sealing.seal_data(payload).unwrap();
|
||||
println!("sealed_data: {:?}", &sealed_data);
|
||||
fs::write(DATA_PATH, &sealed_data).expect("Failed to write file {DATA_PATH}");
|
||||
}
|
||||
|
||||
fn unseal_data(sgx_sealing: SgxSealing, sealed_data: Vec<u8>) {
|
||||
println!("sealed_data: {:?}", &sealed_data);
|
||||
let unsealed_data = sgx_sealing.un_seal_data(sealed_data).unwrap();
|
||||
println!("unsealed_data: {:?}", &unsealed_data);
|
||||
|
||||
let unsealed_utf8_string = String::from_utf8_lossy(&unsealed_data);
|
||||
println!("unsealed data utf8: \"{unsealed_utf8_string}\"");
|
||||
}
|
||||
|
@ -1978,13 +1978,20 @@ extern "C" {
|
||||
supplemental_data_size: u32,
|
||||
supplemental_data: *mut u8,
|
||||
) -> i32;
|
||||
pub fn dcap_generate_key(
|
||||
pub fn dcap_quote_close(handle: *mut ::std::os::raw::c_void);
|
||||
}
|
||||
|
||||
// occlum_utils occlum-detee/tools/toolchains/utils_lib
|
||||
extern "C" {
|
||||
pub fn utils_ioctl_open() -> *mut ::std::os::raw::c_void;
|
||||
pub fn utils_gen_key(
|
||||
handle: *mut ::std::os::raw::c_void,
|
||||
key: *mut sgx_key_128bit_t,
|
||||
key_request: *const sgx_key_request_t,
|
||||
) -> i32;
|
||||
pub fn dcap_quote_close(handle: *mut ::std::os::raw::c_void);
|
||||
pub fn utils_ioctl_close(handle: *mut ::std::os::raw::c_void);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct __locale_data {
|
||||
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder},
|
||||
RaTlsConfig, RaTlsConfigBuilder, RaTlsError,
|
||||
RaTlsConfig, RaTlsConfigBuilder, SgxError,
|
||||
};
|
||||
use rustls::client::danger::HandshakeSignatureValid;
|
||||
use rustls::crypto::{aws_lc_rs, verify_tls12_signature, verify_tls13_signature, CryptoProvider};
|
||||
@ -79,7 +79,7 @@ pub struct RaTlsClientCertResolver {
|
||||
}
|
||||
|
||||
impl RaTlsClientCertResolver {
|
||||
pub fn new() -> Result<Self, RaTlsError> {
|
||||
pub fn new() -> Result<Self, SgxError> {
|
||||
let builder = RaTlsCertificateBuilder::new().with_common_name("Client".to_string());
|
||||
let cert = builder.build().map(Arc::new)?;
|
||||
Ok(Self { cert })
|
||||
@ -101,7 +101,7 @@ impl ResolvesClientCert for RaTlsClientCertResolver {
|
||||
}
|
||||
|
||||
impl RaTlsConfigBuilder<ClientConfig> for ClientConfig {
|
||||
fn from_ratls_config(config: RaTlsConfig) -> Result<Self, RaTlsError> {
|
||||
fn from_ratls_config(config: RaTlsConfig) -> Result<Self, SgxError> {
|
||||
Ok(Self::builder()
|
||||
.dangerous()
|
||||
.with_custom_certificate_verifier(Arc::new(RaTlsServerCertVerifier::new(config)))
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::{RaTlsConfigBuilder, RaTlsError};
|
||||
use crate::{RaTlsConfigBuilder, SgxError};
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
use crate::quote::{Quote, STATIC_QUOTE};
|
||||
|
||||
use crate::quote::{SealingKeyPolicy, Sgx128BitKey, IOCTL_CLIENT};
|
||||
use rustls::{ClientConfig, ServerConfig};
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub type Measurement = [u8; 32];
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
@ -57,7 +57,7 @@ impl InstanceMeasurement {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_current_mrsigner(self) -> Result<Self, RaTlsError> {
|
||||
pub fn with_current_mrsigner(self) -> Result<Self, SgxError> {
|
||||
let quote = Self::generate_static_empty_quote()?;
|
||||
let mrsigner_from_quote = quote.mrsigner().into();
|
||||
|
||||
@ -78,7 +78,7 @@ impl InstanceMeasurement {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_current_mrenclave(self) -> Result<Self, RaTlsError> {
|
||||
pub fn with_current_mrenclave(self) -> Result<Self, SgxError> {
|
||||
let quote = Self::generate_static_empty_quote()?;
|
||||
let mrenclave_from_quote = quote.mrenclave().into();
|
||||
|
||||
@ -99,7 +99,7 @@ impl InstanceMeasurement {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_current_measurements() -> Result<Self, RaTlsError> {
|
||||
pub fn with_current_measurements() -> Result<Self, SgxError> {
|
||||
let quote = Self::generate_static_empty_quote()?;
|
||||
|
||||
Ok(Self {
|
||||
@ -110,7 +110,7 @@ impl InstanceMeasurement {
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_static_empty_quote() -> Result<&'static Quote, RaTlsError> {
|
||||
fn generate_static_empty_quote() -> Result<&'static Quote, SgxError> {
|
||||
Ok(STATIC_QUOTE.as_ref().map_err(|e| e.clone())?)
|
||||
}
|
||||
|
||||
@ -163,60 +163,22 @@ impl RaTlsConfig {
|
||||
}
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub(crate) fn is_allowed_quote(&self, quote: &Quote) -> Result<(), RaTlsError> {
|
||||
pub(crate) fn is_allowed_quote(&self, quote: &Quote) -> Result<(), SgxError> {
|
||||
match self
|
||||
.allowed_instances
|
||||
.iter()
|
||||
.any(|im| im.check_quote_measurements(quote))
|
||||
{
|
||||
true => Ok(()),
|
||||
false => Err(RaTlsError::QuoteError(format!(
|
||||
"{:?} is not allowed",
|
||||
quote
|
||||
))),
|
||||
false => Err(SgxError::QuoteError(format!("{:?} is not allowed", quote))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_server_config(self) -> Result<ServerConfig, RaTlsError> {
|
||||
pub fn into_server_config(self) -> Result<ServerConfig, SgxError> {
|
||||
ServerConfig::from_ratls_config(self)
|
||||
}
|
||||
|
||||
pub fn into_client_config(self) -> Result<ClientConfig, RaTlsError> {
|
||||
pub fn into_client_config(self) -> Result<ClientConfig, SgxError> {
|
||||
ClientConfig::from_ratls_config(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SealingConfig {
|
||||
#[cfg(feature = "occlum")]
|
||||
pub sealing_key: Sgx128BitKey,
|
||||
}
|
||||
|
||||
impl SealingConfig {
|
||||
#[cfg(feature = "occlum")]
|
||||
fn generate_static_empty_quote() -> Result<&'static Quote, RaTlsError> {
|
||||
Ok(STATIC_QUOTE.as_ref().map_err(|e| e.clone())?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub fn new() -> Result<Self, RaTlsError> {
|
||||
let quote = Self::generate_static_empty_quote()?;
|
||||
let policy = SealingKeyPolicy::MrEnclave;
|
||||
let sealing_key = IOCTL_CLIENT
|
||||
.lock()
|
||||
.unwrap()
|
||||
.generate_sealing_key(quote, policy)?;
|
||||
Ok(Self { sealing_key })
|
||||
}
|
||||
|
||||
pub fn print_sealing_key(&self) {
|
||||
#[cfg(feature = "occlum")]
|
||||
println!("Sealing key: {:?}", self.sealing_key);
|
||||
#[cfg(not(feature = "occlum"))]
|
||||
println!("Enable occlum feature");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "occlum"))]
|
||||
pub fn new() -> Result<Self, RaTlsError> {
|
||||
Ok(Self {})
|
||||
}
|
||||
}
|
||||
|
18
src/error.rs
18
src/error.rs
@ -1,22 +1,28 @@
|
||||
use std::{error::Error, fmt::Display};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RaTlsError {
|
||||
pub enum SgxError {
|
||||
CertificateBuildError(String),
|
||||
QuoteError(String),
|
||||
DcapError(String),
|
||||
SealingError(String),
|
||||
UnSealingError(String),
|
||||
}
|
||||
|
||||
impl Display for RaTlsError {
|
||||
impl Display for SgxError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
RaTlsError::CertificateBuildError(ref message) => {
|
||||
SgxError::CertificateBuildError(ref message) => {
|
||||
write!(f, "CertificateBuildError: {}", message)
|
||||
}
|
||||
RaTlsError::QuoteError(ref message) => write!(f, "QuoteVerifyError: {}", message),
|
||||
RaTlsError::DcapError(ref message) => write!(f, "DcapError: {}", message),
|
||||
SgxError::QuoteError(ref message) => write!(f, "QuoteVerifyError: {}", message),
|
||||
SgxError::DcapError(ref message) => write!(f, "DcapError: {}", message),
|
||||
SgxError::SealingError(ref message) => write!(f, "SealingError: {}", message),
|
||||
SgxError::UnSealingError(ref message) => {
|
||||
write!(f, "UnSealingError: {}", message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for RaTlsError {}
|
||||
impl Error for SgxError {}
|
||||
|
142
src/ioctl.rs
Normal file
142
src/ioctl.rs
Normal file
@ -0,0 +1,142 @@
|
||||
use crate::bindings::*;
|
||||
use crate::error::SgxError;
|
||||
use crate::quote::{ReportData, VerifyResult};
|
||||
use log::{trace, warn};
|
||||
use std::time::Instant;
|
||||
|
||||
type HandleType = *mut ::std::os::raw::c_void;
|
||||
|
||||
// TODO: it should be refactored. makes it abstract and hide quote_size and supplemental_size
|
||||
pub struct SgxIoctlClient {
|
||||
fd: HandleType,
|
||||
quote_size: Option<u32>,
|
||||
supplemental_size: Option<u32>,
|
||||
}
|
||||
|
||||
// Needed to numb the compiler
|
||||
unsafe impl Send for SgxIoctlClient {}
|
||||
|
||||
impl SgxIoctlClient {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
fd: std::ptr::null_mut(),
|
||||
quote_size: None,
|
||||
supplemental_size: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle(&mut self) -> Result<HandleType, SgxError> {
|
||||
if self.fd.is_null() {
|
||||
let handle = unsafe { dcap_quote_open() };
|
||||
if handle.is_null() {
|
||||
return Err(SgxError::DcapError(
|
||||
"Failed to open DCAP quote device".to_string(),
|
||||
));
|
||||
}
|
||||
self.fd = handle;
|
||||
}
|
||||
Ok(self.fd)
|
||||
}
|
||||
|
||||
fn get_quote_size(&mut self) -> Result<u32, SgxError> {
|
||||
if self.quote_size.is_none() {
|
||||
let size = unsafe { dcap_get_quote_size(self.handle()?) };
|
||||
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, SgxError> {
|
||||
if self.supplemental_size.is_none() {
|
||||
let size = unsafe { dcap_get_supplemental_data_size(self.handle()?) };
|
||||
trace!("DCAP supplemental data size is {}", size);
|
||||
self.supplemental_size = Some(size);
|
||||
}
|
||||
|
||||
Ok(*self.supplemental_size.as_ref().unwrap())
|
||||
}
|
||||
|
||||
pub fn generate_quote(&mut self, report_data: ReportData) -> Result<Vec<u8>, SgxError> {
|
||||
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>, SgxError> {
|
||||
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(SgxError::DcapError(
|
||||
"Failed to generate DCAP quote".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(quote_buf)
|
||||
}
|
||||
|
||||
pub fn verify_quote(&mut self, quote_buf: &[u8]) -> Result<VerifyResult, SgxError> {
|
||||
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(SgxError::QuoteError(format!(
|
||||
"DCAP quote verification returned: {:?}",
|
||||
result
|
||||
)))
|
||||
}
|
||||
|
||||
fn verify_quote_inner(&mut self, quote_buf: &[u8]) -> Result<VerifyResult, SgxError> {
|
||||
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(SgxError::DcapError(
|
||||
"Failed to verify DCAP quote".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SgxIoctlClient {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.fd.is_null() {
|
||||
dcap_quote_close(self.fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
src/lib.rs
18
src/lib.rs
@ -7,20 +7,30 @@ mod server;
|
||||
#[cfg(feature = "occlum")]
|
||||
mod utils;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
mod ioctl;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
mod bindings;
|
||||
pub mod prelude;
|
||||
#[cfg(feature = "occlum")]
|
||||
mod quote;
|
||||
//mod sscert;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(feature = "occlum")]
|
||||
mod sgx_consts;
|
||||
|
||||
#[cfg(feature = "sealing")]
|
||||
mod sealing;
|
||||
|
||||
pub use crate::config::RaTlsConfig;
|
||||
pub use crate::config::SealingConfig;
|
||||
#[cfg(feature = "sealing")]
|
||||
pub use crate::sealing::SgxSealing;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub use crate::config::InstanceMeasurement;
|
||||
|
||||
pub use crate::error::RaTlsError;
|
||||
pub use crate::error::SgxError;
|
||||
|
||||
#[cfg(feature = "actix-web")]
|
||||
pub use crate::http::actix_web;
|
||||
@ -29,5 +39,5 @@ pub use crate::http::actix_web;
|
||||
pub use crate::http::reqwest;
|
||||
|
||||
pub trait RaTlsConfigBuilder<T> {
|
||||
fn from_ratls_config(config: RaTlsConfig) -> Result<T, RaTlsError>;
|
||||
fn from_ratls_config(config: RaTlsConfig) -> Result<T, SgxError>;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub use crate::RaTlsConfig;
|
||||
pub use crate::SealingConfig;
|
||||
#[cfg(feature = "sealing")]
|
||||
pub use crate::SgxSealing;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub use crate::config::InstanceMeasurement;
|
||||
|
260
src/quote.rs
260
src/quote.rs
@ -1,63 +1,18 @@
|
||||
use crate::bindings::*;
|
||||
use crate::error::RaTlsError;
|
||||
use crate::error::SgxError;
|
||||
use crate::ioctl::SgxIoctlClient;
|
||||
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 const SGX_FLAGS_INITTED: uint64_t = 0x0000_0000_0000_0001; //If set, then the enclave is initialized
|
||||
pub const SGX_FLAGS_DEBUG: uint64_t = 0x0000_0000_0000_0002; //If set, then the enclave is debug
|
||||
pub const SGX_FLAGS_MODE64BIT: uint64_t = 0x0000_0000_0000_0004; //If set, then the enclave is 64 bit
|
||||
pub const SGX_FLAGS_PROVISION_KEY: uint64_t = 0x0000_0000_0000_0010; //If set, then the enclave has access to provision key
|
||||
pub const SGX_FLAGS_EINITTOKEN_KEY: uint64_t = 0x0000_0000_0000_0020; //If set, then the enclave has access to EINITTOKEN key
|
||||
pub const SGX_FLAGS_KSS: uint64_t = 0x0000_0000_0000_0080; //If set enclave uses KSS
|
||||
pub const SGX_FLAGS_AEX_NOTIFY: uint64_t = 0x0000_0000_0000_0400; //If set, then the enclave enables AEX Notify
|
||||
pub const FLAGS_NON_SECURITY_BITS: uint64_t = 0x00FF_FFFF_FFFF_FFC0
|
||||
| SGX_FLAGS_MODE64BIT
|
||||
| SGX_FLAGS_PROVISION_KEY
|
||||
| SGX_FLAGS_EINITTOKEN_KEY;
|
||||
pub const TSEAL_DEFAULT_FLAGSMASK: uint64_t = !FLAGS_NON_SECURITY_BITS;
|
||||
pub const FLAGS_SECURITY_BITS_RESERVED: uint64_t =
|
||||
!(FLAGS_NON_SECURITY_BITS | SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG | SGX_FLAGS_KSS);
|
||||
pub const MISC_NON_SECURITY_BITS: uint32_t = 0x0FFF_FFFF;
|
||||
pub const TSEAL_DEFAULT_MISCMASK: uint32_t = !MISC_NON_SECURITY_BITS;
|
||||
|
||||
// TODO Intel sgx sdk 2.4
|
||||
pub const SGX_KEYSELECT_LICENSE: uint16_t = 0x0000;
|
||||
pub const SGX_KEYSELECT_PROVISION: uint16_t = 0x0001;
|
||||
pub const SGX_KEYSELECT_PROVISION_SEAL: uint16_t = 0x0002;
|
||||
pub const SGX_KEYSELECT_REPORT: uint16_t = 0x0003;
|
||||
pub const SGX_KEYSELECT_SEAL: uint16_t = 0x0004;
|
||||
|
||||
// Key Policy
|
||||
pub const SGX_KEYPOLICY_MRENCLAVE: uint16_t = 0x0001; /* Derive key using the enclave's ENCLAVE measurement register */
|
||||
pub const SGX_KEYPOLICY_MRSIGNER: uint16_t = 0x0002; /* Derive key using the enclave's SINGER measurement register */
|
||||
pub const SGX_KEYPOLICY_NOISVPRODID: uint16_t = 0x0004; /* Derive key without the enclave's ISVPRODID */
|
||||
pub const SGX_KEYPOLICY_CONFIGID: uint16_t = 0x0008; /* Derive key with the enclave's CONFIGID */
|
||||
pub const SGX_KEYPOLICY_ISVFAMILYID: uint16_t = 0x0010; /* Derive key with the enclave's ISVFAMILYID */
|
||||
pub const SGX_KEYPOLICY_ISVEXTPRODID: uint16_t = 0x0020; /* Derive key with the enclave's ISVEXTPRODID */
|
||||
|
||||
pub const SGX_KEYID_SIZE: size_t = 32;
|
||||
pub const SGX_CPUSVN_SIZE: size_t = 16;
|
||||
pub const SGX_CONFIGID_SIZE: size_t = 64;
|
||||
pub const SGX_KEY_REQUEST_RESERVED2_BYTES: size_t = 434;
|
||||
|
||||
pub enum SealingKeyPolicy {
|
||||
MrSigner,
|
||||
MrEnclave,
|
||||
}
|
||||
|
||||
pub type Sgx128BitKey = sgx_key_128bit_t;
|
||||
|
||||
pub struct Quote {
|
||||
buf: Vec<u8>,
|
||||
report_body: *const sgx_report_body_t,
|
||||
pub(crate) report_body: *const sgx_report_body_t,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for Quote {
|
||||
type Error = RaTlsError;
|
||||
type Error = SgxError;
|
||||
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>();
|
||||
@ -65,7 +20,7 @@ impl TryFrom<Vec<u8>> for Quote {
|
||||
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!(
|
||||
return Err(SgxError::QuoteError(format!(
|
||||
"Failed to parse DCAP quote, min {minimal}, act {actual}"
|
||||
)));
|
||||
}
|
||||
@ -88,7 +43,7 @@ struct QuoteHeader {
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Quote {
|
||||
type Error = RaTlsError;
|
||||
type Error = SgxError;
|
||||
|
||||
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
|
||||
buf.to_vec().try_into()
|
||||
@ -96,7 +51,7 @@ impl TryFrom<&[u8]> for Quote {
|
||||
}
|
||||
|
||||
impl TryFrom<ReportData> for Quote {
|
||||
type Error = RaTlsError;
|
||||
type Error = SgxError;
|
||||
|
||||
fn try_from(value: ReportData) -> Result<Self, Self::Error> {
|
||||
Self::from_report_data(value)
|
||||
@ -112,7 +67,7 @@ impl Deref for Quote {
|
||||
}
|
||||
|
||||
impl Quote {
|
||||
pub fn from_report_data(data: ReportData) -> Result<Self, RaTlsError> {
|
||||
pub fn from_report_data(data: ReportData) -> Result<Self, SgxError> {
|
||||
IOCTL_CLIENT
|
||||
.lock()
|
||||
.unwrap()
|
||||
@ -120,7 +75,7 @@ impl Quote {
|
||||
.try_into()
|
||||
}
|
||||
|
||||
pub fn from_slice(slice: &[u8]) -> Result<Self, RaTlsError> {
|
||||
pub fn from_slice(slice: &[u8]) -> Result<Self, SgxError> {
|
||||
slice.try_into()
|
||||
}
|
||||
|
||||
@ -128,7 +83,7 @@ impl Quote {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn verify(&self) -> Result<VerifyResult, RaTlsError> {
|
||||
pub fn verify(&self) -> Result<VerifyResult, SgxError> {
|
||||
IOCTL_CLIENT.lock().unwrap().verify_quote(self.buf.as_ref())
|
||||
}
|
||||
|
||||
@ -181,8 +136,8 @@ impl Debug for Quote {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref IOCTL_CLIENT: Mutex<IoctlClient> = {
|
||||
let client = IoctlClient::new();
|
||||
pub static ref IOCTL_CLIENT: Mutex<SgxIoctlClient> = {
|
||||
let client = SgxIoctlClient::new();
|
||||
Mutex::new(client)
|
||||
};
|
||||
}
|
||||
@ -194,200 +149,11 @@ lazy_static! {
|
||||
// unsafe impl Send for Quote {}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref STATIC_QUOTE: Result<Quote, RaTlsError> = Quote::from_report_data([0u8; 64]);
|
||||
pub static ref STATIC_QUOTE: Result<Quote, SgxError> = Quote::from_report_data([0u8; 64]);
|
||||
}
|
||||
|
||||
unsafe impl Sync for Quote {}
|
||||
|
||||
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 handle.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.handle()?) };
|
||||
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.supplemental_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())
|
||||
}
|
||||
|
||||
/// Generate a sealing key for the given policy and SGX report
|
||||
/// The sealing key is used to encrypt/decrypt data in the enclave
|
||||
/// The quote must be previously generated using the `generate_quote`
|
||||
pub fn generate_sealing_key(
|
||||
&mut self,
|
||||
quote: &Quote,
|
||||
policy: SealingKeyPolicy,
|
||||
) -> Result<Sgx128BitKey, RaTlsError> {
|
||||
let report_body = unsafe { *quote.report_body };
|
||||
let mut key_policy = match policy {
|
||||
SealingKeyPolicy::MrSigner => SGX_KEYPOLICY_MRSIGNER,
|
||||
SealingKeyPolicy::MrEnclave => SGX_KEYPOLICY_MRENCLAVE,
|
||||
};
|
||||
|
||||
if (report_body.attributes.flags & SGX_FLAGS_KSS) != 0 {
|
||||
const KEY_POLICY_KSS: uint16_t =
|
||||
SGX_KEYPOLICY_CONFIGID | SGX_KEYPOLICY_ISVFAMILYID | SGX_KEYPOLICY_ISVEXTPRODID;
|
||||
key_policy = key_policy | KEY_POLICY_KSS;
|
||||
}
|
||||
|
||||
// Intel sgx sdk 1.8
|
||||
let attribute_mask = sgx_attributes_t {
|
||||
flags: TSEAL_DEFAULT_FLAGSMASK,
|
||||
xfrm: 0,
|
||||
};
|
||||
|
||||
let mut key_id = sgx_key_id_t::default();
|
||||
|
||||
let misc_mask: sgx_misc_select_t = TSEAL_DEFAULT_MISCMASK;
|
||||
|
||||
let mut key = sgx_key_128bit_t::default();
|
||||
let key_request = sgx_key_request_t {
|
||||
key_name: SGX_KEYSELECT_SEAL,
|
||||
key_policy,
|
||||
isv_svn: report_body.isv_svn,
|
||||
reserved1: 0_u16,
|
||||
cpu_svn: report_body.cpu_svn,
|
||||
attribute_mask,
|
||||
key_id,
|
||||
misc_mask,
|
||||
config_svn: report_body.config_svn,
|
||||
reserved2: [0_u8; SGX_KEY_REQUEST_RESERVED2_BYTES],
|
||||
};
|
||||
|
||||
let ret_code = unsafe { dcap_generate_key(self.handle()?, &mut key, &key_request) };
|
||||
if ret_code < 0 {
|
||||
return Err(RaTlsError::DcapError(
|
||||
"Failed to generate DCAP sealing key".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(key)
|
||||
}
|
||||
}
|
||||
|
||||
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)]
|
||||
|
@ -2,7 +2,7 @@ use std::error::Error;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
use crate::utils::hash_sha512;
|
||||
use crate::{error::RaTlsError, RaTlsConfig};
|
||||
use crate::{error::SgxError, RaTlsConfig};
|
||||
use log::error;
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
@ -18,7 +18,7 @@ use rustls::{pki_types::CertificateDer, sign::CertifiedKey};
|
||||
use x509_parser::{nom::Parser, oid_registry::Oid, prelude::X509CertificateParser, public_key};
|
||||
|
||||
pub trait CertificateBuilder: Send + Sync {
|
||||
fn build(&self) -> Result<CertifiedKey, RaTlsError>;
|
||||
fn build(&self) -> Result<CertifiedKey, SgxError>;
|
||||
}
|
||||
|
||||
struct RaTlsCertifiedKey {
|
||||
@ -86,16 +86,16 @@ impl RaTlsCertificateBuilder {
|
||||
}
|
||||
|
||||
impl CertificateBuilder for RaTlsCertificateBuilder {
|
||||
fn build(&self) -> Result<CertifiedKey, RaTlsError> {
|
||||
fn build(&self) -> Result<CertifiedKey, SgxError> {
|
||||
let cert_key = self.build_internal().map_err(|e| {
|
||||
let err = RaTlsError::CertificateBuildError(e.to_string());
|
||||
let err = SgxError::CertificateBuildError(e.to_string());
|
||||
error!("{}", err);
|
||||
err
|
||||
})?;
|
||||
|
||||
let private_key_der = PrivateKeyDer::from(PrivatePkcs8KeyDer::from(cert_key.key_der));
|
||||
let signing_key = any_supported_type(&private_key_der).map_err(|e| {
|
||||
let err = RaTlsError::CertificateBuildError(e.to_string());
|
||||
let err = SgxError::CertificateBuildError(e.to_string());
|
||||
error!("{}", err);
|
||||
err
|
||||
})?;
|
||||
|
@ -1,2 +0,0 @@
|
||||
#[cfg(feature = "occlum")]
|
||||
use crate::quote::{Quote, STATIC_QUOTE};
|
21
src/sealing/decrypt.rs
Normal file
21
src/sealing/decrypt.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit, Nonce};
|
||||
|
||||
use super::SgxSealing;
|
||||
use crate::SgxError;
|
||||
|
||||
impl SgxSealing {
|
||||
pub fn un_seal_data(self, payload_encrypted_packet: Vec<u8>) -> Result<Vec<u8>, SgxError> {
|
||||
let sealing_key = self.get_aes256_sealing_key()?;
|
||||
|
||||
let aes_encryption_256bit_key = Key::<Aes256Gcm>::from_slice(&sealing_key);
|
||||
let nonce = Nonce::from_slice(&payload_encrypted_packet[..12]); // nonce (IV) 96-bits (12); is prepending while encryping
|
||||
let raw_cipher_text = &payload_encrypted_packet[12..];
|
||||
|
||||
let cipher = Aes256Gcm::new(aes_encryption_256bit_key);
|
||||
let clear_text = cipher
|
||||
.decrypt(nonce, raw_cipher_text.as_ref())
|
||||
.map_err(|e| SgxError::UnSealingError(e.to_string()))?;
|
||||
|
||||
Ok(clear_text)
|
||||
}
|
||||
}
|
26
src/sealing/encrypt.rs
Normal file
26
src/sealing/encrypt.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use aes_gcm::{
|
||||
aead::{Aead, AeadCore, OsRng},
|
||||
Aes256Gcm, Key, KeyInit,
|
||||
};
|
||||
|
||||
use super::SgxSealing;
|
||||
use crate::SgxError;
|
||||
|
||||
impl SgxSealing {
|
||||
pub fn seal_data(self, payload_plain_text: Vec<u8>) -> Result<Vec<u8>, SgxError> {
|
||||
let sealing_key = self.get_aes256_sealing_key()?;
|
||||
|
||||
let aes_encryption_256bit_key = Key::<Aes256Gcm>::from_slice(&sealing_key);
|
||||
let nonce = Aes256Gcm::generate_nonce(&mut OsRng); // 96-bits (12); unique per message
|
||||
|
||||
let cipher = Aes256Gcm::new(aes_encryption_256bit_key);
|
||||
let mut ciphertext = cipher
|
||||
.encrypt(&nonce, payload_plain_text.as_ref())
|
||||
.map_err(|e| SgxError::SealingError(e.to_string()))?;
|
||||
|
||||
let mut encrypted_packet = nonce.to_vec();
|
||||
encrypted_packet.append(&mut ciphertext);
|
||||
|
||||
Ok(encrypted_packet)
|
||||
}
|
||||
}
|
19
src/sealing/key_derivation.rs
Normal file
19
src/sealing/key_derivation.rs
Normal file
@ -0,0 +1,19 @@
|
||||
use pbkdf2::pbkdf2_hmac_array;
|
||||
use sha2::Sha256;
|
||||
|
||||
use super::SgxSealing;
|
||||
use crate::SgxError;
|
||||
|
||||
pub type SealingKey256BitDerived = [u8; 32];
|
||||
|
||||
impl SgxSealing {
|
||||
pub fn get_aes256_sealing_key(self) -> Result<SealingKey256BitDerived, SgxError> {
|
||||
let mrsigner_for_salt = Self::get_current_sgx_quote()?.mrsigner().m;
|
||||
|
||||
Ok(pbkdf2_hmac_array::<Sha256, 32>(
|
||||
&self.sealing_key,
|
||||
&mrsigner_for_salt,
|
||||
25519,
|
||||
))
|
||||
}
|
||||
}
|
8
src/sealing/mod.rs
Normal file
8
src/sealing/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
mod decrypt;
|
||||
mod encrypt;
|
||||
pub mod key_derivation;
|
||||
pub mod sealing_config;
|
||||
pub mod sealing_error;
|
||||
|
||||
pub use sealing_config::SealingConfig;
|
||||
pub use sealing_error::SealingError;
|
107
src/sealing/sgx_sealing.rs
Normal file
107
src/sealing/sgx_sealing.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use crate::bindings::*;
|
||||
use crate::error::SgxError;
|
||||
use crate::ioctl::SgxIoctlClient;
|
||||
#[cfg(feature = "occlum")]
|
||||
use crate::quote::{Quote, IOCTL_CLIENT, STATIC_QUOTE};
|
||||
use crate::sgx_consts::{
|
||||
SGX_FLAGS_KSS, SGX_KEYPOLICY_CONFIGID, SGX_KEYPOLICY_ISVEXTPRODID, SGX_KEYPOLICY_ISVFAMILYID,
|
||||
SGX_KEYPOLICY_MRENCLAVE, SGX_KEYPOLICY_MRSIGNER, SGX_KEYSELECT_SEAL,
|
||||
SGX_KEY_REQUEST_RESERVED2_BYTES, TSEAL_DEFAULT_FLAGSMASK, TSEAL_DEFAULT_MISCMASK,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum SealingKeyPolicy {
|
||||
MrSigner,
|
||||
MrEnclave,
|
||||
}
|
||||
|
||||
pub type Sgx128BitKey = sgx_key_128bit_t;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SgxSealing {
|
||||
#[cfg(feature = "occlum")]
|
||||
pub sealing_key: Sgx128BitKey,
|
||||
}
|
||||
|
||||
impl SgxSealing {
|
||||
#[cfg(feature = "occlum")]
|
||||
pub(crate) fn get_current_sgx_quote() -> Result<&'static Quote, SgxError> {
|
||||
Ok(STATIC_QUOTE.as_ref().map_err(|e| e.clone())?)
|
||||
}
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
pub fn new() -> Result<Self, SgxError> {
|
||||
// by default, use MrEnclave key policy
|
||||
Self::with_policy(SealingKeyPolicy::MrEnclave)
|
||||
}
|
||||
|
||||
pub fn with_policy(policy: SealingKeyPolicy) -> Result<Self, SgxError> {
|
||||
let quote = Self::get_current_sgx_quote()?;
|
||||
let sealing_key = IOCTL_CLIENT
|
||||
.lock()
|
||||
.unwrap()
|
||||
.generate_sealing_key(quote, policy)?;
|
||||
Ok(Self { sealing_key })
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "occlum"))]
|
||||
pub fn new() -> Result<Self, SgxError> {
|
||||
Ok(Self {})
|
||||
}
|
||||
}
|
||||
|
||||
impl SgxIoctlClient {
|
||||
/// Generate a sealing key for the given policy and SGX report
|
||||
/// The sealing key is used to encrypt/decrypt data in the enclave
|
||||
/// The quote must be previously generated using the `generate_quote`
|
||||
fn generate_sealing_key(
|
||||
&mut self,
|
||||
quote: &Quote,
|
||||
policy: SealingKeyPolicy,
|
||||
) -> Result<Sgx128BitKey, SgxError> {
|
||||
let report_body = unsafe { *quote.report_body };
|
||||
let mut key_policy = match policy {
|
||||
SealingKeyPolicy::MrSigner => SGX_KEYPOLICY_MRSIGNER,
|
||||
SealingKeyPolicy::MrEnclave => SGX_KEYPOLICY_MRENCLAVE,
|
||||
};
|
||||
|
||||
if (report_body.attributes.flags & SGX_FLAGS_KSS) != 0 {
|
||||
const KEY_POLICY_KSS: uint16_t =
|
||||
SGX_KEYPOLICY_CONFIGID | SGX_KEYPOLICY_ISVFAMILYID | SGX_KEYPOLICY_ISVEXTPRODID;
|
||||
key_policy = key_policy | KEY_POLICY_KSS;
|
||||
}
|
||||
|
||||
// Intel sgx sdk 1.8
|
||||
let attribute_mask = sgx_attributes_t {
|
||||
flags: TSEAL_DEFAULT_FLAGSMASK,
|
||||
xfrm: 0,
|
||||
};
|
||||
|
||||
let key_id = sgx_key_id_t::default();
|
||||
|
||||
let misc_mask: sgx_misc_select_t = TSEAL_DEFAULT_MISCMASK;
|
||||
|
||||
let mut key = sgx_key_128bit_t::default();
|
||||
let key_request = sgx_key_request_t {
|
||||
key_name: SGX_KEYSELECT_SEAL,
|
||||
key_policy,
|
||||
isv_svn: report_body.isv_svn,
|
||||
reserved1: 0_u16,
|
||||
cpu_svn: report_body.cpu_svn,
|
||||
attribute_mask,
|
||||
key_id,
|
||||
misc_mask,
|
||||
config_svn: report_body.config_svn,
|
||||
reserved2: [0_u8; SGX_KEY_REQUEST_RESERVED2_BYTES],
|
||||
};
|
||||
|
||||
let ret_code = unsafe { utils_gen_key(self.handle()?, &mut key, &key_request) };
|
||||
if ret_code < 0 {
|
||||
return Err(SgxError::DcapError(
|
||||
"Failed to generate DCAP sealing key".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(key)
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder},
|
||||
RaTlsConfig, RaTlsConfigBuilder, RaTlsError,
|
||||
RaTlsConfig, RaTlsConfigBuilder, SgxError,
|
||||
};
|
||||
use rustls::client::danger::HandshakeSignatureValid;
|
||||
use rustls::crypto::{aws_lc_rs, verify_tls12_signature, verify_tls13_signature, CryptoProvider};
|
||||
@ -81,7 +81,7 @@ pub struct RaTlsServerCertResolver {
|
||||
}
|
||||
|
||||
impl RaTlsServerCertResolver {
|
||||
pub fn new() -> Result<Self, RaTlsError> {
|
||||
pub fn new() -> Result<Self, SgxError> {
|
||||
let builder = RaTlsCertificateBuilder::new().with_common_name("Client".to_string());
|
||||
let cert = builder.build().map(Arc::new)?;
|
||||
Ok(Self { cert })
|
||||
@ -95,7 +95,7 @@ impl ResolvesServerCert for RaTlsServerCertResolver {
|
||||
}
|
||||
|
||||
impl RaTlsConfigBuilder<ServerConfig> for ServerConfig {
|
||||
fn from_ratls_config(config: RaTlsConfig) -> Result<Self, RaTlsError> {
|
||||
fn from_ratls_config(config: RaTlsConfig) -> Result<Self, SgxError> {
|
||||
Ok(Self::builder()
|
||||
.with_client_cert_verifier(Arc::new(RaTlsClientCertVerifier::new(config)))
|
||||
.with_cert_resolver(Arc::new(RaTlsServerCertResolver::new()?)))
|
||||
|
38
src/sgx_consts.rs
Normal file
38
src/sgx_consts.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::bindings::*;
|
||||
|
||||
pub const SGX_FLAGS_INITTED: uint64_t = 0x0000_0000_0000_0001; //If set, then the enclave is initialized
|
||||
pub const SGX_FLAGS_DEBUG: uint64_t = 0x0000_0000_0000_0002; //If set, then the enclave is debug
|
||||
pub const SGX_FLAGS_MODE64BIT: uint64_t = 0x0000_0000_0000_0004; //If set, then the enclave is 64 bit
|
||||
pub const SGX_FLAGS_PROVISION_KEY: uint64_t = 0x0000_0000_0000_0010; //If set, then the enclave has access to provision key
|
||||
pub const SGX_FLAGS_EINITTOKEN_KEY: uint64_t = 0x0000_0000_0000_0020; //If set, then the enclave has access to EINITTOKEN key
|
||||
pub const SGX_FLAGS_KSS: uint64_t = 0x0000_0000_0000_0080; //If set enclave uses KSS
|
||||
pub const SGX_FLAGS_AEX_NOTIFY: uint64_t = 0x0000_0000_0000_0400; //If set, then the enclave enables AEX Notify
|
||||
pub const FLAGS_NON_SECURITY_BITS: uint64_t = 0x00FF_FFFF_FFFF_FFC0
|
||||
| SGX_FLAGS_MODE64BIT
|
||||
| SGX_FLAGS_PROVISION_KEY
|
||||
| SGX_FLAGS_EINITTOKEN_KEY;
|
||||
pub const TSEAL_DEFAULT_FLAGSMASK: uint64_t = !FLAGS_NON_SECURITY_BITS;
|
||||
pub const FLAGS_SECURITY_BITS_RESERVED: uint64_t =
|
||||
!(FLAGS_NON_SECURITY_BITS | SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG | SGX_FLAGS_KSS);
|
||||
pub const MISC_NON_SECURITY_BITS: uint32_t = 0x0FFF_FFFF;
|
||||
pub const TSEAL_DEFAULT_MISCMASK: uint32_t = !MISC_NON_SECURITY_BITS;
|
||||
|
||||
// TODO Intel sgx sdk 2.4
|
||||
pub const SGX_KEYSELECT_LICENSE: uint16_t = 0x0000;
|
||||
pub const SGX_KEYSELECT_PROVISION: uint16_t = 0x0001;
|
||||
pub const SGX_KEYSELECT_PROVISION_SEAL: uint16_t = 0x0002;
|
||||
pub const SGX_KEYSELECT_REPORT: uint16_t = 0x0003;
|
||||
pub const SGX_KEYSELECT_SEAL: uint16_t = 0x0004;
|
||||
|
||||
// Key Policy
|
||||
pub const SGX_KEYPOLICY_MRENCLAVE: uint16_t = 0x0001; /* Derive key using the enclave's ENCLAVE measurement register */
|
||||
pub const SGX_KEYPOLICY_MRSIGNER: uint16_t = 0x0002; /* Derive key using the enclave's SINGER measurement register */
|
||||
pub const SGX_KEYPOLICY_NOISVPRODID: uint16_t = 0x0004; /* Derive key without the enclave's ISVPRODID */
|
||||
pub const SGX_KEYPOLICY_CONFIGID: uint16_t = 0x0008; /* Derive key with the enclave's CONFIGID */
|
||||
pub const SGX_KEYPOLICY_ISVFAMILYID: uint16_t = 0x0010; /* Derive key with the enclave's ISVFAMILYID */
|
||||
pub const SGX_KEYPOLICY_ISVEXTPRODID: uint16_t = 0x0020; /* Derive key with the enclave's ISVEXTPRODID */
|
||||
|
||||
pub const SGX_KEYID_SIZE: size_t = 32;
|
||||
pub const SGX_CPUSVN_SIZE: size_t = 16;
|
||||
pub const SGX_CONFIGID_SIZE: size_t = 64;
|
||||
pub const SGX_KEY_REQUEST_RESERVED2_BYTES: size_t = 434;
|
@ -1,67 +0,0 @@
|
||||
// use rustls::{server::{ClientCertVerified, ClientCertVerifier, ResolvesServerCert}, sign::CertifiedKey, Certificate, Error, ServerConfig, DistinguishedNames};
|
||||
// use std::{sync::Arc, time::SystemTime};
|
||||
//
|
||||
// use crate::{
|
||||
// racert::{CertificateBuilder, RaTlsCertificate, RaTlsCertificateBuilder},
|
||||
// RaTlsConfig, RaTlsConfigBuilder, RaTlsError,
|
||||
// };
|
||||
//
|
||||
// pub struct RaTlsClientCertVerifier {
|
||||
// config: RaTlsConfig,
|
||||
// }
|
||||
//
|
||||
// impl RaTlsClientCertVerifier {
|
||||
// pub fn new(config: RaTlsConfig) -> Self {
|
||||
// Self { config }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl ClientCertVerifier for RaTlsClientCertVerifier {
|
||||
// fn verify_client_cert(
|
||||
// &self,
|
||||
// end_entity: &Certificate,
|
||||
// _intermediates: &[Certificate],
|
||||
// _now: SystemTime,
|
||||
// ) -> Result<ClientCertVerified, Error> {
|
||||
// end_entity.verify_quote(&self.config).map_err(|e| {
|
||||
// println!("{:?}", e);
|
||||
// rustls::Error::General(e.to_string())
|
||||
// })?;
|
||||
//
|
||||
// Ok(ClientCertVerified::assertion())
|
||||
// }
|
||||
//
|
||||
// fn client_auth_root_subjects(&self) -> Option<DistinguishedNames> {
|
||||
// Some(DistinguishedNames::new())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub struct RaTlsServerCertResolver {
|
||||
// cert: Arc<CertifiedKey>,
|
||||
// }
|
||||
//
|
||||
// impl RaTlsServerCertResolver {
|
||||
// pub fn new() -> Result<Self, RaTlsError> {
|
||||
// let builder = RaTlsCertificateBuilder::new().with_common_name("Client".to_string());
|
||||
// let cert = builder.build().map(Arc::new)?;
|
||||
// Ok(Self { cert })
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl ResolvesServerCert for RaTlsServerCertResolver {
|
||||
// fn resolve(
|
||||
// &self,
|
||||
// _client_hello: rustls::server::ClientHello,
|
||||
// ) -> Option<std::sync::Arc<CertifiedKey>> {
|
||||
// Some(self.cert.clone())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl RaTlsConfigBuilder<ServerConfig> for ServerConfig {
|
||||
// fn from_ratls_config(config: RaTlsConfig) -> Result<Self, RaTlsError> {
|
||||
// Ok(Self::builder()
|
||||
// .with_safe_defaults()
|
||||
// .with_client_cert_verifier(Arc::new(RaTlsClientCertVerifier::new(config)))
|
||||
// .with_cert_resolver(Arc::new(RaTlsServerCertResolver::new()?)))
|
||||
// }
|
||||
// }
|
Loading…
Reference in New Issue
Block a user