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/attester: add IBM Secure Execution driver framework #492

Merged
merged 3 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ env_logger = "0.11.3"
hex = "0.4.3"
hmac = "0.12.1"
jwt-simple = "0.11"
kbs-types = "0.5.3"
kbs-types = "0.6.0"
lazy_static = "1.4.0"
log = "0.4.14"
openssl = "0.10"
Expand All @@ -52,6 +52,7 @@ ring = "0.17"
rsa = "0.9.2"
rstest = "0.17"
serde = { version = "1.0", features = ["derive"] }
serde_with = { version = "1.11.0", features = ["base64"] }
serde_json = "1.0"
serial_test = "2"
sha2 = "0.10.7"
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ else ifeq ($(TEE_PLATFORM), snp)
ATTESTER = snp-attester
else ifeq ($(TEE_PLATFORM), az-snp-vtpm)
ATTESTER = az-snp-vtpm-attester
else ifeq ($(TEE_PLATFORM), se)
ATTESTER = se-attester
else ifeq ($(TEE_PLATFORM), all)
ATTESTER = all-attesters
ifeq ($(NO_RESOURCE_PROVIDER), true)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ The `TEE_PLATFORM` parameter can be
- `snp`: for AMD SEV-SNP
- `amd`: for both AMD SEV(-ES) and AMD SEV-SNP
- `az-snp-vtpm`: for AMD SEV-SNP with Azure vTPM
- `se`: for IBM Secure Execution (SE)

by default, `kbs`/`sev` as a resource provider will be built in Confidential Data Hub. If you do not want enable any
default except for only builtin `offline-fs-kbc`, you can build with `NO_RESOURCE_PROVIDER` flag set to `true`.
Expand Down
1 change: 1 addition & 0 deletions attestation-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ AA supports different kinds of hardware TEE attesters, now
| az-snp-vtpm-attester| Azure SEV-SNP CVM |
| az-tdx-vtpm-attester| Azure TDX CVM |
| cca-attester | Arm Confidential Compute Architecture (CCA) |
| se-attester | IBM Secure Execution (SE) |

To build AA with all available attesters and install, use
```shell
Expand Down
1 change: 1 addition & 0 deletions attestation-agent/attestation-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ 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"]
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved

# Either `rust-crypto` or `openssl` should be enabled to work as underlying crypto module
rust-crypto = ["kbs_protocol?/rust-crypto"]
Expand Down
1 change: 1 addition & 0 deletions attestation-agent/attestation-agent/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ fn main() -> std::io::Result<()> {
"AZ_SNP_VTPM_ATTESTER",
"AZ_TDX_VTPM_ATTESTER",
"SNP_ATTESTER",
"SE_ATTESTER",
]);

let out_dir = env::var("OUT_DIR").unwrap();
Expand Down
5 changes: 5 additions & 0 deletions attestation-agent/attester/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ kbs-types.workspace = true
log.workspace = true
nix = { version = "0.28", 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 }
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
scroll = { version = "0.12.0", default-features = false, features = ["derive", "std"], optional = true }
serde.workspace = true
serde_json.workspace = true
serde_with.workspace = true
sev = { version = "3.1.1", default-features = false, features = [
"snp",
], optional = true }
Expand Down Expand Up @@ -51,6 +53,8 @@ all-attesters = [
"snp-attester",
"csv-attester",
"cca-attester",
# se-attester feature can work only on s390x target arch.
"se-attester",
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
]

# tsm-report enables a module that helps attesters to use Linux TSM_REPORTS for generating
Expand All @@ -64,5 +68,6 @@ az-tdx-vtpm-attester = ["az-tdx-vtpm"]
snp-attester = ["sev"]
csv-attester = ["csv-rs", "codicon", "hyper", "hyper-tls", "tokio"]
cca-attester = ["nix"]
se-attester = ["pv"]

bin = ["tokio/rt", "tokio/macros", "all-attesters"]
13 changes: 13 additions & 0 deletions attestation-agent/attester/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ pub mod csv;
#[cfg(feature = "tsm-report")]
pub mod tsm_report;

#[cfg(feature = "se-attester")]
#[cfg(target_arch = "s390x")]
pub mod se;

pub type BoxedAttester = Box<dyn Attester + Send + Sync>;

impl TryFrom<Tee> for BoxedAttester {
Expand All @@ -55,6 +59,9 @@ impl TryFrom<Tee> for BoxedAttester {
Tee::Snp => Box::<snp::SnpAttester>::default(),
#[cfg(feature = "csv-attester")]
Tee::Csv => Box::<csv::CsvAttester>::default(),
#[cfg(feature = "se-attester")]
#[cfg(target_arch = "s390x")]
Tee::Se => Box::<se::SeAttester>::default(),
_ => bail!("TEE is not supported!"),
};

Expand Down Expand Up @@ -126,6 +133,12 @@ pub fn detect_tee_type() -> Tee {
return Tee::Cca;
}

#[cfg(feature = "se-attester")]
#[cfg(target_arch = "s390x")]
if se::detect_platform() {
return Tee::Se;
}

log::warn!("No TEE platform detected. Sample Attester will be used.");
Tee::Sample
}
107 changes: 107 additions & 0 deletions attestation-agent/attester/src/se/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (C) Copyright IBM Corp. 2024
//
// SPDX-License-Identifier: Apache-2.0
//

use super::Attester;
use anyhow::*;
use log::debug;
use pv::{
request::BootHdrTags,
uv::{AttestationCmd, ConfigUid, UvDevice},
};
use serde::{Deserialize, Serialize};
use serde_json;
use serde_with::{base64::Base64, serde_as};

pub fn detect_platform() -> bool {
// run always on s390x machine
let v = std::fs::read("/sys/firmware/uv/prot_virt_guest").unwrap_or_else(|_| vec![0]);
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
let v: u8 = String::from_utf8_lossy(&v[..1]).parse().unwrap_or(0);
v == 1
}

#[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct UserData {
#[serde_as(as = "Base64")]
image_btph: Vec<u8>,
}

#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
pub struct SeAttestationRequest {
#[serde_as(as = "Base64")]
request_blob: Vec<u8>,
measurement_size: u32,
additional_size: u32,
#[serde_as(as = "Base64")]
encr_measurement_key: Vec<u8>,
#[serde_as(as = "Base64")]
encr_request_nonce: Vec<u8>,
#[serde_as(as = "Base64")]
image_hdr_tags: BootHdrTags,
}

#[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SeAttestationResponse {
#[serde_as(as = "Base64")]
measurement: Vec<u8>,
#[serde_as(as = "Base64")]
additional_data: Vec<u8>,
#[serde_as(as = "Base64")]
user_data: Vec<u8>,
#[serde_as(as = "Base64")]
cuid: ConfigUid,
#[serde_as(as = "Base64")]
encr_measurement_key: Vec<u8>,
#[serde_as(as = "Base64")]
encr_request_nonce: Vec<u8>,
#[serde_as(as = "Base64")]
image_hdr_tags: BootHdrTags,
}

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

#[async_trait::async_trait]
impl Attester for SeAttester {
async fn get_evidence(&self, req: Vec<u8>) -> Result<String> {
// req is serialized SeAttestationRequest String bytes
// TODO, calculate optional userdata based on the boot partition etc.
let image_btph = "optional check";
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
let userdata = UserData {
image_btph: image_btph.into(),
};

debug!("userdata json: {userdata:#?}");
// req is serialized SeAttestationRequest String bytes
let request: SeAttestationRequest = serde_json::from_slice(req)?;
let user_data = serde_json::to_vec(&userdata)?;
let mut uvc: AttestationCmd = AttestationCmd::new_request(
request.request_blob.clone().into(),
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
Some(user_data.to_vec()),
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
request.measurement_size,
request.additional_size,
)?;
let uv = UvDevice::open()?;
uv.send_cmd(&mut uvc)?;
let cuid = uvc.cuid();
let additional_data = uvc
.additional_owned()
.ok_or(anyhow!("Failed to get additinal data."))?;
let response: SeAttestationResponse = SeAttestationResponse {
measurement: uvc.measurement().to_vec(),
additional_data,
user_data,
cuid: *cuid,
encr_measurement_key: request.encr_measurement_key,
encr_request_nonce: request.encr_request_nonce,
image_hdr_tags: request.image_hdr_tags,
};

debug!("response json: {response:#?}");
Ok(serde_json::to_string(&response)?)
}
}
1 change: 1 addition & 0 deletions attestation-agent/kbc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ az-snp-vtpm-attester= ["kbs_protocol/az-snp-vtpm-attester"]
az-tdx-vtpm-attester= ["kbs_protocol/az-tdx-vtpm-attester"]
snp-attester = ["kbs_protocol/snp-attester"]
cca-attester = ["kbs_protocol/cca-attester"]
se-attester = ["kbs_protocol/se-attester"]

sample_kbc = []
eaa_kbc = ["foreign-types"]
Expand Down
1 change: 1 addition & 0 deletions attestation-agent/kbs_protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ az-tdx-vtpm-attester = ["attester/az-tdx-vtpm-attester"]
snp-attester = ["attester/snp-attester"]
csv-attester = ["attester/csv-attester"]
cca-attester = ["attester/cca-attester"]
se-attester = ["attester/se-attester"]

rust-crypto = ["reqwest/rustls-tls", "crypto/rust-crypto"]
openssl = ["reqwest/native-tls-vendored", "crypto/openssl"]
23 changes: 19 additions & 4 deletions attestation-agent/kbs_protocol/src/client/rcar_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use std::time::Duration;

use anyhow::{bail, Context};
use async_trait::async_trait;
use kbs_types::{Attestation, Challenge, ErrorInformation, Request, Response};
use base64::{engine::general_purpose::STANDARD, Engine};
use kbs_types::{Attestation, Challenge, ErrorInformation, Request, Response, Tee};
use log::{debug, warn};
use resource_uri::ResourceUri;
use serde::Deserialize;
Expand Down Expand Up @@ -140,7 +141,9 @@ impl KbsClient<Box<dyn EvidenceProvider>> {
});
let runtime_data =
serde_json::to_string(&runtime_data).context("serialize runtime data failed")?;
let evidence = self.generate_evidence(runtime_data).await?;
let evidence = self
.generate_evidence(tee, runtime_data, challenge.nonce)
.await?;
debug!("get evidence with challenge: {evidence}");

let attest_endpoint = format!("{}/{KBS_PREFIX}/attest", self.kbs_host_url);
Expand Down Expand Up @@ -179,11 +182,23 @@ impl KbsClient<Box<dyn EvidenceProvider>> {
Ok(())
}

async fn generate_evidence(&self, runtime_data: String) -> Result<String> {
async fn generate_evidence(
&self,
tee: Tee,
runtime_data: String,
nonce: String,
) -> Result<String> {
debug!("Challenge nonce: {nonce}");
huoqifeng marked this conversation as resolved.
Show resolved Hide resolved
let mut hasher = Sha384::new();
hasher.update(runtime_data);

let ehd = hasher.finalize().to_vec();
let ehd = match tee {
// IBM SE uses nonce as runtime_data to pass attestation_request
Tee::Se => STANDARD
.decode(nonce)
.map_err(|e| Error::GetEvidence(e.to_string()))?,
_ => hasher.finalize().to_vec(),
};

let tee_evidence = self
.provider
Expand Down
Loading