az_snp_vtpm/
amd_kds.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::certs::{AmdChain, Vcek};
5use crate::HttpError;
6use openssl::x509::X509;
7use sev::firmware::guest::AttestationReport;
8use thiserror::Error;
9
10const KDS_CERT_SITE: &str = "https://kdsintf.amd.com";
11const KDS_VCEK: &str = "/vcek/v1";
12const SEV_PROD_NAME: &str = "Milan";
13const KDS_CERT_CHAIN: &str = "cert_chain";
14
15fn get(url: &str) -> Result<Vec<u8>, HttpError> {
16    let mut body = ureq::get(url).call().map_err(Box::new)?.into_reader();
17    let mut buffer = Vec::new();
18    body.read_to_end(&mut buffer)?;
19    Ok(buffer)
20}
21
22#[derive(Error, Debug)]
23pub enum AmdKdsError {
24    #[error("openssl error")]
25    OpenSsl(#[from] openssl::error::ErrorStack),
26    #[error("Http error")]
27    Http(#[from] HttpError),
28}
29
30/// Retrieve the AMD chain of trust (ASK & ARK) from AMD's KDS
31pub fn get_cert_chain() -> Result<AmdChain, AmdKdsError> {
32    let url = format!("{KDS_CERT_SITE}{KDS_VCEK}/{SEV_PROD_NAME}/{KDS_CERT_CHAIN}");
33    let bytes = get(&url)?;
34
35    let certs = X509::stack_from_pem(&bytes)?;
36    let ask = certs[0].clone();
37    let ark = certs[1].clone();
38
39    let chain = AmdChain { ask, ark };
40
41    Ok(chain)
42}
43
44fn hexify(bytes: &[u8]) -> String {
45    let mut hex_string = String::new();
46    for byte in bytes {
47        hex_string.push_str(&format!("{byte:02x}"));
48    }
49    hex_string
50}
51
52/// Retrieve a VCEK cert from AMD's KDS, based on an AttestationReport's platform information
53pub fn get_vcek(report: &AttestationReport) -> Result<Vcek, AmdKdsError> {
54    let hw_id = hexify(&report.chip_id);
55    let url = format!(
56        "{KDS_CERT_SITE}{KDS_VCEK}/{SEV_PROD_NAME}/{hw_id}?blSPL={:02}&teeSPL={:02}&snpSPL={:02}&ucodeSPL={:02}",
57        report.reported_tcb.bootloader,
58        report.reported_tcb.tee,
59        report.reported_tcb.snp,
60        report.reported_tcb.microcode
61    );
62
63    let bytes = get(&url)?;
64    let cert = X509::from_der(&bytes)?;
65    let vcek = Vcek(cert);
66    Ok(vcek)
67}