Skip to content

Commit

Permalink
aa/attester: IBM SE implementation PoC
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 22, 2024
1 parent 201c5ac commit 45ab965
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 33 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 All @@ -68,3 +69,7 @@ ttrpc-codegen = "0.4.2"
url = "2.3.1"
uuid = "1"
zeroize = "1.5.7"

[patch.crates-io]
s390_pv = { path = "/root/src/tmp_pv_crate/rust/pv" }
s390_pv_core = { path = "/root/src/tmp_pv_crate/rust/pv_core" }
6 changes: 6 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" }
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 = "1.2.0", default-features = false, features = [
"snp",
], optional = true }
Expand Down Expand Up @@ -68,3 +70,7 @@ cca-attester = ["nix"]
se-attester = []

bin = ["tokio/rt", "tokio/macros", "all-attesters"]

[patch.crates-io]
s390_pv = { path = "/root/src/tmp_pv_crate/rust/pv" }
s390_pv_core = { path = "/root/src/tmp_pv_crate/rust/pv_core" }
136 changes: 122 additions & 14 deletions attestation-agent/attester/src/se/ibmse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,133 @@
// SPDX-License-Identifier: Apache-2.0
//

use anyhow::*;
use async_trait;
// Copyright (C) Copyright IBM Corp. 2024
//
// SPDX-License-Identifier: Apache-2.0
//

#[derive(Default)]
pub struct FakeSeAttest {}
use anyhow::{anyhow, Context, Result};
use log::{debug, warn};
use openssl::{
encrypt::{Encrypter, Decrypter},
pkey::{PKey, Public, Private},
rsa::{Rsa, Padding},
};
use pv::{
attest::{
AdditionalData, AttestationFlags, AttestationItems, AttestationMeasAlg,
AttestationMeasurement, AttestationRequest, AttestationVersion,
},
misc::{open_file, read_certs, read_file, HexSlice},
request::{
BootHdrTags, ReqEncrCtx, Request, SymKeyType,
CertVerifier, HkdVerifier,
},
uv::{AttestationCmd, ConfigUid, UvDevice},
};
use serde::{Deserialize, Serialize};
use serde_json;
use serde_with::{
base64::Base64,
serde_as,
};
use std::{fs::File, io::Read};
use pv::utils::pv_guest_bit_set as is_se_guest

#[async_trait::async_trait]
pub trait IbmSeAttester {
fn is_se_guest(&self) -> bool;
async fn perform(&self, _request: Vec<u8>, _userdata: Vec<u8>) -> Result<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,
}

#[async_trait::async_trait]
impl IbmSeAttester for FakeSeAttest {
fn is_se_guest(&self) -> bool {
false
impl SeAttestationRequest {
pub fn to_uvc(&self, user_data: &[u8]) -> Result<AttestationCmd> {
let cmd = AttestationCmd::new_request(
self.request_blob.clone(),
user_data.to_vec(),
self.measurement_size,
Some(self.additional_size),
)?;
Ok(cmd)
}

async fn perform(&self, _request: Vec<u8>, _userdata: Vec<u8>) -> Result<Vec<u8>> {
Result::Ok("test".as_bytes().to_vec())
pub fn from_slice(request: &[u8]) -> Result<Self> {
serde_json::from_slice(request).context("Failed to deserialize JSON data")
}
}

#[serde_as]
#[derive(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,
}

impl SeAttestationResponse {
pub fn create(
measurement: &[u8],
additional_data: &[u8],
user_data: &[u8],
cuid: &ConfigUid,
encr_measurement_key: &[u8],
encr_request_nonce: &[u8],
image_hdr_tags: &BootHdrTags,
) -> Result<Self> {
Ok(Self {
measurement: measurement.to_vec(),
additional_data: additional_data.to_vec(),
user_data: user_data.to_vec(),
cuid: *cuid,
encr_measurement_key: encr_measurement_key.to_vec(),
encr_request_nonce: encr_request_nonce.to_vec(),
image_hdr_tags: *image_hdr_tags,
})
}
}

fn perform(req: &[u8], user_data: &[u8]) -> Result<SeAttestationResponse> {
let request = SeAttestationRequest::from_slice(req)?;
let mut uvc: AttestationCmd = request.to_uvc(user_data)?;
let uv = UvDevice::open()?;
uv.send_cmd(&mut uvc)?;

let measurement = uvc.measurement().to_vec().clone();
let cuid = uvc.cuid();
let additional_data = uvc
.additional_owned()
.ok_or(anyhow!("Failed to get additinal data."))?;
let encr_measurement_key = &request.encr_measurement_key;
let encr_request_nonce = &request.encr_request_nonce;
let image_hdr_tags = &request.image_hdr_tags;

SeAttestationResponse::create(
&measurement,
&additional_data,
user_data,
cuid,
encr_measurement_key,
encr_request_nonce,
image_hdr_tags,
)
}
21 changes: 3 additions & 18 deletions attestation-agent/attester/src/se/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,22 @@
//

use super::Attester;
use crate::se::ibmse::FakeSeAttest;
use crate::se::ibmse::IbmSeAttester;
use anyhow::*;
use base64::prelude::*;
use serde::{Deserialize, Serialize};

pub mod ibmse;

pub fn detect_platform() -> bool {
// TODO replace FakeSeAttest with real IBM SE crate
let attester = FakeSeAttest::default();
attester.is_se_guest()
ibmse.is_se_guest()
}

#[derive(Serialize, Deserialize)]
struct SeEvidence {
quote: Vec<u8>,
}

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

#[async_trait::async_trait]
impl Attester for SeAttester {
async fn get_evidence(&self, attestation_request: Vec<u8>) -> Result<String> {
// TODO replace FakeSeAttest with real IBM SE crate
let attester = FakeSeAttest::default();
let userdata = "userdata".as_bytes().to_vec();
let evidence = attester.perform(attestation_request, userdata).await?;

Ok(BASE64_STANDARD.encode(evidence))
let evidence = ibmse.perform(attestation_request, userdata).await?;
serde_json::to_string(&evidence).context("Serialize SE evidence failed")
}
}

Expand Down
5 changes: 4 additions & 1 deletion attestation-agent/kbs_protocol/src/client/rcar_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,10 @@ impl KbsClient<Box<dyn EvidenceProvider>> {
let mut ehd = hasher.finalize().to_vec();
// IBM SE uses challenge_extra_params as runtime_data to pass attestation_request
if tee == Tee::Se {
ehd = challenge_extra_params.into_bytes();
// This is base64 encoded SeAttestationRequest
// we need decode it as &[u8] and pass it to IBM SE attester.get_evidence
//ehd = challenge_extra_params.into_bytes();
ehd = BASE64_STANDARD.decode(challenge_extra_params)
}

let tee_evidence = self
Expand Down

0 comments on commit 45ab965

Please sign in to comment.