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

AA: Update CcaAttester to use TSM Report ABI #595

Merged
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
1 change: 0 additions & 1 deletion 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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ else ifeq ($(TEE_PLATFORM), amd)
else
RESOURCE_PROVIDER = sev,kbs
endif
else ifeq ($(TEE_PLATFORM), cca)
ATTESTER = cca-attester
endif
# TODO: Add support for CCA and CSV
# TODO: Add support for CSV

ifeq ($(ARCH), $(filter $(ARCH), s390x powerpc64le))
$(info s390x/powerpc64le only supports gnu)
Expand Down
11 changes: 10 additions & 1 deletion attestation-agent/attestation-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,22 @@ kbs = ["kbs_protocol/background_check", "token"]
# CoCoAS Attestation Token
coco_as = ["reqwest", "token"]

all-attesters = ["tdx-attester", "sgx-attester", "az-snp-vtpm-attester", "az-tdx-vtpm-attester", "snp-attester", "se-attester"]
all-attesters = [
"tdx-attester",
"sgx-attester",
"az-snp-vtpm-attester",
"az-tdx-vtpm-attester",
"snp-attester",
"se-attester",
"cca-attester",
]
tdx-attester = ["kbs_protocol?/tdx-attester", "attester/tdx-attester"]
sgx-attester = ["kbs_protocol?/sgx-attester", "attester/sgx-attester"]
az-snp-vtpm-attester = ["kbs_protocol?/az-snp-vtpm-attester", "attester/az-snp-vtpm-attester"]
az-tdx-vtpm-attester = ["kbs_protocol?/az-tdx-vtpm-attester", "attester/az-tdx-vtpm-attester"]
snp-attester = ["kbs_protocol?/snp-attester", "attester/snp-attester"]
se-attester = ["kbs_protocol?/se-attester", "attester/se-attester"]
cca-attester = ["kbs_protocol?/cca-attester", "attester/cca-attester"]

# Either `rust-crypto` or `openssl` should be enabled to work as underlying crypto module
rust-crypto = ["kbs_protocol?/rust-crypto"]
Expand Down
3 changes: 1 addition & 2 deletions attestation-agent/attester/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ clap = { workspace = true, features = ["derive"], optional = true }
hex.workspace = true
kbs-types.workspace = true
log.workspace = true
nix = { workspace = true, optional = true, features = ["ioctl", "fs"] }
occlum_dcap = { git = "https://github.com/occlum/occlum", tag = "v0.29.7", optional = true }
pv = { version = "0.10.0", package = "s390_pv", optional = true }
scroll = { version = "0.12.0", default-features = false, features = ["derive", "std"], optional = true }
Expand Down Expand Up @@ -68,7 +67,7 @@ az-snp-vtpm-attester = ["az-snp-vtpm"]
az-tdx-vtpm-attester = ["az-tdx-vtpm"]
snp-attester = ["sev"]
csv-attester = ["csv-rs", "codicon", "hyper", "hyper-tls", "tokio"]
cca-attester = ["nix"]
cca-attester = ["tsm-report"]
se-attester = ["pv"]

bin = ["tokio/rt", "tokio/macros", "clap"]
87 changes: 19 additions & 68 deletions attestation-agent/attester/src/cca/mod.rs
Original file line number Diff line number Diff line change
@@ -1,105 +1,56 @@
// Copyright (c) 2023 Arm Ltd.
// Copyright (c) 2023-2024 Arm Ltd.
//
// SPDX-License-Identifier: Apache-2.0
//

use super::tsm_report::*;
use super::Attester;
use anyhow::*;
use base64::Engine;
use nix::fcntl::{open, OFlag};
use nix::sys::stat::Mode;
use nix::unistd::close;
use serde::{Deserialize, Serialize};
use std::path::Path;

const CCA_DEVICE_PATH: &str = "/dev/cca_attestation";
const CCA_CHALLENGE_SIZE: usize = 64;

// NOTE: The path might be different when the CCA feature is public available, will come back to update the actual path if needed.
pub fn detect_platform() -> bool {
Path::new(CCA_DEVICE_PATH).exists()
#[cfg(target_arch = "aarch64")]
return TsmReportPath::new(TsmReportProvider::Cca).is_ok();
#[cfg(not(target_arch = "aarch64"))]
return false;
}

#[derive(Debug, Default)]
pub struct CCAAttester {}
pub struct CcaAttester {}

#[derive(Serialize, Deserialize)]
struct CcaEvidence {
/// CCA token
token: Vec<u8>,
}

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct cca_ioctl_request {
challenge: [u8; 64],
token: [u8; 4096],
token_length: u64,
}

nix::ioctl_readwrite!(cca_attestation_request, b'A', 1, cca_ioctl_request);

#[async_trait::async_trait]
impl Attester for CCAAttester {
impl Attester for CcaAttester {
async fn get_evidence(&self, mut challenge: Vec<u8>) -> Result<String> {
challenge.resize(64, 0);
let token = attestation(challenge)?;
if challenge.len() > CCA_CHALLENGE_SIZE {
bail!("CCA Attester: Challenge size must be {CCA_CHALLENGE_SIZE} bytes or less.");
}

challenge.resize(CCA_CHALLENGE_SIZE, 0);
let tsm = TsmReportPath::new(TsmReportProvider::Cca)?;
Xynnn007 marked this conversation as resolved.
Show resolved Hide resolved
let token = tsm.attestation_report(TsmReportData::Cca(challenge))?;
let evidence = CcaEvidence { token };
let ev = serde_json::to_string(&evidence).context("Serialize CCA evidence failed")?;
let ev =
serde_json::to_string(&evidence).context("Serialization of CCA evidence failed")?;
Ok(ev)
}
}

fn attestation(challenge: Vec<u8>) -> Result<Vec<u8>, Error> {
log::info!("cca_test::attestation started");

let challenge = challenge.as_slice().try_into()?;

match open(CCA_DEVICE_PATH, OFlag::empty(), Mode::empty()) {
Result::Ok(f) => {
log::info!("cca_test::attestation opening attestation succeeded");
let mut request = cca_ioctl_request {
challenge,
token: [0u8; 4096],
token_length: 0u64,
};

// this is unsafe code block since ioctl call `cca_attestation_request` has the unsafe signature.
match unsafe { cca_attestation_request(f, &mut request) } {
Result::Ok(c) => {
log::info!("cca_test::attestation ioctl call succeeded ({})", c);
log::info!(
"cca_test::attestation token is {} bytes long",
request.token_length
);
let base64 = base64::engine::general_purpose::STANDARD
.encode(&request.token[0..(request.token_length as usize)]);
log::info!("cca_test::attestation token = {:x?}", base64);
let token = request.token[0..(request.token_length as usize)].to_vec();
close(f)?;
Ok(token)
}
Err(e) => {
log::error!("cca_test::attestation ioctl failed! {}", e);
close(f)?;
bail!(e)
}
}
}
Err(err) => {
log::error!("cca_test::attestation opening attestation failed! {}", err);
bail!(err)
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[ignore]
#[tokio::test]
async fn test_cca_get_evidence() {
let attester = CCAAttester::default();
let attester = CcaAttester::default();
let report_data: Vec<u8> = vec![0; 48];
let evidence = attester.get_evidence(report_data).await;
assert!(evidence.is_ok());
Expand Down
2 changes: 1 addition & 1 deletion attestation-agent/attester/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl TryFrom<Tee> for BoxedAttester {
#[cfg(feature = "az-tdx-vtpm-attester")]
Tee::AzTdxVtpm => Box::<az_tdx_vtpm::AzTdxVtpmAttester>::default(),
#[cfg(feature = "cca-attester")]
Tee::Cca => Box::<cca::CCAAttester>::default(),
Tee::Cca => Box::<cca::CcaAttester>::default(),
#[cfg(feature = "snp-attester")]
Tee::Snp => Box::<snp::SnpAttester>::default(),
#[cfg(feature = "csv-attester")]
Expand Down
4 changes: 4 additions & 0 deletions attestation-agent/attester/src/tsm_report/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ pub enum TsmReportError {

#[derive(PartialEq, Debug, EnumString)]
pub enum TsmReportProvider {
#[strum(serialize = "arm_cca_guest\n")]
Cca,
#[strum(serialize = "tdx_guest\n")]
Tdx,
#[strum(serialize = "sev_guest\n")]
Sev,
}

pub enum TsmReportData {
Cca(Vec<u8>),
Tdx(Vec<u8>),
Sev(u8, Vec<u8>),
}
Expand Down Expand Up @@ -85,6 +88,7 @@ impl TsmReportPath {
let report_path = self.path.as_path();

let report_data = match provider_data {
TsmReportData::Cca(inblob) => inblob,
TsmReportData::Tdx(inblob) => inblob,
TsmReportData::Sev(privlevel, inblob) => {
// TODO: untested
Expand Down
Loading