Skip to content

Commit 4c899f1

Browse files
committed
Add negative tests and fix issues with attestaion verification
1 parent 1a55996 commit 4c899f1

File tree

2 files changed

+121
-3
lines changed

2 files changed

+121
-3
lines changed

src/attestation/mod.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ pub struct AttestationVerifier {
145145
///
146146
/// If this is empty, anything will be accepted - but measurements are always injected into HTTP
147147
/// headers, so that they can be verified upstream
148-
accepted_measurements: Vec<MeasurementRecord>,
148+
pub accepted_measurements: Vec<MeasurementRecord>,
149149
/// A PCCS service to use - defaults to Intel PCS
150-
pccs_url: Option<String>,
150+
pub pccs_url: Option<String>,
151151
}
152152

153153
impl AttestationVerifier {
@@ -202,6 +202,9 @@ impl AttestationVerifier {
202202
.await?
203203
}
204204
AttestationType::None => {
205+
if self.has_remote_attestion() {
206+
return Err(AttestationError::AttestationTypeNotAccepted);
207+
}
205208
if attestation_payload.attestation.is_empty() {
206209
return Ok(None);
207210
} else {
@@ -216,7 +219,8 @@ impl AttestationVerifier {
216219
// look through all our accepted measurements
217220
self.accepted_measurements
218221
.iter()
219-
.find(|a| a.attestation_type == attestation_type && a.measurements == measurements);
222+
.find(|a| a.attestation_type == attestation_type && a.measurements == measurements)
223+
.ok_or(AttestationError::MeasurementsNotAccepted)?;
220224

221225
Ok(Some(measurements))
222226
}
@@ -409,4 +413,8 @@ pub enum AttestationError {
409413
QuoteParse(#[from] QuoteParseError),
410414
#[error("Attestation type not supported")]
411415
AttestationTypeNotSupported,
416+
#[error("Attestation type not accepted")]
417+
AttestationTypeNotAccepted,
418+
#[error("Measurements not accepted")]
419+
MeasurementsNotAccepted,
412420
}

src/lib.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
329329
}
330330

331331
/// A proxy client which forwards http traffic to a proxy-server
332+
#[derive(Debug)]
332333
pub struct ProxyClient {
333334
/// The underlying TCP listener
334335
listener: TcpListener,
@@ -817,6 +818,10 @@ where
817818

818819
#[cfg(test)]
819820
mod tests {
821+
use crate::attestation::measurements::{
822+
CvmImageMeasurements, MeasurementRecord, PlatformMeasurements,
823+
};
824+
820825
use super::*;
821826
use test_helpers::{
822827
default_measurements, example_http_service, example_service, generate_certificate_chain,
@@ -1115,4 +1120,109 @@ mod tests {
11151120

11161121
assert_eq!(retrieved_chain, cert_chain);
11171122
}
1123+
1124+
// Negative test - server does not provide attestation but client requires it
1125+
// Server has no attestaion, client has no attestation and no client auth
1126+
#[tokio::test]
1127+
async fn fails_on_no_attestation_when_expected() {
1128+
let target_addr = example_http_service().await;
1129+
1130+
let (cert_chain, private_key) = generate_certificate_chain("127.0.0.1".parse().unwrap());
1131+
let (server_config, client_config) = generate_tls_config(cert_chain.clone(), private_key);
1132+
1133+
let proxy_server = ProxyServer::new_with_tls_config(
1134+
cert_chain,
1135+
server_config,
1136+
"127.0.0.1:0",
1137+
target_addr,
1138+
Arc::new(NoQuoteGenerator),
1139+
AttestationVerifier::do_not_verify(),
1140+
)
1141+
.await
1142+
.unwrap();
1143+
1144+
let proxy_addr = proxy_server.local_addr().unwrap();
1145+
1146+
tokio::spawn(async move {
1147+
proxy_server.accept().await.unwrap();
1148+
});
1149+
1150+
let proxy_client_result = ProxyClient::new_with_tls_config(
1151+
client_config,
1152+
"127.0.0.1:0".to_string(),
1153+
proxy_addr.to_string(),
1154+
Arc::new(NoQuoteGenerator),
1155+
AttestationVerifier::mock(),
1156+
None,
1157+
)
1158+
.await;
1159+
1160+
assert!(matches!(
1161+
proxy_client_result.unwrap_err(),
1162+
ProxyError::Attestation(AttestationError::AttestationTypeNotAccepted)
1163+
));
1164+
}
1165+
1166+
// Negative test - server does not provide attestation but client requires it
1167+
// Server has no attestaion, client has no attestation and no client auth
1168+
#[tokio::test]
1169+
async fn fails_on_bad_measurements() {
1170+
let target_addr = example_http_service().await;
1171+
1172+
let (cert_chain, private_key) = generate_certificate_chain("127.0.0.1".parse().unwrap());
1173+
let (server_config, client_config) = generate_tls_config(cert_chain.clone(), private_key);
1174+
1175+
let proxy_server = ProxyServer::new_with_tls_config(
1176+
cert_chain,
1177+
server_config,
1178+
"127.0.0.1:0",
1179+
target_addr,
1180+
Arc::new(DcapTdxQuoteGenerator {
1181+
attestation_type: AttestationType::DcapTdx,
1182+
}),
1183+
AttestationVerifier::do_not_verify(),
1184+
)
1185+
.await
1186+
.unwrap();
1187+
1188+
let proxy_addr = proxy_server.local_addr().unwrap();
1189+
1190+
tokio::spawn(async move {
1191+
proxy_server.accept().await.unwrap();
1192+
});
1193+
1194+
let attestation_verifier = AttestationVerifier {
1195+
accepted_measurements: vec![MeasurementRecord {
1196+
attestation_type: AttestationType::DcapTdx,
1197+
measurement_id: "test".to_string(),
1198+
measurements: Measurements {
1199+
platform: PlatformMeasurements {
1200+
mrtd: [0; 48],
1201+
rtmr0: [0; 48],
1202+
},
1203+
cvm_image: CvmImageMeasurements {
1204+
rtmr1: [1; 48], // This differs from the mock measurements given
1205+
rtmr2: [0; 48],
1206+
rtmr3: [0; 48],
1207+
},
1208+
},
1209+
}],
1210+
pccs_url: None,
1211+
};
1212+
1213+
let proxy_client_result = ProxyClient::new_with_tls_config(
1214+
client_config,
1215+
"127.0.0.1:0".to_string(),
1216+
proxy_addr.to_string(),
1217+
Arc::new(NoQuoteGenerator),
1218+
attestation_verifier,
1219+
None,
1220+
)
1221+
.await;
1222+
1223+
assert!(matches!(
1224+
proxy_client_result.unwrap_err(),
1225+
ProxyError::Attestation(AttestationError::MeasurementsNotAccepted)
1226+
));
1227+
}
11181228
}

0 commit comments

Comments
 (0)