From 4c8cdfe83a5aa2e0e7c032093a13350d4f9b2559 Mon Sep 17 00:00:00 2001 From: Tobin Feldman-Fitzthum Date: Fri, 4 Oct 2024 12:01:49 -0500 Subject: [PATCH] rvps: change interface to get all reference values Previously we expected the caller of the RVPS to provide a name for the reference value that they wanted. In the AS we were flattening the TCB claims to get this name. Ultimately, the names of the TCB claims do not map directly onto the names of the required reference values. This changes the interface to have the RVPS determine which reference values to send. At the moment, it simply sends all of them. This allows the reference values that are used to mostly be set within the policy itself, which is probably a good idea. In the future, the RVPS should be improved to include a context abtraction that allows groups of reference values to be provided to the AS. Signed-off-by: Tobin Feldman-Fitzthum --- attestation-service/src/lib.rs | 18 +++----- protos/reference.proto | 4 +- rvps/src/bin/rvps-tool.rs | 12 ++---- rvps/src/bin/server/mod.rs | 13 ++---- .../extractor_modules/sample/mod.rs | 9 ++-- rvps/src/native.rs | 43 ++++++++----------- rvps/src/reference_value.rs | 31 +++++++------ rvps/src/store/local_fs/mod.rs | 10 +++++ rvps/src/store/local_json/mod.rs | 7 +++ rvps/src/store/mod.rs | 10 ++--- 10 files changed, 77 insertions(+), 80 deletions(-) diff --git a/attestation-service/src/lib.rs b/attestation-service/src/lib.rs index e0bf5167f..f2a71145f 100644 --- a/attestation-service/src/lib.rs +++ b/attestation-service/src/lib.rs @@ -207,16 +207,9 @@ impl AttestationService { runtime_data_claims, tee, )?; - debug!("tcb_claims: {:#?}", tcb_claims); - // TODO: now that claims aren't flattened, this will not work. - // reference values do not map onto claim names anyway. - // change RVPS to provide all reference values for a given - // context. - let reference_data_map = self - .get_reference_data(tcb_claims.keys()) - .await + let reference_data_map = self.rvps.get_digests().await .map_err(|e| anyhow!("Generate reference data failed: {:?}", e))?; debug!("reference_data_map: {:#?}", reference_data_map); @@ -241,13 +234,12 @@ impl AttestationService { Ok(attestation_results_token) } - async fn get_reference_data<'a, I>(&self, tcb_claims: I) -> Result>> - where - I: Iterator, - { + async fn get_reference_data<'a, I>(&self) -> Result>> { let mut data = HashMap::new(); + let reference_values = self.rvps.get_digests().await?; + for + for key in tcb_claims { - let reference_value = self.rvps.get_digests(key).await?; if !reference_value.is_empty() { debug!("Successfully get reference values of {key} from RVPS."); } diff --git a/protos/reference.proto b/protos/reference.proto index e550893ee..7adefeb4c 100644 --- a/protos/reference.proto +++ b/protos/reference.proto @@ -2,9 +2,7 @@ syntax = "proto3"; package reference; -message ReferenceValueQueryRequest { - string name = 1; -} +message ReferenceValueQueryRequest {} message ReferenceValueQueryResponse { string reference_value_results = 1; diff --git a/rvps/src/bin/rvps-tool.rs b/rvps/src/bin/rvps-tool.rs index 8065eee92..709a8d4fa 100644 --- a/rvps/src/bin/rvps-tool.rs +++ b/rvps/src/bin/rvps-tool.rs @@ -31,11 +31,9 @@ async fn register(addr: &str, provenance_path: &str) -> Result<()> { Ok(()) } -async fn query(addr: &str, name: &str) -> Result<()> { +async fn query(addr: &str) -> Result<()> { let mut client = ReferenceValueProviderServiceClient::connect(addr.to_string()).await?; - let req = tonic::Request::new(ReferenceValueQueryRequest { - name: name.to_string(), - }); + let req = tonic::Request::new(ReferenceValueQueryRequest {}); let rvs = client .query_reference_value(req) @@ -77,10 +75,6 @@ struct QueryArgs { /// The address of target RVPS #[arg(short, long, default_value = DEFAULT_ADDR)] addr: String, - - /// The name to query reference value - #[arg(short, long)] - name: String, } #[tokio::main] @@ -100,6 +94,6 @@ async fn main() -> Result<()> { match cli { Cli::Register(para) => register(¶.addr, ¶.path).await, - Cli::Query(para) => query(¶.addr, ¶.name).await, + Cli::Query(para) => query(¶.addr).await, } } diff --git a/rvps/src/bin/server/mod.rs b/rvps/src/bin/server/mod.rs index f12881d50..94473876e 100644 --- a/rvps/src/bin/server/mod.rs +++ b/rvps/src/bin/server/mod.rs @@ -31,21 +31,16 @@ impl RVPSServer { impl ReferenceValueProviderService for RVPSServer { async fn query_reference_value( &self, - request: Request, + _request: Request, ) -> Result, Status> { - let request = request.into_inner(); - - info!("query {}", request.name); - let rvs = self .rvps .lock() .await - .get_digests(&request.name) + .get_digests() .await - .map_err(|e| Status::aborted(format!("Query reference value: {e}")))? - .map(|rvs| rvs.hash_values) - .unwrap_or_default(); + .map_err(|e| Status::aborted(format!("Query reference value: {e}")))?; + let reference_value_results = serde_json::to_string(&rvs) .map_err(|e| Status::aborted(format!("Serde reference value: {e}")))?; info!("Reference values: {}", reference_value_results); diff --git a/rvps/src/extractors/extractor_modules/sample/mod.rs b/rvps/src/extractors/extractor_modules/sample/mod.rs index 46af628f7..23020ee83 100644 --- a/rvps/src/extractors/extractor_modules/sample/mod.rs +++ b/rvps/src/extractors/extractor_modules/sample/mod.rs @@ -33,7 +33,7 @@ pub struct SampleExtractor; const DEFAULT_ALG: &str = "sha384"; /// The reference value will be expired in the default time (months) -const DEFAULT_EXPIRED_TIME: u32 = 12; +const MONTHS_BEFORE_EXPIRATION: u32 = 12; impl Extractor for SampleExtractor { fn verify_and_extract(&self, provenance_base64: &str) -> Result> { @@ -54,12 +54,13 @@ impl Extractor for SampleExtractor { let time = Utc::now() .with_nanosecond(0) - .and_then(|t| t.checked_add_months(Months::new(DEFAULT_EXPIRED_TIME))); + .and_then(|t| t.checked_add_months(Months::new(MONTHS_BEFORE_EXPIRATION))); + match time { - Some(expired) => Some(ReferenceValue { + Some(expiration) => Some(ReferenceValue { version: REFERENCE_VALUE_VERSION.into(), name: name.to_string(), - expired, + expiration, hash_value: rvs, }), None => { diff --git a/rvps/src/native.rs b/rvps/src/native.rs index 78ef07ba1..30298e64d 100644 --- a/rvps/src/native.rs +++ b/rvps/src/native.rs @@ -4,16 +4,15 @@ // use anyhow::{bail, Context, Result}; -use chrono::{DateTime, Utc}; use log::{info, warn}; -use std::time::SystemTime; +use std::collections::HashMap; use crate::{store::StoreType, Config}; use super::{ extractors::{Extractors, ExtractorsImpl}, pre_processor::{PreProcessor, PreProcessorAPI}, - Message, Store, TrustedDigest, MESSAGE_VERSION, + Message, Store, MESSAGE_VERSION, }; /// The core of the RVPS, s.t. componants except communication componants. @@ -71,28 +70,24 @@ impl Core { Ok(()) } - pub async fn get_digests(&self, name: &str) -> Result> { - let rv = self.store.get(name).await?; - match rv { - None => Ok(None), - Some(rv) => { - let now: DateTime = DateTime::from(SystemTime::now()); - if now > *rv.expired() { - warn!("Reference value of {} is expired.", name); - return Ok(None); - } - - let hash_values = rv - .hash_values() - .iter() - .map(|pair| pair.value().to_owned()) - .collect(); - - Ok(Some(TrustedDigest { - name: name.to_owned(), - hash_values, - })) + pub async fn get_digests(&self) -> Result>> { + let mut rv_map = HashMap::new(); + let reference_values = self.store.get_values().await?; + + for rv in reference_values { + if rv.expired() { + warn!("Reference value of {} is expired.", rv.name()); + continue; } + + let hash_values = rv + .hash_values() + .iter() + .map(|pair| pair.value().to_owned()) + .collect(); + + rv_map.insert(rv.name().to_string(), hash_values); } + Ok(rv_map) } } diff --git a/rvps/src/reference_value.rs b/rvps/src/reference_value.rs index 4e5877649..1b19f6a34 100644 --- a/rvps/src/reference_value.rs +++ b/rvps/src/reference_value.rs @@ -8,6 +8,7 @@ use anyhow::{anyhow, Result}; use chrono::{DateTime, NaiveDateTime, Timelike, Utc}; use serde::{Deserialize, Deserializer, Serialize}; +use std::time::SystemTime; /// Default version of ReferenceValue pub const REFERENCE_VALUE_VERSION: &str = "0.1.0"; @@ -53,7 +54,7 @@ fn primitive_date_time_from_str<'de, D: Deserializer<'de>>( /// Here, ReferenceValue is stored inside RVPS. Its format MAY be modified. /// * `version`: version of the reference value format. /// * `name`: name of the artifact related to this reference value. -/// * `expired`: expired time for this reference value. +/// * `expiration`: Time after which refrence valid is invalid /// * `hash_value`: A set of key-value pairs, each indicates a hash /// algorithm and its relative hash value for the artifact. /// The actual struct deliver from RVPS to AS is @@ -65,7 +66,7 @@ pub struct ReferenceValue { pub version: String, pub name: String, #[serde(deserialize_with = "primitive_date_time_from_str")] - pub expired: DateTime, + pub expiration: DateTime, #[serde(rename = "hash-value")] pub hash_value: Vec, } @@ -76,7 +77,7 @@ fn default_version() -> String { } impl ReferenceValue { - /// Create a new `ReferenceValue`, the `expired` + /// Create a new `ReferenceValue`, the `expiration` /// field's nanosecond will be set to 0. This avoid /// a rare bug that when the nanosecond of the time /// is not 0, the test case will fail. @@ -84,7 +85,7 @@ impl ReferenceValue { Ok(ReferenceValue { version: REFERENCE_VALUE_VERSION.into(), name: String::new(), - expired: Utc::now() + expiration: Utc::now() .with_nanosecond(0) .ok_or_else(|| anyhow!("set nanosecond failed."))?, hash_value: Vec::new(), @@ -103,14 +104,18 @@ impl ReferenceValue { } /// Set expired time of the ReferenceValue. - pub fn set_expired(mut self, expired: DateTime) -> Self { - self.expired = expired.with_nanosecond(0).expect("Set nanosecond failed."); + pub fn set_expiration(mut self, expiration: DateTime) -> Self { + self.expiration = expiration + .with_nanosecond(0) + .expect("Set nanosecond failed."); self } - /// Get expired of the ReferenceValue. - pub fn expired(&self) -> &DateTime { - &self.expired + /// Check whether reference value is expired + pub fn expired(&self) -> bool { + let now: DateTime = DateTime::from(SystemTime::now()); + + now > self.expiration } /// Set hash value of the ReferenceValue. @@ -162,13 +167,13 @@ mod test { .expect("create ReferenceValue failed.") .set_version("1.0.0") .set_name("artifact") - .set_expired(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()) + .set_expiration(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()) .add_hash_value("sha512".into(), "123".into()); assert_eq!(rv.version(), "1.0.0"); let rv_json = json!({ - "expired": "1970-01-01T00:00:00Z", + "expiration": "1970-01-01T00:00:00Z", "name": "artifact", "version": "1.0.0", "hash-value": [{ @@ -187,12 +192,12 @@ mod test { .expect("create ReferenceValue failed.") .set_version("1.0.0") .set_name("artifact") - .set_expired(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()) + .set_expiration(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap()) .add_hash_value("sha512".into(), "123".into()); assert_eq!(rv.version(), "1.0.0"); let rv_json = r#"{ - "expired": "1970-01-01T00:00:00Z", + "expiration": "1970-01-01T00:00:00Z", "name": "artifact", "version": "1.0.0", "hash-value": [{ diff --git a/rvps/src/store/local_fs/mod.rs b/rvps/src/store/local_fs/mod.rs index 6d8931a65..7f7cf5dc5 100644 --- a/rvps/src/store/local_fs/mod.rs +++ b/rvps/src/store/local_fs/mod.rs @@ -72,6 +72,16 @@ impl Store for LocalFs { None => Ok(None), } } + + async fn get_values(&self) -> Result> { + let mut values = Vec::new(); + + for (_k,v) in self.engine.iter().flatten() { + values.push(serde_json::from_slice(&v)?); + } + + Ok(values) + } } #[cfg(test)] diff --git a/rvps/src/store/local_json/mod.rs b/rvps/src/store/local_json/mod.rs index 91ba8a1ac..b08bbeb0c 100644 --- a/rvps/src/store/local_json/mod.rs +++ b/rvps/src/store/local_json/mod.rs @@ -71,4 +71,11 @@ impl Store for LocalJson { let rv = rvs.into_iter().find(|rv| rv.name == name); Ok(rv) } + + async fn get_values(&self) -> Result> { + let _ = self.lock.read().await; + let file = tokio::fs::read(&self.file_path).await?; + let rvs: Vec = serde_json::from_slice(&file)?; + Ok(rvs) + } } diff --git a/rvps/src/store/mod.rs b/rvps/src/store/mod.rs index 4113e5378..0fd951efd 100644 --- a/rvps/src/store/mod.rs +++ b/rvps/src/store/mod.rs @@ -39,16 +39,16 @@ impl StoreType { } /// Interface of a `Store`. -/// We only provide a simple instance here which implements -/// Store. In more scenarios, RV should be stored in persistent -/// storage, like database, file and so on. All of the mentioned -/// forms will have the same interface as following. +/// Reference value storage facilities should implement this trait. #[async_trait] pub trait Store { /// Store a reference value. If the given `name` exists, /// return the previous `Some`, otherwise return `None` async fn set(&self, name: String, rv: ReferenceValue) -> Result>; - // Retrieve a reference value + // Retrieve reference value by name async fn get(&self, name: &str) -> Result>; + + // Retrieve reference values + async fn get_values(&self) -> Result>; }