Skip to content
This repository has been archived by the owner on Nov 21, 2023. It is now read-only.

Commit

Permalink
Add initial support for a hygon csv verifier
Browse files Browse the repository at this point in the history
Signed-off-by: fangbaoshun <[email protected]>
  • Loading branch information
BaoshunFang committed Aug 16, 2023
1 parent 8945823 commit 1eaa909
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 4 deletions.
3 changes: 2 additions & 1 deletion as-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
kbs-types = "0.4"
# TODO: change it to "0.5", once released.
kbs-types = { git = "https://github.com/virtee/kbs-types", rev = "c90df0e" }
serde.workspace = true
serde_json.workspace = true
11 changes: 8 additions & 3 deletions attestation-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ edition = "2021"

[features]
default = [ "rvps-native", "all-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier" ]
all-verifier = [ "tdx-verifier", "sgx-verifier", "snp-verifier", "az-snp-vtpm-verifier", "csv-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 = [ "asn1-rs", "openssl", "sev", "x509-parser" ]
csv-verifier = [ "openssl", "csv-rs", "codicon" ]

rvps-native = []
rvps-grpc = [ "tonic" ]
Expand All @@ -29,10 +30,11 @@ eventlog-rs = { version = "0.1.3", optional = true }
futures = "0.3.17"
hex = "0.4.3"
sgx-dcap-quoteverify-rs = { git = "https://github.com/intel/SGXDataCenterAttestationPrimitives", tag = "DCAP_1.16", optional = true }
kbs-types = "0.4"
# TODO: change it to "0.5", once released.
kbs-types = { git = "https://github.com/virtee/kbs-types", rev = "c90df0e" }
lazy_static = "1.4.0"
log.workspace = true
openssl = { version = "0.10.43", optional = true }
openssl = { version = "0.10.55", optional = true }
path-clean = "1.0.1"
prost.workspace = true
scroll = { version = "0.11.0", default-features = false, features = ["derive"], optional = true }
Expand All @@ -50,6 +52,9 @@ tokio.workspace = true
tonic = { workspace = true, optional = true }
uuid = { version = "1.1.2", features = ["v4"] }
x509-parser = { version = "0.14.0", optional = true }
# TODO: change it to "0.1", once released.
csv-rs = { git = "https://gitee.com/anolis/csv-rs", rev = "8a90aac", optional = true }
codicon = { version = "3.0", optional = true }

[build-dependencies]
shadow-rs.workspace = true
Expand Down
Binary file added attestation-service/src/verifier/csv/hrk.cert
Binary file not shown.
164 changes: 164 additions & 0 deletions attestation-service/src/verifier/csv/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright (C) Hygon Info Technologies Ltd.
//
// SPDX-License-Identifier: Apache-2.0
//

use anyhow::{anyhow, Context, Result};
extern crate serde;
use self::serde::{Deserialize, Serialize};
use super::*;
use async_trait::async_trait;
use base64::Engine;
use serde_json::json;
use sha2::{Digest, Sha384};
use csv_rs::{
api::guest::{AttestationReport, Body},
certs::{ca, csv, Verifiable},
};
use codicon::Decoder;
use kbs_types::TeePubKey;

#[derive(Serialize, Deserialize)]
struct CertificateChain {
hsk: ca::Certificate,
cek: csv::Certificate,
pek: csv::Certificate,
}

#[derive(Serialize, Deserialize)]
struct CsvEvidence {
attestation_report: AttestationReport,
cert_chain: CertificateChain,
}

pub const HRK: &[u8] = include_bytes!("hrk.cert");

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

#[async_trait]
impl Verifier for CsvVerifier {
async fn evaluate(
&self,
nonce: String,
attestation: &Attestation,
) -> Result<TeeEvidenceParsedClaim> {
let tee_evidence = serde_json::from_str::<CsvEvidence>(&attestation.tee_evidence)
.context("Deserialize Quote failed.")?;

verify_report_signature(&tee_evidence)?;

let report_raw = restore_attestation_report(tee_evidence.attestation_report)?;

let expected_report_data = calculate_expected_report_data(&nonce, &attestation.tee_pubkey);
if report_raw.body.report_data != expected_report_data {
return Err(anyhow!("Report Data Mismatch"));
}

parse_tee_evidence(&report_raw)
}
}

fn calculate_expected_report_data(nonce: &String, tee_pubkey: &TeePubKey) -> [u8; 64] {
let mut hasher = Sha384::new();

hasher.update(nonce.as_bytes());
hasher.update(&tee_pubkey.k_mod);
hasher.update(&tee_pubkey.k_exp);

let partial_hash = hasher.finalize();

let mut hash = [0u8; 64];
hash[..48].copy_from_slice(&partial_hash);

hash
}

fn verify_report_signature(evidence: &CsvEvidence) -> Result<()> {
// Verify certificate chain
let hrk = ca::Certificate::decode(&mut &HRK[..], ())?;
(&hrk, &hrk).verify()
.context("HRK cert Signature validation failed.")?;
(&hrk, &evidence.cert_chain.hsk).verify()
.context("HSK cert Signature validation failed.")?;
(&evidence.cert_chain.hsk, &evidence.cert_chain.cek).verify()
.context("CEK cert Signature validation failed.")?;
(&evidence.cert_chain.cek, &evidence.cert_chain.pek).verify()
.context("PEK cert Signature validation failed.")?;

// Verify the TEE Hardware signature.
(&evidence.cert_chain.pek, &evidence.attestation_report).verify()
.context("Attestation Report Signature validation failed.")?;

Ok(())
}

fn xor_with_anonce(data: &mut [u8], anonce: &u32){
let mut anonce_array = [0u8; 4];
anonce_array[..].copy_from_slice(&anonce.to_le_bytes());

for (index, item) in data.iter_mut().enumerate() {
*item ^= anonce_array[index % 4];
}
}

fn restore_attestation_report(report: AttestationReport) -> Result<AttestationReport> {
let body = &report.body;
let mut user_pubkey_digest = body.user_pubkey_digest.clone();
xor_with_anonce(&mut user_pubkey_digest, &report.anonce);
let mut vm_id = body.vm_id.clone();
xor_with_anonce(&mut vm_id, &report.anonce);
let mut vm_version = body.vm_version.clone();
xor_with_anonce(&mut vm_version, &report.anonce);
let mut report_data = body.report_data.clone();
xor_with_anonce(&mut report_data, &report.anonce);
let mut mnonce = body.mnonce.clone();
xor_with_anonce(&mut mnonce, &report.anonce);
let mut measure = body.measure.clone();
xor_with_anonce(&mut measure, &report.anonce);

let policy = report.body.policy.xor(&report.anonce);

Ok(AttestationReport {
body: Body {
user_pubkey_digest,
vm_id,
vm_version,
report_data,
mnonce,
measure,
policy,
},
..report
})
}

// Dump the CSV information from the report.
fn parse_tee_evidence(report: &AttestationReport) -> Result<TeeEvidenceParsedClaim> {
let body = &report.body;
let claims_map = json!({
// policy fields
"policy_nodbg": format!("{}",body.policy.nodbg()),
"policy_noks": format!("{}", body.policy.noks()),
"policy_es": format!("{}", body.policy.es()),
"policy_nosend": format!("{}", body.policy.nosend()),
"policy_domain": format!("{}", body.policy.domain()),
"policy_csv": format!("{}", body.policy.csv()),
"policy_csv3": format!("{}", body.policy.csv3()),
"policy_asid_reuse": format!("{}", body.policy.asid_reuse()),
"policy_hsk_version": format!("{}", body.policy.hsk_version()),
"policy_cek_version": format!("{}", body.policy.cek_version()),
"policy_api_major": format!("{}", body.policy.api_major()),
"policy_api_minor": format!("{}", body.policy.api_minor()),

// launch info inject with pdh and session data
"user_pubkey_digest": format!("{}", base64::engine::general_purpose::STANDARD.encode(body.user_pubkey_digest)),
"vm_id": format!("{}", base64::engine::general_purpose::STANDARD.encode(body.vm_id)),
"vm_version": format!("{}", base64::engine::general_purpose::STANDARD.encode(body.vm_version)),

// measurement
"measurement": format!("{}", base64::engine::general_purpose::STANDARD.encode(body.measure)),
});

Ok(claims_map as TeeEvidenceParsedClaim)
}
12 changes: 12 additions & 0 deletions attestation-service/src/verifier/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ pub mod tdx;
#[cfg(feature = "sgx-verifier")]
pub mod sgx;

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

pub(crate) fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>> {
match tee {
Tee::Sev | Tee::Cca => todo!(),
Expand Down Expand Up @@ -57,6 +60,15 @@ pub(crate) fn to_verifier(tee: &Tee) -> Result<Box<dyn Verifier + Send + Sync>>
}
}
}
Tee::Csv => {
cfg_if::cfg_if! {
if #[cfg(feature = "csv-verifier")] {
Ok(Box::<csv::CsvVerifier>::default() as Box<dyn Verifier + Send + Sync>)
} else {
anyhow::bail!("feature `csv-verifier` is not enabled!");
}
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions bin/grpc-as/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ fn to_kbs_tee(tee: GrpcTee) -> Tee {
GrpcTee::Sgx => Tee::Sgx,
GrpcTee::Snp => Tee::Snp,
GrpcTee::Tdx => Tee::Tdx,
GrpcTee::Csv => Tee::Csv,
GrpcTee::Sample => Tee::Sample,
}
}
Expand Down
1 change: 1 addition & 0 deletions protos/attestation.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum Tee {
SNP = 2;
TDX = 3;
Sample = 4;
CSV = 6;
}

message AttestationRequest {
Expand Down

0 comments on commit 1eaa909

Please sign in to comment.