Skip to content

Commit

Permalink
rvps: change interface to get all reference values
Browse files Browse the repository at this point in the history
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 <tobin@ibm.com>
  • Loading branch information
fitzthum committed Oct 4, 2024
1 parent 171c133 commit eb81436
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 102 deletions.
23 changes: 2 additions & 21 deletions attestation-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,15 +207,11 @@ 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())
.rvps
.get_digests()
.await
.map_err(|e| anyhow!("Generate reference data failed: {:?}", e))?;
debug!("reference_data_map: {:#?}", reference_data_map);
Expand All @@ -241,21 +237,6 @@ impl AttestationService {
Ok(attestation_results_token)
}

async fn get_reference_data<'a, I>(&self, tcb_claims: I) -> Result<HashMap<String, Vec<String>>>
where
I: Iterator<Item = &'a String>,
{
let mut data = HashMap::new();
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.");
}
data.insert(key.to_string(), reference_value);
}
Ok(data)
}

/// Registry a new reference value
pub async fn register_reference_value(&mut self, message: &str) -> Result<()> {
self.rvps.verify_and_extract(message).await
Expand Down
11 changes: 4 additions & 7 deletions attestation-service/src/rvps/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use anyhow::*;
use async_trait::async_trait;
use core::result::Result::Ok;
use reference_value_provider_service::{Config, Core};
use std::collections::HashMap;

pub struct Rvps {
core: Core,
Expand All @@ -22,13 +23,9 @@ impl RvpsApi for Rvps {
Ok(())
}

async fn get_digests(&self, name: &str) -> Result<Vec<String>> {
let hashes = self
.core
.get_digests(name)
.await?
.unwrap_or_default()
.hash_values;
async fn get_digests(&self) -> Result<HashMap<String, Vec<String>>> {
let hashes = self.core.get_digests().await?;

Ok(hashes)
}
}
7 changes: 3 additions & 4 deletions attestation-service/src/rvps/grpc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::rvps::RvpsError;
use anyhow::{Context, Result};
use std::collections::HashMap;
use tokio::sync::Mutex;

use self::rvps_api::{
Expand Down Expand Up @@ -42,10 +43,8 @@ impl RvpsApi for Agent {
Ok(())
}

async fn get_digests(&self, name: &str) -> Result<Vec<String>> {
let req = tonic::Request::new(ReferenceValueQueryRequest {
name: name.to_string(),
});
async fn get_digests(&self) -> Result<HashMap<String, Vec<String>>> {
let req = tonic::Request::new(ReferenceValueQueryRequest {});
let res = self
.client
.lock()
Expand Down
6 changes: 3 additions & 3 deletions attestation-service/src/rvps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use log::{info, warn};
use reference_value_provider_service::config::{Config as RvpsCrateConfig, DEFAULT_STORAGE_TYPE};
use serde::Deserialize;
use serde_json::{json, Value};
use std::collections::HashMap;
use thiserror::Error;

/// The interfaces of Reference Value Provider Service
Expand All @@ -19,9 +20,8 @@ pub trait RvpsApi {
/// Verify the given message and register the reference value included.
async fn verify_and_extract(&mut self, message: &str) -> Result<()>;

/// Get the reference values / golden values / expected digests in hex of the
/// given component name.
async fn get_digests(&self, name: &str) -> Result<Vec<String>>;
/// Get the reference values / golden values / expected digests in hex.
async fn get_digests(&self) -> Result<HashMap<String, Vec<String>>>;
}

#[cfg(feature = "rvps-grpc")]
Expand Down
4 changes: 1 addition & 3 deletions protos/reference.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ syntax = "proto3";

package reference;

message ReferenceValueQueryRequest {
string name = 1;
}
message ReferenceValueQueryRequest {}

message ReferenceValueQueryResponse {
string reference_value_results = 1;
Expand Down
12 changes: 3 additions & 9 deletions rvps/src/bin/rvps-tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand All @@ -100,6 +94,6 @@ async fn main() -> Result<()> {

match cli {
Cli::Register(para) => register(&para.addr, &para.path).await,
Cli::Query(para) => query(&para.addr, &para.name).await,
Cli::Query(para) => query(&para.addr).await,
}
}
13 changes: 4 additions & 9 deletions rvps/src/bin/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,16 @@ impl RVPSServer {
impl ReferenceValueProviderService for RVPSServer {
async fn query_reference_value(
&self,
request: Request<ReferenceValueQueryRequest>,
_request: Request<ReferenceValueQueryRequest>,
) -> Result<Response<ReferenceValueQueryResponse>, 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);
Expand Down
9 changes: 5 additions & 4 deletions rvps/src/extractors/extractor_modules/sample/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<ReferenceValue>> {
Expand All @@ -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 => {
Expand Down
43 changes: 19 additions & 24 deletions rvps/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -71,28 +70,24 @@ impl Core {
Ok(())
}

pub async fn get_digests(&self, name: &str) -> Result<Option<TrustedDigest>> {
let rv = self.store.get(name).await?;
match rv {
None => Ok(None),
Some(rv) => {
let now: DateTime<Utc> = 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<HashMap<String, Vec<String>>> {
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)
}
}
31 changes: 18 additions & 13 deletions rvps/src/reference_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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
Expand All @@ -65,7 +66,7 @@ pub struct ReferenceValue {
pub version: String,
pub name: String,
#[serde(deserialize_with = "primitive_date_time_from_str")]
pub expired: DateTime<Utc>,
pub expiration: DateTime<Utc>,
#[serde(rename = "hash-value")]
pub hash_value: Vec<HashValuePair>,
}
Expand All @@ -76,15 +77,15 @@ 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.
pub fn new() -> Result<Self> {
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(),
Expand All @@ -103,14 +104,18 @@ impl ReferenceValue {
}

/// Set expired time of the ReferenceValue.
pub fn set_expired(mut self, expired: DateTime<Utc>) -> Self {
self.expired = expired.with_nanosecond(0).expect("Set nanosecond failed.");
pub fn set_expiration(mut self, expiration: DateTime<Utc>) -> Self {
self.expiration = expiration
.with_nanosecond(0)
.expect("Set nanosecond failed.");
self
}

/// Get expired of the ReferenceValue.
pub fn expired(&self) -> &DateTime<Utc> {
&self.expired
/// Check whether reference value is expired
pub fn expired(&self) -> bool {
let now: DateTime<Utc> = DateTime::from(SystemTime::now());

now > self.expiration
}

/// Set hash value of the ReferenceValue.
Expand Down Expand Up @@ -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": [{
Expand All @@ -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": [{
Expand Down
10 changes: 10 additions & 0 deletions rvps/src/store/local_fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ impl Store for LocalFs {
None => Ok(None),
}
}

async fn get_values(&self) -> Result<Vec<ReferenceValue>> {
let mut values = Vec::new();

for (_k, v) in self.engine.iter().flatten() {
values.push(serde_json::from_slice(&v)?);
}

Ok(values)
}
}

#[cfg(test)]
Expand Down
7 changes: 7 additions & 0 deletions rvps/src/store/local_json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<ReferenceValue>> {
let _ = self.lock.read().await;
let file = tokio::fs::read(&self.file_path).await?;
let rvs: Vec<ReferenceValue> = serde_json::from_slice(&file)?;
Ok(rvs)
}
}
Loading

0 comments on commit eb81436

Please sign in to comment.