blob: d10cb1c5cbd318562a5ff0b857678689b8a8cdc1 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use std::collections::HashMap;
use anyhow::{bail, ensure, Result};
use serde::{Deserialize, Deserializer};
use sgx_types::types::SHA256_HASH_SIZE;
pub type SgxMeasurement = [u8; SHA256_HASH_SIZE];
#[derive(Debug, Deserialize, Copy, Clone, Eq, PartialEq)]
pub struct EnclaveMeasurement {
#[serde(deserialize_with = "from_hex")]
pub mr_signer: SgxMeasurement,
#[serde(deserialize_with = "from_hex")]
pub mr_enclave: SgxMeasurement,
}
impl EnclaveMeasurement {
pub fn new(mr_enclave: SgxMeasurement, mr_signer: SgxMeasurement) -> Self {
Self {
mr_enclave,
mr_signer,
}
}
}
/// Deserializes a hex string to a `SgxMeasurement` (i.e., [0; 32]).
pub fn from_hex<'de, D>(deserializer: D) -> Result<SgxMeasurement, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
String::deserialize(deserializer).and_then(|string| {
let v = hex::decode(&string).map_err(|_| Error::custom("ParseError"))?;
let mut array = [0; SHA256_HASH_SIZE];
let bytes = &v[..array.len()]; // panics if not enough data
array.copy_from_slice(bytes);
Ok(array)
})
}
#[derive(Clone)]
pub struct EnclaveAttr {
pub measurement: EnclaveMeasurement,
}
pub struct EnclaveInfo {
pub measurements: HashMap<String, EnclaveMeasurement>,
}
#[derive(Debug, Deserialize)]
#[serde(transparent)]
struct EnclaveInfoToml(HashMap<String, EnclaveMeasurement>);
impl EnclaveInfo {
pub fn verify_and_new<T, U>(
enclave_info: &[u8],
public_keys: &[T],
signatures: &[U],
) -> Result<Self>
where
T: AsRef<[u8]>,
U: AsRef<[u8]>,
{
ensure!(
signatures.len() <= public_keys.len(),
"Invalid number of public keys"
);
if !Self::verify(enclave_info, public_keys, signatures) {
bail!("Invalid enclave_info");
}
Ok(Self::from_bytes(enclave_info))
}
#[cfg(feature = "app")]
pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
let bytes = std::fs::read(path)?;
Ok(Self::from_bytes(&bytes))
}
pub fn from_bytes(enclave_info: &[u8]) -> Self {
let config: EnclaveInfoToml = toml::from_slice(enclave_info)
.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, EnclaveMeasurement::new(v.mr_enclave, v.mr_signer));
}
Self {
measurements: info_map,
}
}
pub fn verify<T, U>(enclave_info: &[u8], public_keys: &[T], signatures: &[U]) -> bool
where
T: AsRef<[u8]>,
U: AsRef<[u8]>,
{
use ring::signature;
for s in signatures {
let mut verified = false;
for k in public_keys {
if signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, k)
.verify(enclave_info, s.as_ref())
.is_ok()
{
verified = true;
}
}
if !verified {
return false;
}
}
true
}
pub fn get_enclave_attr(&self, service_name: &str) -> Option<EnclaveAttr> {
self.measurements
.get(service_name)
.map(|measurement| EnclaveAttr {
measurement: *measurement,
})
}
}