Skip to content

Commit

Permalink
Rust SDK framework for CC API VM SDK [Ready to Merge] (#31)
Browse files Browse the repository at this point in the history
* initial commit for Rust SDK framework for CC API VM SDK

* update according to comments: move type TPM to 0

* clear code and format

* This commit fix follows:
1. update crate common/cctrusetd_base does not depend on std crates
2. change crate name from cctrusted to cctrusted_vm for VM SDK to in-sync with Python latest update
3. define trait CCTrustedApi in crate common/cctrusetd_base to define general cc trusted APIs
4. change api to sdk concept in cctrusted_vm crate
5. move CVM related functions to cctrusted_vm crate
6. update TCG algo list to reflact review comments by Jiewen

* updates according to review comments:
- add github action for rust check
- add license and lincense check
- update code format according to rust code check feedback

* rust github action: update rust toolchain

* refine rust check github action

* refine the action

* update runner

* update code format according to rust code scan report

* update cargo base work dir

* add check for VM SDK
  • Loading branch information
hairongchen authored Jan 11, 2024
1 parent d1e1472 commit 490259d
Show file tree
Hide file tree
Showing 25 changed files with 1,303 additions and 0 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/pr-check-rust.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Rust Code Scan

on:
push:
branches:
- main
paths:
- 'common/rust/cctrusted_base/src/**.rs'
- 'common/rust/cctrusted_base/src/tdx/**.rs'
- 'common/rust/cctrusted_base/src/tpm/**.rs'
- 'vmsdk/rust/cctrusted_vm/src/**.rs'
- 'vmsdk/rust/sample/src/**.rs'
- '.github/workflows/pr-check-rust.yaml'
pull_request:
paths:
- 'common/rust/cctrusted_base/src/**.rs'
- 'common/rust/cctrusted_base/src/tdx/**.rs'
- 'common/rust/cctrusted_base/src/tpm/**.rs'
- 'vmsdk/rust/cctrusted_vm/src/**.rs'
- 'vmsdk/rust/sample/src/**.rs'
- '.github/workflows/pr-check-rust.yaml'
workflow_dispatch:

jobs:
codescan:
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@v3

- name: Set up Rust action
uses: actions-rs/toolchain@v1
with:
toolchain: 1.70.0

- name: Install dependencies
run: |
sudo apt update && yes | DEBIAN_FRONTEND=noninteractive sudo apt install -y libcryptsetup-dev clang protobuf-compiler protobuf-c-compiler libprotobuf-c-dev libprotobuf-c1 build-essential pkg-config libssl-dev
- name: Run cargo check for cctrusted_base
run: |
cd common/rust/cctrusted_base/
cargo check
cargo fmt -- --check
cargo clippy
cargo install --locked cargo-deny
cargo deny check
- name: Run cargo check for VM SDK
run: |
cd vmsdk/rust/cctrusted_vm/
cargo check
cargo fmt -- --check
cargo clippy
cargo deny check
17 changes: 17 additions & 0 deletions common/rust/cctrusted_base/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "cctrusted_base"
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"

[lib]
name = "cctrusted_base"
path = "src/lib.rs"

[dependencies]
anyhow = "1.0"
base64 = "0.13.0"
log = "0.4.20"
sha2 = "0.10"
lazy_static = "1.4.0"
hashbrown = "0.14"
35 changes: 35 additions & 0 deletions common/rust/cctrusted_base/deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[advisories]
vulnerability = "deny"
unmaintained = "warn"
yanked = "warn"
notice = "warn"

[licenses]
unlicensed = "warn"
allow = [
"MIT",
"Apache-2.0",
"ISC",
"BSD-3-Clause",
"Unicode-DFS-2016",
]

copyleft = "warn"
allow-osi-fsf-free = "neither"
default = "deny"
confidence-threshold = 0.8

[[licenses.clarify]]
name = "ring"
expression = "MIT AND ISC AND OpenSSL"
license-files = [
{ path = "LICENSE", hash = 0xbd0eed23 }
]

[bans]
multiple-versions = "warn"
wildcards = "allow"

[sources]
unknown-registry = "warn"
unknown-git = "warn"
128 changes: 128 additions & 0 deletions common/rust/cctrusted_base/src/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use crate::api_data::Algorithm;
use crate::api_data::*;
use crate::eventlog::TcgEventLog;
use crate::tcg::TcgDigest;
use crate::tdx::quote::TdxQuote;
use crate::tpm::quote::TpmQuote;
use anyhow::*;
use core::mem;
use core::result::Result;
use core::result::Result::Ok;

pub trait CCTrustedApi {
/***
Get the cc report for given nonce and data.
The cc report is signing of attestation data (IMR values or hashes of IMR
values), made by a trusted foundation (TPM) using a key trusted by the
verifier.
Different trusted foundation may use different cc report format.
Args:
nonce (String): against replay attacks
data (String): user data
extraArgs: for TPM, it will be given list of IMR/PCRs
Returns:
The cc report byte array or error information
*/
fn get_cc_report(
nonce: String,
data: String,
_extra_args: ExtraArgs,
) -> Result<CcReport, anyhow::Error>;

/***
Dump the given cc report in hex and char format
Args:
report (Vec<u8>): cc report to be printed
Returns:
None
*/
fn dump_cc_report(report: &Vec<u8>);

/***
Get measurement register according to given selected index and algorithms
Each trusted foundation in CC environment provides the multiple measurement
registers, the count is update to ``get_measurement_count()``. And for each
measurement register, it may provides multiple digest for different algorithms.
Args:
index (u8): the index of measurement register,
algo_id (u8): the alrogithms ID
Returns:
TcgDigest struct
*/
fn get_cc_measurement(_index: u8, _algo_id: u8) -> TcgDigest;

/***
Get eventlog for given index and count.
TCG log in Eventlog. Verify to spoof events in the TCG log, hence defeating
remotely-attested measured-boot.
To measure the full CC runtime environment, the eventlog may include addtional
OS type and cloud native type event beyond the measured-boot.
Returns:
TcgEventLog struct
*/
fn get_cc_eventlog(_start: u16, _count: u16) -> TcgEventLog;

/***
Get the default Digest algorithms supported by trusted foundation.
Different trusted foundation may support different algorithms, for example
the Intel TDX use SHA384, TPM uses SHA256.
Beyond the default digest algorithm, some trusted foundation like TPM
may support multiple algorithms.
Returns:
The Algorithm struct
*/
fn get_default_algorithm() -> Result<Algorithm, anyhow::Error>;
}

/***
trait to be implemented for cc report parsing.
the cooresponding implementation of parse_cc_report will be called according to
intented return format and the return of the trait function depends on
the type of cc report, e.g.: TdxQuote, TpmQuote and etc.
TDX quote parsing Example:
if following is provided:
let tdx_quote: TdxQuote = parse_cc_report(cc_report_str);
then this implementation in api.rs will be called:
fn parse_cc_report(report: Vec<u8>) -> Result<TdxQuote, anyhow::Error>;
*/
pub trait ParseCcReport<T> {
fn parse_cc_report(_report: Vec<u8>) -> Result<T, anyhow::Error>;
}

// API function parses raw cc report to TdxQuote struct
impl ParseCcReport<TdxQuote> for CcReport {
fn parse_cc_report(report: Vec<u8>) -> Result<TdxQuote, anyhow::Error> {
match TdxQuote::parse_tdx_quote(report) {
Ok(tdx_quote) => unsafe {
let report: &TdxQuote = mem::transmute(&tdx_quote);
Ok(report.clone())
},
Err(e) => Err(anyhow!("[parse_cc_report] error parse tdx quote: {:?}", e)),
}
}
}

// API function parses raw cc report to TpmQuote struct
impl ParseCcReport<TpmQuote> for CcReport {
fn parse_cc_report(_report: Vec<u8>) -> Result<TpmQuote, anyhow::Error> {
todo!()
}
}
40 changes: 40 additions & 0 deletions common/rust/cctrusted_base/src/api_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use crate::cc_type::TeeType;

/***
************************************
* API get_cc_report() related data *
************************************
*/
// input of API get_cc_report()
// this struct is used in vTPM and other CVM scenarios
// e.g.: vTPM may need report based on selective PCRs
pub struct ExtraArgs {}

// return of API get_cc_report()
pub struct CcReport {
pub cc_report: Vec<u8>,
pub cc_type: TeeType,
}

/***
**************************************
* API parse_cc_report() related data *
**************************************
*/
/***
the return data structure is defined in cctrusted_base
e.g.:
- cctrusted_base::tdx::quote::TdxQuote;
- cctrusted_base::tpm::quote::TpmQuote;
*/

/***
********************************************
* API get_default_algorithm() related data *
********************************************
*/
// return structure for get_default_algorithm
pub struct Algorithm {
pub algo_id: u8,
pub algo_id_str: String,
}
59 changes: 59 additions & 0 deletions common/rust/cctrusted_base/src/binary_blob.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use log::info;

/* dumnp raw cc report in following format:
00000000 04 00 02 00 81 00 00 00 00 00 00 00 93 9A 72 33 ..............r3
00000010 F7 9C 4C A9 94 0A 0D B3 95 7F 06 07 D5 68 59 C7 ..L..........hY.
00000020 35 FB B4 91 29 27 55 B2 E8 E8 23 B6 00 00 00 00 5...)'U...#.....
...
*/

pub fn dump_data(data: &Vec<u8>) {
let mut index: usize = 0;
let mut linestr = "".to_string();
let mut printstr = "".to_string();

let printable = vec![
' ', '\t', '\n', '\r', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E',
'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
'f', 'A', 'B', 'C', 'D', 'E', 'F', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-',
'.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}',
'~', '"', '!',
];

while index < data.len() {
if index % 16 == 0 {
if !printstr.is_empty() {
info!("{} {}", linestr, printstr);
printstr = "".to_string();
}
linestr = format!("{:08X} ", ((index / 16) as u16) * 16);
}

let v = data[index];
linestr.push_str(format!("{:02X} ", v).as_str());
match printable.iter().position(|&c| c == (v as char)) {
Some(_) => {
if !(0x9..=0xD).contains(&v) {
printstr.push_str(core::str::from_utf8(&[v]).unwrap());
} else {
printstr.push('.');
}
}
None => printstr.push('.'),
}

index += 1;
}

if index % 16 != 0 {
let mut blank = "".to_string();
for _ in 1..=(16 - index % 16) {
blank.push_str(" ");
}
info!("{}{} {}", linestr, blank, printstr);
} else if index == data.len() {
info!("{} {}", linestr, printstr);
}
}
38 changes: 38 additions & 0 deletions common/rust/cctrusted_base/src/cc_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use hashbrown::HashMap;

// supported TEE types
#[derive(Clone, Eq, Hash, PartialEq)]
pub enum TeeType {
PLAIN = -1,
TPM = 0,
TDX = 1,
SEV = 2,
CCA = 3,
}

// TEE type to type name string mapping
lazy_static! {
pub static ref TEE_NAME_MAP: HashMap<TeeType, String> = {
let mut map: HashMap<TeeType, String> = HashMap::new();
map.insert(TeeType::PLAIN, "PLAIN".to_string());
map.insert(TeeType::TDX, "TDX".to_string());
map.insert(TeeType::SEV, "SEV".to_string());
map.insert(TeeType::CCA, "CCA".to_string());
map.insert(TeeType::TPM, "TPM".to_string());
map
};
}

// public known device node path
pub const TEE_TPM_PATH: &str = "/dev/tpm0";
pub const TEE_TDX_1_0_PATH: &str = "/dev/tdx-guest";
pub const TEE_TDX_1_5_PATH: &str = "/dev/tdx_guest";
pub const TEE_SEV_PATH: &str = "/dev/sev-guest";
pub const TEE_CCA_PATH: &str = "";

// holds the TEE type info
#[derive(Clone)]
pub struct CcType {
pub tee_type: TeeType,
pub tee_type_str: String,
}
2 changes: 2 additions & 0 deletions common/rust/cctrusted_base/src/eventlog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// struct for standard TCG eventlog
pub struct TcgEventLog {}
11 changes: 11 additions & 0 deletions common/rust/cctrusted_base/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#[macro_use]
extern crate lazy_static;

pub mod api;
pub mod api_data;
pub mod binary_blob;
pub mod cc_type;
pub mod eventlog;
pub mod tcg;
pub mod tdx;
pub mod tpm;
Loading

0 comments on commit 490259d

Please sign in to comment.