Skip to content

Commit

Permalink
Verifier: IBM SE implementation
Browse files Browse the repository at this point in the history
Signed-off-by: Qi Feng Huo <[email protected]>
  • Loading branch information
Qi Feng Huo committed May 13, 2024
1 parent 708167d commit 7c10203
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 67 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ tokio = { version = "1.23.0", features = ["full"] }
tempfile = "3.4.0"
tonic = "0.8.1"
tonic-build = "0.8.0"

8 changes: 6 additions & 2 deletions attestation-service/attestation-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[features]
default = [ "restful-bin", "rvps-grpc", "rvps-builtin", "all-verifier" ]
default = [ "restful-bin", "rvps-grpc", "rvps-builtin" ]
all-verifier = [ "verifier/all-verifier" ]
tdx-verifier = [ "verifier/tdx-verifier" ]
sgx-verifier = [ "verifier/sgx-verifier" ]
Expand Down Expand Up @@ -63,7 +63,11 @@ thiserror = { workspace = true, optional = true }
tokio.workspace = true
tonic = { workspace = true, optional = true }
uuid = { version = "1.1.2", features = ["v4"] }
verifier = { path = "../verifier", default-features = false }
[target.'cfg(not(target_arch = "s390x"))'.dependencies]
verifier = { path = "../verifier", default-features = false, features = ["all-verifier"] }

[target.'cfg(target_arch = "s390x")'.dependencies]
verifier = { path = "../verifier", default-features = false, features = ["se-verifier"] }

[build-dependencies]
shadow-rs.workspace = true
Expand Down
8 changes: 7 additions & 1 deletion attestation-service/verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ az-tdx-vtpm-verifier = [ "az-tdx-vtpm", "openssl", "tdx-verifier" ]
snp-verifier = [ "asn1-rs", "openssl", "sev", "x509-parser" ]
csv-verifier = [ "openssl", "csv-rs", "codicon" ]
cca-verifier = [ "ear", "jsonwebtoken", "veraison-apiclient" ]
se-verifier = [ "openssl" ]
se-verifier = [ "openssl", "pv" ]

[dependencies]
anyhow.workspace = true
Expand All @@ -36,9 +36,11 @@ jsonwebtoken = { workspace = true, default-features = false, optional = true }
kbs-types.workspace = true
log.workspace = true
openssl = { version = "0.10.55", optional = true }
pv = { version = "0.10.0", package = "s390_pv" }
scroll = { version = "0.11.0", default-features = false, features = ["derive"], optional = true }
serde.workspace = true
serde_json.workspace = true
serde_yaml = "0.9.0"
sev = { version = "1.2.0", features = ["openssl", "snp"], optional = true }
sgx-dcap-quoteverify-rs = { git = "https://github.com/intel/SGXDataCenterAttestationPrimitives", tag = "DCAP_1.16", optional = true }
strum.workspace = true
Expand All @@ -55,3 +57,7 @@ assert-json-diff.workspace = true
rstest.workspace = true
serial_test.workspace = true
tokio.workspace = true

[patch.crates-io]
s390_pv = { path = "/root/src/tmp_pv_crate/pv" }
s390_pv_core = { path = "/root/src/tmp_pv_crate/pv_core" }
195 changes: 155 additions & 40 deletions attestation-service/verifier/src/se/ibmse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,163 @@
// SPDX-License-Identifier: Apache-2.0
//

use anyhow::*;
use async_trait;

#[derive(Default)]
pub struct FakeSeAttest {}

#[async_trait::async_trait]
pub trait SeFakeVerifier {
async fn create<'a, 'b, 'c>(
&self,
_hkd_files: Vec<String>,
_cert_file: &'a str,
_signing_file: &'b str,
_arpk_file: &'c str,
) -> Result<Vec<u8>>;

async fn verify<'a, 'b>(
&self,
_evidence: &[u8],
_arpk_file: &'a str,
_hdr_file: &'b str,
) -> Result<Vec<u8>>;
use anyhow::{anyhow, bail, Context, Result};
use log::{debug, warn};
use pv::{
attest::{
AdditionalData, AttestationFlags, AttestationItems, AttestationMeasAlg,
AttestationMeasurement, AttestationRequest, AttestationVersion, ExchangeFormatCtx,
ExchangeFormatVersion,
},
misc::{CertificateOptions, open_file, read_exact_file, write_file, HexSlice},
request::{openssl::pkey::PKey, BootHdrTags, Confidential, ReqEncrCtx, Request, SymKey, SymKeyType},
};
use serde::Serialize;
use serde_yaml;
use std::{fmt::Display, io::Read, process::ExitCode};

const EXIT_CODE_ATTESTATION_FAIL: u8 = 2;

#[derive(Serialize)]
struct VerifyOutput<'a> {
cuid: HexSlice<'a>,
#[serde(skip_serializing_if = "Option::is_none")]
additional_data: Option<HexSlice<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
additional_data_fields: Option<AdditionalData<HexSlice<'a>>>,
#[serde(skip_serializing_if = "Option::is_none")]
user_data: Option<HexSlice<'a>>,
}

impl<'a> VerifyOutput<'a> {
fn from_exchange(ctx: &'a ExchangeFormatCtx, flags: &AttestationFlags) -> Result<Self> {
let additional_data_fields = ctx
.additional()
.map(|a| AdditionalData::from_slice(a, flags))
.transpose()?;
let user_data = ctx.user().map(|u| u.into());

Ok(Self {
cuid: ctx.config_uid()?.into(),
additional_data: ctx.additional().map(|a| a.into()),
additional_data_fields,
user_data,
})
}
}

#[async_trait::async_trait]
impl SeFakeVerifier for FakeSeAttest {
async fn create<'a, 'b, 'c>(
&self,
_hkd_files: Vec<String>,
_cert_file: &'a str,
_signing_file: &'b str,
_arpk_file: &'c str,
) -> Result<Vec<u8>> {
Result::Ok("test".as_bytes().to_vec())
impl<'a> Display for VerifyOutput<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Config UID:")?;
writeln!(f, "{:#}", self.cuid)?;
if let Some(data) = &self.additional_data {
writeln!(f, "Additional-data:")?;
writeln!(f, "{:#}", data)?;
}
if let Some(data) = &self.additional_data_fields {
writeln!(f, "Additional-data content:")?;
writeln!(f, "{:#}", data)?;
}
if let Some(data) = &self.user_data {
writeln!(f, "user-data:")?;
writeln!(f, "{:#}", data)?;
}
Ok(())
}
}

pub fn verify(input: &mut dyn Read, hdr_file: String, arpk_file: String, output: &mut Vec<u8>, user_data: &mut Vec<u8>) -> Result<ExitCode> {
let mut img = open_file(&hdr_file)?;
let arpk = SymKey::Aes256(
read_exact_file(&arpk_file, "Attestation request protection key").map(Confidential::new)?,
);
let hdr = BootHdrTags::from_se_image(&mut img)?;
let ctx = ExchangeFormatCtx::read(mut input, true)?;

let (auth, conf) = AttestationRequest::decrypt_bin(ctx.arcb(), &arpk)?;
let meas_key = PKey::hmac(conf.measurement_key())?;
let items = AttestationItems::from_exchange(&ctx, &hdr, conf.nonce())?;

async fn verify<'a, 'b>(
&self,
_evidence: &[u8],
_arpk_file: &'a str,
_hkd_files: &'b str,
) -> Result<Vec<u8>> {
Result::Ok("test".as_bytes().to_vec())
let measurement =
AttestationMeasurement::calculate(items, AttestationMeasAlg::HmacSha512, &meas_key)?;

let uv_meas = ctx.measurement().ok_or(anyhow!(
"The input is missing the measurement. It is probably no attestation response"
))?;
if !measurement.eq_secure(uv_meas) {
debug!("Measurement values:");
debug!("Recieved: {}", HexSlice::from(uv_meas));
debug!("Calculated: {}", HexSlice::from(measurement.as_ref()));
warn!("Attestation measurement verification failed. Calculated and received attestation measurement are not equal.");
return Ok(ExitCode::from(EXIT_CODE_ATTESTATION_FAIL));
}
}
warn!("Attestation measurement verified");
// Error impossible CUID is present Attestation verified
let pr_data = VerifyOutput::from_exchange(&ctx, auth.flags())?;

warn!("{pr_data}");
serde_yaml::to_writer(output, &pr_data)?;

// How to get user_data, what's data here???
if let Some(user_data) = &user_data {
match ctx.user() {
Some(data) => write_file(user_data, data, "user-data")?,
None => {
warn!("Location for `user-data` specified, but respose does not contain any user-data")
}
}
};

Ok(ExitCode::SUCCESS)
}

pub fn create(host_key_documents: Vec<String>, certs: Vec<String>, crls: Vec<String>, arpk_file: String, root_ca: Option<String>) -> Result<Vec<u8>> {
let att_version = AttestationVersion::One;
let meas_alg = AttestationMeasAlg::HmacSha512;

let mut att_flags = AttestationFlags::default();
att_flags.set_image_phkh();

let mut arcb = AttestationRequest::new(att_version, meas_alg, att_flags)?;
debug!("Generated Attestation request");

let certificate_args = CertificateOptions {
host_key_documents,
no_verify: true,
certs,
crls,
offline: true,
root_ca,
};
// Add host-key documents
certificate_args
.get_verified_hkds("attestation request")?
.into_iter()
.for_each(|k| arcb.add_hostkey(k));
debug!("Added all host-keys");

let encr_ctx =
ReqEncrCtx::random(SymKeyType::Aes256).context("Failed to generate random input")?;
let ser_arcb = arcb.encrypt(&encr_ctx)?;
warn!("Successfully generated the request");

let output: Vec<u8>;
let exch_ctx = ExchangeFormatCtx::new_request(
ser_arcb,
meas_alg.exp_size(),
arcb.flags().expected_additional_size().into(),
)?;
exch_ctx.write(&mut output, ExchangeFormatVersion::One)?;

let arpk = match encr_ctx.prot_key() {
SymKey::Aes256(k) => k,
_ => bail!("Unexpected key type"),
};
write_file(
&arpk_file,
arpk.value(),
"Attestation request Protection Key",
)?;

Result::Ok(output)
}
39 changes: 15 additions & 24 deletions attestation-service/verifier/src/se/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use super::*;
use async_trait::async_trait;
use base64::prelude::*;
use serde_json::json;
use std::io::Cursor;
use pv::misc::CertificateOptions;
use crate::{InitDataHash, ReportData};
use crate::se::ibmse::FakeSeAttest;
use crate::se::ibmse::SeFakeVerifier;

pub mod ibmse;

Expand All @@ -31,19 +31,13 @@ impl Verifier for SeVerifier {
&self,
_tee_parameters: String,
) -> Result<String> {

// TODO replace FakeSeAttest with real IBM SE crate
let attester = FakeSeAttest::default();

// TODO replace the placeholder
let hkds: Vec<String> = vec![String::new(); 2];
let certk = "cert_file_path";
let signk = "sign_file_path";
let arpk = "arpk_file_path";
let certs: Vec<String> = vec![String::new(); 2];
let crls: Vec<String> = vec![];
let arpk = String::from("arpk_file_path");
let root_ca = Option::Some(String::from("root_ca"));

let challenge = attester.create(hkds, certk, signk, arpk)
.await
.context("Create SE attestation request failed: {:?}")?;
let challenge = ibmse::create(hkds, certs, crls, arpk, root_ca)?;

Ok(BASE64_STANDARD.encode(challenge))
}
Expand All @@ -54,21 +48,18 @@ async fn verify_evidence(
_expected_report_data: &ReportData<'_>,
_expected_init_data_hash: &InitDataHash<'_>,
) -> Result<TeeEvidenceParsedClaim> {
// TODO replace FakeSeAttest with real IBM SE crate
let attester = FakeSeAttest::default();

// TODO replace the placeholder
let arpk = "arpk_file_path";
let hdr = "hdr_file_path";
let arpk = String::from("arpk_file_path");
let hdr = String::from("hdr_file_path");

let se = attester.verify(evidence, arpk, hdr)
.await
.context("Verify SE attestation evidence failed: {:?}")?;
let mut cursor = Cursor::new(evidence);
let mut output: Vec<u8> = vec![];
let mut userdata: Vec<u8> = vec![];
let _res = ibmse::verify(&mut cursor, hdr, arpk, &mut output, &mut userdata);

let claims_map = json!({
"serial_number": format!("{}", "SE-ID"),
"measurement": format!("{}", BASE64_STANDARD.encode(se.clone())),
"report_data": format!("{}", BASE64_STANDARD.encode(se.clone())),
"measurement": format!("{}", BASE64_STANDARD.encode(output.clone())),
"report_data": format!("{}", BASE64_STANDARD.encode(userdata.clone())),
});

Ok(claims_map as TeeEvidenceParsedClaim)
Expand Down

0 comments on commit 7c10203

Please sign in to comment.