Skip to content

Commit

Permalink
AA/attester: add check_init_data support for TDX and SNP
Browse files Browse the repository at this point in the history
In TDX, we use tdx_attest crate to get a raw hardware tdx report to
parse the MRCONFIGID field.

In SNP, we use sev crate to get a hardware report to parse HOSTDATA
field.

The input one should be resize as the evidence field inside the TEE
evidence to compare.

Signed-off-by: Magnus Kulke <[email protected]>
Signed-off-by: Dan Mihai <[email protected]>
Signed-off-by: Xynnn007 <[email protected]>
  • Loading branch information
Xynnn007 authored and ChengyuZhu6 committed Feb 5, 2024
1 parent ff1538e commit b6035af
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 2 deletions.
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion attestation-agent/attester/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ kbs-types.workspace = true
log.workspace = true
nix = { version = "0.26.2", optional = true }
occlum_dcap = { git = "https://github.com/occlum/occlum", tag = "v0.29.7", optional = true }
scroll = { version = "0.11.0", default-features = false, features = ["derive"], optional = true }
serde.workspace = true
serde_json.workspace = true
sev = { version = "1.2.0", default-features = false, features = [
"snp",
], optional = true }
strum.workspace = true
tdx-attest-rs = { git = "https://github.com/intel/SGXDataCenterAttestationPrimitives", tag = "DCAP_1.16", optional = true }
thiserror.workspace = true
# TODO: change it to "0.1", once released.
csv-rs = { git = "https://github.com/openanolis/csv-rs", rev = "b74aa8c", optional = true }
codicon = { version = "3.0", optional = true }
Expand All @@ -52,7 +54,7 @@ all-attesters = [
"cca-attester",
]

tdx-attester = ["tdx-attest-rs"]
tdx-attester = ["scroll", "tdx-attest-rs"]
sgx-attester = ["occlum_dcap"]
az-snp-vtpm-attester = ["az-snp-vtpm"]
az-tdx-vtpm-attester = ["az-tdx-vtpm"]
Expand Down
1 change: 1 addition & 0 deletions attestation-agent/attester/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use anyhow::*;
use kbs_types::Tee;

pub mod sample;
pub mod utils;

#[cfg(feature = "az-snp-vtpm-attester")]
pub mod az_snp_vtpm;
Expand Down
24 changes: 24 additions & 0 deletions attestation-agent/attester/src/snp/hostdata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2024 Microsoft Corporation
// Copyright (c) 2024 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//

use thiserror::Error;

#[derive(Error, Debug)]
pub enum GetHostDataError {
#[error("Open Sev guest firmware failed: {0}")]
OpenSevGuestFirmware(#[from] std::io::Error),

#[error("Get report failed: {0}")]
GetReportError(#[from] sev::error::UserApiError),
}

pub fn get_snp_host_data() -> Result<[u8; 32], GetHostDataError> {
let mut firmware = sev::firmware::guest::Firmware::open()?;
let report_data: [u8; 64] = [0; 64];
let report = firmware.get_report(None, Some(report_data), Some(0))?;

Ok(report.host_data)
}
14 changes: 14 additions & 0 deletions attestation-agent/attester/src/snp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// SPDX-License-Identifier: Apache-2.0
//

use crate::utils::pad;

use super::Attester;
use anyhow::*;
use serde::{Deserialize, Serialize};
Expand All @@ -11,6 +13,8 @@ use sev::firmware::guest::Firmware;
use sev::firmware::host::CertTableEntry;
use std::path::Path;

mod hostdata;

pub fn detect_platform() -> bool {
Path::new("/sys/devices/platform/sev-guest").exists()
}
Expand Down Expand Up @@ -47,4 +51,14 @@ impl Attester for SnpAttester {

serde_json::to_string(&evidence).context("Serialize SNP evidence failed")
}

async fn check_init_data(&self, init_data: &[u8]) -> Result<()> {
let hostdata = hostdata::get_snp_host_data().context("Get HOSTDATA failed")?;
let init_data: [u8; 32] = pad(init_data);
if init_data != hostdata {
bail!("HOSTDATA does not match.");
}

Ok(())
}
}
35 changes: 34 additions & 1 deletion attestation-agent/attester/src/tdx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@
// SPDX-License-Identifier: Apache-2.0
//

use crate::utils::pad;

use super::Attester;
use anyhow::*;
use base64::Engine;
use log::debug;
use scroll::Pread;
use serde::{Deserialize, Serialize};
use std::path::Path;
use tdx_attest_rs;
use tdx_attest_rs::{self, tdx_report_t};

mod report;

const TDX_REPORT_DATA_SIZE: usize = 64;
const CCEL_PATH: &str = "/sys/firmware/acpi/tables/data/CCEL";
Expand Down Expand Up @@ -90,6 +96,33 @@ impl Attester for TdxAttester {

Ok(())
}

async fn check_init_data(&self, init_data: &[u8]) -> Result<()> {
let mut report = tdx_report_t { d: [0; 1024] };
match tdx_attest_rs::tdx_att_get_report(None, &mut report) {
tdx_attest_rs::tdx_attest_error_t::TDX_ATTEST_SUCCESS => {
debug!("Successfully get report")
}
error_code => {
bail!(
"TDX Attester: Failed to get TD report. Error code: {:?}",
error_code
);
}
};

let td_report = report
.d
.pread::<report::TdReport>(0)
.map_err(|e| anyhow!("Parse TD report failed: {:?}", e))?;

let init_data: [u8; 48] = pad(init_data);
if init_data != td_report.tdinfo.mrconfigid {
bail!("Init data does not match!");
}

Ok(())
}
}

#[cfg(test)]
Expand Down
99 changes: 99 additions & 0 deletions attestation-agent/attester/src/tdx/report.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright (c) 2024 Microsoft Corporation
// Copyright (c) 2024 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//

use scroll::Pread;

#[repr(C)]
#[derive(Pread)]
/// Type header of TDREPORT_STRUCT.
pub struct TdTransportType {
/// Type of the TDREPORT (0 - SGX, 81 - TDX, rest are reserved).
pub type_: u8,

/// Subtype of the TDREPORT (Default value is 0).
pub sub_type: u8,

/// TDREPORT version (Default value is 0).
pub version: u8,

/// Added for future extension.
pub reserved: u8,
}

#[repr(C)]
#[derive(Pread)]
/// TDX guest report data, MAC and TEE hashes.
pub struct ReportMac {
/// TDREPORT type header.
pub type_: TdTransportType,

/// Reserved for future extension.
pub reserved1: [u8; 12],

/// CPU security version.
pub cpu_svn: [u8; 16],

/// SHA384 hash of TEE TCB INFO.
pub tee_tcb_info_hash: [u8; 48],

/// SHA384 hash of TDINFO_STRUCT.
pub tee_td_info_hash: [u8; 48],

/// User defined unique data passed in TDG.MR.REPORT request.
pub reportdata: [u8; 64],

/// Reserved for future extension.
pub reserved2: [u8; 32],

/// CPU MAC ID.
pub mac: [u8; 32],
}

#[repr(C)]
#[derive(Pread)]
/// TDX guest measurements and configuration.
pub struct TdInfo {
/// TDX Guest attributes (like debug, spet_disable, etc).
pub attr: [u8; 8],

/// Extended features allowed mask.
pub xfam: u64,

/// Build time measurement register.
pub mrtd: [u64; 6],

/// Software-defined ID for non-owner-defined configuration of the guest - e.g., run-time or OS configuration.
pub mrconfigid: [u8; 48],

/// Software-defined ID for the guest owner.
pub mrowner: [u64; 6],

/// Software-defined ID for owner-defined configuration of the guest - e.g., specific to the workload.
pub mrownerconfig: [u64; 6],

/// Run time measurement registers.
pub rtmr: [u64; 24],

/// For future extension.
pub reserved: [u64; 14],
}

#[repr(C)]
#[derive(Pread)]
/// Output of TDCALL[TDG.MR.REPORT].
pub struct TdReport {
/// Mac protected header of size 256 bytes.
pub report_mac: ReportMac,

/// Additional attestable elements in the TCB are not reflected in the report_mac.
pub tee_tcb_info: [u8; 239],

/// Added for future extension.
pub reserved: [u8; 17],

/// Measurements and configuration data of size 512 bytes.
pub tdinfo: TdInfo,
}
15 changes: 15 additions & 0 deletions attestation-agent/attester/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2024 Microsoft Corporation
//
// SPDX-License-Identifier: Apache-2.0
//

pub fn pad<const T: usize>(input: &[u8]) -> [u8; T] {
let mut output = [0; T];
let len = input.len();
if len > T {
output.copy_from_slice(&input[..T]);
} else {
output[..len].copy_from_slice(input);
}
output
}

0 comments on commit b6035af

Please sign in to comment.