1use crate::{SdkError, SdkResult};
2use sev::{
3 certs::snp::{Certificate, Chain, Verifiable, builtin::milan, ca},
4 firmware::{guest::AttestationReport, host::TcbVersion},
5};
6use sha2::{Digest, Sha512};
7use std::collections::BTreeMap;
8
9#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
11pub struct SevSnp;
12
13impl SevSnp {
14 pub const KDS_CERT_SITE: &'static str = "https://kdsintf.amd.com";
16 pub const KDS_VCEK: &'static str = "/vcek/v1";
18 pub const PRODUCT_NAME: &'static str = "Milan";
20
21 pub fn vcek_url(attestation_report: &AttestationReport) -> String {
23 let AttestationReport {
24 chip_id,
25 reported_tcb:
26 TcbVersion {
27 bootloader,
28 tee,
29 snp,
30 microcode,
31 ..
32 },
33 ..
34 } = attestation_report;
35
36 format!(
37 "{}{}{}/{}?blSPL={bootloader:0>2}&teeSPL={tee:0>2}&snpSPL={snp:0>2}&ucodeSPL={microcode:0>2}",
38 Self::KDS_CERT_SITE,
39 Self::KDS_VCEK,
40 Self::PRODUCT_NAME,
41 hex::encode(chip_id)
42 )
43 }
44
45 pub fn verify(
47 attestation_report: &AttestationReport,
48 attestation_data: &BTreeMap<String, Vec<u8>>,
49 signatures: &[Vec<u8>],
50 challenge: &[u8],
51 vcek_certificate: &Certificate,
52 ) -> SdkResult<()> {
53 verify_certificate(vcek_certificate, attestation_report)?;
54 verify_challenge(challenge, attestation_data, signatures, attestation_report)
55 }
56}
57
58fn verify_certificate(vek: &Certificate, report: &AttestationReport) -> SdkResult<()> {
59 let ark = milan::ark().expect("to get the ark");
60 let ask = milan::ask().expect("to get the ask");
61
62 let ca = ca::Chain { ark, ask };
63 let chain = Chain {
64 ca,
65 vek: vek.clone(),
66 };
67 Verifiable::verify((&chain, report))?;
68 Ok(())
69}
70
71fn verify_challenge(
72 challenge: &[u8],
73 data: &BTreeMap<String, Vec<u8>>,
74 signatures: &[Vec<u8>],
75 attestation_report: &AttestationReport,
76) -> SdkResult<()> {
77 let mut hasher = Sha512::default();
78 hasher.update("noonce");
79 hasher.update(challenge);
80
81 hasher.update("data");
82 for (key, value) in data {
83 hasher.update(key);
84 hasher.update(value);
85 }
86 if !signatures.is_empty() {
87 hasher.update("signatures");
88 for signature in signatures {
89 hasher.update(signature);
90 }
91 }
92
93 let hash: [u8; 64] = hasher.finalize().into();
94
95 if attestation_report.report_data != hash {
96 return Err(SdkError::Attestation);
97 }
98 Ok(())
99}