Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions crates/attestation-provider-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,13 @@ async fn main() -> anyhow::Result<()> {
None => MeasurementPolicy::accept_anything(),
};

let attestation_verifier =
AttestationVerifier::new(measurement_policy, None, cli.log_dcap_quote, false);
let mut attestation_verifier_builder = AttestationVerifier::builder(measurement_policy);

if cli.log_dcap_quote {
attestation_verifier_builder = attestation_verifier_builder.dump_dcap_quotes();
}

let attestation_verifier = attestation_verifier_builder.build();

let attestation_message =
attestation_provider_client(server_addr, attestation_verifier).await?;
Expand Down
132 changes: 95 additions & 37 deletions crates/attestation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use pccs::{Pccs, PccsError};
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::{dcap::DcapVerificationError, measurements::MeasurementPolicy};
use crate::{dcap::DcapVerificationError, gcp::GcpFirmwareCache, measurements::MeasurementPolicy};

/// Used in attestation type detection to check if we are on GCP
const GCP_METADATA_API: &str = "http://metadata.google.internal";
Expand Down Expand Up @@ -318,63 +318,116 @@ impl AttestationGenerator {
#[derive(Clone, Debug)]
pub struct AttestationVerifier {
/// The measurement policy with accepted values and attestation types
pub measurement_policy: MeasurementPolicy,
/// If this is empty, anything will be accepted - but measurements are
/// always injected into HTTP headers, so that they can be verified
/// upstream A PCCS service to use - defaults to Intel PCS
pub pccs_url: Option<String>,
measurement_policy: MeasurementPolicy,
/// Whether to write quotes to files on disk
pub dump_dcap_quotes: bool,
dump_dcap_quotes: bool,
#[cfg(feature = "azure")]
/// Whether to override outdated TCB when on Azure
///
/// This provides a workaround for a known outdated FMSPC used by Azure
pub override_azure_outdated_tcb: bool,
override_azure_outdated_tcb: bool,
/// Internal cache for collateral
pub internal_pccs: Option<Pccs>,
internal_pccs: Option<Pccs>,
/// Cached GCP firmware blobs indexed by MRTD
known_gcp_firmware: gcp::GcpFirmwareCache,
}

/// Options used to construct an [AttestationVerifier]
pub struct AttestationVerifierBuilder {
/// The measurement policy with accepted values and attestation types
measurement_policy: MeasurementPolicy,
/// A PCCS service to use - defaults to Intel PCS
pccs_url: Option<String>,
dump_dcap_quotes: bool,
#[cfg(feature = "azure")]
override_azure_outdated_tcb: bool,
internal_pccs_prewarm: Option<bool>,
}

impl AttestationVerifierBuilder {
pub fn build(self) -> AttestationVerifier {
AttestationVerifier::build(self)
}

/// Whether to write quotes to files on disk
pub fn dump_dcap_quotes(mut self) -> Self {
self.dump_dcap_quotes = true;
self
}

/// Whether to override outdated TCB when on Azure
///
/// This provides a workaround for a known outdated FMSPC used by Azure
#[cfg(feature = "azure")]
pub fn override_azure_outdated_tcb(mut self) -> Self {
self.override_azure_outdated_tcb = true;
self
}

/// Do not keep an internal DCAP collateral cache
pub fn with_no_internal_pccs(mut self) -> Self {
self.internal_pccs_prewarm = None;
self
}

/// Keep a DCAP collateral cache, and pre-fill it with all available
/// collateral
pub fn with_pccs_prewarmed(mut self) -> Self {
self.internal_pccs_prewarm = Some(true);
self
}

/// Keep a DCAP collateral cache, starting empty
pub fn with_pccs_not_prewarmed(mut self) -> Self {
self.internal_pccs_prewarm = Some(false);
self
}

/// Set the URL used by internal PCCS
pub fn pccs_url(mut self, pccs_url: String) -> Self {
self.pccs_url = Some(pccs_url);
self
}
}

impl AttestationVerifier {
fn build(
measurement_policy: MeasurementPolicy,
pccs_url: Option<String>,
dump_dcap_quotes: bool,
override_azure_outdated_tcb: bool,
known_gcp_firmware: gcp::GcpFirmwareCache,
) -> Self {
fn build(builder: AttestationVerifierBuilder) -> Self {
let internal_pccs = builder.internal_pccs_prewarm.map(|with_prewarm| {
if with_prewarm {
Pccs::new(builder.pccs_url)
} else {
Pccs::new_without_prewarm(builder.pccs_url)
}
});

Self {
measurement_policy,
pccs_url: pccs_url.clone(),
dump_dcap_quotes,
override_azure_outdated_tcb,
internal_pccs: Some(Pccs::new(pccs_url)),
known_gcp_firmware,
measurement_policy: builder.measurement_policy,
dump_dcap_quotes: builder.dump_dcap_quotes,
#[cfg(feature = "azure")]
override_azure_outdated_tcb: builder.override_azure_outdated_tcb,
internal_pccs,
known_gcp_firmware: GcpFirmwareCache::new(),
}
}

pub fn new(
measurement_policy: MeasurementPolicy,
pccs_url: Option<String>,
dump_dcap_quotes: bool,
override_azure_outdated_tcb: bool,
) -> Self {
Self::build(
pub fn builder(measurement_policy: MeasurementPolicy) -> AttestationVerifierBuilder {
AttestationVerifierBuilder {
measurement_policy,
pccs_url,
dump_dcap_quotes,
override_azure_outdated_tcb,
gcp::GcpFirmwareCache::new(),
)
pccs_url: None,
dump_dcap_quotes: false,
#[cfg(feature = "azure")]
override_azure_outdated_tcb: false,
internal_pccs_prewarm: Some(true),
}
}

/// Create an [AttestationVerifier] which will only allow no attestation
/// and will reject if one is given
pub fn expect_none() -> Self {
Self {
measurement_policy: MeasurementPolicy::expect_none(),
pccs_url: None,
dump_dcap_quotes: false,
#[cfg(feature = "azure")]
override_azure_outdated_tcb: false,
internal_pccs: None,
known_gcp_firmware: gcp::GcpFirmwareCache::new(),
Expand All @@ -386,8 +439,8 @@ impl AttestationVerifier {
pub fn mock() -> Self {
Self {
measurement_policy: MeasurementPolicy::mock(),
pccs_url: None,
dump_dcap_quotes: false,
#[cfg(feature = "azure")]
override_azure_outdated_tcb: false,
internal_pccs: None,
known_gcp_firmware: gcp::GcpFirmwareCache::new(),
Expand All @@ -399,8 +452,8 @@ impl AttestationVerifier {
pub fn mock_with_pccs(pccs_url: String) -> Self {
Self {
measurement_policy: MeasurementPolicy::mock(),
pccs_url: None,
dump_dcap_quotes: false,
#[cfg(feature = "azure")]
override_azure_outdated_tcb: false,
internal_pccs: Some(Pccs::new(Some(pccs_url))),
known_gcp_firmware: gcp::GcpFirmwareCache::new(),
Expand Down Expand Up @@ -581,6 +634,11 @@ impl AttestationVerifier {
pub fn has_remote_attestation(&self) -> bool {
self.measurement_policy.has_remote_attestation()
}

/// Returns the measurement policy used
pub fn measurement_policy(&self) -> &MeasurementPolicy {
&self.measurement_policy
}
}

/// Write attestation data to a log file
Expand Down
9 changes: 3 additions & 6 deletions crates/attested-tls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,9 +1091,7 @@ mod tests {
) -> AttestedCertificateVerifier {
let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap();
let verifier = AttestationVerifier::mock_with_pccs(mock_pcs_server.base_url.clone());
if let Some(ref pccs) = verifier.internal_pccs {
pccs.ready().await.unwrap();
}
verifier.ready().await.unwrap();

let mut builder =
AttestedCertificateVerifier::build(verifier).with_crypto_provider(provider);
Expand Down Expand Up @@ -1544,9 +1542,8 @@ mod tests {
.unwrap();
let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap();
let verifier = AttestationVerifier::mock_with_pccs(mock_pcs_server.base_url.clone());
if let Some(ref pccs) = verifier.internal_pccs {
pccs.ready().await.unwrap();
}
verifier.ready().await.unwrap();

let verifier = AttestedCertificateVerifier::build(verifier)
.with_crypto_provider(provider)
.with_allowed_leaf_cert_pubkey(&key_pair.public_key_der())
Expand Down
5 changes: 2 additions & 3 deletions crates/attested-tls/tests/nested_tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,8 @@ fn attested_server_config(server_name: &str, provider: Arc<CryptoProvider>) -> S
async fn attested_client_config(provider: Arc<CryptoProvider>) -> ClientConfig {
let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap();
let verifier = AttestationVerifier::mock_with_pccs(mock_pcs_server.base_url.clone());
if let Some(ref pccs) = verifier.internal_pccs {
pccs.ready().await.unwrap();
}
verifier.ready().await.unwrap();

let verifier = AttestedCertificateVerifier::build(verifier)
.with_crypto_provider(provider.clone())
.finish()
Expand Down
Loading