-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Richard Zak <[email protected]>
- Loading branch information
Showing
13 changed files
with
738 additions
and
48 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]> | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
use serde::de::Error; | ||
use serde::{Deserialize, Deserializer, Serialize}; | ||
use sgx::parameters::{Attributes, Features, Xfrm}; | ||
use std::ops::BitAnd; | ||
|
||
#[derive(Clone, Deserialize, Debug, Default, Serialize)] | ||
#[serde(deny_unknown_fields)] | ||
pub struct Config { | ||
/// Values for `mrsigner` in the report body. | ||
/// This is the list of public keys which have signed the Enarx binary. | ||
#[serde(default)] | ||
#[serde(deserialize_with = "from_hex")] | ||
pub enarx_signer: Option<Vec<Vec<u8>>>, | ||
|
||
/// Values for `features`. | ||
#[serde(default)] | ||
#[serde(deserialize_with = "from_features")] | ||
pub features: Option<u64>, | ||
|
||
/// Value allowed for `cpusvn`. | ||
pub cpu_svn: Option<Vec<u8>>, | ||
|
||
/// Value for `isv_svn`, do not allow versions below this. | ||
pub enclave_security_version: Option<u16>, | ||
|
||
/// Value for `isv_prodid`, do not allow versions below this. | ||
pub enclave_product_id: Option<u16>, | ||
} | ||
|
||
fn from_hex<'de, D>(deserializer: D) -> Result<Option<Vec<Vec<u8>>>, D::Error> | ||
where | ||
D: Deserializer<'de>, | ||
{ | ||
let s: Vec<&str> = Deserialize::deserialize(deserializer)?; | ||
|
||
let mut outer_vec = Vec::new(); | ||
for hash_string in s { | ||
outer_vec.push(hex::decode(hash_string).map_err(|_| Error::custom("invalid hex"))?); | ||
} | ||
|
||
Ok(Some(outer_vec)) | ||
} | ||
|
||
fn from_features<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error> | ||
where | ||
D: Deserializer<'de>, | ||
{ | ||
let s: &str = Deserialize::deserialize(deserializer)?; | ||
|
||
let mut flags = Features::empty(); | ||
|
||
for flag in s.to_string().split("|") { | ||
match flag.trim() { | ||
"Debug" => { | ||
flags = flags | Features::DEBUG; | ||
} | ||
_ => return Err(D::Error::custom(format!("unknown flag '{}'", flag))), | ||
} | ||
} | ||
|
||
Ok(Some(flags.bits())) | ||
} | ||
|
||
impl Into<Attributes> for Config { | ||
fn into(self) -> Attributes { | ||
let feats = match self.features { | ||
Some(f) => Features::from_bits_truncate(f), | ||
None => Features::empty(), | ||
}; | ||
Attributes::new(feats, Xfrm::empty()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::config::Config; | ||
|
||
#[test] | ||
fn test_empty_config() { | ||
let config_raw = r#" | ||
"#; | ||
|
||
let config_obj: Config = toml::from_str(config_raw).expect("Couldn't deserialize"); | ||
assert!(config_obj.enarx_signer.is_none()); | ||
assert!(config_obj.enclave_security_version.is_none()); | ||
assert!(config_obj.cpu_svn.is_none()); | ||
} | ||
|
||
#[test] | ||
fn test_list_of_hashes() { | ||
let config_raw = r#" | ||
enarx_signer = ["1234567890", "00112233445566778899"] | ||
"#; | ||
|
||
let config_obj: Config = toml::from_str(config_raw).expect("Couldn't deserialize"); | ||
assert!(config_obj.enarx_signer.is_some()); | ||
assert_eq!(config_obj.enarx_signer.clone().unwrap().len(), 2); | ||
assert_eq!( | ||
config_obj.enarx_signer.clone().unwrap().first().unwrap(), | ||
&hex::decode("1234567890").unwrap() | ||
); | ||
assert_eq!( | ||
config_obj.enarx_signer.unwrap().get(1).unwrap(), | ||
&hex::decode("00112233445566778899").unwrap() | ||
); | ||
assert!(config_obj.cpu_svn.is_none()); | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]> | ||
// SPDX-License-Identifier: AGPL-3.0-only | ||
|
||
mod quote; | ||
pub mod config; | ||
pub mod quote; | ||
|
||
use cryptography::ext::*; | ||
use quote::traits::ParseBytes; | ||
|
||
use std::fmt::Debug; | ||
|
||
use crate::config::Config; | ||
use anyhow::{anyhow, Result}; | ||
use cryptography::const_oid::ObjectIdentifier; | ||
use cryptography::sha2::{Digest, Sha256}; | ||
|
@@ -29,7 +31,7 @@ impl Sgx { | |
pub const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.6.1.4.1.58270.1.2"); | ||
pub const ATT: bool = true; | ||
|
||
fn trusted<'c>(&'c self, chain: &'c [Certificate<'c>]) -> Result<&'c TbsCertificate<'c>> { | ||
pub fn trusted<'c>(&'c self, chain: &'c [Certificate<'c>]) -> Result<&'c TbsCertificate<'c>> { | ||
let mut signer = &self.0[0].tbs_certificate; | ||
for cert in self.0.iter().chain(chain.iter()) { | ||
signer = signer.verify_crt(cert)?; | ||
|
@@ -38,7 +40,13 @@ impl Sgx { | |
Ok(signer) | ||
} | ||
|
||
pub fn verify(&self, cri: &CertReqInfo<'_>, ext: &Extension<'_>, dbg: bool) -> Result<bool> { | ||
pub fn verify( | ||
&self, | ||
cri: &CertReqInfo<'_>, | ||
ext: &Extension<'_>, | ||
config: Option<&Config>, | ||
dbg: bool, | ||
) -> Result<bool> { | ||
if ext.critical { | ||
return Err(anyhow!("sgx extension cannot be critical")); | ||
} | ||
|
@@ -85,33 +93,52 @@ impl Sgx { | |
return Err(anyhow!("sgx report data is invalid")); | ||
} | ||
|
||
if rpt.mrenclave != [0u8; 32] { | ||
return Err(anyhow!("untrusted enarx runtime")); | ||
if config.is_some() { | ||
let config_ref = config.as_ref().unwrap(); | ||
if config_ref.enarx_signer.is_some() { | ||
let mut signed = false; | ||
for signer in config_ref.enarx_signer.as_ref().unwrap() { | ||
if rpt.mrsigner == signer.as_slice() { | ||
signed = true; | ||
break; | ||
} | ||
} | ||
if !signed { | ||
return Err(anyhow!("untrusted enarx signer")); | ||
} | ||
} | ||
|
||
if config_ref.cpu_svn.is_some() { | ||
let conf_version = config_ref.cpu_svn.as_ref().unwrap(); | ||
for index in 0..rpt.cpusvn.len() { | ||
if rpt.cpusvn.get(index).unwrap() < conf_version.get(index).unwrap() { | ||
return Err(anyhow!("untrusted cpu")); | ||
} | ||
} | ||
} | ||
|
||
if config_ref.enclave_product_id.is_some() | ||
&& rpt.enclave_product_id() != config_ref.enclave_product_id.unwrap() | ||
{ | ||
return Err(anyhow!("untrusted enclave product id")); | ||
} | ||
|
||
if config_ref.enclave_security_version.is_some() | ||
&& rpt.enclave_security_version() < config_ref.enclave_security_version.unwrap() | ||
{ | ||
return Err(anyhow!("untrusted enclave")); | ||
} | ||
} | ||
|
||
if rpt.mrsigner != [0u8; 32] { | ||
return Err(anyhow!("untrusted enarx signer")); | ||
} | ||
|
||
if rpt.cpusvn != [0u8; 16] { | ||
return Err(anyhow!("untrusted cpu")); | ||
} | ||
|
||
if rpt.attributes() != Attributes::default() { | ||
// Bitwise operations for `Attributes` don't seem to work with objects that | ||
// implement `InTo<Attribute>` | ||
/*if rpt.attributes() != Attributes::default() { | ||
return Err(anyhow!("untrusted attributes")); | ||
} | ||
}*/ | ||
|
||
if rpt.misc_select() != MiscSelect::default() { | ||
return Err(anyhow!("untrusted misc select")); | ||
} | ||
|
||
if rpt.enclave_product_id() != u16::MAX { | ||
return Err(anyhow!("untrusted enclave product id")); | ||
} | ||
|
||
if rpt.enclave_security_version() < u16::MAX { | ||
return Err(anyhow!("untrusted enclave")); | ||
} | ||
} | ||
|
||
Ok(false) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use cryptography; | ||
use cryptography::x509::attr::Attribute; | ||
use cryptography::x509::request::{CertReq, ExtensionReq}; | ||
use cryptography::x509::Certificate; | ||
use der::Decode; | ||
use sgx_validation::quote::traits::ParseBytes; | ||
use sgx_validation::quote::Quote; | ||
use sgx_validation::Sgx; | ||
use std::env; | ||
use std::fs::File; | ||
use std::io::Read; | ||
use std::path::Path; | ||
|
||
fn main() { | ||
let args: Vec<String> = env::args().collect(); | ||
let fname = Path::new(args.get(1).expect("CSR file not specified")); | ||
let mut file = File::open(fname).expect("no such file"); | ||
let mut contents = Vec::new(); | ||
file.read_to_end(&mut contents) | ||
.expect("failed to read file"); | ||
|
||
let cr = CertReq::from_der(&contents).expect("failed to decode DER"); | ||
let cri = cr.info; | ||
#[allow(unused_variables)] | ||
for Attribute { oid, values } in cri.attributes.iter() { | ||
for any in values.iter() { | ||
let ereq: ExtensionReq<'_> = any.decode_into().unwrap(); | ||
for ext in Vec::from(ereq) { | ||
let (quote, bytes): (Quote<'_>, _) = | ||
ext.extn_value.parse().expect("failed to parse"); | ||
let chain = quote.chain().unwrap(); | ||
let chain = chain | ||
.iter() | ||
.map(|c| Certificate::from_der(c)) | ||
.collect::<Result<Vec<_>, _>>() | ||
.unwrap(); | ||
|
||
// Validate the report. | ||
let sgx = Sgx::default(); | ||
let pck = sgx.trusted(&chain).unwrap(); | ||
let report = quote.verify(pck).unwrap(); | ||
println!("{:?}", report); | ||
sgx.verify(&cri, &ext, None, false).unwrap(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.