Skip to content

Commit

Permalink
Make Orchestrator generic with the Attester
Browse files Browse the repository at this point in the history
This required creating a temporary (already deprecated) trait to support
clients that still expect a separate `application_keys` field in the
evidence. It might take many months for all client installations to be
updated, so this trait is needed to unblock the Intel TDX attestation.

BUG: 380442628

Change-Id: If87d01ec893472a7b0970d925a4327aff29836cd
  • Loading branch information
conradgrobler committed Jan 16, 2025
1 parent 82caf8d commit f26388b
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 76 deletions.
59 changes: 8 additions & 51 deletions oak_attestation/src/dice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ use prost::Message;
use sha2::Digest;
use zeroize::Zeroize;

#[allow(deprecated)]
use crate::ApplicationKeysAttester;

pub trait MeasureDigest {
fn measure_digest(&self) -> RawDigest;
}
Expand Down Expand Up @@ -70,62 +73,16 @@ pub struct DiceAttester {
signing_key: SigningKey,
}

// TODO: b/366141836 - Remove this implementation once all Oak clients have been
// updated to the EventLog attestation.
impl DiceAttester {
/// Adds an additional layer of evidence to the DICE data.
///
/// The evidence is in the form of a CWT certificate that contains the
/// `additional_claims` provided. Adding a layer generates a new ECA
/// private key for the layer and uses it to replace the existing
/// signing key. The CWT certificate contains the public key for this new
/// signing key.
pub fn add_layer(&mut self, layer_data: LayerData) -> anyhow::Result<()> {
// The last evidence layer contains the certificate for the current signing key.
// Since the builder contains an existing signing key there must be at
// least one layer of evidence that contains the certificate.
let layer_evidence = self
.evidence
.layers
.last()
.ok_or_else(|| anyhow::anyhow!("no evidence layers found"))?;
let claims_set = get_claims_set_from_certificate_bytes(&layer_evidence.eca_certificate)
.map_err(anyhow::Error::msg)?;

// The issuer for the next layer is the subject of the current last layer.
let issuer_id = claims_set.subject.ok_or_else(|| anyhow!("no subject in certificate"))?;

let evidence = &mut self.evidence;
let (signing_key, verifying_key) = generate_ecdsa_key_pair();

let eca_certificate = generate_signing_certificate(
&self.signing_key,
issuer_id,
&verifying_key,
layer_data.additional_claims,
)
.map_err(anyhow::Error::msg)
.context("couldn't generate ECA certificate for the next layer")?;
evidence.layers.push(LayerEvidence {
eca_certificate: eca_certificate.to_vec().map_err(anyhow::Error::msg)?,
});
// Replacing the signing key will cause the previous signing key to be dropped,
// which will zero out its memory.
self.signing_key = signing_key;
self.evidence
.event_log
.get_or_insert_with(EventLog::default)
.encoded_events
.push(layer_data.encoded_event);
Ok(())
}

// TODO: b/368030563 - Remove this implementation once all client library
// instances use the applications keys from the event log.
#[allow(deprecated)]
impl ApplicationKeysAttester for DiceAttester {
/// Adds the CWT certificates application keys to the DICE data.
///
/// Since no additional evidence can be added after the application keys are
/// added, this consumes DICE data, discards the signing key and returns
/// the finalized evidence.
pub fn add_application_keys(
fn add_application_keys(
self,
layer_data: LayerData,
kem_public_key: &[u8],
Expand Down
27 changes: 27 additions & 0 deletions oak_attestation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,31 @@

extern crate alloc;

use dice::LayerData;
use oak_proto_rust::oak::attestation::v1::Evidence;
use p256::ecdsa::VerifyingKey;

pub mod dice;

/// Deprecated trait that allow for explicitly adding application keys to the
/// attestation evidence.
#[deprecated = "Use application keys from the event log."]
pub trait ApplicationKeysAttester {
// TODO: b/368030563 - Remove this trait once all client library instances use
// the applications keys from the event log.

/// Adds certificates representing the application keys to the attestation
/// evidence.
//
/// This is an outdated approach that has been replaced by adding the
/// applications keys to the event log. It is only retained for
/// compatibility while some client deployments still expect this format.
fn add_application_keys(
self,
layer_data: LayerData,
kem_public_key: &[u8],
verifying_key: &VerifyingKey,
group_kem_public_key: Option<&[u8]>,
group_verifying_key: Option<&VerifyingKey>,
) -> anyhow::Result<Evidence>;
}
11 changes: 9 additions & 2 deletions oak_containers/orchestrator/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ rust_library(
"src/lib.rs",
"src/logging.rs",
],
crate_features = ["bazel"],
# TODO: b/368030563 - Remove this feature once all client library instances use
# the applications keys from the event log.
crate_features = [
"application_keys",
],
deps = [
"//oak_attestation",
"//oak_attestation_types",
Expand Down Expand Up @@ -77,7 +81,10 @@ rust_library(
rust_test(
name = "oak_containers_orchestrator_test",
crate = ":oak_containers_orchestrator",
crate_features = ["bazel"],
crate_features = [
"bazel",
"application_keys",
],
data = [
"//oak_containers/orchestrator/testdata:cdi.json",
"//oak_containers/orchestrator/testdata:oci_spec_base.json",
Expand Down
6 changes: 6 additions & 0 deletions oak_containers/orchestrator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ authors = ["Juliette Pretot <[email protected]>"]
edition = "2021"
license = "Apache-2.0"

[features]
# TODO: b/368030563 - Remove this feature once all client library instances use
# the applications keys from the event log.
application_keys = []
default = ["application_keys"]

[dependencies]
anyhow = "*"
clap = { version = "*", features = ["derive", "env"] }
Expand Down
20 changes: 14 additions & 6 deletions oak_containers/orchestrator/src/dice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ use std::{
};

use anyhow::Context;
use oak_attestation::dice::DiceAttester;
use oak_attestation_types::util::Serializable;
#[allow(deprecated)]
use oak_attestation::ApplicationKeysAttester;
use oak_attestation_types::{attester::Attester, util::Serializable};
use zeroize::Zeroize;

/// The path to the file where the DICE data provided by Stage 1 is stored.
Expand All @@ -30,11 +31,16 @@ const STAGE1_DICE_DATA_PATH: &str = "/oak/dice";
///
/// The file is also overwritten with zeros to ensure it cannot be reused by
/// another process.
pub fn load_stage1_dice_data() -> anyhow::Result<DiceAttester> {
#[allow(deprecated)]
pub fn load_stage1_dice_data<A: Attester + Serializable + ApplicationKeysAttester>(
) -> anyhow::Result<A> {
load_stage1_dice_data_from_path(STAGE1_DICE_DATA_PATH)
}

fn load_stage1_dice_data_from_path(path: &str) -> anyhow::Result<DiceAttester> {
#[allow(deprecated)]
fn load_stage1_dice_data_from_path<A: Attester + Serializable + ApplicationKeysAttester>(
path: &str,
) -> anyhow::Result<A> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
Expand All @@ -45,7 +51,7 @@ fn load_stage1_dice_data_from_path(path: &str) -> anyhow::Result<DiceAttester> {
let mut buffer = Vec::with_capacity(size);
file.read_to_end(&mut buffer).context("couldn't read DICE data from file")?;

let result = DiceAttester::deserialize(&buffer[..]).context("couldn't parse DICE data")?;
let result = A::deserialize(&buffer[..]).context("couldn't parse DICE data")?;

buffer.zeroize();
file.rewind()?;
Expand All @@ -64,6 +70,8 @@ fn load_stage1_dice_data_from_path(path: &str) -> anyhow::Result<DiceAttester> {
mod tests {
use std::fs;

use oak_attestation::dice::DiceAttester;

use super::*;

#[test]
Expand All @@ -76,7 +84,7 @@ mod tests {
#[cfg(not(feature = "bazel"))]
fs::copy("testdata/test_dice", DICE_DATA_PATH).unwrap();

load_stage1_dice_data_from_path(DICE_DATA_PATH).unwrap();
load_stage1_dice_data_from_path::<DiceAttester>(DICE_DATA_PATH).unwrap();
let mut file = OpenOptions::new().read(true).open(DICE_DATA_PATH).unwrap();
let mut buffer = Vec::with_capacity(DICE_DATA_SIZE);
file.read_to_end(&mut buffer).unwrap();
Expand Down
41 changes: 26 additions & 15 deletions oak_containers/orchestrator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ use std::{path::PathBuf, sync::Arc};
use anyhow::{anyhow, Context};
use clap::Parser;
use launcher_client::LauncherClient;
use oak_attestation_types::attester::Attester;
#[allow(deprecated)]
use oak_attestation::ApplicationKeysAttester;
use oak_attestation_types::{attester::Attester, util::Serializable};
use oak_containers_agent::{metrics::MetricsConfig, set_error_handler};
use oak_containers_attestation::generate_instance_keys;
use oak_proto_rust::oak::containers::v1::KeyProvisioningRole;
Expand Down Expand Up @@ -51,7 +53,8 @@ struct Args {
runtime_user: String,
}

pub async fn main() -> anyhow::Result<()> {
#[allow(deprecated)]
pub async fn main<A: Attester + ApplicationKeysAttester + Serializable>() -> anyhow::Result<()> {
crate::logging::setup()?;

let args = Args::parse();
Expand Down Expand Up @@ -99,7 +102,7 @@ pub async fn main() -> anyhow::Result<()> {
.map_err(|error| anyhow!("couldn't get application config: {:?}", error))?;

// Create a container event and add it to the event log.
let mut attester = crate::dice::load_stage1_dice_data()?;
let mut attester: A = crate::dice::load_stage1_dice_data()?;
let container_event = oak_containers_attestation::create_container_event(
&container_bundle,
&application_config,
Expand All @@ -111,18 +114,26 @@ pub async fn main() -> anyhow::Result<()> {

// Add the container event to the DICE chain.
let container_layer = oak_containers_attestation::create_container_dice_layer(&container_event);
let evidence = attester.add_application_keys(
container_layer,
&instance_public_keys.encryption_public_key,
&instance_public_keys.signing_public_key,
if let Some(ref group_public_keys) = group_public_keys {
Some(&group_public_keys.encryption_public_key)
} else {
None
},
None,
)?;

let evidence = {
#[cfg(feature = "application_keys")]
{
attester.add_application_keys(
container_layer,
&instance_public_keys.encryption_public_key,
&instance_public_keys.signing_public_key,
if let Some(ref group_public_keys) = group_public_keys {
Some(&group_public_keys.encryption_public_key)
} else {
None
},
None,
)?
}
#[cfg(not(feature = "application_keys"))]
{
attester.quote()?
}
};
// Send the attestation evidence to the Hostlib.
launcher_client
.send_attestation_evidence(evidence.clone())
Expand Down
1 change: 1 addition & 0 deletions oak_containers/orchestrator_bin/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ rust_binary(
name = "bin/oak_containers_orchestrator",
srcs = ["src/main.rs"],
deps = [
"//oak_attestation",
"//oak_containers/orchestrator",
"@oak_crates_index//:anyhow",
"@oak_crates_index//:tikv-jemallocator",
Expand Down
2 changes: 1 addition & 1 deletion oak_containers/orchestrator_bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ static ALLOCATOR: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
oak_containers_orchestrator::main().await
oak_containers_orchestrator::main::<oak_attestation::dice::DiceAttester>().await
}
4 changes: 3 additions & 1 deletion oak_containers_sdk/src/standalone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
use anyhow::{Context, Result};
use async_trait::async_trait;
use oak_attestation::dice::DiceAttester;
#[allow(deprecated)]
use oak_attestation::{dice::DiceAttester, ApplicationKeysAttester};
use oak_attestation_types::attester::Attester;
use oak_containers_attestation::{InstanceKeys, InstancePublicKeys};
use oak_crypto::{
Expand Down Expand Up @@ -196,6 +197,7 @@ impl StandaloneOrchestrator {
oak_containers_attestation::create_container_dice_layer(&container_event);

// Add application keys and generate the final evidence.
#[allow(deprecated)]
let evidence = attester.add_application_keys(
container_layer,
&instance_public_keys.encryption_public_key,
Expand Down

0 comments on commit f26388b

Please sign in to comment.