lit_sdk/
sev_snp.rs

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/// Handler for Sev SNP attestation reports for LIT
10#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
11pub struct SevSnp;
12
13impl SevSnp {
14    /// The KDS CERT url
15    pub const KDS_CERT_SITE: &'static str = "https://kdsintf.amd.com";
16    /// The sub url
17    pub const KDS_VCEK: &'static str = "/vcek/v1";
18    /// The product name
19    pub const PRODUCT_NAME: &'static str = "Milan";
20
21    /// Get the vcek url
22    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    /// Verify the attestation report and provided inner data
46    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}