dcap_retrieve_pckid/
lib.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#![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}