dcap_retrieve_pckid/
lib.rs1#![deny(warnings)]
8use std::convert::TryInto;
9use std::fmt;
10
11use anyhow::anyhow;
12use aesm_client::AesmClient;
13use dcap_ql::quote::{Qe3CertDataPpid, Quote, Quote3SignatureEcdsaP256, QuoteHeader};
14use sgx_isa::Targetinfo;
15#[cfg(windows)]
16use sgxs_loaders::enclaveapi::Sgx as IsgxDevice;
17#[cfg(unix)]
18use sgxs_loaders::isgx::Device as IsgxDevice;
19
20fn get_algorithm_id(key_id: &Vec<u8>) -> u32 {
21 const ALGORITHM_OFFSET: usize = 154;
22
23 let mut bytes: [u8; 4] = Default::default();
24 bytes.copy_from_slice(&key_id[ALGORITHM_OFFSET..ALGORITHM_OFFSET + 4]);
25 u32::from_le_bytes(bytes)
26}
27
28struct PrintHex<'a>(&'a [u8]);
29
30impl<'a> fmt::Display for PrintHex<'a> {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 for b in self.0 {
33 write!(f, "{:02x}", b)?;
34 }
35 Ok(())
36 }
37}
38
39pub struct PckId {
40 pub cd_ppid: Qe3CertDataPpid<'static>,
41 pub qe_id: [u8; 16],
42}
43
44impl ToString for PckId {
45 fn to_string(&self) -> String {
46 format!(
47 "{ppid},{pceid},{cpusvn},{pcesvn},{qe3id}",
48 ppid = PrintHex(&self.cd_ppid.ppid),
49 pceid = PrintHex(&self.cd_ppid.pceid.to_le_bytes()),
50 cpusvn = PrintHex(&self.cd_ppid.cpusvn),
51 pcesvn = PrintHex(&self.cd_ppid.pcesvn.to_le_bytes()),
52 qe3id = PrintHex(&self.qe_id),
53 )
54 }
55}
56
57pub fn retrieve_pckid_str() -> Result<PckId, anyhow::Error> {
58 const SGX_QL_ALG_ECDSA_P256: u32 = 2;
59
60 let mut device = IsgxDevice::new()
61 .map_err(|err| anyhow::Error::from(err).context("Error opening SGX device"))?
62 .einittoken_provider(AesmClient::new())
63 .build();
64
65 let client = AesmClient::new();
66
67 let key_ids = client
68 .get_supported_att_key_ids()
69 .map_err(|err| anyhow::Error::from(err).context("AESM communication error getting attestation key ID"))?;
70
71 let ecdsa_key_id = key_ids
72 .into_iter()
73 .find(|id| SGX_QL_ALG_ECDSA_P256 == get_algorithm_id(id))
74 .ok_or(anyhow!("No appropriate attestation key ID"))?;
75
76 let quote_info = client
77 .init_quote_ex(ecdsa_key_id.clone())
78 .map_err(|err| anyhow::Error::from(err).context("Error during quote initialization"))?;
79
80 let ti = Targetinfo::try_copy_from(quote_info.target_info()).unwrap();
81 let report = report_test::report(&ti, &mut device).unwrap();
82
83 let res = client
84 .get_quote_ex(ecdsa_key_id, report.as_ref().to_owned(), None, vec![0; 16])
85 .map_err(|err| anyhow::Error::from(err).context("Error obtaining quote"))?;
86
87 let quote = Quote::parse(res.quote()).map_err(|err| err.context("Error parsing quote"))?;
88 let QuoteHeader::V3 { user_data, .. } = quote.header();
89 let sig = quote
90 .signature::<Quote3SignatureEcdsaP256>()
91 .map_err(|err| err.context("Error parsing requested signature type"))?;
92 let cd_ppid = sig
93 .certification_data::<Qe3CertDataPpid>()
94 .map_err(|err| err.context("Error parsing requested signature type"))?;
95
96 Ok(PckId {
97 cd_ppid: cd_ppid.clone_owned(),
98 qe_id: user_data[0..16].try_into().unwrap(),
99 })
100}