Add dcap rust based library and C test program

Signed-off-by: Zheng, Qi <huaiqing.zq@antgroup.com>
This commit is contained in:
Zheng, Qi 2021-07-07 14:33:08 +08:00 committed by Zongmin.Gu
parent ba630d3cae
commit 1990196208
9 changed files with 598 additions and 0 deletions

@ -0,0 +1,38 @@
# SGX DCAP Remote Attestation Demo in Rust
This project demonstrates how to do Intel SGX DCAP (Datacenter Attestation
Primitives) remote attestation on Occlum. Occlum provides SGX capabilities to
applications through ioctls on device `/dev/sgx`.
## Prerequisites
- Platform: Intel SGX enabled platform with DCAP installed. Follow [DCAP
Quick Install
Guide](https://software.intel.com/content/www/us/en/develop/articles/intel-software-guard-extensions-data-center-attestation-primitives-quick-install-guide.html)
for the detailed installation procedure.
- Occlum: Compile Occlum on a DCAP-installed platform by invoking `make`. The
compilation will look for the needed DCAP libraries. The needed libraries
include `libsgx_quote_ex, libsgx_quote_ex_sim, libsgx_dcap_tvl,
libsgx_dcap_ql and libsgx_dcap_quoteverify`.
## Run this demo on Occlum
You can run the DCAP quote generation and verification demo, including dcap library build, rust test demo and C test demo on Occlum via
```
./run_dcap_quote_on_occlum.sh
```
## Preinstalled DCAP package in Ubuntu 18.04 and CentOS 8.1
The DCAP package has been preinstalled in the Occlum official docker images
including Ubuntu 18.04 and CentOS 8.1 since Occlum 0.19.0. The versions of DCAP
package and PCCS should keep the same to avoid incompatibility. The demo is verified
in Occlum 0.23.1 in which the DCAP version is 1.10, so PCCS should also be version 1.10
to work with the preinstalled DCAP package. Remember to configure `/etc/sgx_default_qcnl.conf`
in the container according to your PCCS setting after running the docker image.
As DCAP 1.10 is not the latest, the demo application running in the container of
the official image will output a warning: `WARN: App: Verification completed
with Non-terminal result: a002`. The `a002` of type `sgx_ql_qv_result_t` in the
warning indicates the quote is good but TCB level of the platform is out of
date.

@ -0,0 +1,12 @@
CC := gcc
LIBPATH := ../dcap_lib/target/debug
.PHONY: all clean
all: dcap_c_test
dcap_c_test: dcap_c_test.c
$(CC) $^ -fPIE -pie -o $@ -L $(LIBPATH) -ldcap_quote
clean:
rm -rf dcap_c_test

@ -0,0 +1,122 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sgx_quote_3.h"
#include "dcap_quote.h"
void main() {
void *handle;
uint32_t quote_size, supplemental_size;
uint8_t *p_quote_buffer, *p_supplemental_buffer;
sgx_quote3_t *p_quote;
sgx_report_body_t *p_rep_body;
sgx_report_data_t *p_rep_data;
sgx_ql_auth_data_t *p_auth_data;
sgx_ql_ecdsa_sig_data_t *p_sig_data;
sgx_ql_certification_data_t *p_cert_data;
int32_t ret;
handle = dcap_quote_open();
quote_size = dcap_get_quote_size(handle);
printf("quote size = %d\n", quote_size);
p_quote_buffer = (uint8_t*)malloc(quote_size);
if (NULL == p_quote_buffer) {
printf("Couldn't allocate quote_buffer\n");
goto CLEANUP;
}
memset(p_quote_buffer, 0, quote_size);
sgx_report_data_t report_data = { 0 };
char *data = "ioctl DCAP report data example";
memcpy(report_data.d, data, strlen(data));
// Get the Quote
ret = dcap_generate_quote(handle, p_quote_buffer, &report_data);
if (0 != ret) {
printf( "Error in dcap_generate_quote.\n");
goto CLEANUP;
}
printf("DCAP generate quote successfully\n");
p_quote = (sgx_quote3_t *)p_quote_buffer;
p_rep_body = (sgx_report_body_t *)(&p_quote->report_body);
p_rep_data = (sgx_report_data_t *)(&p_rep_body->report_data);
p_sig_data = (sgx_ql_ecdsa_sig_data_t *)p_quote->signature_data;
p_auth_data = (sgx_ql_auth_data_t*)p_sig_data->auth_certification_data;
p_cert_data = (sgx_ql_certification_data_t *)((uint8_t *)p_auth_data + sizeof(*p_auth_data) + p_auth_data->size);
if (memcmp((void *)p_rep_data, (void *)&report_data, sizeof(sgx_report_data_t)) != 0) {
printf("mismathced report data\n");
goto CLEANUP;
}
printf("cert_key_type = 0x%x\n", p_cert_data->cert_key_type);
supplemental_size = dcap_get_supplemental_data_size(handle);
printf("supplemental_size size = %d\n", supplemental_size);
p_supplemental_buffer = (uint8_t *)malloc(supplemental_size);
if (NULL == p_supplemental_buffer) {
printf("Couldn't allocate supplemental buffer\n");
goto CLEANUP;
}
memset(p_supplemental_buffer, 0, supplemental_size);
uint32_t collateral_expiration_status = 1;
sgx_ql_qv_result_t quote_verification_result = SGX_QL_QV_RESULT_UNSPECIFIED;
ret = dcap_verify_quote(
handle,
p_quote_buffer,
quote_size,
&collateral_expiration_status,
&quote_verification_result,
supplemental_size,
p_supplemental_buffer
);
if (0 != ret) {
printf( "Error in dcap_verify_quote.\n");
goto CLEANUP;
}
if (collateral_expiration_status != 0) {
printf("the verification collateral has expired\n");
}
switch (quote_verification_result) {
case SGX_QL_QV_RESULT_OK:
printf("Succeed to verify the quote!\n");
break;
case SGX_QL_QV_RESULT_CONFIG_NEEDED:
case SGX_QL_QV_RESULT_OUT_OF_DATE:
case SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED:
case SGX_QL_QV_RESULT_SW_HARDENING_NEEDED:
case SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED:
printf("WARN: App: Verification completed with Non-terminal result: %x\n",
quote_verification_result);
break;
case SGX_QL_QV_RESULT_INVALID_SIGNATURE:
case SGX_QL_QV_RESULT_REVOKED:
case SGX_QL_QV_RESULT_UNSPECIFIED:
default:
printf("\tError: App: Verification completed with Terminal result: %x\n",
quote_verification_result);
goto CLEANUP;
}
printf("DCAP verify quote successfully\n");
CLEANUP:
if (NULL != p_quote_buffer) {
free(p_quote_buffer);
}
if (NULL != p_supplemental_buffer) {
free(p_supplemental_buffer);
}
dcap_quote_close(handle);
}

@ -0,0 +1,30 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "sgx_urts.h"
#include "sgx_report.h"
#include "sgx_qve_header.h"
#include "sgx_dcap_ql_wrapper.h"
#include "sgx_pce.h"
#include "sgx_error.h"
void *dcap_quote_open(void);
uint32_t dcap_get_quote_size(void *handle);
int32_t dcap_generate_quote(void *handle, uint8_t *quote_buf, const sgx_report_data_t *report_data);
uint32_t dcap_get_supplemental_data_size(void *handle);
int32_t dcap_verify_quote(void *handle,
const uint8_t *quote_buf,
uint32_t quote_size,
uint32_t *collateral_expiration_status,
sgx_ql_qv_result_t *quote_verification_result,
uint32_t supplemental_data_size,
uint8_t *supplemental_data);
void dcap_quote_close(void *handle);

@ -0,0 +1,14 @@
[package]
name = "dcap_quote"
version = "0.1.0"
authors = ["Zheng, Qi <huaiqing.zq@antgroup.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
sgx_types = { path = "../../../../deps/rust-sgx-sdk/sgx_types" }
libc = "0.2"
[lib]
crate-type = ["cdylib", "rlib"]

@ -0,0 +1,123 @@
extern crate dcap_quote;
use std::str;
use dcap_quote::*;
use sgx_types::{
sgx_report_data_t, sgx_ql_qv_result_t, sgx_report_body_t, sgx_quote3_t
};
struct DcapDemo {
dcap_quote: DcapQuote,
quote_size: u32,
quote_buf_ptr: *mut u8,
req_data: sgx_report_data_t,
supplemental_size: u32,
suppl_buf_ptr: *mut u8,
}
impl DcapDemo {
pub fn new(report_data: &str) -> Self {
let mut dcap = DcapQuote::new();
let quote_size = dcap.get_quote_size();
let supplemental_size = dcap.get_supplemental_data_size();
let mut quote_buf: Vec<u8> = vec![0; quote_size as usize];
let quote_ptr = quote_buf.as_mut_ptr();
let mut suppl_buf: Vec<u8> = vec![0; supplemental_size as usize];
let suppl_ptr = suppl_buf.as_mut_ptr();
let mut req_data = sgx_report_data_t::default();
//fill in the report data array
for (pos, val) in report_data.as_bytes().iter().enumerate() {
req_data.d[pos] = *val;
}
Self {
dcap_quote: dcap,
quote_size: quote_size,
quote_buf_ptr: quote_ptr,
req_data: req_data,
supplemental_size: supplemental_size,
suppl_buf_ptr: suppl_ptr
}
}
fn dcap_quote_gen(&mut self) -> Result<i32, &'static str> {
self.dcap_quote.generate_quote(self.quote_buf_ptr, &mut self.req_data).unwrap();
println!("DCAP generate quote successfully");
Ok( 0 )
}
fn dcap_quote_get_report_body(&mut self) -> Result<*const sgx_report_body_t, &'static str> {
let quote3: *mut sgx_quote3_t = self.quote_buf_ptr as *mut sgx_quote3_t;
let report_body = unsafe { &((*quote3).report_body) };
Ok(report_body)
}
fn dcap_quote_get_report_data(&mut self) -> Result<*const sgx_report_data_t, &'static str> {
let report_body_ptr = self.dcap_quote_get_report_body().unwrap();
let report_data_ptr = unsafe { &(*report_body_ptr).report_data };
Ok(report_data_ptr)
}
fn dcap_quote_ver(&mut self) -> Result<sgx_ql_qv_result_t, &'static str> {
let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED;
let mut status = 1;
let mut verify_arg = IoctlVerDCAPQuoteArg {
quote_buf: self.quote_buf_ptr,
quote_size: self.quote_size,
collateral_expiration_status: &mut status,
quote_verification_result: &mut quote_verification_result,
supplemental_data_size: self.supplemental_size,
supplemental_data: self.suppl_buf_ptr,
};
self.dcap_quote.verify_quote(&mut verify_arg).unwrap();
println!("DCAP verify quote successfully");
Ok( quote_verification_result )
}
}
impl Drop for DcapDemo {
fn drop(&mut self) {
self.dcap_quote.close();
}
}
fn main() {
let report_str = "Dcap demo sample";
let mut dcap_demo = DcapDemo::new(report_str);
println!("Generate quote with report data : {}", report_str);
dcap_demo.dcap_quote_gen().unwrap();
// compare the report data in quote buffer
let report_data_ptr = dcap_demo.dcap_quote_get_report_data().unwrap();
let string = str::from_utf8( unsafe { &(*report_data_ptr).d } ).unwrap();
if report_str == &string[..report_str.len()] {
println!("Report data from Quote: '{}' exactly matches.", string);
} else {
println!("Report data from Quote: '{}' doesn't match !!!", string);
}
let result = dcap_demo.dcap_quote_ver().unwrap();
match result {
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => {
println!("Succeed to verify the quote!");
},
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED |
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE |
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED |
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED |
sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => {
println!("WARN: App: Verification completed with Non-terminal result: {}", result);
},
_ => println!("Error: App: Verification completed with Terminal result: {}", result),
}
}

@ -0,0 +1,118 @@
use libc::*;
use std::ffi::CString;
use sgx_types::{
sgx_report_data_t, sgx_ql_qv_result_t
};
const SGXIOC_GET_DCAP_QUOTE_SIZE: c_ulong = 0x80047307;
const SGXIOC_GEN_DCAP_QUOTE: c_ulong = 0xc0187308;
const SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE: c_ulong = 0x80047309;
const SGXIOC_VER_DCAP_QUOTE: c_ulong = 0xc030730a;
// Copy from occlum/src/libos/src/fs/dev_fs/dev_sgx/mod.rs
//#[allow(dead_code)]
#[repr(C)]
pub struct IoctlGenDCAPQuoteArg {
pub report_data: *const sgx_report_data_t, // Input
pub quote_size: *mut u32, // Input/output
pub quote_buf: *mut u8, // Output
}
// Copy from occlum/src/libos/src/fs/dev_fs/dev_sgx/mod.rs
//#[allow(dead_code)]
#[repr(C)]
pub struct IoctlVerDCAPQuoteArg {
pub quote_buf: *const u8, // Input
pub quote_size: u32, // Input
pub collateral_expiration_status: *mut u32, // Output
pub quote_verification_result: *mut sgx_ql_qv_result_t, // Output
pub supplemental_data_size: u32, // Input (optional)
pub supplemental_data: *mut u8, // Output (optional)
}
pub struct DcapQuote {
fd: c_int,
quote_size: u32,
supplemental_size: u32,
}
impl DcapQuote {
pub fn new() -> Self {
println!("DcapQuote: new");
let path = CString::new("/dev/sgx").unwrap();
let fd = unsafe { libc::open(path.as_ptr(), O_RDONLY) };
if fd > 0 {
Self {
fd: fd,
quote_size: 0,
supplemental_size: 0,
}
} else {
panic!("Open /dev/sgx failed")
}
}
pub fn get_quote_size(&mut self) -> u32 {
println!("DcapQuote: get_quote_size");
let size: u32 = 0;
let ret = unsafe { libc::ioctl(self.fd, SGXIOC_GET_DCAP_QUOTE_SIZE, &size) };
if ret < 0 {
panic!("IOCTRL SGXIOC_GET_DCAP_QUOTE_SIZE failed");
} else {
self.quote_size = size;
size
}
}
pub fn generate_quote(&mut self, quote_buf: *mut u8, report_data: *const sgx_report_data_t) -> Result<i32, &'static str> {
println!("DcapQuote: generate_quote");
let quote_arg: IoctlGenDCAPQuoteArg = IoctlGenDCAPQuoteArg {
report_data: report_data,
quote_size: &mut self.quote_size,
quote_buf: quote_buf,
};
let ret = unsafe { libc::ioctl(self.fd, SGXIOC_GEN_DCAP_QUOTE, &quote_arg) };
if ret < 0 {
Err("IOCTRL SGXIOC_GEN_DCAP_QUOTE failed")
} else {
Ok( 0 )
}
}
pub fn get_supplemental_data_size(&mut self) -> u32 {
println!("DcapQuote: get_supplemental_data_size");
let size: u32 = 0;
let ret = unsafe { libc::ioctl(self.fd, SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE, &size) };
if ret < 0 {
panic!("IOCTRL SGXIOC_GET_DCAP_SUPPLEMENTAL_SIZE failed");
} else {
self.supplemental_size = size;
size
}
}
pub fn verify_quote(&mut self, verify_arg: *mut IoctlVerDCAPQuoteArg) -> Result<i32, &'static str> {
println!("DcapQuote: verify_quote");
let ret = unsafe { libc::ioctl(self.fd, SGXIOC_VER_DCAP_QUOTE, verify_arg) };
if ret < 0 {
println!("ret = {}", ret);
Err("IOCTRL SGXIOC_VER_DCAP_QUOTE failed")
} else {
Ok( 0 )
}
}
pub fn close(&mut self) {
println!("DcapQuote: close");
unsafe { libc::close(self.fd) };
}
}

@ -0,0 +1,109 @@
use std::boxed::Box;
use libc::{c_void};
use sgx_types::{
sgx_report_data_t, sgx_ql_qv_result_t
};
mod dcap_quote;
pub use crate::dcap_quote::*;
#[no_mangle]
pub extern "C" fn dcap_quote_open() -> *mut c_void {
Box::into_raw(Box::new(DcapQuote::new())) as *mut c_void
}
#[no_mangle]
pub extern "C" fn dcap_get_quote_size(handle: *mut c_void) -> u32 {
if handle.is_null() {
return 0
}
let dcap = unsafe {
&mut *(handle as *mut DcapQuote)
};
dcap.get_quote_size()
}
#[no_mangle]
pub extern "C" fn dcap_generate_quote(
handle: *mut c_void,
quote_buf: *mut u8,
report_data: *const sgx_report_data_t) -> i32
{
if handle.is_null() {
return -1
}
let dcap = unsafe {
&mut *(handle as *mut DcapQuote)
};
dcap.generate_quote(quote_buf, report_data).unwrap();
0
}
#[no_mangle]
pub extern "C" fn dcap_get_supplemental_data_size(handle: *mut c_void) -> u32 {
if handle.is_null() {
return 0
}
let dcap = unsafe {
&mut *(handle as *mut DcapQuote)
};
dcap.get_supplemental_data_size()
}
#[no_mangle]
pub extern "C" fn dcap_verify_quote(
handle: *mut c_void,
quote_buf: *const u8,
quote_size: u32,
collateral_expiration_status: *mut u32,
quote_verification_result: *mut sgx_ql_qv_result_t,
supplemental_data_size: u32,
supplemental_data: *mut u8) -> i32
{
if handle.is_null() {
return -1
}
let dcap = unsafe {
&mut *(handle as *mut DcapQuote)
};
let mut verify_arg = IoctlVerDCAPQuoteArg {
quote_buf: quote_buf,
quote_size: quote_size,
collateral_expiration_status: collateral_expiration_status,
quote_verification_result: quote_verification_result,
supplemental_data_size: supplemental_data_size,
supplemental_data: supplemental_data,
};
dcap.verify_quote(&mut verify_arg).unwrap();
0
}
#[no_mangle]
pub extern "C" fn dcap_quote_close(handle: *mut c_void) {
if handle.is_null() {
return
}
let dcap = unsafe {
&mut *(handle as *mut DcapQuote)
};
dcap.close();
unsafe {
Box::from_raw(handle);
}
}

@ -0,0 +1,32 @@
#!/bin/bash
occlum_glibc=/opt/occlum/glibc/lib/
set -e
BLUE='\033[1;34m'
NC='\033[0m'
INSTANCE_DIR="occlum_instance"
pushd dcap_lib
cargo build --all-targets
popd
make -C c_app
rm -rf ${INSTANCE_DIR} && occlum new ${INSTANCE_DIR}
cd ${INSTANCE_DIR}
cp ../dcap_lib/target/debug/examples/dcap_test image/bin
cp ../dcap_lib/target/debug/libdcap_quote.so image/$occlum_glibc
cp ../c_app/dcap_c_test image/bin
cp $occlum_glibc/libdl.so.2 image/$occlum_glibc
cp $occlum_glibc/librt.so.1 image/$occlum_glibc
occlum build
echo -e "${BLUE}occlum run rust test /bin/dcap_test${NC}"
occlum run /bin/dcap_test
echo -e "************"
echo -e "${BLUE}occlum run C test /bin/dcap_c_test${NC}"
occlum run /bin/dcap_c_test