Skip to content

Commit

Permalink
aa/attester: IBM SE driver (#1)
Browse files Browse the repository at this point in the history
* aa/attester: add IBM Secure Execution evidence driver framework

Signed-off-by: Qi Feng Huo <[email protected]>

* aa/attester: IBM SE use nonce to pass attestation request

Signed-off-by: Qi Feng Huo <[email protected]>

---------

Signed-off-by: Qi Feng Huo <[email protected]>
  • Loading branch information
Qi Feng Huo authored Jun 4, 2024
1 parent 33a8723 commit ac1d677
Show file tree
Hide file tree
Showing 13 changed files with 156 additions and 7 deletions.
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"]

# 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 }
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",
]

# 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]);
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";
let userdata = UserData {
image_btph: image_btph.into(),
};

debug!("userdata json: {:#?}", &userdata.clone());
// 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(),
Some(user_data.to_vec()),
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.clone());
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}");
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

0 comments on commit ac1d677

Please sign in to comment.