Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust SDK: get TDX quote via vsock #15

Merged
merged 2 commits into from
Mar 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/rust/cctrusted_vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ log = "0.4.20"
nix = "0.26.2"
base64 = "0.13.0"
rand = "0.8.5"
vsock = "0.4.0"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
tokio-stream = "0.1.14"
2 changes: 1 addition & 1 deletion src/rust/cctrusted_vm/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl CCTrustedApi for API {
match build_cvm() {
Ok(mut cvm) => {
// call CVM trait defined methods
cvm.dump();
// cvm.dump();
Ok(CcReport {
cc_report: match cvm.process_cc_report(nonce, data) {
Ok(r) => r,
Expand Down
160 changes: 144 additions & 16 deletions src/rust/cctrusted_vm/src/tdvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,21 @@ use anyhow::*;
use cctrusted_base::api_data::ReplayResult;
use cctrusted_base::cc_type::*;
use cctrusted_base::eventlog::EventLogs;
use cctrusted_base::tcg::EventLogEntry;
use cctrusted_base::tcg::*;
use cctrusted_base::tdx::common::*;
use cctrusted_base::tdx::quote::*;
use cctrusted_base::tdx::report::*;
use cctrusted_base::tdx::rtmr::TdxRTMR;
use cctrusted_base::tdx::{common::*, quote::*, report::*, rtmr::TdxRTMR};
use core::convert::TryInto;
use core::mem;
use core::mem::*;
use core::ptr;
use core::result::Result;
use core::result::Result::Ok;
use log::info;
use nix::sys::socket::*;
use nix::*;
use std::fs::read_to_string;
use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::fs::{read_to_string, File};
use std::io::{BufReader, Read};
use std::os::fd::AsRawFd;
use std::path::Path;
use vsock::VMADDR_CID_HOST;

// TDX ioctl operation code to be used for get TDX quote and TD Report
pub enum TdxOperation {
Expand Down Expand Up @@ -222,20 +218,152 @@ impl CVM for TdxVM {
//build QGS request message
let qgs_msg = Tdx::generate_qgs_quote_msg(report_data_array);

let qgs_msg_bytes = unsafe {
let ptr = &qgs_msg as *const qgs_msg_get_quote_req as *const u8;
core::slice::from_raw_parts(ptr, size_of::<qgs_msg_get_quote_req>())
};

// use TDVMCALL by default except vsock config exists at ATTEST_CFG_FILE_PATH
let mut tdvmcall_flag = true;
let mut port: u32 = 0;
if Path::new(ATTEST_CFG_FILE_PATH).exists() {
let data_lines: Vec<String> = read_to_string(ATTEST_CFG_FILE_PATH)
.unwrap()
.lines()
.map(String::from)
.collect();

for line in data_lines {
if line.contains("port") {
let element = line
.split('=')
.last()
.expect("[process_cc_report] invalid vsock port config")
.trim_matches(' ');
port = element.parse().unwrap();
if port >= 65536 {
return Err(anyhow!(
"[process_cc_report] invalid vsock port config at {}",
ATTEST_CFG_FILE_PATH
));
}
tdvmcall_flag = false;
break;
}
}
}

// get quote using vsock instead of TDVMCALL
if !tdvmcall_flag {
log::info!("[process_cc_report] get TDX quote with vsock");
const HEADER_SIZE: u32 = 4;
const QUOTE_BUFFER_SIZE: usize = 10000;
let qgs_msg_bytes_array: [u8; (16 + 8 + TDX_REPORT_LEN) as usize] =
unsafe { transmute(qgs_msg) };
let msg_size: u32 = qgs_msg_bytes_array.len().try_into().unwrap();
let msg_size_bytes_array: [u8; HEADER_SIZE as usize] = msg_size.to_be().to_ne_bytes();

let mut p_blob_payload = [0; (HEADER_SIZE + 16 + 8 + TDX_REPORT_LEN) as usize];
p_blob_payload[..4].copy_from_slice(&msg_size_bytes_array);
p_blob_payload[4..].copy_from_slice(&qgs_msg_bytes_array);

let vsock_addr = VsockAddr::new(VMADDR_CID_HOST, port);
let qgs_vsocket = socket(
AddressFamily::Vsock,
SockType::Stream,
SockFlag::empty(),
None,
)
.context("[get_td_report] failed to create vsock socket")?;

let _ = connect(qgs_vsocket.as_raw_fd(), &vsock_addr)
.with_context(|| "[get_td_report] failed to connect to qgs vsock".to_string());

match send(qgs_vsocket.as_raw_fd(), &p_blob_payload, MsgFlags::empty()) {
Ok(written_bytes) => {
if written_bytes != p_blob_payload.len() {
return Err(anyhow!(
"[process_cc_report] send to qgs vsock failed: send {} bytes",
written_bytes
));
}
}
Err(e) => {
return Err(anyhow!(
"[get_td_report] Fail to send to qgs vsock: {:?}",
e
))
}
}

let mut return_size_bytes_array = [0; HEADER_SIZE as usize];
match recv(
qgs_vsocket.as_raw_fd(),
&mut return_size_bytes_array,
MsgFlags::empty(),
) {
Ok(read_bytes) => {
if read_bytes != HEADER_SIZE.try_into().unwrap() {
return Err(anyhow!("[process_cc_report] read size header from qgs vsock failed: read {} bytes", read_bytes));
}
}
Err(e) => {
return Err(anyhow!(
"[get_td_report] Fail to read size header from qgs vsock: {:?}",
e
))
}
}

let mut in_msg_size = 0;
for i in 0..HEADER_SIZE {
in_msg_size = (in_msg_size << 8) + (return_size_bytes_array[i as usize]) as u32;
}

let mut return_quote_bytes_array = [0; QUOTE_BUFFER_SIZE];
match recv(
qgs_vsocket.as_raw_fd(),
&mut return_quote_bytes_array,
MsgFlags::empty(),
) {
Ok(read_qgs_response_bytes) => {
if read_qgs_response_bytes == 0 {
return Err(anyhow!(
"[process_cc_report] read quote body from qgs vsock failed: got 0 byte"
));
}
}
Err(e) => {
return Err(anyhow!(
"[get_td_report] Fail to read quote body from qgs vsock: {:?}",
e
))
}
}

let qgs_msg_resp = unsafe {
let raw_ptr =
ptr::addr_of!(return_quote_bytes_array) as *mut qgs_msg_get_quote_resp;
raw_ptr.as_mut().unwrap() as &mut qgs_msg_get_quote_resp
};

let _ = shutdown(qgs_vsocket.as_raw_fd(), Shutdown::Both);

return Ok(qgs_msg_resp.id_quote[0..(qgs_msg_resp.quote_size as usize)].to_vec());
}

log::info!("[process_cc_report] get TDX quote with TDVMCALL");

//build quote generation request header
let mut quote_header = tdx_quote_hdr {
version: 1,
status: 0,
in_len: (mem::size_of_val(&qgs_msg) + 4) as u32,
in_len: (size_of_val(&qgs_msg) + 4) as u32,
out_len: 0,
data_len_be_bytes: (1048_u32).to_be_bytes(),
data: [0; TDX_QUOTE_LEN],
};

let qgs_msg_bytes = unsafe {
let ptr = &qgs_msg as *const qgs_msg_get_quote_req as *const u8;
core::slice::from_raw_parts(ptr, mem::size_of::<qgs_msg_get_quote_req>())
};
quote_header.data[0..(16 + 8 + TDX_REPORT_LEN) as usize]
.copy_from_slice(&qgs_msg_bytes[0..((16 + 8 + TDX_REPORT_LEN) as usize)]);

Expand Down Expand Up @@ -304,7 +432,7 @@ impl CVM for TdxVM {
//inspect the response and retrive quote data
let out_len = quote_header.out_len;
let qgs_msg_resp_size =
unsafe { core::mem::transmute::<[u8; 4], u32>(quote_header.data_len_be_bytes) }.to_be();
unsafe { transmute::<[u8; 4], u32>(quote_header.data_len_be_bytes) }.to_be();

let qgs_msg_resp = unsafe {
let raw_ptr = ptr::addr_of!(quote_header.data) as *mut qgs_msg_get_quote_resp;
Expand Down
2 changes: 1 addition & 1 deletion src/rust/sample/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ anyhow = "1.0"
log = "0.4.20"
env_logger = "0.10.1"
base64 = "0.13.0"
rand = "0.8.5"
rand = "0.8.5"
6 changes: 4 additions & 2 deletions src/rust/sample/src/cc-sample-quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ fn main() {
}
};

info!("cc report size {}", report.cc_report.len());

// dump the cc report with API "dump_cc_report"
//info!("call cc trusted API [dump_cc_report] to dump cc report!");
API::dump_cc_report(&report.cc_report);
// info!("call cc trusted API [dump_cc_report] to dump cc report!");
// API::dump_cc_report(&report.cc_report);

// parse the cc report with API "parse_cc_report"
if report.cc_type == TeeType::TDX {
Expand Down