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 framework for CC API VM SDK [Ready to Merge] #31

Merged
merged 13 commits into from
Jan 11, 2024
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
Loading