Skip to content

Commit

Permalink
Verifier: Add IBM Secure Execution verifier driver framework
Browse files Browse the repository at this point in the history
Signed-off-by: Qi Feng Huo <huoqif@cn.ibm.com>
  • Loading branch information
Qi Feng Huo committed Mar 6, 2024
1 parent 9b8ef6c commit 362c641
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ clap = { version = "4", features = ["derive"] }
config = "0.13.3"
env_logger = "0.10.0"
hex = "0.4.3"
kbs-types = "0.5.3"
kbs-types = "0.5.3" // TODO, update to pick new TEE type for IBM Secure Eexcution (SE) in https://github.com/virtee/kbs-types/blob/main/src/lib.rs#L24
jsonwebtoken = "9"
log = "0.4.17"
prost = "0.11.0"
Expand Down
3 changes: 3 additions & 0 deletions attestation-service/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Today, the AS can validate evidence from the following TEEs:
- Hygon CSV
- Intel TDX with vTPM on Azure
- AMD SEV-SNP with vTPM on Azure
- IBM Secure Execution (SE)

# Overview
```
Expand Down Expand Up @@ -102,6 +103,7 @@ Please refer to the individual verifiers for the specific format of the evidence
- Azure TDX vTPM: [Evidence](./verifier/src/az_tdx_vtpm/mod.rs)
- Arm CCA: [CcaEvidence](./verifier/src/cca/mod.rs)
- Hygon CSV: [CsvEvidence](./verifier/src/csv/mod.rs)
- IBM Secure Execution (SE) [(SeEvidence)](./verifier/src/se/mod.rs)

## Output

Expand Down Expand Up @@ -154,6 +156,7 @@ Supported Verifier Drivers:
- `azsnpvtpm`: Verifier Driver for Azure vTPM based on SNP (Azure SNP vTPM)
- `cca`: Verifier Driver for Confidential Compute Architecture (Arm CCA).
- `csv`: Verifier Driver for China Security Virtualization (Hygon CSV).
- `se`: Verifier Driver for IBM Secure Execution (SE).

## Policy Engine

Expand Down
5 changes: 5 additions & 0 deletions attestation-service/attestation-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ impl AttestationService {
pub async fn register_reference_value(&mut self, message: &str) -> Result<()> {
self.rvps.verify_and_extract(message).await
}

pub async fn generate_challenge(&self, tee: Tee, nonce: &str) -> Result<Challenge> {
let verifier = verifier::to_verifier(&tee)?;
verifier.generate_challenge(nonce)
}
}

/// Get the expected init/runtime data and potential claims due to the given input
Expand Down
3 changes: 2 additions & 1 deletion attestation-service/verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ edition = "2021"

[features]
default = [ "all-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "az-tdx-vtpm-verifier", "csv-verifier", "cca-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "az-tdx-vtpm-verifier", "csv-verifier", "cca-verifier", "se-verifier" ]
tdx-verifier = [ "eventlog-rs", "scroll", "sgx-dcap-quoteverify-rs" ]
sgx-verifier = [ "scroll", "sgx-dcap-quoteverify-rs" ]
az-snp-vtpm-verifier = [ "az-snp-vtpm", "sev", "snp-verifier" ]
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" ]

[dependencies]
anyhow.workspace = true
Expand Down
26 changes: 25 additions & 1 deletion attestation-service/verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::cmp::Ordering;

use anyhow::*;
use async_trait::async_trait;
use kbs_types::Tee;
use kbs_types::{Challenge, Tee};
use log::warn;

pub mod sample;
Expand All @@ -28,6 +28,9 @@ pub mod csv;
#[cfg(feature = "cca-verifier")]
pub mod cca;

#[cfg(feature = "se-verifier")]
pub mod se;

pub fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>> {
match tee {
Tee::Sev => todo!(),
Expand Down Expand Up @@ -99,6 +102,17 @@ pub fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>> {
}
}
}

Tee::Se => {
cfg_if::cfg_if! {
if #[cfg(feature = "se-verifier")] {
Ok(Box::<se::Se>::default() as Box<dyn Verifier + Send + Sync>)
} else {
bail!("feature `se-verifier` is not enabled for `verifier` crate.")
}
}
}

}
}

Expand Down Expand Up @@ -152,6 +166,16 @@ pub trait Verifier {
expected_report_data: &ReportData,
expected_init_data_hash: &InitDataHash,
) -> Result<TeeEvidenceParsedClaim>;

async fn generate_challenge(
&self,
nonce: &str) -> Result<Challenge> {

Result::Ok(Challenge {
nonce,
extra_params: String::new(),
})
}
}

/// Padding or truncate the given data slice to the given `len` bytes.
Expand Down
62 changes: 62 additions & 0 deletions attestation-service/verifier/src/se/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (C) Copyright IBM Corp. 2024
//
// SPDX-License-Identifier: Apache-2.0
//

use async_trait::async_trait;
use anyhow::anyhow;
use base64::prelude::*;
use kbs_types::{Challenge, Tee};
use crate::{InitDataHash, ReportData};
use super::{TeeEvidenceParsedClaim, Verifier};
use crate::se::seattest::FakeSeAttest;
use crate::se::seattest::SeFakeVerifier;

pub mod seattest;

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

#[async_trait]
impl Verifier for SeVerifier {
async fn evaluate(
&self,
evidence: &[u8],
expected_report_data: &ReportData,
expected_init_data_hash: &InitDataHash,
) -> Result<TeeEvidenceParsedClaim> {
verify_evidence(evidence, expected_report_data, expected_init_data_hash)
.await
.map_err(|e| anyhow!("Se Verifier: {:?}", e))
}

async fn generate_challenge(&self, tee: Tee, nonce: &str) -> Result<Challenge> {
/// TODO replace FakeSeAttest with real crate
let attester = FakeSeAttest::default();

let hkds: Vec<String> = vec![String::new(); 2];
let certk = String::new();
let signk = String::new();
let arpk = String::new();
Result::Ok(Challenge {
nonce,
extra_params: BASE64_STANDARD.encode(attester.create(hkds, certk, signk, arpk)),
})
}
}

async fn verify_evidence(
evidence: &[u8],
expected_report_data: &ReportData<'_>,
expected_init_data_hash: &InitDataHash<'_>,
) -> Result<TeeEvidenceParsedClaim> {
/// TODO replace FakeSeAttest with real crate
let attester = FakeSeAttest::default();

let arpk = String::new();
let hdr = String::new();
let se = attester.verify(evidence, arpk, hdr);

let v = serde_json::to_value(se?).context("build json value from the se evidence")?;
Ok(v as TeeEvidenceParsedClaim)
}
50 changes: 50 additions & 0 deletions attestation-service/verifier/src/se/seattest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (C) Copyright IBM Corp. 2024
//
// 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(
&self,
hkdFiles: Vec<String>,
certFile: &String,
signingFile: &String,
arpkFile: &String
) -> Result<Vec<u8>>;

async fn verify(
&self,
evidence: Vec<u8>,
arpkFile: &String,
hdr: Vec<u8>
) -> Result<Vec<u8>>;
}

#[async_trait::async_trait]
impl SeFakeVerifier for FakeSeAttest {
async fn create(
&self,
hkdFiles: Vec<String>,
certFile: &String,
signingFile: &String,
arpkFile: &String
) -> Result<Vec<u8>> {
Result::Ok(Vec::new())
}

async fn verify(
&self,
evidence: Vec<u8>,
arpkFile: &String,
hdr: Vec<u8>
) -> Result<Vec<u8>> {
Result::Ok(Vec::new())
}
}
1 change: 1 addition & 0 deletions kbs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ In conjunction with the AS or Intel Trust Authority (ITA), the KBS supports the
- Intel SGX
- ARM CCA
- Hygon CSV
- IBM Secure Execution (SE)

# Deployment Configurations

Expand Down
16 changes: 15 additions & 1 deletion kbs/src/api/src/attestation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use attestation_service::config::Config as AsConfig;
use coco::grpc::*;
#[cfg(feature = "intel-trust-authority-as")]
use intel_trust_authority::*;
use kbs_types::Tee;
use kbs_types::{Challenge, Request, Tee};

#[cfg(feature = "coco-as")]
#[allow(missing_docs)]
Expand All @@ -32,6 +32,9 @@ pub trait Attest: Send + Sync {
/// Verify Attestation Evidence
/// Return Attestation Results Token
async fn verify(&self, tee: Tee, nonce: &str, attestation: &str) -> Result<String>;

/// generate the challenge payload to pass to attester based on Tee and nonce
async fn generate_challenge(&self, tee: Tee, nonce: &str) -> Result<Challenge>;
}

/// Attestation Service
Expand Down Expand Up @@ -89,4 +92,15 @@ impl AttestationService {
AttestationService::IntelTA(inner) => inner.set_policy(input).await,
}
}

pub async fn generate_challenge(&self, tee: Tee, nonce: &str) -> Result<Challenge> {
match self {
#[cfg(feature = "coco-as-grpc")]
AttestationService::CoCoASgRPC(inner) => inner.generate_challenge(tee, nonce).await,
#[cfg(any(feature = "coco-as-builtin", feature = "coco-as-builtin-no-verifier"))]
AttestationService::CoCoASBuiltIn(inner) => inner.generate_challenge(tee, nonce, attestation).await,
#[cfg(feature = "intel-trust-authority-as")]
AttestationService::IntelTA(inner) => inner.generate_challenge(tee, nonce).await,
}
}
}
16 changes: 15 additions & 1 deletion kbs/src/api/src/http/attest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,31 @@ use anyhow::anyhow;
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use base64::Engine;
use log::{error, info};
use rand::{thread_rng, Rng};
use serde_json::json;

fn nonce() -> Result<String> {
let mut nonce: Vec<u8> = vec![0; 32];

thread_rng()
.try_fill(&mut nonce[..])
.map_err(anyhow::Error::from)?;

Ok(STANDARD.encode(&nonce))
}

/// POST /auth
pub(crate) async fn auth(
request: web::Json<Request>,
map: web::Data<SessionMap>,
timeout: web::Data<i64>,
attestation_service: web::Data<Arc<AttestationService>>,
) -> Result<HttpResponse> {
info!("request: {:?}", &request);

let session = SessionStatus::auth(request.0, **timeout)
let challenge = attestation_service.generate_challenge(nonce()?);

let session = SessionStatus::auth(request.0, **timeout, challenge)
.map_err(|e| Error::FailedAuthentication(format!("Session: {e}")))?;

let response = HttpResponse::Ok()
Expand Down
19 changes: 3 additions & 16 deletions kbs/src/api/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,12 @@ use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use kbs_types::{Challenge, Request};
use log::warn;
use rand::{thread_rng, Rng};
// use rand::{thread_rng, Rng};
use semver::Version;
use uuid::Uuid;

pub(crate) static KBS_SESSION_ID: &str = "kbs-session-id";

fn nonce() -> Result<String> {
let mut nonce: Vec<u8> = vec![0; 32];

thread_rng()
.try_fill(&mut nonce[..])
.map_err(anyhow::Error::from)?;

Ok(STANDARD.encode(&nonce))
}

/// Finite State Machine model for RCAR handshake
pub(crate) enum SessionStatus {
Authed {
Expand Down Expand Up @@ -63,7 +53,7 @@ macro_rules! impl_member {
}

impl SessionStatus {
pub fn auth(request: Request, timeout: i64) -> Result<Self> {
pub fn auth(request: Request, timeout: i64, challenge: &Challenge) -> Result<Self> {
let version = Version::parse(&request.version).map_err(anyhow::Error::from)?;
if !crate::VERSION_REQ.matches(&version) {
bail!("Invalid Request version {}", request.version);
Expand All @@ -74,10 +64,7 @@ impl SessionStatus {

Ok(Self::Authed {
request,
challenge: Challenge {
nonce: nonce()?,
extra_params: String::new(),
},
challenge,
id,
timeout,
})
Expand Down

0 comments on commit 362c641

Please sign in to comment.