Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for skipping attestation report verification #4774

Merged
merged 4 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 2 additions & 1 deletion oak_attestation/src/dice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ pub fn stage0_dice_data_to_proto(value: Stage0DiceData) -> anyhow::Result<DiceDa

fn tee_platform_to_proto(src: oak_dice::evidence::TeePlatform) -> TeePlatform {
match src {
oak_dice::evidence::TeePlatform::Unspecified => TeePlatform::Unspecified,
oak_dice::evidence::TeePlatform::AmdSevSnp => TeePlatform::AmdSevSnp,
oak_dice::evidence::TeePlatform::IntelTdx => TeePlatform::IntelTdx,
oak_dice::evidence::TeePlatform::Unspecified => TeePlatform::Unspecified,
oak_dice::evidence::TeePlatform::None => TeePlatform::None,
}
}

Expand Down
65 changes: 45 additions & 20 deletions oak_attestation_verification/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ use oak_proto_rust::oak::{
attestation::v1::{
attestation_results::Status, binary_reference_value, endorsements,
extracted_evidence::EvidenceValues, reference_values, root_layer_data::Report,
AmdAttestationReport, AmdSevReferenceValues, ApplicationKeys, ApplicationLayerData,
ApplicationLayerEndorsements, ApplicationLayerReferenceValues, AttestationResults,
BinaryReferenceValue, CbData, CbEndorsements, CbReferenceValues, ContainerLayerData,
ContainerLayerEndorsements, ContainerLayerReferenceValues, Endorsements, Evidence,
ExtractedEvidence, IntelTdxAttestationReport, IntelTdxReferenceValues, KernelLayerData,
KernelLayerEndorsements, KernelLayerReferenceValues, OakContainersData,
root_layer_reference_values, AmdAttestationReport, AmdSevReferenceValues, ApplicationKeys,
ApplicationLayerData, ApplicationLayerEndorsements, ApplicationLayerReferenceValues,
AttestationResults, BinaryReferenceValue, CbData, CbEndorsements, CbReferenceValues,
ContainerLayerData, ContainerLayerEndorsements, ContainerLayerReferenceValues,
Endorsements, Evidence, ExtractedEvidence, IntelTdxAttestationReport,
IntelTdxReferenceValues, KernelLayerData, KernelLayerEndorsements,
KernelLayerReferenceValues, MockAttestationReport, OakContainersData,
OakContainersEndorsements, OakContainersReferenceValues, OakRestrictedKernelData,
OakRestrictedKernelEndorsements, OakRestrictedKernelReferenceValues, ReferenceValues,
RootLayerData, RootLayerEndorsements, RootLayerEvidence, RootLayerReferenceValues,
Expand Down Expand Up @@ -142,6 +143,7 @@ pub fn verify(
{
Report::SevSnp(values) => values.report_data.as_ref(),
Report::Tdx(values) => values.report_data.as_ref(),
Report::Mock(values) => values.report_data.as_ref(),
};
// The report data contains 64 bytes by default, but we only use the first 32 bytes at the
// moment.
Expand Down Expand Up @@ -431,6 +433,7 @@ fn verify_root_attestation_signature(
verify_attestation_report_signature(&vcek, report)
}
TeePlatform::IntelTdx => anyhow::bail!("not supported"),
TeePlatform::None => Ok(()),
}
}

Expand All @@ -441,21 +444,29 @@ fn verify_root_layer(
_endorsements: Option<&RootLayerEndorsements>,
reference_values: &RootLayerReferenceValues,
) -> anyhow::Result<()> {
if let Some(root_layer_reference_values::Type::Skip(_)) = reference_values.r#type {
return Ok(());
}
match values.report.as_ref() {
Some(Report::SevSnp(report_values)) => verify_amd_sev_attestation_report(
report_values,
reference_values
.amd_sev
.as_ref()
.context("AMD SEV-SNP reference values not found")?,
),
Some(Report::Tdx(report_values)) => verify_intel_tdx_attestation_report(
report_values,
reference_values
.intel_tdx
.as_ref()
.context("Intel TDX reference values not found")?,
),
Some(Report::SevSnp(report_values)) => {
if let Some(root_layer_reference_values::Type::AmdSev(reference)) =
reference_values.r#type.as_ref()
{
verify_amd_sev_attestation_report(report_values, reference)
} else {
anyhow::bail!("AMD SEV-SNP reference values not found");
}
}
Some(Report::Tdx(report_values)) => {
if let Some(root_layer_reference_values::Type::IntelTdx(reference)) =
reference_values.r#type.as_ref()
{
verify_intel_tdx_attestation_report(report_values, reference)
} else {
anyhow::bail!("Intel TDX reference values not found");
}
}
Some(Report::Mock(_report_values)) => Ok(()),
None => Err(anyhow::anyhow!("no attestation report")),
}
}
Expand Down Expand Up @@ -822,6 +833,20 @@ fn extract_root_values(root_layer: &RootLayerEvidence) -> anyhow::Result<RootLay
})
}
TeePlatform::IntelTdx => Err(anyhow::anyhow!("not supported")),
TeePlatform::None => {
// We use an unsigned, mostly empty AMD SEV-SNP attestation report as a mock when not
// running in a TEE.
let report = AttestationReport::ref_from(&root_layer.remote_attestation_report)
.context("invalid mock attestation report")?;

report.validate().map_err(|msg| anyhow::anyhow!(msg))?;

let report_data = report.data.report_data.as_ref().to_vec();

Ok(RootLayerData {
report: Some(Report::Mock(MockAttestationReport { report_data })),
})
}
}
}

Expand Down
Binary file not shown.
23 changes: 23 additions & 0 deletions oak_attestation_verification/testdata/mock_evidence.textproto
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# proto-file: proto/attestation/evidence.proto
# proto-message: oak.attestaton.v1.Evidence
#
# Attestation evidence generated when not running on a TEE.
# Generated on 8 Feb 2024. `mock_evidence.binarypb` is the same instance in
# serialized binary format.
#
# The stage0 binary is measured in the attestation report.
root_layer {
platform: NONE
remote_attestation_report: "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000l\025\313\320C\030T\201i\347\024\300\363\023\241\306\' \003\317f\341\231\"\330D\306D2\r\336\214\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OOC, did you make this with a hex editor (i.e. by hand)? Where does it come from?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was taken from the debug log of an instance when running without AMD SEV-SNP.

eca_public_key: "\247\001\002\002T\355\215\321Z\334ux&\262\214\370*\232L\217\023\307\010.\007\0038.\004\201\002 \001!X \024\221\3475\317u\245\372\226\236uTX\307\323l\336\242y\206\305\357\r\244\036)(\036HZ\330\004\"X \023=\367r@\000\177\334\331<\014\034\345\336\006\223w\343\3125\335\263\243\201UFx\241\346n\030\036"
}
layers {
eca_certificate: "\204D\241\0018.\241\004RAsymmetricECDSA256Y\001\341\245\001x(ed8dd15adc757826b28cf82a9a4c8f13c7082e07\002x(2c315ded0740742804d1056ecca0a472feb87fc2:\000GDWXg\247\001\002\002T,1]\355\007@t(\004\321\005n\314\240\244r\376\270\177\302\0038.\004\201\002 \001!X \240Uo\306\246*;\275\357\340\033h\367\252\026\313\362\227\037\246\000\037\344\234g3b\351\343B\276\264\"X R\251\233+\363\340;\250\317Q-GD\005;y\263\327c\332\022\343e\013XQ\251l\2716\020\224:\000GDXB \000:\000GDZ\246:\000GD`\241:\000GDkX \223\004R\310\222\320\027gg\215ky^\312\302[\344\2152x\363[XQ)\024\353\362`]\371c:\000GDa\241:\000GDkX \215c\241+\037t\"\023\367\360\222\\\226\tZx\363\\\371JL\221\274\'\221\236D\252\312\311\026\035:\000GDb\241:\000GDkX \002\263\372yk\225:\363\271D\200\207p\260*\207\255\227\323w9\320\215\346\001m\"\203(8T<:\000GDc\241:\000GDkX *\247\3275\275\031\370-\0069\254A\334\207\r\342$\217\003=\005\231d\010}7\310\\,\2126\023:\000GDd\241:\000GDkX \001u>\274BEU\250\r5\255\252!\365\310\305\360\tH.\213\\\305\332\360I\274\033\277\376\274{:\000GDe\241:\000GDkX Z\200J\367\351\007t\222\332\302\342\333g\020\246\315\246\207\331]A\\rA\225\321\2051\010\"\261\260X@\251\022:\344\324\314o%\246\024-\373\274\331M\357\312{\325S\3153\261rch9\177\010J\027#\007\235\221q\253\005\2034\035:\233\\~\344\347$\'\265\271\\eYrg\263N\022\337\227\314\304W"
}
layers {
eca_certificate: "\204D\241\0018.\241\004RAsymmetricECDSA256Y\001\000\245\001x(2c315ded0740742804d1056ecca0a472feb87fc2\002x(824798eb43ead4d88ebc68ce6cdb52cfe1546b84:\000GDWXg\247\001\002\002T\202G\230\353C\352\324\330\216\274h\316l\333R\317\341Tk\204\0038.\004\201\002 \001!X \253\3322?Xq\375`^\214p\207\267\233\324Y\253F\216Kh\273\232\0363\\-\312\323\365\'A\"X M\032>?7\317\233A9\024\240$\376[\370\264\3118j{D\243?1\023\260\004\276\232 \306\016:\000GDXB \000:\000GD\\\241:\000GDf\241:\000GDkX \277u\264\344\262\306).\327s\244\347\372P\303\253\252\210\tf\315~V\257\220*\217\261\030\273\214}X@\375\334\177ks?\213\230n\321\222\007\331\"\225qk\210*\276|\343bg\214N\215\'\277\200\350\2325\362.t\t\002c\360Y\247BH\016\300\014s\205Z\r\007\375v\314q\234\347\013\240\006\243T\302"
}
application_keys {
encryption_public_key_certificate: "\204D\241\0018.\241\004RAsymmetricECDSA256Y\001\n\245\001x(824798eb43ead4d88ebc68ce6cdb52cfe1546b84\002x(d98d5083465d75e56b9554149efc002903a17cfb:\000GDWXD\246\001\001\002T\331\215P\203F]u\345k\225T\024\236\374\000)\003\241|\373\0038\036\004\201\005 \004!X \321\257x\257)\311e\365}\323R\202\033\'0\336YS\024\203\016G\200;\357\252\272\206FY\237d:\000GDXB \000:\000GD^\242:\000GDh\241:\000GDkX P>\323\307\242=\3354U_\227?Q\255~<.\301[\362aSv{\377\211j\260\024\301l\200:\000GDi\241:\000GDkX \033\336\262\213\304\362\020\333\233B\2421`\370\027\307\005\357\371\210\334g\302\342\350\356O\216\345\223RzX@\301\246?y\361\036G\321\013\232?\313;/\177\343\202C:\325$\016\221\270\031A\377\204pZ|+\371\345\304\320\363\343M\216P\026\242\373\344<\037;/\332.\311\321#%\344\006!\006\t\316\306.\360"
signing_public_key_certificate: "\204D\241\0018.\241\004RAsymmetricECDSA256Y\001-\245\001x(824798eb43ead4d88ebc68ce6cdb52cfe1546b84\002x(8c69d3a14ea82ad66acc603e141b13282e1dc173:\000GDWXg\247\001\002\002T\214i\323\241N\250*\326j\314`>\024\033\023(.\035\301s\0038.\004\201\002 \001!X \351\345G?\306\355\366\347\020y\211\344~b\3077Z\303\036[Kf\377\311Z\317\3432:(\361K\"X \335w\353[\0070\353\3569\207@\231\001\342\031\3738\023Tp\360>\215\377&\357w.\262\341\'\334:\000GDXB \000:\000GD^\242:\000GDh\241:\000GDkX P>\323\307\242=\3354U_\227?Q\255~<.\301[\362aSv{\377\211j\260\024\301l\200:\000GDi\241:\000GDkX \033\336\262\213\304\362\020\333\233B\2421`\370\027\307\005\357\371\210\334g\302\342\350\356O\216\345\223RzX@\253+\222V\206n?_r\207\337\270\037\325\2108\340M\357%8L\376&\310\247\347\337\203\230\02729\204\210\302\276\027\236\r\315\347\376LU\316\214}AU\376\032\333k\255\370&\323\016\352\304B\177_"
}
49 changes: 37 additions & 12 deletions oak_attestation_verification/tests/verifier_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use oak_attestation_verification::{
verifier::{to_attestation_results, verify},
};
use oak_proto_rust::oak::attestation::v1::{
attestation_results::Status, AmdSevReferenceValues, BinaryReferenceValue,
attestation_results::Status, binary_reference_value, reference_values,
root_layer_reference_values, AmdSevReferenceValues, BinaryReferenceValue,
ContainerLayerEndorsements, ContainerLayerReferenceValues, EndorsementReferenceValue,
Endorsements, Evidence, KernelLayerEndorsements, KernelLayerReferenceValues,
OakContainersEndorsements, OakContainersReferenceValues, ReferenceValues,
Expand All @@ -37,16 +38,23 @@ const VCEK_MILAN_CERT_DER: &str = "testdata/vcek_milan.der";
const ENDORSER_PUBLIC_KEY_PATH: &str = "testdata/oak-development.pem";
const REKOR_PUBLIC_KEY_PATH: &str = "testdata/rekor_public_key.pem";
const EVIDENCE_PATH: &str = "testdata/evidence.binarypb";
const MOCK_EVIDENCE_PATH: &str = "testdata/mock_evidence.binarypb";

// Pretend the tests run at this time: 1 Nov 2023, 9:00 UTC
const NOW_UTC_MILLIS: i64 = 1698829200000;

// Creates a valid evidence instance.
// Creates a valid AMD SEV-SNP evidence instance.
fn create_evidence() -> Evidence {
let serialized = fs::read(EVIDENCE_PATH).expect("could not read evidence");
Evidence::decode(serialized.as_slice()).expect("could not decode evidence")
}

// Creates a valid mock evidence instance.
fn create_mock_evidence() -> Evidence {
let serialized = fs::read(MOCK_EVIDENCE_PATH).expect("could not read evidence");
Evidence::decode(serialized.as_slice()).expect("could not decode evidence")
}

// Creates valid endorsements for an Oak Containers chain.
fn create_endorsements() -> Endorsements {
let endorsement = fs::read(ENDORSEMENT_PATH).expect("couldn't read endorsement");
Expand Down Expand Up @@ -109,11 +117,7 @@ fn create_reference_values() -> ReferenceValues {
rekor_public_key,
};
let skip = BinaryReferenceValue {
r#type: Some(
oak_proto_rust::oak::attestation::v1::binary_reference_value::Type::Skip(
SkipVerification {},
),
),
r#type: Some(binary_reference_value::Type::Skip(SkipVerification {})),
};
let brv = BinaryReferenceValue {
r#type: Some(
Expand All @@ -132,8 +136,7 @@ fn create_reference_values() -> ReferenceValues {
};

let root_layer = RootLayerReferenceValues {
amd_sev: Some(amd_sev),
intel_tdx: None,
r#type: Some(root_layer_reference_values::Type::AmdSev(amd_sev)),
};
let kernel_layer = KernelLayerReferenceValues {
kernel_image: Some(skip.clone()),
Expand All @@ -157,9 +160,7 @@ fn create_reference_values() -> ReferenceValues {
container_layer: Some(container_layer),
};
ReferenceValues {
r#type: Some(
oak_proto_rust::oak::attestation::v1::reference_values::Type::OakContainers(vs),
),
r#type: Some(reference_values::Type::OakContainers(vs)),
}
}

Expand All @@ -179,6 +180,30 @@ fn verify_succeeds() {
assert!(p.status() == Status::Success);
}

#[test]
fn verify_mock_evidence() {
let evidence = create_mock_evidence();
let endorsements = create_endorsements();
let mut reference_values = create_reference_values();
if let Some(reference_values::Type::OakContainers(reference)) = reference_values.r#type.as_mut()
{
reference.root_layer = Some(RootLayerReferenceValues {
r#type: Some(root_layer_reference_values::Type::Skip(SkipVerification {})),
});
} else {
panic!("invalid reference value type");
}

let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values);
let p = to_attestation_results(&r);

eprintln!("======================================");
eprintln!("code={} reason={}", p.status as i32, p.reason);
eprintln!("======================================");
assert!(r.is_ok());
assert!(p.status() == Status::Success);
}

#[test]
fn verify_fails_with_manipulated_root_public_key() {
let mut evidence = create_evidence();
Expand Down
10 changes: 9 additions & 1 deletion oak_dice/src/evidence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub enum TeePlatform {
AmdSevSnp = 1,
/// Intel TDX.
IntelTdx = 2,
/// None.
None = 3,
}

/// Attestation evidence generated by Stage 0.
Expand Down Expand Up @@ -99,10 +101,16 @@ impl RootLayerEvidence {

pub fn get_remote_attestation_report(&self) -> Result<&[u8], &'static str> {
match self.get_tee_platform()? {
TeePlatform::None => {
// We use a mock attestation report based on the AMD SEV-SNP report when we run
// without a TEE.
Ok(&self.remote_attestation_report[..AMD_SEV_SNP_ATTESTATION_REPORT_SIZE])
}
TeePlatform::AmdSevSnp => {
Ok(&self.remote_attestation_report[..AMD_SEV_SNP_ATTESTATION_REPORT_SIZE])
}
_ => Ok(&self.remote_attestation_report),
TeePlatform::IntelTdx => Ok(&self.remote_attestation_report),
TeePlatform::Unspecified => Err("TEE platform not specified"),
}
}

Expand Down
Loading
Loading