Skip to content

Commit

Permalink
Add implementation of AESM client for SGX
Browse files Browse the repository at this point in the history
  • Loading branch information
parthsane committed Mar 19, 2020
1 parent bb10e94 commit a22a993
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 0 deletions.
121 changes: 121 additions & 0 deletions aesm-client/src/imp/sgx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use std::time::Duration;
use std::net::TcpStream;
use std::io::{Read,Write};

use byteorder::{LittleEndian, NativeEndian, ReadBytesExt, WriteBytesExt};
use protobuf::Message;

pub use error::{AesmError, Error, Result};
use {
AesmRequest, FromResponse, QuoteInfo, QuoteResult, QuoteType,
Request_GetQuoteRequest, Request_InitQuoteRequest,
};

/// This timeout is an argument in AESM request protobufs.
///
/// This value should be used for requests that can be completed locally, i.e.
/// without network interaction.
const LOCAL_AESM_TIMEOUT_US: u32 = 1_000_000;
/// This timeout is an argument in AESM request protobufs.
///
/// This value should be used for requests that might need interaction with
/// remote servers, such as provisioning EPID.
const REMOTE_AESM_TIMEOUT_US: u32 = 30_000_000;

#[derive(Debug)]
pub struct AesmClient {
tcp_stream: TcpStream,
}

impl AesmClient {
pub fn new(tcp_stream: TcpStream) -> Self {
AesmClient { tcp_stream }
}

fn open_socket(&self) -> Result<TcpStream> {
let sock = self.tcp_stream.try_clone()?;
let _ = sock.set_write_timeout(Some(Duration::from_micros(LOCAL_AESM_TIMEOUT_US as _)))?;
Ok(sock)
}

pub fn try_connect(&self) -> Result<()> {
self.open_socket().map(|_| ())
}

fn transact<T: AesmRequest>(&self, req: T) -> Result<T::Response> {
let mut sock = self.open_socket()?;

let _ = sock.set_read_timeout(req.get_timeout().map(|t| Duration::from_micros(t as _)))?;

let req_bytes = req
.into()
.write_to_bytes()
.expect("Failed to serialize protobuf");
sock.write_u32::<NativeEndian>(req_bytes.len() as u32)?;
sock.write_all(&req_bytes)?;

let res_len = sock.read_u32::<NativeEndian>()?;
let mut res_bytes = vec![0; res_len as usize];
sock.read_exact(&mut res_bytes)?;

let res = T::Response::from_response(protobuf::parse_from_bytes(&res_bytes))?;
Ok(res)
}

/// Obtain target info from QE.
pub fn init_quote(&self) -> Result<QuoteInfo> {
let mut req = Request_InitQuoteRequest::new();
req.set_timeout(LOCAL_AESM_TIMEOUT_US);

let mut res = self.transact(req)?;

let (target_info, mut gid) = (res.take_targetInfo(), res.take_gid());

// AESM gives it to us little-endian, we want big-endian for writing into IAS URL with to_hex()
gid.reverse();

Ok(QuoteInfo { target_info, gid })
}

/// Obtain remote attestation quote from QE.
pub fn get_quote(
&self,
session: &QuoteInfo,
report: Vec<u8>,
spid: Vec<u8>,
sig_rl: Vec<u8>,
quote_type: QuoteType,
nonce: Vec<u8>,
) -> Result<QuoteResult> {
let mut req = Request_GetQuoteRequest::new();
req.set_report(report);
req.set_quote_type(quote_type.into());
req.set_spid(spid);
req.set_nonce(nonce);
req.set_buf_size(session.quote_buffer_size(&sig_rl));
if sig_rl.len() != 0 {
req.set_sig_rl(sig_rl);
}
req.set_qe_report(true);
req.set_timeout(REMOTE_AESM_TIMEOUT_US);

let mut res = self.transact(req)?;

let (mut quote, qe_report) = (res.take_quote(), res.take_qe_report());

// AESM allocates a buffer of the size we supplied and returns the whole
// thing to us, regardless of how much space QE needed. Trim the excess.
// The signature length is a little endian word at offset 432 in the quote
// structure. See "QUOTE Structure" in the IAS API Spec.
let sig_len = (&quote[432..436]).read_u32::<LittleEndian>().unwrap();
let new_len = 436 + sig_len as usize;
if quote.len() < new_len {
// Quote is already too short, should not happen.
// Probably we are interpreting the quote structure incorrectly.
return Err(Error::InvalidQuoteSize);
}
quote.truncate(new_len);

Ok(QuoteResult::new(quote, qe_report))
}
}
21 changes: 21 additions & 0 deletions aesm-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ extern crate sgx_isa;

#[cfg(feature = "sgxs")]
use std::result::Result as StdResult;
#[cfg(target_env = "sgx")]
use std::net::TcpStream;

use protobuf::ProtobufResult;
#[cfg(feature = "sgxs")]
use sgxs::einittoken::{Einittoken, EinittokenProvider};
#[cfg(feature = "sgxs")]
use sgx_isa::{Attributes, Sigstruct};

include!(concat!(env!("OUT_DIR"), "/mod_aesm_proto.rs"));
Expand All @@ -47,6 +50,9 @@ mod imp;
#[cfg(unix)]
#[path = "imp/unix.rs"]
mod imp;
#[cfg(target_env = "sgx")]
#[path = "imp/sgx.rs"]
mod imp;
#[cfg(unix)]
pub mod unix {
use std::path::Path;
Expand Down Expand Up @@ -150,15 +156,29 @@ impl QuoteResult {
}
}

#[cfg(not(target_env = "sgx"))]
#[derive(Default, Debug, Clone)]
pub struct AesmClient {
inner: imp::AesmClient
}

// TODO: Find a better alternative to removing Clone and Default trait
#[cfg(target_env = "sgx")]
#[derive(Debug)]
pub struct AesmClient {
inner: imp::AesmClient
}


impl AesmClient {
#[cfg(not(target_env = "sgx"))]
pub fn new() -> Self {
AesmClient { inner: imp::AesmClient::new() }
}
#[cfg(target_env = "sgx")]
pub fn new(tcp_stream: TcpStream) -> Self {
AesmClient { inner: imp::AesmClient::new(tcp_stream) }
}

/// Test the connection with AESM.
///
Expand Down Expand Up @@ -192,6 +212,7 @@ impl AesmClient {
)
}

#[cfg(feature = "sgxs")]
pub fn get_launch_token(
&self,
sigstruct: &Sigstruct,
Expand Down

0 comments on commit a22a993

Please sign in to comment.