Skip to content
Permalink
Browse files

Polish measurement and signature verification (#163)

  • Loading branch information
mssun committed Dec 15, 2019
1 parent 2c5ab42 commit db1a8b5f1aa42d4b4e5144cdec81e7f178129a6c
@@ -6,15 +6,15 @@ def find_hex_value(content, section):
hex_bytes = ''.join(content[index+1:index+3]).split()
return ''.join(['%02x' % int(x, 16) for x in hex_bytes])

mrsigner = "mrsigner->value:\n"
enclave_hash = "metadata->enclave_css.body.enclave_hash.m:\n"
mr_signer = "mrsigner->value:\n"
mr_enclave = "metadata->enclave_css.body.enclave_hash.m:\n"

content = sys.stdin.readlines()

mrsigner_hex = find_hex_value(content, mrsigner)
enclave_hash_hex = find_hex_value(content, enclave_hash)
mr_signer_hex = find_hex_value(content, mr_signer)
mr_enclave_hex = find_hex_value(content, mr_enclave)

sys.stdout.write("""[{}]
mrsigner = "{}"
enclave_hash = "{}"
""".format(sys.argv[1], mrsigner_hex, enclave_hash_hex))
mr_enclave = "{}"
mr_signer = "{}"
""".format(sys.argv[1], mr_enclave_hex, mr_signer_hex))
@@ -25,12 +25,13 @@ use std::{net, path};

use fns_proto::{InvokeTaskRequest, InvokeTaskResponse};
use mesatee_core::config::{OutboundDesc, TargetDesc};
use mesatee_core::rpc::{channel, sgx};
use mesatee_core::rpc::channel;
use tdfs_external_proto::{DFSRequest, DFSResponse};
use teaclave_utils;
use teaclave_utils::EnclaveMeasurement;
use tms_external_proto::{TaskRequest, TaskResponse};

type EnclaveInfo = std::collections::HashMap<String, (sgx::SgxMeasure, sgx::SgxMeasure)>;
type EnclaveInfo = std::collections::HashMap<String, EnclaveMeasurement>;

#[derive(Debug, PartialEq)]
enum Endpoint {
@@ -142,10 +143,9 @@ fn main() -> CliResult {
let (key, sig_path) = auditor;
enclave_signers.push((key.as_slice(), sig_path.as_path()));
}
let enclave_info = teaclave_utils::load_and_verify_enclave_info(
&args.enclave_info,
enclave_signers.as_slice(),
);
let enclave_info_content = fs::read_to_string(&args.enclave_info)
.unwrap_or_else(|_| panic!("Cannot find enclave info at {:?}.", args.enclave_info));
let enclave_info = teaclave_utils::load_enclave_info(&enclave_info_content);

let reader: Box<dyn Read> = match args.input {
Some(i) => Box::new(io::BufReader::new(fs::File::open(i)?)),
@@ -19,10 +19,11 @@
// we cannot use the &'static str in this struct.

use crate::rpc::sgx::load_presigned_enclave_info;
use crate::rpc::sgx::{EnclaveAttr, SgxMeasure};
use crate::rpc::sgx::EnclaveAttr;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::prelude::v1::*;
use teaclave_utils::EnclaveMeasurement;

#[derive(Clone)]
pub struct TargetDesc {
@@ -52,7 +53,7 @@ impl OutboundDesc {
OutboundDesc::Sgx(get_trusted_enclave_attr(vec!["fns"]))
}

pub fn new(measures: (SgxMeasure, SgxMeasure)) -> OutboundDesc {
pub fn new(measures: EnclaveMeasurement) -> OutboundDesc {
OutboundDesc::Sgx(EnclaveAttr {
measures: vec![measures],
quote_checker: universal_quote_check,
@@ -74,7 +75,7 @@ impl ServiceConfig {
use lazy_static::lazy_static;

lazy_static! {
pub static ref ENCLAVE_IDENTITIES: HashMap<String, (SgxMeasure, SgxMeasure)> =
pub static ref ENCLAVE_IDENTITIES: HashMap<String, EnclaveMeasurement> =
load_presigned_enclave_info();
}

@@ -21,7 +21,6 @@
use serde::{de::DeserializeOwned, Serialize};
#[cfg(feature = "mesalock_sgx")]
use sgx_types::c_int;
use sgx_types::SGX_HASH_SIZE;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use std::io::{self, Read, Write};
@@ -39,6 +38,7 @@ use crate::Result;
use teaclave_config::build_config::BUILD_CONFIG;
use teaclave_config::runtime_config::RUNTIME_CONFIG;
use teaclave_utils;
use teaclave_utils::EnclaveMeasurement;

#[macro_use]
mod fail;
@@ -60,40 +60,43 @@ pub fn prelude() {
ra::get_ra_cert();
}

pub type SgxMeasure = [u8; SGX_HASH_SIZE];

// TODO: We hardcoded THREE auditors for now. Later we need to support arbitrary numbers of auditors.
pub(crate) fn load_presigned_enclave_info() -> HashMap<String, (SgxMeasure, SgxMeasure)> {
pub(crate) fn load_presigned_enclave_info() -> HashMap<String, EnclaveMeasurement> {
use teaclave_config::ConfigSource;

#[cfg(not(feature = "mesalock_sgx"))]
use std::fs;
#[cfg(feature = "mesalock_sgx")]
use std::untrusted::fs;

let ConfigSource::Path(ref enclave_info_path) = RUNTIME_CONFIG.audit.enclave_info;
let ConfigSource::Path(ref auditor_0_signature_path) =
RUNTIME_CONFIG.audit.auditor_signatures[0];
let ConfigSource::Path(ref auditor_1_signature_path) =
RUNTIME_CONFIG.audit.auditor_signatures[1];
let ConfigSource::Path(ref auditor_2_signature_path) =
RUNTIME_CONFIG.audit.auditor_signatures[2];

let enclave_signers: Vec<(&'static [u8], &std::path::Path)> = vec![
(
BUILD_CONFIG.auditor_public_keys[0],
&auditor_0_signature_path,
),
(
BUILD_CONFIG.auditor_public_keys[1],
&auditor_1_signature_path,
),
(
BUILD_CONFIG.auditor_public_keys[2],
&auditor_2_signature_path,
),
];

teaclave_utils::load_and_verify_enclave_info(&enclave_info_path, enclave_signers.as_slice())
let enclave_info_content = fs::read_to_string(enclave_info_path)
.unwrap_or_else(|_| panic!("Cannot find enclave info at {:?}.", enclave_info_path));

if RUNTIME_CONFIG.audit.auditor_signatures.len() < BUILD_CONFIG.auditor_public_keys.len() {
panic!("Number of auditor signatures is not enough for verification.")
}

let mut signatures: Vec<Vec<u8>> = vec![];
for ConfigSource::Path(ref path) in &RUNTIME_CONFIG.audit.auditor_signatures {
let signature =
fs::read(path).unwrap_or_else(|_| panic!("Cannot find signature file {:?}.", path));
signatures.push(signature);
}

if !teaclave_utils::verify_enclave_info(
enclave_info_content.as_bytes(),
BUILD_CONFIG.auditor_public_keys,
&signatures,
) {
panic!("Failed to verify the signatures of enclave info.");
}

teaclave_utils::load_enclave_info(&enclave_info_content)
}

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

@@ -108,9 +111,9 @@ impl Eq for EnclaveAttr {}

impl Hash for EnclaveAttr {
fn hash<H: Hasher>(&self, state: &mut H) {
for (m1, m2) in &self.measures {
m1.hash(state);
m2.hash(state);
for m in &self.measures {
m.mr_enclave.hash(state);
m.mr_signer.hash(state);
}
(self.quote_checker as usize).hash(state);
}
@@ -156,9 +159,10 @@ impl EnclaveAttr {
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(|(mr_signer, mr_enclave)| {
mr_signer == this_mr_signer && mr_enclave == this_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)
}
@@ -210,11 +210,6 @@ use teaclave_utils;
use tms_external_client::TMSClient;
pub use tms_external_proto::TaskStatus;

const SGX_HASH_SIZE: usize = 32;

/// `SgxMeasure` stores the value of MRENCLAVE and MRSIGNER.
pub type SgxMeasure = [u8; SGX_HASH_SIZE];

/// `Mesatee` stands for a connection to MesaTEE Service
///
/// To connect to a MesaTEE Service, one should be clear about:
@@ -380,10 +375,14 @@ impl Mesatee {
for (der, hash) in enclave_info.enclave_signers.iter() {
enclave_signers.push((&der, hash.as_path()));
}
let enclave_identities = teaclave_utils::load_and_verify_enclave_info(
&enclave_info.enclave_info_file_path,
&enclave_signers,
);
let enclave_info_content = fs::read_to_string(&enclave_info.enclave_info_file_path)
.unwrap_or_else(|_| {
panic!(
"Cannot find enclave info at {:?}.",
enclave_info.enclave_info_file_path
)
});
let enclave_identities = teaclave_utils::load_enclave_info(&enclave_info_content);

let tms_outbound_desc = OutboundDesc::new(
*enclave_identities
@@ -11,7 +11,6 @@ default = []
mesalock_sgx = ["sgx_tstd"]

[dependencies]
log = { version = "0.4.6" }
ring = { version = "0.16.5" }
serde = { version = "1.0.92" }
serde_derive = { version = "1.0.92" }
@@ -4,14 +4,14 @@ extern crate sgx_tstd as std;
#[cfg(feature = "mesalock_sgx")]
use std::prelude::v1::*;

#[macro_use]
extern crate log;
use serde::Deserializer;
use serde_derive::Deserialize;
use std::collections::HashMap;

type Result<T> = std::result::Result<T, UtilsError>;
type SgxMeasure = [u8; 32];
use sgx_types::SGX_HASH_SIZE;

pub type SgxMeasurement = [u8; SGX_HASH_SIZE];

pub enum UtilsError {
ParseError,
@@ -26,7 +26,7 @@ fn decode_hex_digit(digit: char) -> Result<u8> {
}
}

pub fn decode_hex(hex: &str) -> Result<Vec<u8>> {
fn decode_hex(hex: &str) -> Result<Vec<u8>> {
let mut r: Vec<u8> = Vec::new();
let mut chars = hex.chars().enumerate();
loop {
@@ -48,8 +48,7 @@ pub fn decode_spid(hex: &str) -> Result<sgx_types::sgx_spid_t> {
let hex = hex.trim();

if hex.len() < 16 * 2 {
debug!("Input spid file len ({}) is incorrect!", hex.len());
return Ok(spid);
return Err(UtilsError::ParseError);
}

let decoded_vec = decode_hex(hex)?;
@@ -73,16 +72,16 @@ pub fn percent_decode(orig: String) -> Result<String> {
Ok(ret)
}

/// Deserializes a hex string to a `SgxMeasure` (i.e., [0; 32]).
pub fn from_hex<'de, D>(deserializer: D) -> std::result::Result<SgxMeasure, D::Error>
/// Deserializes a hex string to a `SgxMeasurement` (i.e., [0; 32]).
pub fn from_hex<'de, D>(deserializer: D) -> std::result::Result<SgxMeasurement, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
use serde::Deserialize;
String::deserialize(deserializer).and_then(|string| {
let v = decode_hex(&string).map_err(|_| Error::custom("ParseError"))?;
let mut array: SgxMeasure = [0; 32];
let mut array = [0; SGX_HASH_SIZE];
let bytes = &v[..array.len()]; // panics if not enough data
array.copy_from_slice(bytes);
Ok(array)
@@ -91,55 +90,56 @@ where

#[derive(Debug, Deserialize)]
#[serde(transparent)]
struct EnclaveInfoToml(HashMap<String, EnclaveInfo>);
struct EnclaveInfoToml(HashMap<String, EnclaveMeasurement>);

#[derive(Debug, Deserialize)]
struct EnclaveInfo {
#[derive(Debug, Deserialize, Copy, Clone, Eq, PartialEq)]
pub struct EnclaveMeasurement {
#[serde(deserialize_with = "from_hex")]
mrsigner: SgxMeasure,
pub mr_signer: SgxMeasurement,
#[serde(deserialize_with = "from_hex")]
enclave_hash: SgxMeasure,
pub mr_enclave: SgxMeasurement,
}

// This function fails when enclave info signatures mismatch hard-coded
// auditor keys. We expect the program to crash in those cases
pub fn load_and_verify_enclave_info(
enclave_info_file_path: &std::path::Path,
// A vector of signer meta info, each tuple is
// (harded-coded public key, file path to signature of enclave_info.toml)
enclave_signers: &[(&[u8], &std::path::Path)],
) -> std::collections::HashMap<String, (SgxMeasure, SgxMeasure)> {
#[cfg(not(feature = "mesalock_sgx"))]
use std::fs::{self, File};
#[cfg(feature = "mesalock_sgx")]
use std::untrusted::fs::{self, File};

use std::io::Read;

let content = fs::read_to_string(enclave_info_file_path)
.unwrap_or_else(|_| panic!("cannot find enclave info at {:?}", enclave_info_file_path));

// verify autenticity of enclave identity info
for signer in enclave_signers {
let mut sig_file = File::open(signer.1)
.unwrap_or_else(|_| panic!("cannot find signature file at {:?}", signer.1));
let mut sig = Vec::<u8>::new();
sig_file
.read_to_end(&mut sig)
.unwrap_or_else(|_| panic!("cannot read signature from {:?}", signer.1));

use ring::signature;
let public_key =
signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, signer.0);
public_key
.verify(content.as_bytes(), sig.as_slice())
.expect("invalid signature for enclave info file");
impl EnclaveMeasurement {
pub fn new(mr_enclave: SgxMeasurement, mr_signer: SgxMeasurement) -> Self {
Self {
mr_enclave,
mr_signer,
}
}
}

pub fn verify_enclave_info(
enclave_info: &[u8],
public_keys: &[&[u8]],
signatures: &[Vec<u8>],
) -> bool {
use ring::signature;

for k in public_keys {
let mut verified = false;
for s in signatures {
if signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, k)
.verify(enclave_info, &s)
.is_ok()
{
verified = true;
}
}
if !verified {
return false;
}
}

true
}

pub fn load_enclave_info(content: &str) -> std::collections::HashMap<String, EnclaveMeasurement> {
let config: EnclaveInfoToml =
toml::from_str(&content).expect("Content not correct, unable to load enclave info.");
let mut info_map = std::collections::HashMap::new();
for (k, v) in config.0 {
info_map.insert(k, (v.mrsigner, v.enclave_hash));
info_map.insert(k, EnclaveMeasurement::new(v.mr_enclave, v.mr_signer));
}

info_map

0 comments on commit db1a8b5

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