secGear/0082-optimize-ima-verify.patch
steven ygui cdbe318f8c backport patches
(cherry picked from commit 09f96d31f45e35ba932a9478062cd3fc3c07253c)
2024-11-08 11:46:16 +08:00

244 lines
9.8 KiB
Diff

From 7d54eae7dbfdbad1de6bac40468c8de9a7260a8b Mon Sep 17 00:00:00 2001
From: houmingyong <houmingyong@huawei.com>
Date: Mon, 26 Aug 2024 20:13:49 +0800
Subject: [PATCH 1/2] optimize ima verify
Signed-off-by: houmingyong <houmingyong@huawei.com>
---
.../attestation-service/service/src/lib.rs | 17 +++-
.../attestation-service/verifier/src/lib.rs | 20 ----
.../verifier/src/virtcca/ima.rs | 93 +++++++++----------
.../verifier/src/virtcca/mod.rs | 13 ++-
4 files changed, 69 insertions(+), 74 deletions(-)
diff --git a/service/attestation/attestation-service/service/src/lib.rs b/service/attestation/attestation-service/service/src/lib.rs
index cc3f4328..3ec73d3d 100644
--- a/service/attestation/attestation-service/service/src/lib.rs
+++ b/service/attestation/attestation-service/service/src/lib.rs
@@ -100,11 +100,20 @@ impl AttestationService {
let verifier = Verifier::default();
let claims_evidence = verifier.verify_evidence(user_data, evidence).await?;
- let mut passed = false;
- let ima_result = verifier.verify_ima(evidence, &claims_evidence).await;
- if ima_result.is_ok() {
- passed = true;
+ let mut passed = true;
+ log::debug!("claims evidece ima: {:?}", claims_evidence["ima"].clone());
+ match claims_evidence["ima"].clone() {
+ serde_json::Value::Object(obj) => {
+ for (_k, v) in obj {
+ if v == Value::Bool(false) {
+ passed = false;
+ break;
+ }
+ }
+ }
+ _ => log::debug!("no ima result"),
}
+
// get reference by keys in claims_evidence
let mut ops_refs = ReferenceOps::default();
let refs_of_claims = ops_refs.query(&claims_evidence["payload"].to_string());
diff --git a/service/attestation/attestation-service/verifier/src/lib.rs b/service/attestation/attestation-service/verifier/src/lib.rs
index 58df3bd4..0b776c29 100644
--- a/service/attestation/attestation-service/verifier/src/lib.rs
+++ b/service/attestation/attestation-service/verifier/src/lib.rs
@@ -34,10 +34,6 @@ pub struct Verifier {}
#[async_trait]
pub trait VerifierAPIs {
async fn verify_evidence(&self, user_data: &[u8], evidence: &[u8]) -> Result<TeeClaim>;
- async fn verify_ima(&self,
- evidence: &[u8],
- claim: &serde_json::Value,
- ) -> Result<()>;
}
const MAX_CHALLENGE_LEN: usize = 64;
@@ -61,20 +57,4 @@ impl VerifierAPIs for Verifier {
_ => bail!("unsupported tee type:{:?}", tee_type),
}
}
- async fn verify_ima(&self,
- evidence: &[u8],
- claim: &serde_json::Value,
- ) -> Result<()> {
- let aa_evidence: Evidence = serde_json::from_slice(evidence)?;
- let tee_type = aa_evidence.tee;
- let digest_list_file = "/etc/attestation/attestation-service/verifier/digest_list_file".to_string();
- match tee_type {
- #[cfg(feature = "virtcca-verifier")]
- TeeType::Virtcca => virtcca::ima::ImaVerify::default().ima_verify(evidence, claim, digest_list_file),
- _ => {
- log::info!("unsupported ima type:{:?}", tee_type);
- Ok(())
- },
- }
- }
}
diff --git a/service/attestation/attestation-service/verifier/src/virtcca/ima.rs b/service/attestation/attestation-service/verifier/src/virtcca/ima.rs
index 44292e83..30a151fa 100644
--- a/service/attestation/attestation-service/verifier/src/virtcca/ima.rs
+++ b/service/attestation/attestation-service/verifier/src/virtcca/ima.rs
@@ -12,46 +12,20 @@
use anyhow::{Result, bail};
use ima_measurements::{Event, EventData, Parser};
use fallible_iterator::FallibleIterator;
-use std::fs;
-use std::process::Command;
-use serde_json::Value;
-use rand::Rng;
+use serde_json::{Value, Map, json};
-use attestation_types::{Evidence, VirtccaEvidence};
+const IMA_REFERENCE_FILE: &str = "/etc/attestation/attestation-service/verifier/virtcca/ima/digest_list_file";
-#[derive(Debug)]
-pub struct ImaVerify {
- log_path: String,
-}
-
-impl Default for ImaVerify {
- fn default() -> Self {
- let mut rng = rand::thread_rng();
- let n: u64 = rng.gen();
- ImaVerify {
- // log_path: format!("/tmp/attestation-service/ima-log-{}", n), // todo fs::write depends attestation-service dir exist
- log_path: format!("/tmp/ima-log-{}", n),
- }
- }
-}
+#[derive(Debug, Default)]
+pub struct ImaVerify {}
impl ImaVerify {
- // todo return detail verify result list with policy
- pub fn ima_verify(&self, evidence: &[u8], claim: &Value, digest_list_file: String) -> Result<()> {
- let aa_evidence: Evidence = serde_json::from_slice(evidence)?;
- let evidence = aa_evidence.evidence.as_bytes();
- let virtcca_ev: VirtccaEvidence = serde_json::from_slice(evidence)?;
- let ima_log = match virtcca_ev.ima_log {
- Some(ima_log) => ima_log,
- _ => {log::info!("no ima log"); return Ok(())},
- };
-
- fs::write(&self.log_path, &ima_log).expect("write img log failed");
- let f = fs::File::open(&self.log_path).expect("ima log file not found");
-
- let claim_ima_log_hash = claim["payload"]["cvm"]["rem"][0].clone();
- let mut parser = Parser::new(f);
+ pub fn ima_verify(&self, ima_log: &[u8], ima_log_hash: Vec<u8>) -> Result<Value> {
+ if ima_log.to_vec().is_empty() {
+ return Ok(json!({}));
+ }
+ let mut parser = Parser::new(ima_log);
let mut events: Vec<Event> = Vec::new();
while let Some(event) = parser.next()? {
events.push(event);
@@ -60,32 +34,55 @@ impl ImaVerify {
let pcr_values = parser.pcr_values();
let pcr_10 = pcr_values.get(&10).expect("PCR 10 not measured");
let string_pcr_sha256 = hex::encode(pcr_10.sha256);
+ let string_ima_log_hash = hex::encode(ima_log_hash);
- if Value::String(string_pcr_sha256.clone()) != claim_ima_log_hash {
- log::error!("ima log verify failed string_pcr_sha256 {}, string_claim_ima_log_hash {}", string_pcr_sha256, claim_ima_log_hash);
+ if string_pcr_sha256.clone() != string_ima_log_hash {
+ log::error!("ima log verify failed string_pcr_sha256 {}, string_ima_log_hash {}",
+ string_pcr_sha256, string_ima_log_hash);
bail!("ima log hash verify failed");
}
+ let ima_refs: Vec<_> = file_reader(IMA_REFERENCE_FILE)?
+ .into_iter()
+ .map(String::from)
+ .collect();
+
+ let mut ima_detail = Map::new();
// parser each file digest in ima log, and compare with reference base value
for event in events {
- let file_digest = match event.data {
- EventData::ImaNg{digest, name} => {drop(name); digest.digest},
+ let (name ,file_digest) = match event.data {
+ EventData::ImaNg{digest, name} => (name, digest.digest),
_ => bail!("Inalid event {:?}", event),
};
let hex_str_digest = hex::encode(file_digest);
- //log::info!("hex_str_digest {}", hex_str_digest);
- let output = Command::new("grep")
- .arg("-E")
- .arg("-i")
- .arg(&hex_str_digest)
- .arg(&digest_list_file)
- .output()?;
- if output.stdout.is_empty() {
+ if ima_refs.contains(&hex_str_digest) {
+ ima_detail.insert(name, Value::Bool(true));
+ } else {
log::error!("there is no refernce base value of file digest {:?}", hex_str_digest);
+ ima_detail.insert(name, Value::Bool(false));
}
}
+ let js_ima_detail: Value = ima_detail.into();
+ log::debug!("ima verify detail result: {:?}", js_ima_detail);
- Ok(())
+ Ok(js_ima_detail)
}
}
+use std::io::BufRead;
+use std::io::BufReader;
+fn file_reader(file_path: &str) -> ::std::io::Result<Vec<String>> {
+ let file = std::fs::File::open(file_path)?;
+ let mut strings = Vec::<String>::new();
+ let mut reader = BufReader::new(file);
+ let mut buf = String::new();
+ let mut n: usize;
+ loop {
+ n = reader.read_line(&mut buf)?;
+ if n == 0 { break; }
+ buf.pop();
+ strings.push(buf.clone());
+ buf.clear();
+ }
+ Ok(strings)
+}
diff --git a/service/attestation/attestation-service/verifier/src/virtcca/mod.rs b/service/attestation/attestation-service/verifier/src/virtcca/mod.rs
index 3ececb78..a99f9358 100644
--- a/service/attestation/attestation-service/verifier/src/virtcca/mod.rs
+++ b/service/attestation/attestation-service/verifier/src/virtcca/mod.rs
@@ -103,10 +103,18 @@ impl Evidence {
// verify cvm token
evidence.verify_cvm_token(user_data)?;
+ // verify ima
+ let ima_log = match virtcca_ev.ima_log {
+ Some(ima_log) => ima_log,
+ _ => {log::info!("no ima log"); vec![]},
+ };
+ let ima: serde_json::Value = ima::ImaVerify::default()
+ .ima_verify(&ima_log, evidence.cvm_token.rem[0].clone())?;
+
// todo parsed TeeClaim
- evidence.parse_claim_from_evidence()
+ evidence.parse_claim_from_evidence(ima)
}
- fn parse_claim_from_evidence(&self) -> Result<TeeClaim> {
+ fn parse_claim_from_evidence(&self, ima: serde_json::Value) -> Result<TeeClaim> {
let payload = json!({
"vcca.cvm.challenge": hex::encode(self.cvm_token.challenge.clone()),
"vcca.cvm.rpv": hex::encode(self.cvm_token.rpv.clone()),
@@ -120,6 +128,7 @@ impl Evidence {
let claim = json!({
"tee": "vcca",
"payload" : payload,
+ "ima": ima,
});
Ok(claim as TeeClaim)
}
--
2.46.0