Skip to content

Commit 654f23d

Browse files
committed
Refactor DCAP code into a module
1 parent 14bb292 commit 654f23d

File tree

3 files changed

+108
-212
lines changed

3 files changed

+108
-212
lines changed

src/attestation/azure.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//! Microsoft Azure Attestation (MAA) evidence generation and verification
12
use az_tdx_vtpm::{hcl, imds, report, vtpm};
23
use tokio_rustls::rustls::pki_types::CertificateDer;
34
// use openssl::pkey::{PKey, Public};

src/attestation/dcap.rs

Lines changed: 88 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,108 @@
1+
//! Data Center Attestation Primitives (DCAP) evidence generation and verification
12
use crate::attestation::{
2-
compute_report_input, generate_quote, get_quote_input_data,
3+
compute_report_input,
34
measurements::{CvmImageMeasurements, Measurements, PlatformMeasurements},
4-
AttestationError, AttestationType, QuoteGenerator, QuoteVerifier, PCS_URL,
5+
AttestationError,
56
};
67

7-
use dcap_qvl::{collateral::get_collateral_for_fmspc, quote::Quote};
8+
use configfs_tsm::QuoteGenerationError;
9+
use dcap_qvl::{
10+
collateral::get_collateral_for_fmspc,
11+
quote::{Quote, Report},
12+
};
813
use tokio_rustls::rustls::pki_types::CertificateDer;
914

10-
/// Quote generation using configfs_tsm
11-
#[derive(Clone)]
12-
pub struct DcapTdxQuoteGenerator {
13-
pub attestation_type: AttestationType,
14-
}
15-
16-
impl QuoteGenerator for DcapTdxQuoteGenerator {
17-
/// Type of attestation used
18-
fn attestation_type(&self) -> AttestationType {
19-
self.attestation_type
20-
}
15+
/// For fetching collateral directly from Intel, if no PCCS is specified
16+
const PCS_URL: &str = "https://api.trustedservices.intel.com";
2117

22-
async fn create_attestation(
23-
&self,
24-
cert_chain: &[CertificateDer<'_>],
25-
exporter: [u8; 32],
26-
) -> Result<Vec<u8>, AttestationError> {
27-
let quote_input = compute_report_input(cert_chain, exporter)?;
18+
/// Quote generation using configfs_tsm
19+
pub async fn create_dcap_attestation(
20+
cert_chain: &[CertificateDer<'_>],
21+
exporter: [u8; 32],
22+
) -> Result<Vec<u8>, AttestationError> {
23+
let quote_input = compute_report_input(cert_chain, exporter)?;
2824

29-
Ok(generate_quote(quote_input)?)
30-
}
25+
Ok(generate_quote(quote_input)?)
3126
}
3227

33-
/// Verify DCAP TDX quotes, allowing them if they have one of a given set of platform-specific and
34-
/// OS image specific measurements
35-
#[derive(Clone)]
36-
pub struct DcapTdxQuoteVerifier {
37-
pub attestation_type: AttestationType,
38-
/// Platform specific allowed Measurements
39-
/// Currently an option as this may be determined internally on a per-platform basis (Eg: GCP)
40-
pub accepted_platform_measurements: Option<Vec<PlatformMeasurements>>,
41-
/// OS-image specific allows measurement - this is effectively a list of allowed OS images
42-
pub accepted_cvm_image_measurements: Vec<CvmImageMeasurements>,
43-
/// URL of a PCCS (defaults to Intel PCS)
44-
pub pccs_url: Option<String>,
45-
}
28+
/// Verify a DCAP TDX quote, and return the measurement values
29+
pub async fn verify_dcap_attestation(
30+
input: Vec<u8>,
31+
cert_chain: &[CertificateDer<'_>],
32+
exporter: [u8; 32],
33+
pccs_url: Option<String>,
34+
) -> Result<Measurements, AttestationError> {
35+
let quote_input = compute_report_input(cert_chain, exporter)?;
36+
let (platform_measurements, image_measurements) = if cfg!(not(test)) {
37+
let now = std::time::SystemTime::now()
38+
.duration_since(std::time::UNIX_EPOCH)?
39+
.as_secs();
40+
let quote = Quote::parse(&input)?;
4641

47-
impl QuoteVerifier for DcapTdxQuoteVerifier {
48-
/// Type of attestation used
49-
fn attestation_type(&self) -> AttestationType {
50-
self.attestation_type
51-
}
42+
let ca = quote.ca()?;
43+
let fmspc = hex::encode_upper(quote.fmspc()?);
44+
let collateral = get_collateral_for_fmspc(
45+
&pccs_url.clone().unwrap_or(PCS_URL.to_string()),
46+
fmspc,
47+
ca,
48+
false, // Indicates not SGX
49+
)
50+
.await?;
5251

53-
async fn verify_attestation(
54-
&self,
55-
input: Vec<u8>,
56-
cert_chain: &[CertificateDer<'_>],
57-
exporter: [u8; 32],
58-
) -> Result<Option<Measurements>, AttestationError> {
59-
let quote_input = compute_report_input(cert_chain, exporter)?;
60-
let (platform_measurements, image_measurements) = if cfg!(not(test)) {
61-
let now = std::time::SystemTime::now()
62-
.duration_since(std::time::UNIX_EPOCH)?
63-
.as_secs();
64-
let quote = Quote::parse(&input)?;
52+
let _verified_report = dcap_qvl::verify::verify(&input, &collateral, now)?;
6553

66-
let ca = quote.ca()?;
67-
let fmspc = hex::encode_upper(quote.fmspc()?);
68-
let collateral = get_collateral_for_fmspc(
69-
&self.pccs_url.clone().unwrap_or(PCS_URL.to_string()),
70-
fmspc,
71-
ca,
72-
false,
73-
)
74-
.await?;
75-
76-
let _verified_report = dcap_qvl::verify::verify(&input, &collateral, now)?;
54+
let measurements = (
55+
PlatformMeasurements::from_dcap_qvl_quote(&quote)?,
56+
CvmImageMeasurements::from_dcap_qvl_quote(&quote)?,
57+
);
58+
if get_quote_input_data(quote.report) != quote_input {
59+
return Err(AttestationError::InputMismatch);
60+
}
61+
measurements
62+
} else {
63+
// In tests we use mock quotes which will fail to verify
64+
let quote = tdx_quote::Quote::from_bytes(&input)?;
65+
if quote.report_input_data() != quote_input {
66+
return Err(AttestationError::InputMismatch);
67+
}
7768

78-
let measurements = (
79-
PlatformMeasurements::from_dcap_qvl_quote(&quote)?,
80-
CvmImageMeasurements::from_dcap_qvl_quote(&quote)?,
81-
);
82-
if get_quote_input_data(quote.report) != quote_input {
83-
return Err(AttestationError::InputMismatch);
84-
}
85-
measurements
86-
} else {
87-
// In tests we use mock quotes which will fail to verify
88-
let quote = tdx_quote::Quote::from_bytes(&input)?;
89-
if quote.report_input_data() != quote_input {
90-
return Err(AttestationError::InputMismatch);
91-
}
69+
(
70+
PlatformMeasurements::from_tdx_quote(&quote),
71+
CvmImageMeasurements::from_tdx_quote(&quote),
72+
)
73+
};
9274

93-
(
94-
PlatformMeasurements::from_tdx_quote(&quote),
95-
CvmImageMeasurements::from_tdx_quote(&quote),
96-
)
97-
};
75+
Ok(Measurements {
76+
platform: platform_measurements,
77+
cvm_image: image_measurements,
78+
})
79+
}
9880

99-
if let Some(accepted_platform_measurements) = &self.accepted_platform_measurements
100-
&& !accepted_platform_measurements.contains(&platform_measurements)
101-
{
102-
return Err(AttestationError::UnacceptablePlatformMeasurements);
103-
}
81+
/// Create a mock quote for testing on non-confidential hardware
82+
#[cfg(test)]
83+
fn generate_quote(input: [u8; 64]) -> Result<Vec<u8>, QuoteGenerationError> {
84+
let attestation_key = tdx_quote::SigningKey::random(&mut rand_core::OsRng);
85+
let provisioning_certification_key = tdx_quote::SigningKey::random(&mut rand_core::OsRng);
86+
Ok(tdx_quote::Quote::mock(
87+
attestation_key.clone(),
88+
provisioning_certification_key.clone(),
89+
input,
90+
b"Mock cert chain".to_vec(),
91+
)
92+
.as_bytes())
93+
}
10494

105-
if !self
106-
.accepted_cvm_image_measurements
107-
.contains(&image_measurements)
108-
{
109-
return Err(AttestationError::UnacceptableOsImageMeasurements);
110-
}
95+
/// Create a quote
96+
#[cfg(not(test))]
97+
fn generate_quote(input: [u8; 64]) -> Result<Vec<u8>, QuoteGenerationError> {
98+
configfs_tsm::create_quote(input)
99+
}
111100

112-
Ok(Some(Measurements {
113-
platform: platform_measurements,
114-
cvm_image: image_measurements,
115-
}))
101+
/// Given a [Report] get the input data regardless of report type
102+
fn get_quote_input_data(report: Report) -> [u8; 64] {
103+
match report {
104+
Report::TD10(r) => r.report_data,
105+
Report::TD15(r) => r.base.report_data,
106+
Report::SgxEnclave(r) => r.report_data,
116107
}
117108
}

0 commit comments

Comments
 (0)