Add ioctls on /dev/sgx for SGX remote attestation
1. Add ioctl command `SGXIOC_GET_EPID_GROUP_ID` for /dev/sgx 2. Add ioctl command `SGXIOC_GEN_QUOTE` for /dev/sgx 3. Add test cases
This commit is contained in:
parent
7024fa81ec
commit
3c1378b7eb
@ -1,11 +1,13 @@
|
|||||||
enclave {
|
enclave {
|
||||||
from "sgx_stdio.edl" import *;
|
|
||||||
from "sgx_backtrace.edl" import *;
|
from "sgx_backtrace.edl" import *;
|
||||||
|
from "sgx_stdio.edl" import *;
|
||||||
from "sgx_tstdc.edl" import *;
|
from "sgx_tstdc.edl" import *;
|
||||||
from "sgx_tstd.edl" import *;
|
from "sgx_tstd.edl" import *;
|
||||||
from "sgx_tprotected_fs.edl" import *;
|
from "sgx_tprotected_fs.edl" import *;
|
||||||
from "sgx_net.edl" import *;
|
from "sgx_net.edl" import *;
|
||||||
|
|
||||||
|
include "sgx_quote.h"
|
||||||
|
|
||||||
trusted {
|
trusted {
|
||||||
/* define ECALLs here. */
|
/* define ECALLs here. */
|
||||||
public int libos_boot([in, string] const char* executable_path, [user_check] const char** argv);
|
public int libos_boot([in, string] const char* executable_path, [user_check] const char** argv);
|
||||||
@ -24,5 +26,19 @@ enclave {
|
|||||||
void ocall_sched_yield(void);
|
void ocall_sched_yield(void);
|
||||||
int ocall_sched_getaffinity([out] int *error, int pid, size_t cpusize, [out, size=cpusize] unsigned char* buf);
|
int ocall_sched_getaffinity([out] int *error, int pid, size_t cpusize, [out, size=cpusize] unsigned char* buf);
|
||||||
int ocall_sched_setaffinity([out] int *error, int pid, size_t cpusize, [in, size=cpusize] const unsigned char* buf);
|
int ocall_sched_setaffinity([out] int *error, int pid, size_t cpusize, [in, size=cpusize] const unsigned char* buf);
|
||||||
|
|
||||||
|
sgx_status_t ocall_sgx_init_quote(
|
||||||
|
[out] sgx_target_info_t *target_info,
|
||||||
|
[out] sgx_epid_group_id_t *epid_group_id);
|
||||||
|
sgx_status_t ocall_sgx_get_quote(
|
||||||
|
[in, size=sigrl_len] uint8_t* sigrl,
|
||||||
|
uint32_t sigrl_len,
|
||||||
|
[in] sgx_report_t* report,
|
||||||
|
sgx_quote_sign_type_t quote_type,
|
||||||
|
[in] sgx_spid_t* spid,
|
||||||
|
[in] sgx_quote_nonce_t* nonce,
|
||||||
|
[out] sgx_report_t* qe_report,
|
||||||
|
[out, size=quote_buf_len] uint8_t* quote_buf,
|
||||||
|
uint32_t quote_buf_len);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
16
src/libos/Cargo.lock
generated
16
src/libos/Cargo.lock
generated
@ -14,7 +14,9 @@ dependencies = [
|
|||||||
"rcore-fs-sefs 0.1.0",
|
"rcore-fs-sefs 0.1.0",
|
||||||
"serde 1.0.84",
|
"serde 1.0.84",
|
||||||
"serde_json 1.0.36",
|
"serde_json 1.0.36",
|
||||||
|
"sgx_tcrypto 1.0.6",
|
||||||
"sgx_trts 1.0.6",
|
"sgx_trts 1.0.6",
|
||||||
|
"sgx_tse 1.0.6",
|
||||||
"sgx_tstd 1.0.6",
|
"sgx_tstd 1.0.6",
|
||||||
"sgx_types 1.0.6",
|
"sgx_types 1.0.6",
|
||||||
"xmas-elf 0.6.2",
|
"xmas-elf 0.6.2",
|
||||||
@ -354,6 +356,13 @@ dependencies = [
|
|||||||
"sgx_types 1.0.6",
|
"sgx_types 1.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tcrypto"
|
||||||
|
version = "1.0.6"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_types 1.0.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sgx_tprotected_fs"
|
name = "sgx_tprotected_fs"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
@ -370,6 +379,13 @@ dependencies = [
|
|||||||
"sgx_types 1.0.6",
|
"sgx_types 1.0.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sgx_tse"
|
||||||
|
version = "1.0.6"
|
||||||
|
dependencies = [
|
||||||
|
"sgx_types 1.0.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sgx_tstd"
|
name = "sgx_tstd"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -29,3 +29,5 @@ xmas-elf = { path = "../../deps/xmas-elf" }
|
|||||||
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
|
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
|
||||||
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace"] }
|
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace"] }
|
||||||
sgx_trts = { path = "../../deps/rust-sgx-sdk/sgx_trts" }
|
sgx_trts = { path = "../../deps/rust-sgx-sdk/sgx_trts" }
|
||||||
|
sgx_tse = { path = "../../deps/rust-sgx-sdk/sgx_tse" }
|
||||||
|
sgx_tcrypto = { path = "../../deps/rust-sgx-sdk/sgx_tcrypto" }
|
||||||
|
@ -30,7 +30,7 @@ LIBOS_RS_A := $(BUILD_DIR)/lib/libocclum_rs.a
|
|||||||
LIBCOMPILER_RT_PATCH_A := $(BUILD_DIR)/lib/libcompiler-rt-patch.a
|
LIBCOMPILER_RT_PATCH_A := $(BUILD_DIR)/lib/libcompiler-rt-patch.a
|
||||||
|
|
||||||
# All source code
|
# All source code
|
||||||
RUST_SRCS := $(wildcard src/*.rs src/*/*.rs src/*/*/*.rs)
|
RUST_SRCS := $(wildcard src/*.rs src/*/*.rs src/*/*/*.rs src/*/*/*/*.rs)
|
||||||
RUST_TARGET_DIR := $(BUILD_DIR)/src/libos/cargo-target
|
RUST_TARGET_DIR := $(BUILD_DIR)/src/libos/cargo-target
|
||||||
RUST_OUT_DIR := $(BUILD_DIR)/lib
|
RUST_OUT_DIR := $(BUILD_DIR)/lib
|
||||||
EDL_C_SRCS := $(addprefix $(BUILD_DIR)/src/libos/,src/Enclave_t.c src/Enclave_t.h)
|
EDL_C_SRCS := $(addprefix $(BUILD_DIR)/src/libos/,src/Enclave_t.c src/Enclave_t.h)
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DevSgx;
|
|
||||||
|
|
||||||
const SGX_MAGIC_CHAR: u8 = 's' as u8;
|
|
||||||
|
|
||||||
/// Ioctl to check if EDMM (Enclave Dynamic Memory Management) is supported
|
|
||||||
const SGX_CMD_NUM_IS_EDMM_SUPPORTED: u32 =
|
|
||||||
StructuredIoctlNum::new::<i32>(0, SGX_MAGIC_CHAR, StructuredIoctlArgType::Output).as_u32();
|
|
||||||
|
|
||||||
impl File for DevSgx {
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<()> {
|
|
||||||
let nonbuiltin_cmd = match cmd {
|
|
||||||
IoctlCmd::NonBuiltin(nonbuiltin_cmd) => nonbuiltin_cmd,
|
|
||||||
_ => return_errno!(EINVAL, "unknown ioctl cmd for /dev/sgx"),
|
|
||||||
};
|
|
||||||
let cmd_num = nonbuiltin_cmd.cmd_num().as_u32();
|
|
||||||
match cmd_num {
|
|
||||||
SGX_CMD_NUM_IS_EDMM_SUPPORTED => {
|
|
||||||
let arg = nonbuiltin_cmd.arg_mut::<i32>()?;
|
|
||||||
*arg = 0; // no support for now
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return_errno!(EINVAL, "unknown ioctl cmd for /dev/sgx");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
17
src/libos/src/fs/dev_sgx/attestation/mod.rs
Normal file
17
src/libos/src/fs/dev_sgx/attestation/mod.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//! SGX attestation.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use sgx_tse::*;
|
||||||
|
use sgx_types::*;
|
||||||
|
|
||||||
|
mod sgx_attestation_agent;
|
||||||
|
mod sgx_quote;
|
||||||
|
|
||||||
|
pub use sgx_types::{
|
||||||
|
sgx_epid_group_id_t, sgx_quote_nonce_t, sgx_quote_sign_type_t, sgx_quote_t, sgx_report_data_t,
|
||||||
|
sgx_spid_t, sgx_target_info_t,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub use self::sgx_attestation_agent::SgxAttestationAgent;
|
||||||
|
pub use self::sgx_quote::SgxQuote;
|
206
src/libos/src/fs/dev_sgx/attestation/sgx_attestation_agent.rs
Normal file
206
src/libos/src/fs/dev_sgx/attestation/sgx_attestation_agent.rs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
//! SGX EPID group ID retrieval and quote generation.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct SgxAttestationAgent {
|
||||||
|
inner: Option<InnerAgent>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SgxAttestationAgent {
|
||||||
|
pub fn new() -> SgxAttestationAgent {
|
||||||
|
Self { inner: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_epid_group_id(&mut self) -> Result<sgx_epid_group_id_t> {
|
||||||
|
self.init_inner()?;
|
||||||
|
self.inner.as_mut().unwrap().get_epid_group_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_quote(
|
||||||
|
&mut self,
|
||||||
|
sigrl: Option<&[u8]>,
|
||||||
|
report_data: &sgx_report_data_t,
|
||||||
|
quote_type: sgx_quote_sign_type_t,
|
||||||
|
spid: &sgx_spid_t,
|
||||||
|
nonce: &sgx_quote_nonce_t,
|
||||||
|
) -> Result<SgxQuote> {
|
||||||
|
self.init_inner()?;
|
||||||
|
self.inner
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.generate_quote(sigrl, report_data, quote_type, spid, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_inner(&mut self) -> Result<()> {
|
||||||
|
if self.inner.is_none() {
|
||||||
|
let inner = InnerAgent::new()?;
|
||||||
|
self.inner = Some(inner);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerAgent {
|
||||||
|
target_info: sgx_target_info_t,
|
||||||
|
epid_group_id: sgx_epid_group_id_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InnerAgent {
|
||||||
|
pub fn new() -> Result<Self> {
|
||||||
|
let (target_info, epid_group_id) = Self::init_fields()?;
|
||||||
|
Ok(Self {
|
||||||
|
target_info,
|
||||||
|
epid_group_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_fields() -> Result<(sgx_target_info_t, sgx_epid_group_id_t)> {
|
||||||
|
extern "C" {
|
||||||
|
pub fn ocall_sgx_init_quote(
|
||||||
|
retval: *mut sgx_status_t,
|
||||||
|
target_info: *mut sgx_target_info_t,
|
||||||
|
epid_group_id: *mut sgx_epid_group_id_t,
|
||||||
|
) -> sgx_status_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut target_info = Default::default();
|
||||||
|
let mut epid_group_id = Default::default();
|
||||||
|
unsafe {
|
||||||
|
let mut retval = Default::default();
|
||||||
|
let status = ocall_sgx_init_quote(
|
||||||
|
&mut retval as *mut sgx_status_t,
|
||||||
|
&mut target_info as *mut sgx_target_info_t,
|
||||||
|
&mut epid_group_id as *mut sgx_epid_group_id_t,
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
|
||||||
|
if (retval != sgx_status_t::SGX_SUCCESS) {
|
||||||
|
return_errno!(EINVAL, "ocall_sgx_init_quote failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((target_info, epid_group_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_epid_group_id(&self) -> Result<sgx_epid_group_id_t> {
|
||||||
|
Ok(self.epid_group_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_quote(
|
||||||
|
&mut self,
|
||||||
|
sigrl: Option<&[u8]>,
|
||||||
|
report_data: &sgx_report_data_t,
|
||||||
|
quote_type: sgx_quote_sign_type_t,
|
||||||
|
spid: &sgx_spid_t,
|
||||||
|
nonce: &sgx_quote_nonce_t,
|
||||||
|
) -> Result<SgxQuote> {
|
||||||
|
extern "C" {
|
||||||
|
pub fn ocall_sgx_get_quote(
|
||||||
|
retval: *mut sgx_status_t, // Output
|
||||||
|
sigrl: *const u8, // Input (optional)
|
||||||
|
sigrl_len: u32, // Input (optional)
|
||||||
|
report: *const sgx_report_t, // Input
|
||||||
|
quote_type: sgx_quote_sign_type_t, // Input
|
||||||
|
spid: *const sgx_spid_t, // Input
|
||||||
|
nonce: *const sgx_quote_nonce_t, // Input
|
||||||
|
qe_report: *mut sgx_report_t, // Output
|
||||||
|
quote_buf_ptr: *mut u8, // Output
|
||||||
|
quote_buf_len: u32, // Input
|
||||||
|
) -> sgx_status_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare argments for OCall
|
||||||
|
let (sigrl_ptr, sigrl_size): (*const u8, u32) = {
|
||||||
|
match sigrl {
|
||||||
|
Some(sigrl) => {
|
||||||
|
let sigrl_ptr = sigrl.as_ptr();
|
||||||
|
let sigrl_size = {
|
||||||
|
// FIXME: u32::MAX is not provided by Rust SGX SDK
|
||||||
|
/*
|
||||||
|
if sigrl.len() > u32::MAX {
|
||||||
|
return_errno!(EINVAL, "sigrl is too large");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
sigrl.len() as u32
|
||||||
|
};
|
||||||
|
(sigrl_ptr, sigrl_size)
|
||||||
|
}
|
||||||
|
None => (std::ptr::null(), 0),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let report = rsgx_create_report(&self.target_info, report_data)
|
||||||
|
.map_err(|_e| errno!(EINVAL, "sgx_error"))?;
|
||||||
|
let mut qe_report = sgx_report_t::default();
|
||||||
|
// TODO: what if quote_buf is not big enough?
|
||||||
|
let mut quote_buf = [0_u8; 4096];
|
||||||
|
|
||||||
|
// Do OCall
|
||||||
|
unsafe {
|
||||||
|
let mut retval = Default::default();
|
||||||
|
let status = ocall_sgx_get_quote(
|
||||||
|
&mut retval as *mut sgx_status_t,
|
||||||
|
sigrl_ptr,
|
||||||
|
sigrl_size,
|
||||||
|
&report as *const sgx_report_t,
|
||||||
|
quote_type,
|
||||||
|
spid as *const sgx_spid_t,
|
||||||
|
nonce as *const sgx_quote_nonce_t,
|
||||||
|
&mut qe_report as *mut sgx_report_t,
|
||||||
|
quote_buf.as_mut_ptr() as *mut u8,
|
||||||
|
quote_buf.len() as u32,
|
||||||
|
);
|
||||||
|
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||||
|
|
||||||
|
if retval != sgx_status_t::SGX_SUCCESS {
|
||||||
|
match retval {
|
||||||
|
sgx_status_t::SGX_ERROR_BUSY => {
|
||||||
|
return_errno!(EBUSY, "ocall_sgx_get_quote is temporarily busy")
|
||||||
|
}
|
||||||
|
_ => return_errno!(EINVAL, "ocall_sgx_get_quote failed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the QE report is valid
|
||||||
|
SgxQeReportValidator::new(&self.target_info, nonce).validate(&qe_report)?;
|
||||||
|
|
||||||
|
// Construct the resulting quote
|
||||||
|
let quote = SgxQuote::new("e_buf, &nonce, &qe_report)?;
|
||||||
|
|
||||||
|
Ok(quote)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validating SGX Quoting Enclave (QE) report.
|
||||||
|
struct SgxQeReportValidator<'a> {
|
||||||
|
target_info: &'a sgx_target_info_t,
|
||||||
|
nonce: &'a sgx_quote_nonce_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SgxQeReportValidator<'a> {
|
||||||
|
pub fn new(target_info: &'a sgx_target_info_t, nonce: &'a sgx_quote_nonce_t) -> Self {
|
||||||
|
SgxQeReportValidator { target_info, nonce }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate(&self, qe_report: &sgx_report_t) -> Result<()> {
|
||||||
|
self.validate_integrity(qe_report)?;
|
||||||
|
self.validate_platform(qe_report)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_integrity(&self, qe_report: &sgx_report_t) -> Result<()> {
|
||||||
|
rsgx_verify_report(qe_report)
|
||||||
|
.map_err(|_e| errno!(EINVAL, "quote report is NOT authentic"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_platform(&self, qe_report: &sgx_report_t) -> Result<()> {
|
||||||
|
if self.target_info.mr_enclave.m != qe_report.body.mr_enclave.m
|
||||||
|
|| self.target_info.attributes.flags != qe_report.body.attributes.flags
|
||||||
|
|| self.target_info.attributes.xfrm != qe_report.body.attributes.xfrm
|
||||||
|
{
|
||||||
|
return_errno!(EINVAL, "quote report is NOT produced on the same platform");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
84
src/libos/src/fs/dev_sgx/attestation/sgx_quote.rs
Normal file
84
src/libos/src/fs/dev_sgx/attestation/sgx_quote.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//! SGX Quote in a memory safe representation and with hash validation.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct SgxQuote {
|
||||||
|
quote_buf: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SgxQuote {
|
||||||
|
pub fn new(
|
||||||
|
quote_raw_buf: &[u8],
|
||||||
|
quote_nonce: &sgx_quote_nonce_t,
|
||||||
|
qe_report: &sgx_report_t,
|
||||||
|
) -> Result<SgxQuote> {
|
||||||
|
let quote_buf = Self::new_buf(quote_raw_buf)?;
|
||||||
|
Self::validate_quote_buf("e_buf, quote_nonce, qe_report)?;
|
||||||
|
Ok(SgxQuote { quote_buf })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_buf(quote_raw_buf: &[u8]) -> Result<Vec<u8>> {
|
||||||
|
if quote_raw_buf.len() < std::mem::size_of::<sgx_quote_t>() {
|
||||||
|
return_errno!(EINVAL, "buffer is too small for SGX quote itself");
|
||||||
|
}
|
||||||
|
let quote = unsafe { &*(quote_raw_buf.as_ptr() as *const sgx_quote_t) };
|
||||||
|
let quote_size = std::mem::size_of::<sgx_quote_t>() + quote.signature_len as usize;
|
||||||
|
if quote_size > quote_raw_buf.len() {
|
||||||
|
return_errno!(EINVAL, "buffer is too small for SGX quote with signature");
|
||||||
|
}
|
||||||
|
let quote_buf = quote_raw_buf[..quote_size].to_vec();
|
||||||
|
Ok(quote_buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_quote_buf(
|
||||||
|
quote_buf: &[u8],
|
||||||
|
quote_nonce: &sgx_quote_nonce_t,
|
||||||
|
qe_report: &sgx_report_t,
|
||||||
|
) -> Result<()> {
|
||||||
|
// According to Intel manual:
|
||||||
|
// The purpose of QE report (`qe_report`) is for the ISV enclave to confirm the
|
||||||
|
// quote (i.e., `quote_buf`) received is not modified by the untrusted SW stack,
|
||||||
|
// and not a replay. The implementation in QE is to generate a report targeting
|
||||||
|
// the ISV enclave (i.e., Occlum's enclave), with the lower 32 bytes in
|
||||||
|
// QE report (i.e., `qe_reprot.data.d[..32]`) equivalent to SHA256(quote_nonce||quote_buf).
|
||||||
|
let expected_hash = &qe_report.body.report_data.d[..32];
|
||||||
|
let actual_hash = {
|
||||||
|
let mut quote_nonce_and_buf: Vec<u8> = quote_nonce
|
||||||
|
.rand
|
||||||
|
.iter()
|
||||||
|
.chain(quote_buf.iter())
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
sgx_tcrypto::rsgx_sha256_slice("e_nonce_and_buf).unwrap()
|
||||||
|
};
|
||||||
|
if expected_hash != actual_hash {
|
||||||
|
return_errno!(EINVAL, "invalid quote (unexpected hash)");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fields(&self) -> &sgx_quote_t {
|
||||||
|
unsafe { &*(self.quote_buf.as_ptr() as *const sgx_quote_t) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_signature(&self) -> &[u8] {
|
||||||
|
&self.quote_buf[std::mem::size_of::<sgx_quote_t>()..]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> usize {
|
||||||
|
self.quote_buf.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump_to_buf(&self, dst_buf: &mut [u8]) -> Result<()> {
|
||||||
|
let src_buf = &self.quote_buf;
|
||||||
|
if src_buf.len() > dst_buf.len() {
|
||||||
|
return_errno!(
|
||||||
|
EINVAL,
|
||||||
|
"the given output buffer for quote is NOT big enough"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dst_buf[..src_buf.len()].copy_from_slice(src_buf);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
22
src/libos/src/fs/dev_sgx/consts.rs
Normal file
22
src/libos/src/fs/dev_sgx/consts.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Ioctl to check if EDMM (Enclave Dynamic Memory Management) is supported
|
||||||
|
pub const SGX_CMD_NUM_IS_EDMM_SUPPORTED: u32 =
|
||||||
|
StructuredIoctlNum::new::<i32>(0, SGX_MAGIC_CHAR, StructuredIoctlArgType::Output).as_u32();
|
||||||
|
/// Ioctl to get the EPID group ID
|
||||||
|
pub const SGX_CMD_NUM_GET_EPID_GROUP_ID: u32 = StructuredIoctlNum::new::<sgx_epid_group_id_t>(
|
||||||
|
1,
|
||||||
|
SGX_MAGIC_CHAR,
|
||||||
|
StructuredIoctlArgType::Output,
|
||||||
|
)
|
||||||
|
.as_u32();
|
||||||
|
/// Ioctl to get quote
|
||||||
|
pub const SGX_CMD_NUM_GEN_QUOTE: u32 = StructuredIoctlNum::new::<IoctlGenQuoteArg>(
|
||||||
|
2,
|
||||||
|
SGX_MAGIC_CHAR,
|
||||||
|
StructuredIoctlArgType::InputOutput,
|
||||||
|
)
|
||||||
|
.as_u32();
|
||||||
|
|
||||||
|
/// A magical number that distinguishes SGX ioctls for other ioctls
|
||||||
|
const SGX_MAGIC_CHAR: u8 = 's' as u8;
|
92
src/libos/src/fs/dev_sgx/mod.rs
Normal file
92
src/libos/src/fs/dev_sgx/mod.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
//! SGX Device (/dev/sgx).
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
mod attestation;
|
||||||
|
mod consts;
|
||||||
|
|
||||||
|
use self::attestation::*;
|
||||||
|
use self::consts::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DevSgx;
|
||||||
|
|
||||||
|
impl File for DevSgx {
|
||||||
|
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<()> {
|
||||||
|
let nonbuiltin_cmd = match cmd {
|
||||||
|
IoctlCmd::NonBuiltin(nonbuiltin_cmd) => nonbuiltin_cmd,
|
||||||
|
_ => return_errno!(EINVAL, "unknown ioctl cmd for /dev/sgx"),
|
||||||
|
};
|
||||||
|
let cmd_num = nonbuiltin_cmd.cmd_num().as_u32();
|
||||||
|
match cmd_num {
|
||||||
|
SGX_CMD_NUM_IS_EDMM_SUPPORTED => {
|
||||||
|
let arg = nonbuiltin_cmd.arg_mut::<i32>()?;
|
||||||
|
*arg = 0; // no support for now
|
||||||
|
}
|
||||||
|
SGX_CMD_NUM_GET_EPID_GROUP_ID => {
|
||||||
|
let arg = nonbuiltin_cmd.arg_mut::<sgx_epid_group_id_t>()?;
|
||||||
|
*arg = SGX_ATTEST_AGENT.lock().unwrap().get_epid_group_id()?;
|
||||||
|
}
|
||||||
|
SGX_CMD_NUM_GEN_QUOTE => {
|
||||||
|
// Prepare the arguments
|
||||||
|
let arg = nonbuiltin_cmd.arg_mut::<IoctlGenQuoteArg>()?;
|
||||||
|
let sigrl = {
|
||||||
|
let sigrl_ptr = arg.sigrl_ptr;
|
||||||
|
let sigrl_len = arg.sigrl_len as usize;
|
||||||
|
if !sigrl_ptr.is_null() && sigrl_len > 0 {
|
||||||
|
let sigrl_slice =
|
||||||
|
unsafe { std::slice::from_raw_parts(sigrl_ptr, sigrl_len) };
|
||||||
|
Some(sigrl_slice)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut quote_output_buf = unsafe {
|
||||||
|
let quote_ptr = arg.quote_buf;
|
||||||
|
if quote_ptr.is_null() {
|
||||||
|
return_errno!(EINVAL, "the output buffer for quote cannot point to NULL");
|
||||||
|
}
|
||||||
|
let quote_len = arg.quote_buf_len as usize;
|
||||||
|
std::slice::from_raw_parts_mut(quote_ptr, quote_len)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate the quote
|
||||||
|
let quote = SGX_ATTEST_AGENT.lock().unwrap().generate_quote(
|
||||||
|
sigrl,
|
||||||
|
&arg.report_data,
|
||||||
|
arg.quote_type,
|
||||||
|
&arg.spid,
|
||||||
|
&arg.nonce,
|
||||||
|
)?;
|
||||||
|
quote.dump_to_buf(quote_output_buf)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return_errno!(EINVAL, "unknown ioctl cmd for /dev/sgx");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// The root of file system
|
||||||
|
pub static ref SGX_ATTEST_AGENT: SgxMutex<SgxAttestationAgent> = {
|
||||||
|
SgxMutex::new(SgxAttestationAgent::new())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct IoctlGenQuoteArg {
|
||||||
|
report_data: sgx_report_data_t, // Input
|
||||||
|
quote_type: sgx_quote_sign_type_t, // Input
|
||||||
|
spid: sgx_spid_t, // Input
|
||||||
|
nonce: sgx_quote_nonce_t, // Input
|
||||||
|
sigrl_ptr: *const u8, // Input (optional)
|
||||||
|
sigrl_len: u32, // Input (optional)
|
||||||
|
quote_buf_len: u32, // Input
|
||||||
|
quote_buf: *mut u8, // Output
|
||||||
|
}
|
@ -18,7 +18,9 @@ extern crate sgx_types;
|
|||||||
#[cfg(not(target_env = "sgx"))]
|
#[cfg(not(target_env = "sgx"))]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate sgx_tstd as std;
|
extern crate sgx_tstd as std;
|
||||||
|
extern crate sgx_tcrypto;
|
||||||
extern crate sgx_trts;
|
extern crate sgx_trts;
|
||||||
|
extern crate sgx_tse;
|
||||||
extern crate xmas_elf;
|
extern crate xmas_elf;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
45
src/pal/attestation.c
Normal file
45
src/pal/attestation.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include "sgx_uae_service.h"
|
||||||
|
|
||||||
|
sgx_status_t ocall_sgx_init_quote(
|
||||||
|
sgx_target_info_t *target_info,
|
||||||
|
sgx_epid_group_id_t *epid_group_id)
|
||||||
|
{
|
||||||
|
return sgx_init_quote(target_info, epid_group_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
sgx_status_t ocall_sgx_get_quote(
|
||||||
|
uint8_t* sigrl,
|
||||||
|
uint32_t sigrl_len,
|
||||||
|
sgx_report_t* report,
|
||||||
|
sgx_quote_sign_type_t quote_type,
|
||||||
|
sgx_spid_t* spid,
|
||||||
|
sgx_quote_nonce_t* nonce,
|
||||||
|
sgx_report_t* qe_report,
|
||||||
|
sgx_quote_t* quote_buf,
|
||||||
|
uint32_t quote_buf_len)
|
||||||
|
{
|
||||||
|
sgx_status_t ret = SGX_SUCCESS;
|
||||||
|
|
||||||
|
uint32_t real_quote_len;
|
||||||
|
ret = sgx_calc_quote_size(sigrl, sigrl_len, &real_quote_len);
|
||||||
|
if (ret != SGX_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (quote_buf_len < real_quote_len) {
|
||||||
|
return SGX_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intel's manual:
|
||||||
|
// It's suggested that the caller should wait (typically several seconds
|
||||||
|
// to ten of seconds) and retry this API if SGX_ERROR_BUSY is returned.
|
||||||
|
ret = sgx_get_quote(report,
|
||||||
|
quote_type,
|
||||||
|
spid,
|
||||||
|
nonce,
|
||||||
|
sigrl,
|
||||||
|
sigrl_len,
|
||||||
|
qe_report,
|
||||||
|
quote_buf,
|
||||||
|
real_quote_len);
|
||||||
|
return ret;
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
include ../test_common.mk
|
include ../test_common.mk
|
||||||
|
|
||||||
EXTRA_C_FLAGS :=
|
SGX_SDK ?= /opt/intel/sgxsdk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS := -I$(SGX_SDK)/include
|
||||||
EXTRA_LINK_FLAGS :=
|
EXTRA_LINK_FLAGS :=
|
||||||
BIN_ARGS :=
|
BIN_ARGS :=
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sgx_quote.h>
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test cases for TTY ioctl
|
// Test cases for TTY ioctls
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
int test_tty_ioctl_TIOCGWINSZ(void) {
|
int test_tty_ioctl_TIOCGWINSZ(void) {
|
||||||
@ -20,17 +23,30 @@ int test_tty_ioctl_TIOCGWINSZ(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test cases for SGX ioctl
|
// Test cases for SGX ioctls
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
sgx_report_data_t report_data; // input
|
||||||
|
sgx_quote_sign_type_t quote_type; // input
|
||||||
|
sgx_spid_t spid; // input
|
||||||
|
sgx_quote_nonce_t nonce; // input
|
||||||
|
const uint8_t* sigrl_ptr; // input (optional)
|
||||||
|
uint32_t sigrl_len; // input (optional)
|
||||||
|
uint32_t quote_buf_len; // input
|
||||||
|
union {
|
||||||
|
uint8_t* as_buf;
|
||||||
|
sgx_quote_t* as_quote;
|
||||||
|
} quote; // output
|
||||||
|
} sgxioc_gen_quote_arg_t;
|
||||||
|
|
||||||
#define SGXIOC_IS_EDDM_SUPPORTED _IOR('s', 0, int)
|
#define SGXIOC_IS_EDDM_SUPPORTED _IOR('s', 0, int)
|
||||||
|
#define SGXIOC_GET_EPID_GROUP_ID _IOR('s', 1, sgx_epid_group_id_t)
|
||||||
|
#define SGXIOC_GEN_QUOTE _IOWR('s', 2, sgxioc_gen_quote_arg_t)
|
||||||
|
|
||||||
int test_sgx_ioctl_SGXIOC_IS_EDDM_SUPPORTED(void) {
|
typedef int(*sgx_ioctl_test_body_t)(int sgx_fd);
|
||||||
int sgx_fd;
|
|
||||||
if ((sgx_fd = open("/dev/sgx", O_RDONLY)) < 0) {
|
|
||||||
THROW_ERROR("failed to open /dev/sgx ");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
static int do_SGXIOC_IS_EDDM_SUPPORTED(int sgx_fd) {
|
||||||
int is_edmm_supported = 0;
|
int is_edmm_supported = 0;
|
||||||
if (ioctl(sgx_fd, SGXIOC_IS_EDDM_SUPPORTED, &is_edmm_supported) < 0) {
|
if (ioctl(sgx_fd, SGXIOC_IS_EDDM_SUPPORTED, &is_edmm_supported) < 0) {
|
||||||
THROW_ERROR("failed to ioctl /dev/sgx");
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
||||||
@ -38,18 +54,93 @@ int test_sgx_ioctl_SGXIOC_IS_EDDM_SUPPORTED(void) {
|
|||||||
if (is_edmm_supported != 0) {
|
if (is_edmm_supported != 0) {
|
||||||
THROW_ERROR("SGX EDMM supported are not expected to be enabled");
|
THROW_ERROR("SGX EDMM supported are not expected to be enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sgx_fd);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_SGXIOC_GET_EPID_GROUP_ID(int sgx_fd) {
|
||||||
|
sgx_epid_group_id_t epid_group_id = { 0 };
|
||||||
|
if (ioctl(sgx_fd, SGXIOC_GET_EPID_GROUP_ID, &epid_group_id) < 0) {
|
||||||
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_SGXIOC_GEN_QUOTE(int sgx_fd) {
|
||||||
|
uint8_t quote_buf[2048] = { 0 };
|
||||||
|
sgxioc_gen_quote_arg_t gen_quote_arg = {
|
||||||
|
.report_data = { { 0 } }, // input (empty is ok)
|
||||||
|
.quote_type = SGX_LINKABLE_SIGNATURE, // input
|
||||||
|
.spid = { { 0 } }, // input (empty is ok)
|
||||||
|
.nonce = { { 0 } }, // input (empty is ok)
|
||||||
|
.sigrl_ptr = NULL, // input (optional)
|
||||||
|
.sigrl_len = 0, // input (optional)
|
||||||
|
.quote_buf_len = sizeof(quote_buf), // input
|
||||||
|
.quote = { .as_buf = (uint8_t*) quote_buf } // output
|
||||||
|
};
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int ret = ioctl(sgx_fd, SGXIOC_GEN_QUOTE, &gen_quote_arg);
|
||||||
|
if (ret == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (errno == EAGAIN) {
|
||||||
|
printf("WARN: /dev/sgx is temporarily busy. Try again after 1 second.");
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
THROW_ERROR("failed to ioctl /dev/sgx");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sgx_quote_t* quote = (sgx_quote_t*)quote_buf;
|
||||||
|
if (quote->sign_type != SGX_LINKABLE_SIGNATURE) {
|
||||||
|
THROW_ERROR("invalid quote: wrong sign type");
|
||||||
|
}
|
||||||
|
if (quote->signature_len == 0) {
|
||||||
|
THROW_ERROR("invalid quote: zero-length signature");
|
||||||
|
}
|
||||||
|
if (memcmp(&gen_quote_arg.report_data, "e->report_body.report_data, sizeof(sgx_report_data_t)) != 0) {
|
||||||
|
THROW_ERROR("invalid quote: wrong report data");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_sgx_ioctl_test(sgx_ioctl_test_body_t test_body) {
|
||||||
|
// Init test
|
||||||
|
int sgx_fd;
|
||||||
|
if ((sgx_fd = open("/dev/sgx", O_RDONLY)) < 0) {
|
||||||
|
THROW_ERROR("failed to open /dev/sgx ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do test
|
||||||
|
int ret = test_body(sgx_fd);
|
||||||
|
|
||||||
|
// Clean up test
|
||||||
|
close(sgx_fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_sgx_ioctl_SGXIOC_IS_EDDM_SUPPORTED(void) {
|
||||||
|
return do_sgx_ioctl_test(do_SGXIOC_IS_EDDM_SUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID(void) {
|
||||||
|
return do_sgx_ioctl_test(do_SGXIOC_GET_EPID_GROUP_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_sgx_ioctl_SGXIOC_GEN_QUOTE(void) {
|
||||||
|
return do_sgx_ioctl_test(do_SGXIOC_GEN_QUOTE);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test suite
|
// Test suite
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
static test_case_t test_cases[] = {
|
static test_case_t test_cases[] = {
|
||||||
TEST_CASE(test_tty_ioctl_TIOCGWINSZ),
|
TEST_CASE(test_tty_ioctl_TIOCGWINSZ),
|
||||||
TEST_CASE(test_sgx_ioctl_SGXIOC_IS_EDDM_SUPPORTED)
|
TEST_CASE(test_sgx_ioctl_SGXIOC_IS_EDDM_SUPPORTED),
|
||||||
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GET_EPID_GROUP_ID),
|
||||||
|
TEST_CASE(test_sgx_ioctl_SGXIOC_GEN_QUOTE)
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user