rust_sgx_util/
lib.rs

1//! A safe wrapper around Graphene's [`sgx_util`] C-library.
2//!
3//! [`sgx_util`]: https://github.com/oscarlab/graphene/tree/master/Pal/src/host/Linux-SGX/tools
4//!
5//! ```toml
6//! rust-sgx-util = "0.2"
7//! ```
8//!
9//! For `serde` support, you can enable it with `with_serde` feature:
10//!
11//! ```toml
12//! rust-sgx-util = { version = "0.2", features = ["with_serde"] }
13//! ```
14//!
15//! ## Prerequisites
16//!
17//! Currently, this crate requires you compile and install `sgx_util` as
18//! a shared library.
19//!
20//! ## Usage examples
21//!
22//! You can find usage examples in the `examples` dir of the crate.
23//!
24mod c;
25mod ias;
26#[cfg(feature = "with_serde")]
27mod ser_de;
28
29pub use ias::*;
30
31#[cfg(feature = "with_serde")]
32use serde::{Deserialize, Serialize};
33use std::convert::TryFrom;
34use std::ops::Deref;
35
36/// Convenience wrapper around fallible operation.
37pub type Result<T> = std::result::Result<T, Error>;
38
39/// Error type thrown by fallible operations in this crate.
40#[derive(Debug, thiserror::Error)]
41pub enum Error {
42    /// Failed to initialize `IasHandle`.
43    #[error("failed to initialize IasHandle")]
44    IasInitNullPtr,
45    /// `Quote`'s size is too small.
46    #[error("quote's size is too small")]
47    QuoteTooShort,
48    /// `Nonce` exceeded 32 bytes.
49    #[error("nonce exceeded 32 bytes")]
50    NonceTooLong,
51    /// `IasHandle::get_sigrl` returned nonzero return code.
52    #[error("get_sigrl returned nonzero return code: {}", _0)]
53    IasGetSigrlNonZero(i32),
54    /// `IasHandle::verify_quote` returned nonzero return code.
55    #[error("verify_quote returned nonzero return code: {}", _0)]
56    IasVerifyQuoteNonZero(i32),
57    /// Error while parsing int from string.
58    #[error("parsing int from string: {:?}", _0)]
59    ParseInt(#[from] std::num::ParseIntError),
60    /// Found unexpected interior nul byte.
61    #[error("unexpected interior nul byte: {:?}", _0)]
62    Nul(#[from] std::ffi::NulError),
63    /// (Windows only) Encountered invalid UTF16.
64    #[error("invalid UTF16 encountered: {:?}", _0)]
65    Utf16(#[from] std::string::FromUtf16Error),
66}
67
68/// Set verbosity on/off.
69pub fn set_verbose(verbose: bool) {
70    unsafe { c::set_verbose(verbose) }
71}
72
73/// A thin wrapper around vector of bytes. Represents quote obtained
74/// from the challenged enclave.
75///
76/// # Accessing the underlying bytes buffer
77///
78/// `Quote` implements `Deref<Target=[u8]>`, therefore dereferencing it will
79/// yield its inner buffer of bytes.
80///
81/// # Serializing/deserializing
82///
83/// With `with_serde` feature enabled, `Quote` can be serialized and deserialized
84/// as base64 `String`.
85#[derive(Debug, Clone)]
86#[cfg_attr(feature = "with_serde", derive(Serialize, Deserialize))]
87pub struct Quote(#[cfg_attr(feature = "with_serde", serde(with = "ser_de"))] Vec<u8>);
88
89impl Quote {
90    const REPORT_BEGIN: usize = 368;
91    const REPORT_END: usize = 432;
92
93    /// Returns `report_data` bytes embedded within this `Quote`.
94    ///
95    /// The size of the returned slice is 64 bytes.
96    ///
97    /// # Errors
98    ///
99    /// This function will fail with [`Error::QuoteTooShort`] if `Quote`
100    /// is shorter than `432` bytes. Note that this is only a quick check
101    /// that we can extract the region in `Quote`'s buffer where we expect
102    /// the `report_data` to lie in. We don't do any validations on the
103    /// `Quote` in this method.
104    ///
105    /// [`Error::QuoteTooShort`]: enum.Error.html#variant.QuoteTooShort
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// # use rust_sgx_util::Quote;
111    /// let quote = Quote::from(&[0u8; 438][..]);
112    /// assert_eq!(quote.report_data().unwrap().len(), 64);
113    ///
114    /// let quote = Quote::from(&[0u8; 10][..]);
115    /// assert!(quote.report_data().is_err());
116    /// ```
117    pub fn report_data(&self) -> Result<&[u8]> {
118        self.0
119            .get(Self::REPORT_BEGIN..Self::REPORT_END)
120            .ok_or(Error::QuoteTooShort)
121    }
122}
123
124impl From<&[u8]> for Quote {
125    fn from(bytes: &[u8]) -> Self {
126        Self::from(bytes.to_vec())
127    }
128}
129
130impl From<Vec<u8>> for Quote {
131    fn from(bytes: Vec<u8>) -> Self {
132        Self(bytes)
133    }
134}
135
136impl Deref for Quote {
137    type Target = [u8];
138
139    fn deref(&self) -> &Self::Target {
140        &self.0
141    }
142}
143
144/// A thin wrapper around vector of bytes. Represents nonce obtained
145/// from the challenged enclave.
146///
147/// Nonce cannot be longer than 32 bytes.
148///
149/// # Accessing the underlying bytes buffer
150///
151/// `Nonce` implements `Deref<Target=[u8]>`, therefore dereferencing it will
152/// yield its inner buffer of bytes.
153///
154/// # Serializing/deserializing
155///
156/// With `with_serde` feature enabled, `Nonce` can be serialized and deserialized
157/// as base64 `String`.
158#[derive(Debug, Clone)]
159#[cfg_attr(feature = "with_serde", derive(Serialize, Deserialize))]
160pub struct Nonce(#[cfg_attr(feature = "with_serde", serde(with = "ser_de"))] Vec<u8>);
161
162impl Nonce {
163    fn new<B: Into<Vec<u8>>>(bytes: B) -> Result<Self> {
164        let bytes = bytes.into();
165        if bytes.len() > 32 {
166            return Err(Error::NonceTooLong);
167        }
168        Ok(Self(bytes))
169    }
170}
171
172impl TryFrom<&[u8]> for Nonce {
173    type Error = Error;
174
175    fn try_from(bytes: &[u8]) -> Result<Self> {
176        Self::new(bytes)
177    }
178}
179
180impl Deref for Nonce {
181    type Target = [u8];
182
183    fn deref(&self) -> &Self::Target {
184        &self.0
185    }
186}