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 {
|
||||
from "sgx_stdio.edl" import *;
|
||||
from "sgx_backtrace.edl" import *;
|
||||
from "sgx_stdio.edl" import *;
|
||||
from "sgx_tstdc.edl" import *;
|
||||
from "sgx_tstd.edl" import *;
|
||||
from "sgx_tprotected_fs.edl" import *;
|
||||
from "sgx_net.edl" import *;
|
||||
|
||||
include "sgx_quote.h"
|
||||
|
||||
trusted {
|
||||
/* define ECALLs here. */
|
||||
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);
|
||||
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);
|
||||
};
|
||||
|
||||
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",
|
||||
"serde 1.0.84",
|
||||
"serde_json 1.0.36",
|
||||
"sgx_tcrypto 1.0.6",
|
||||
"sgx_trts 1.0.6",
|
||||
"sgx_tse 1.0.6",
|
||||
"sgx_tstd 1.0.6",
|
||||
"sgx_types 1.0.6",
|
||||
"xmas-elf 0.6.2",
|
||||
@ -354,6 +356,13 @@ dependencies = [
|
||||
"sgx_types 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tcrypto"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"sgx_types 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tprotected_fs"
|
||||
version = "1.0.6"
|
||||
@ -370,6 +379,13 @@ dependencies = [
|
||||
"sgx_types 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tse"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"sgx_types 1.0.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tstd"
|
||||
version = "1.0.6"
|
||||
|
@ -29,3 +29,5 @@ xmas-elf = { path = "../../deps/xmas-elf" }
|
||||
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
|
||||
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace"] }
|
||||
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
|
||||
|
||||
# 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_OUT_DIR := $(BUILD_DIR)/lib
|
||||
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"))]
|
||||
#[macro_use]
|
||||
extern crate sgx_tstd as std;
|
||||
extern crate sgx_tcrypto;
|
||||
extern crate sgx_trts;
|
||||
extern crate sgx_tse;
|
||||
extern crate xmas_elf;
|
||||
#[macro_use]
|
||||
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
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
SGX_SDK ?= /opt/intel/sgxsdk
|
||||
|
||||
EXTRA_C_FLAGS := -I$(SGX_SDK)/include
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
||||
|
@ -1,14 +1,17 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <sgx_quote.h>
|
||||
#include "test.h"
|
||||
|
||||
// ============================================================================
|
||||
// Test cases for TTY ioctl
|
||||
// Test cases for TTY ioctls
|
||||
// ============================================================================
|
||||
|
||||
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_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) {
|
||||
int sgx_fd;
|
||||
if ((sgx_fd = open("/dev/sgx", O_RDONLY)) < 0) {
|
||||
THROW_ERROR("failed to open /dev/sgx ");
|
||||
}
|
||||
typedef int(*sgx_ioctl_test_body_t)(int sgx_fd);
|
||||
|
||||
static int do_SGXIOC_IS_EDDM_SUPPORTED(int sgx_fd) {
|
||||
int is_edmm_supported = 0;
|
||||
if (ioctl(sgx_fd, SGXIOC_IS_EDDM_SUPPORTED, &is_edmm_supported) < 0) {
|
||||
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) {
|
||||
THROW_ERROR("SGX EDMM supported are not expected to be enabled");
|
||||
}
|
||||
|
||||
close(sgx_fd);
|
||||
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
|
||||
// ============================================================================
|
||||
|
||||
static test_case_t test_cases[] = {
|
||||
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() {
|
||||
|
Loading…
Reference in New Issue
Block a user