pcs/
pckid.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
8use std::convert::TryInto;
9use std::fs::File;
10use std::io::{self, BufRead, BufReader, Error, ErrorKind};
11use std::path::Path;
12
13use rustc_serialize::hex::{FromHex, ToHex};
14use serde::{Deserialize, Serialize};
15
16use crate::{CpuSvn, EncPpid, PceId, PceIsvsvn, QeId};
17
18#[derive(Clone, Serialize, Deserialize, Debug, Default, Hash, PartialEq, Eq)]
19pub struct PckID {
20    pub enc_ppid: EncPpid,
21    pub pce_id: PceId,
22    pub cpu_svn: CpuSvn,
23    pub pce_isvsvn: PceIsvsvn,
24    pub qe_id: QeId,
25}
26
27impl ToString for PckID {
28    fn to_string(&self) -> String {
29        let enc_ppid = self.enc_ppid.as_slice();
30        let mut string = String::from("==[ PckId ]==\n");
31        string += format!(" Info:\n").as_str();
32        string += format!(
33            "   Encr. PPID:  {}..{}\n",
34            enc_ppid[..12].to_hex(),
35            enc_ppid[enc_ppid.len() - 3..].to_hex()
36        )
37        .as_str();
38        string += format!("   pce_id:      {}\n", self.pce_id.to_le_bytes().to_hex()).as_str();
39        string += format!("   cpu svn:     {}\n", self.cpu_svn.as_slice().to_hex()).as_str();
40        string += format!("   pce isvsvn:  {}\n", self.pce_isvsvn.to_le_bytes().to_hex()).as_str();
41        string += format!("   qe_id:       {}\n", self.qe_id.as_slice().to_hex()).as_str();
42        return string;
43    }
44}
45
46fn parse_hex_array<'a>(chunk: &'a str, expected_bytes: usize) -> io::Result<Vec<u8>> {
47    if chunk.len() != expected_bytes * 2 {
48        return Err(Error::new(ErrorKind::InvalidData, "Parse error, incorrect field length"));
49    }
50
51    chunk
52        .from_hex()
53        .map_err(|_| Error::new(ErrorKind::InvalidData, "Cannot parse as hexadecimal"))
54}
55
56/// Iterator adapter that returns Results instead of Options.
57struct ResultAdapter<I: Iterator, E, F: Fn() -> E>(I, F);
58
59impl<I: Iterator, E, F: Fn() -> E> ResultAdapter<I, E, F> {
60    fn next(&mut self) -> std::result::Result<I::Item, E> {
61        self.0.next().ok_or_else(|| self.1())
62    }
63}
64
65impl PckID {
66    pub fn parse_line(line: &str) -> io::Result<Self> {
67        let mut fields = ResultAdapter(line.split(","), || Error::new(ErrorKind::InvalidData, "Too few fields"));
68
69        let enc_ppid: EncPpid = parse_hex_array(fields.next()?, 384)?;
70        let pce_id: PceId = u16::from_str_radix(fields.next()?, 16)
71            .map_err(|_| Error::new(ErrorKind::InvalidData, "Cannot parse as hexadecimal"))?;
72        let cpu_svn: CpuSvn = parse_hex_array(fields.next()?, 16)?
73            .try_into()
74            .map_err(|_e| Error::new(ErrorKind::InvalidData, "Incorrect length cpu_svn"))?;
75        let pce_isvsvn: PceIsvsvn = u16::from_str_radix(fields.next()?, 16)
76            .map_err(|_| Error::new(ErrorKind::InvalidData, "Cannot parse as hexadecimal"))?;
77        let qe_id: QeId = parse_hex_array(fields.next()?, 16)?
78            .try_into()
79            .map_err(|_e| Error::new(ErrorKind::InvalidData, "Incorrect length qe_id"))?;
80
81        Ok(PckID {
82            enc_ppid,
83            pce_id,
84            cpu_svn,
85            pce_isvsvn,
86            qe_id,
87        })
88    }
89
90    pub fn parse_file(file: &Path) -> io::Result<Vec<Self>> {
91        let file = File::open(file)?;
92        let mut pck_ids = Vec::new();
93
94        for line_res in BufReader::new(file).lines() {
95            let line = line_res?;
96            let trimmed = line.trim();
97            if trimmed.is_empty() {
98                continue;
99            }
100            let pck_id = PckID::parse_line(trimmed)?;
101            pck_ids.push(pck_id);
102        }
103
104        Ok(pck_ids)
105    }
106}