1use 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
30pub 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
52pub 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}