Skip to content
Permalink
Browse files

[attestation] Refactor remote attestation code (#198)

- Introduce `teaclave_attestation`, a new create for attestation related code.
- This PR also refactor RA related code and move them into the `teaclave_attestation` crate.
- Create a new struct called `SgxQuoteVerifier` to wrap around `EnclaveAttr` and rewrite the original `EnclaveAttr` struct.
- For the `teaclave_attestation`, we start to try `thiserror` and `anyhow` for error management.
  • Loading branch information
mssun committed Dec 30, 2019
1 parent fa7ff61 commit 21cf3bbee75fad82cd61ce74929f6c590d91f514
@@ -12,7 +12,7 @@ path = "src/lib.rs"

[features]
default = []
mesalock_sgx = ["sgx_tstd", "sgx_tcrypto", "sgx_rand", "sgx_tse", "ipc", "teaclave_config/mesalock_sgx", "teaclave_utils/mesalock_sgx"]
mesalock_sgx = ["sgx_tstd", "sgx_tcrypto", "sgx_rand", "sgx_tse", "ipc", "teaclave_config/mesalock_sgx", "teaclave_utils/mesalock_sgx", "teaclave_attestation/mesalock_sgx"]
ipc = []

[dependencies]
@@ -47,3 +47,4 @@ sgx_tse = { version = "1.1.0", optional = true }
teaclave_config = { path = "../teaclave_config" }
teaclave_utils = { path = "../teaclave_utils" }
ipc_attribute = { path = "./ipc_attribute" }
teaclave_attestation = { path = "../teaclave_attestation" }
@@ -18,10 +18,11 @@
// ip/port is dynamically dispatched for fns client.
// we cannot use the &'static str in this struct.

use crate::rpc::sgx::EnclaveAttr;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::prelude::v1::*;
use teaclave_attestation;
use teaclave_attestation::verifier::EnclaveAttr;
use teaclave_config::build_config::BUILD_CONFIG;
use teaclave_config::runtime_config;
use teaclave_config::runtime_config::RuntimeConfig;
@@ -63,7 +64,6 @@ impl OutboundDesc {
pub fn new(measures: EnclaveMeasurement) -> OutboundDesc {
OutboundDesc::Sgx(EnclaveAttr {
measures: vec![measures],
quote_checker: universal_quote_check,
})
}
}
@@ -114,17 +114,10 @@ pub fn runtime_config() -> &'static RuntimeConfig {
.expect("Invalid runtime config, should gracefully exit during enclave_init!")
}

fn universal_quote_check(quote: &crate::rpc::sgx::auth::SgxQuote) -> bool {
quote.status != crate::rpc::sgx::auth::SgxQuoteStatus::UnknownBadStatus
}

pub fn get_trusted_enclave_attr(service_names: Vec<&str>) -> EnclaveAttr {
let measures = service_names
.iter()
.map(|name| *ENCLAVE_IDENTITIES.get(&(*name).to_string()).unwrap())
.collect();
EnclaveAttr {
measures,
quote_checker: universal_quote_check,
}
EnclaveAttr { measures }
}
@@ -22,7 +22,7 @@ cfg_if! {
// preludes provided for SGX enclave.
pub use crate::register_ecall_handler;
pub use crate::rpc::{RpcServer, RpcClient, EnclaveService};
pub use crate::rpc::sgx::{EnclaveAttr, Pipe, PipeConfig};
pub use crate::rpc::sgx::{Pipe, PipeConfig};
pub use crate::ipc::{IpcSender, IpcService, IpcReceiver};
pub use crate::ipc::protos::ECallCommand;
pub use crate::ipc::protos::ecall::{
@@ -25,6 +25,9 @@ use crate::Result;
use net2::TcpBuilder;
use serde::{de::DeserializeOwned, Serialize};

use teaclave_attestation::verifier::EnclaveAttr;
use teaclave_attestation::verifier::SgxQuoteVerifier;

pub struct SgxTrustedChannel<U: Serialize, V: DeserializeOwned> {
client: sgx::PipeClient<U, V>,
}
@@ -36,7 +39,7 @@ where
{
pub fn new(
addr: std::net::SocketAddr,
enclave_attr: sgx::EnclaveAttr,
enclave_attr: EnclaveAttr,
) -> Result<SgxTrustedChannel<U, V>> {
let tcp_builder = TcpBuilder::new_v4()?;
tcp_builder.reuse_address(true)?;
@@ -50,7 +53,7 @@ where
)
.unwrap()
.to_owned(),
server_attr: enclave_attr,
server_verifier: SgxQuoteVerifier::new(enclave_attr),
};
let client = sgx::PipeClient::<U, V>::open(config)?;

@@ -16,12 +16,13 @@
// under the License.

use crate::rpc::sgx;
use crate::rpc::sgx::EnclaveAttr;
use crate::rpc::EnclaveService;
use crate::rpc::RpcServer;
use crate::Result;
use serde::{de::DeserializeOwned, Serialize};
use sgx_types::c_int;
use teaclave_attestation::verifier::EnclaveAttr;
use teaclave_attestation::verifier::SgxQuoteVerifier;

pub struct SgxTrustedServer<U, V, X>
where
@@ -41,7 +42,19 @@ where
X: EnclaveService<U, V>,
{
pub fn new(service: X, fd: c_int, client_attr: Option<EnclaveAttr>) -> Result<Self> {
let config = sgx::PipeConfig { fd, client_attr };
let config = match client_attr {
Some(c) => {
let client_verifier = SgxQuoteVerifier::new(c);
sgx::PipeConfig {
fd,
client_verifier: Some(client_verifier),
}
}
_ => sgx::PipeConfig {
fd,
client_verifier: None,
},
};
Ok(Self {
config,
service,
@@ -17,7 +17,7 @@

use std::sync::Arc;

use crate::rpc::sgx::EnclaveAttr;
use teaclave_attestation::verifier::SgxQuoteVerifier;

#[cfg(feature = "mesalock_sgx")]
use sgx_types::sgx_sha256_hash_t;
@@ -42,23 +42,23 @@ lazy_static! {
#[derive(Default)]
struct ClientConfigCache {
private_key_sha256: sgx_sha256_hash_t,
target_configs: HashMap<Arc<EnclaveAttr>, Arc<rustls::ClientConfig>>,
target_configs: HashMap<Arc<SgxQuoteVerifier>, Arc<rustls::ClientConfig>>,
}

#[cfg(not(feature = "mesalock_sgx"))]
#[derive(Default)]
struct ClientConfigCache {
target_configs: HashMap<Arc<EnclaveAttr>, Arc<rustls::ClientConfig>>,
target_configs: HashMap<Arc<SgxQuoteVerifier>, Arc<rustls::ClientConfig>>,
}

#[cfg(feature = "mesalock_sgx")]
pub(crate) fn get_tls_config(server_attr: Arc<EnclaveAttr>) -> Arc<rustls::ClientConfig> {
pub(crate) fn get_tls_config(server_verifier: Arc<SgxQuoteVerifier>) -> Arc<rustls::ClientConfig> {
use crate::rpc::sgx::ra::get_current_ra_credential;

let ra_credential = get_current_ra_credential();

if let Ok(cfg_cache) = CLIENT_CONFIG_CACHE.try_read() {
if let Some(cfg) = cfg_cache.target_configs.get(&server_attr) {
if let Some(cfg) = cfg_cache.target_configs.get(&server_verifier) {
return cfg.clone();
}
}
@@ -70,7 +70,7 @@ pub(crate) fn get_tls_config(server_attr: Arc<EnclaveAttr>) -> Arc<rustls::Clien
client_cfg.set_single_client_cert(certs, privkey);
client_cfg
.dangerous()
.set_certificate_verifier(server_attr.clone());
.set_certificate_verifier(server_verifier.clone());
client_cfg.versions.clear();
client_cfg.versions.push(rustls::ProtocolVersion::TLSv1_2);

@@ -86,16 +86,16 @@ pub(crate) fn get_tls_config(server_attr: Arc<EnclaveAttr>) -> Arc<rustls::Clien

let _ = cfg_cache
.target_configs
.insert(server_attr, final_arc.clone());
.insert(server_verifier, final_arc.clone());
}

final_arc
}

#[cfg(not(feature = "mesalock_sgx"))]
pub(crate) fn get_tls_config(server_attr: Arc<EnclaveAttr>) -> Arc<rustls::ClientConfig> {
pub(crate) fn get_tls_config(server_verifier: Arc<SgxQuoteVerifier>) -> Arc<rustls::ClientConfig> {
if let Ok(cfg_cache) = CLIENT_CONFIG_CACHE.try_read() {
if let Some(cfg) = cfg_cache.target_configs.get(&server_attr) {
if let Some(cfg) = cfg_cache.target_configs.get(&server_verifier) {
return cfg.clone();
}
}
@@ -104,7 +104,7 @@ pub(crate) fn get_tls_config(server_attr: Arc<EnclaveAttr>) -> Arc<rustls::Clien

client_cfg
.dangerous()
.set_certificate_verifier(server_attr.clone());
.set_certificate_verifier(server_verifier.clone());
client_cfg.versions.clear();
client_cfg.versions.push(rustls::ProtocolVersion::TLSv1_2);

@@ -113,7 +113,7 @@ pub(crate) fn get_tls_config(server_attr: Arc<EnclaveAttr>) -> Arc<rustls::Clien
if let Ok(mut cfg_cache) = CLIENT_CONFIG_CACHE.try_write() {
let _ = cfg_cache
.target_configs
.insert(server_attr, final_arc.clone());
.insert(server_verifier, final_arc.clone());
}

final_arc
@@ -21,7 +21,6 @@
use serde::{de::DeserializeOwned, Serialize};
#[cfg(feature = "mesalock_sgx")]
use sgx_types::c_int;
use std::hash::{Hash, Hasher};
use std::io::{self, Read, Write};
use std::marker::PhantomData;
use std::net::TcpStream;
@@ -36,20 +35,13 @@ use crate::rpc::{EnclaveService, RpcServer};
use crate::rpc::RpcClient;
use crate::Result;

use teaclave_utils;
use teaclave_utils::EnclaveMeasurement;

#[macro_use]
mod fail;
use teaclave_attestation;
use teaclave_attestation::verifier::SgxQuoteVerifier;

pub mod client;
#[cfg(feature = "mesalock_sgx")]
pub mod server;

#[macro_use]
mod cert;
pub mod auth;
pub use auth::*;
#[cfg(feature = "mesalock_sgx")]
mod ra;

@@ -61,113 +53,11 @@ pub fn prelude() -> Result<()> {
ra::init_ra_credential(86400u64)
}

#[derive(Clone)]
pub struct EnclaveAttr {
pub measures: Vec<EnclaveMeasurement>,
pub quote_checker: fn(&SgxQuote) -> bool,
}

impl PartialEq for EnclaveAttr {
fn eq(&self, other: &EnclaveAttr) -> bool {
self.quote_checker as usize == other.quote_checker as usize
&& self.measures == other.measures
}
}

impl Eq for EnclaveAttr {}

impl Hash for EnclaveAttr {
fn hash<H: Hasher>(&self, state: &mut H) {
for m in &self.measures {
m.mr_enclave.hash(state);
m.mr_signer.hash(state);
}
(self.quote_checker as usize).hash(state);
}
}

impl EnclaveAttr {
fn check_in_cert_quote(&self, cert_der: &[u8]) -> bool {
if cfg!(sgx_sim) {
return true;
}

let quote_result = auth::extract_sgx_quote_from_mra_cert(&cert_der);
let quote: SgxQuote = match quote_result {
Err(_) => {
return false;
}
Ok(quote) => quote,
};

// Enclave measures are not tested in test mode since we have
// a dedicated test enclave not known to production enclaves
if cfg!(test_mode) {
return (self.quote_checker)(&quote);
}

let this_mr_signer = &quote.body.report_body.mr_signer;
let this_mr_enclave = &quote.body.report_body.mr_enclave;

let checksum_match = self
.measures
.iter()
.any(|m| &m.mr_signer == this_mr_signer && &m.mr_enclave == this_mr_enclave);

checksum_match && (self.quote_checker)(&quote)
}
}

impl rustls::ServerCertVerifier for EnclaveAttr {
fn verify_server_cert(
&self,
_roots: &rustls::RootCertStore,
certs: &[rustls::Certificate],
_hostname: webpki::DNSNameRef,
_ocsp: &[u8],
) -> std::result::Result<rustls::ServerCertVerified, rustls::TLSError> {
// This call automatically verifies certificate signature
if certs.len() != 1 {
return Err(rustls::TLSError::NoCertificatesPresented);
}
if self.check_in_cert_quote(&certs[0].0) {
Ok(rustls::ServerCertVerified::assertion())
} else {
Err(rustls::TLSError::WebPKIError(
webpki::Error::ExtensionValueInvalid,
))
}
}
}

impl rustls::ClientCertVerifier for EnclaveAttr {
fn client_auth_root_subjects(&self) -> rustls::DistinguishedNames {
rustls::DistinguishedNames::new()
}

fn verify_client_cert(
&self,
certs: &[rustls::Certificate],
) -> std::result::Result<rustls::ClientCertVerified, rustls::TLSError> {
// This call automatically verifies certificate signature
if certs.len() != 1 {
return Err(rustls::TLSError::NoCertificatesPresented);
}
if self.check_in_cert_quote(&certs[0].0) {
Ok(rustls::ClientCertVerified::assertion())
} else {
Err(rustls::TLSError::WebPKIError(
webpki::Error::ExtensionValueInvalid,
))
}
}
}

#[cfg(feature = "mesalock_sgx")]
pub struct PipeConfig {
pub fd: c_int,
// the SGX server can optionally verify the identity of the client
pub client_attr: Option<EnclaveAttr>,
pub client_verifier: Option<SgxQuoteVerifier>,
}

#[cfg(feature = "mesalock_sgx")]
@@ -215,7 +105,7 @@ where
// TODO: Due to switching to the SDK-style design, performing an
// initial RA at enclave start is not longer a viable design. Need
// to refactor the related API.
let rustls_server_cfg = server::get_tls_config(&config.client_attr)?;
let rustls_server_cfg = server::get_tls_config(&config.client_verifier)?;
let sess = rustls::ServerSession::new(&rustls_server_cfg);

Ok(Pipe {
@@ -239,7 +129,7 @@ pub struct PipeClient<U, V> {
pub struct PipeClientConfig {
pub tcp: TcpStream,
pub hostname: webpki::DNSName,
pub server_attr: EnclaveAttr,
pub server_verifier: SgxQuoteVerifier,
}

impl<U, V> Read for PipeClient<U, V> {
@@ -265,7 +155,7 @@ where
{
type Config = PipeClientConfig;
fn open(config: Self::Config) -> Result<Self> {
let rustls_client_cfg = client::get_tls_config(Arc::new(config.server_attr));
let rustls_client_cfg = client::get_tls_config(Arc::new(config.server_verifier));
let sess = rustls::ClientSession::new(&rustls_client_cfg, config.hostname.as_ref());

Ok(PipeClient {

0 comments on commit 21cf3bb

Please sign in to comment.
You can’t perform that action at this time.