blob: bf63b14c7ee51857195644dea95242eaffeaafb5 [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 alloc::boxed::Box;
use alloc::vec::Vec;
use core::mem;
use core::ptr;
use sgx_tcrypto::*;
use sgx_trts::trts::*;
use sgx_tse::*;
use sgx_types::*;
/* intel sgx sdk 2.4 */
const KEY_POLICY_KSS: uint16_t =
SGX_KEYPOLICY_CONFIGID | SGX_KEYPOLICY_ISVFAMILYID | SGX_KEYPOLICY_ISVEXTPRODID;
#[derive(Clone, Default)]
pub struct SgxInternalUnsealedData {
pub payload_size: u32,
pub decrypt: Box<[u8]>,
pub additional: Box<[u8]>,
}
impl SgxInternalUnsealedData {
///
/// Get the payload size of the SgxInternalUnsealedData.
///
#[allow(dead_code)]
pub fn get_payload_size(&self) -> u32 {
self.payload_size
}
///
/// Get the pointer of decrypt buffer in SgxInternalUnsealedData.
///
#[allow(dead_code)]
pub fn get_decrypt_txt(&self) -> &[u8] {
&*self.decrypt
}
///
/// Get the pointer of additional buffer in SgxInternalUnsealedData.
///
#[allow(dead_code)]
pub fn get_additional_txt(&self) -> &[u8] {
&*self.additional
}
}
#[derive(Clone, Default)]
struct SgxPayload {
payload_size: u32,
reserved: [u8; 12],
payload_tag: [u8; SGX_SEAL_TAG_SIZE],
encrypt: Box<[u8]>,
additional: Box<[u8]>,
}
#[derive(Clone, Default)]
pub struct SgxInternalSealedData {
key_request: sgx_key_request_t,
payload_data: SgxPayload,
}
impl SgxInternalSealedData {
pub fn new() -> Self {
SgxInternalSealedData::default()
}
pub fn get_payload_size(&self) -> u32 {
self.payload_data.payload_size
}
pub fn get_payload_tag(&self) -> &[u8; SGX_SEAL_TAG_SIZE] {
&self.payload_data.payload_tag
}
pub fn get_key_request(&self) -> &sgx_key_request_t {
&self.key_request
}
pub fn get_encrypt_txt(&self) -> &[u8] {
&*self.payload_data.encrypt
}
pub fn get_additional_txt(&self) -> &[u8] {
&*self.payload_data.additional
}
pub fn calc_raw_sealed_data_size(add_mac_txt_size: u32, encrypt_txt_size: u32) -> u32 {
let max = u32::MAX;
let sealed_data_size = mem::size_of::<sgx_sealed_data_t>() as u32;
if add_mac_txt_size > max - encrypt_txt_size {
return max;
}
let payload_size: u32 = add_mac_txt_size + encrypt_txt_size;
if payload_size > max - sealed_data_size {
return max;
}
sealed_data_size + payload_size
}
pub fn get_add_mac_txt_len(&self) -> u32 {
let data_size = self.payload_data.additional.len();
if data_size > self.payload_data.payload_size as usize
|| data_size >= u32::MAX as usize
{
u32::MAX
} else {
data_size as u32
}
}
pub fn get_encrypt_txt_len(&self) -> u32 {
let data_size = self.payload_data.encrypt.len();
if data_size > self.payload_data.payload_size as usize
|| data_size >= u32::MAX as usize
{
u32::MAX
} else {
data_size as u32
}
}
pub unsafe fn to_raw_sealed_data_t(
&self,
p: *mut sgx_sealed_data_t,
len: u32,
) -> Option<*mut sgx_sealed_data_t> {
if p.is_null() {
return None;
}
if !rsgx_raw_is_within_enclave(p as *mut u8, len as usize)
&& !rsgx_raw_is_outside_enclave(p as *mut u8, len as usize)
{
return None;
}
let additional_len = self.get_add_mac_txt_len();
let encrypt_len = self.get_encrypt_txt_len();
if (additional_len == u32::MAX) || (encrypt_len == u32::MAX) {
return None;
}
if (additional_len + encrypt_len) != self.get_payload_size() {
return None;
}
let sealed_data_size = sgx_calc_sealed_data_size(additional_len, encrypt_len);
if sealed_data_size == u32::MAX {
return None;
}
if len < sealed_data_size {
return None;
}
let ptr_sealed_data = p as *mut u8;
let ptr_encrypt = ptr_sealed_data.add(mem::size_of::<sgx_sealed_data_t>());
if encrypt_len > 0 {
ptr::copy_nonoverlapping(
self.payload_data.encrypt.as_ptr(),
ptr_encrypt,
encrypt_len as usize,
);
}
if additional_len > 0 {
let ptr_additional = ptr_encrypt.offset(encrypt_len as isize);
ptr::copy_nonoverlapping(
self.payload_data.additional.as_ptr(),
ptr_additional,
additional_len as usize,
);
}
let raw_sealed_data = &mut *p;
raw_sealed_data.key_request = self.key_request;
raw_sealed_data.plain_text_offset = encrypt_len;
raw_sealed_data.aes_data.payload_size = self.payload_data.payload_size;
raw_sealed_data.aes_data.payload_tag = self.payload_data.payload_tag;
Some(p)
}
#[allow(clippy::cast_ptr_alignment)]
pub unsafe fn from_raw_sealed_data_t(p: *mut sgx_sealed_data_t, len: u32) -> Option<Self> {
if p.is_null() {
return None;
}
if !rsgx_raw_is_within_enclave(p as *mut u8, len as usize)
&& !rsgx_raw_is_outside_enclave(p as *mut u8, len as usize)
{
return None;
}
if (len as usize) < mem::size_of::<sgx_sealed_data_t>() {
return None;
}
let raw_sealed_data = &*p;
if raw_sealed_data.plain_text_offset > raw_sealed_data.aes_data.payload_size {
return None;
}
let ptr_sealed_data = p as *mut u8;
let additional_len = sgx_get_add_mac_txt_len(ptr_sealed_data as *const sgx_sealed_data_t);
let encrypt_len = sgx_get_encrypt_txt_len(ptr_sealed_data as *const sgx_sealed_data_t);
if (additional_len == u32::MAX) || (encrypt_len == u32::MAX) {
return None;
}
if (additional_len + encrypt_len) != raw_sealed_data.aes_data.payload_size {
return None;
}
let sealed_data_size = sgx_calc_sealed_data_size(additional_len, encrypt_len);
if sealed_data_size == u32::MAX {
return None;
}
if len < sealed_data_size {
return None;
}
let ptr_encrypt = ptr_sealed_data.add(mem::size_of::<sgx_sealed_data_t>());
let encrypt: Vec<u8> = if encrypt_len > 0 {
let mut temp: Vec<u8> = Vec::with_capacity(encrypt_len as usize);
temp.set_len(encrypt_len as usize);
ptr::copy_nonoverlapping(
ptr_encrypt as *const u8,
temp.as_mut_ptr(),
encrypt_len as usize,
);
temp
} else {
Vec::new()
};
let additional: Vec<u8> = if additional_len > 0 {
let ptr_additional = ptr_encrypt.offset(encrypt_len as isize);
let mut temp: Vec<u8> = Vec::with_capacity(additional_len as usize);
temp.set_len(additional_len as usize);
ptr::copy_nonoverlapping(
ptr_additional as *const u8,
temp.as_mut_ptr(),
additional_len as usize,
);
temp
} else {
Vec::new()
};
let mut sealed_data = Self::default();
sealed_data.key_request = raw_sealed_data.key_request;
sealed_data.payload_data.payload_size = raw_sealed_data.aes_data.payload_size;
sealed_data.payload_data.payload_tag = raw_sealed_data.aes_data.payload_tag;
sealed_data.payload_data.additional = additional.into_boxed_slice();
sealed_data.payload_data.encrypt = encrypt.into_boxed_slice();
Some(sealed_data)
}
pub fn seal_data(additional_text: &[u8], encrypt_text: &[u8]) -> SgxResult<Self> {
//let attribute_mask = sgx_attributes_t{flags: SGX_FLAGS_RESERVED | SGX_FLAGS_INITTED | SGX_FLAGS_DEBUG, xfrm: 0};
/* intel sgx sdk 1.8 */
let attribute_mask = sgx_attributes_t {
flags: TSEAL_DEFAULT_FLAGSMASK,
xfrm: 0,
};
/* intel sgx sdk 2.4 */
let mut key_policy = SGX_KEYPOLICY_MRSIGNER;
let report = rsgx_self_report();
if (report.body.attributes.flags & SGX_FLAGS_KSS) != 0 {
key_policy = SGX_KEYPOLICY_MRSIGNER | KEY_POLICY_KSS;
}
Self::seal_data_ex(
key_policy,
attribute_mask,
TSEAL_DEFAULT_MISCMASK,
additional_text,
encrypt_text,
)
}
pub fn seal_data_ex(
key_policy: u16,
attribute_mask: sgx_attributes_t,
misc_mask: sgx_misc_select_t,
additional_text: &[u8],
encrypt_text: &[u8],
) -> SgxResult<Self> {
let additional_len = additional_text.len();
let encrypt_len = encrypt_text.len();
if (additional_len >= u32::MAX as usize)
|| (encrypt_len >= u32::MAX as usize)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if Self::calc_raw_sealed_data_size(additional_len as u32, encrypt_len as u32)
== u32::MAX
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if encrypt_len == 0 {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if (key_policy
& (!(SGX_KEYPOLICY_MRENCLAVE
| SGX_KEYPOLICY_MRSIGNER
| KEY_POLICY_KSS
| SGX_KEYPOLICY_NOISVPRODID))
!= 0)
|| ((key_policy & (SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) == 0)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if ((attribute_mask.flags & SGX_FLAGS_INITTED) == 0)
|| ((attribute_mask.flags & SGX_FLAGS_DEBUG) == 0)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if !rsgx_slice_is_within_enclave(encrypt_text) {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if additional_len > 0
&& !rsgx_slice_is_within_enclave(additional_text)
&& !rsgx_slice_is_outside_enclave(additional_text)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
//let target_info = sgx_target_info_t::default();
//let report_data = sgx_report_data_t::default();
let mut key_id = sgx_key_id_t::default();
/* intel sgx sdk 2.4 */
let mut report = rsgx_self_report();
let error = rsgx_read_rand(&mut key_id.id);
if error.is_err() {
report = sgx_report_t::default();
key_id = sgx_key_id_t::default();
return Err(error.unwrap_err());
}
let key_request = sgx_key_request_t {
key_name: SGX_KEYSELECT_SEAL,
key_policy,
isv_svn: report.body.isv_svn,
reserved1: 0_u16,
cpu_svn: report.body.cpu_svn,
attribute_mask,
key_id,
misc_mask,
config_svn: report.body.config_svn,
reserved2: [0_u8; SGX_KEY_REQUEST_RESERVED2_BYTES],
};
let payload_iv = [0_u8; SGX_SEAL_IV_SIZE];
let mut result =
Self::seal_data_iv(additional_text, encrypt_text, &payload_iv, &key_request);
if let Ok(ref mut sealed_data) = result {
sealed_data.key_request = key_request
};
report = sgx_report_t::default();
key_id = sgx_key_id_t::default();
result
}
pub fn unseal_data(&self) -> SgxResult<SgxInternalUnsealedData> {
let additional_len = self.get_add_mac_txt_len();
let encrypt_len = self.get_encrypt_txt_len();
if (additional_len == u32::MAX) || (encrypt_len == u32::MAX) {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if Self::calc_raw_sealed_data_size(additional_len, encrypt_len) == u32::MAX {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if encrypt_len < 1 {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if (additional_len + encrypt_len) != self.get_payload_size() {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if !rsgx_raw_is_within_enclave(self as *const _ as *const u8, mem::size_of::<Self>()) {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if !rsgx_slice_is_within_enclave(self.get_encrypt_txt()) {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if additional_len > 0 && !rsgx_slice_is_within_enclave(self.get_additional_txt()) {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
self.unseal_data_helper()
}
pub fn mac_aadata(additional_text: &[u8]) -> SgxResult<Self> {
let attribute_mask = sgx_attributes_t {
flags: TSEAL_DEFAULT_FLAGSMASK,
xfrm: 0,
};
let mut key_policy: u16 = SGX_KEYPOLICY_MRSIGNER;
let report = rsgx_self_report();
if (report.body.attributes.flags & SGX_FLAGS_KSS) != 0 {
key_policy = SGX_KEYPOLICY_MRSIGNER | KEY_POLICY_KSS;
}
Self::mac_aadata_ex(
key_policy,
attribute_mask,
TSEAL_DEFAULT_MISCMASK,
additional_text,
)
}
pub fn mac_aadata_ex(
key_policy: u16,
attribute_mask: sgx_attributes_t,
misc_mask: sgx_misc_select_t,
additional_text: &[u8],
) -> SgxResult<Self> {
let additional_len = additional_text.len();
if additional_len >= u32::MAX as usize {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if Self::calc_raw_sealed_data_size(additional_len as u32, 0_u32) == u32::MAX {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if additional_len == 0 {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if (key_policy
& (!(SGX_KEYPOLICY_MRENCLAVE
| SGX_KEYPOLICY_MRSIGNER
| KEY_POLICY_KSS
| SGX_KEYPOLICY_NOISVPRODID))
!= 0)
|| ((key_policy & (SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) == 0)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if ((attribute_mask.flags & SGX_FLAGS_INITTED) == 0)
|| ((attribute_mask.flags & SGX_FLAGS_DEBUG) == 0)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if !rsgx_slice_is_within_enclave(additional_text)
&& !rsgx_slice_is_outside_enclave(additional_text)
{
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
//let target_info = sgx_target_info_t::default();
//let report_data = sgx_report_data_t::default();
let mut key_id = sgx_key_id_t::default();
/* intel sgx sdk 2.4 */
let mut report = rsgx_self_report();
let error = rsgx_read_rand(&mut key_id.id);
if error.is_err() {
report = sgx_report_t::default();
key_id = sgx_key_id_t::default();
return Err(error.unwrap_err());
}
let key_request = sgx_key_request_t {
key_name: SGX_KEYSELECT_SEAL,
key_policy,
isv_svn: report.body.isv_svn,
reserved1: 0_u16,
cpu_svn: report.body.cpu_svn,
attribute_mask,
key_id,
misc_mask,
config_svn: report.body.config_svn,
reserved2: [0_u8; SGX_KEY_REQUEST_RESERVED2_BYTES],
};
let payload_iv = [0_u8; SGX_SEAL_IV_SIZE];
let mut result = Self::seal_data_iv(additional_text, &[0_u8; 0], &payload_iv, &key_request);
if let Ok(ref mut sealed_data) = result {
sealed_data.key_request = key_request
};
report = sgx_report_t::default();
key_id = sgx_key_id_t::default();
result
}
pub fn unmac_aadata(&self) -> SgxResult<SgxInternalUnsealedData> {
let additional_len = self.get_add_mac_txt_len();
let encrypt_len = self.get_encrypt_txt_len();
if (additional_len == u32::MAX) || (encrypt_len == u32::MAX) {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if additional_len < 1 {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if encrypt_len != 0 {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if Self::calc_raw_sealed_data_size(additional_len, encrypt_len) == u32::MAX {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if (additional_len + encrypt_len) != self.get_payload_size() {
return Err(sgx_status_t::SGX_ERROR_MAC_MISMATCH);
}
if !rsgx_raw_is_within_enclave(self as *const _ as *const u8, mem::size_of::<Self>()) {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
if !rsgx_slice_is_within_enclave(self.get_additional_txt()) {
return Err(sgx_status_t::SGX_ERROR_INVALID_PARAMETER);
}
self.unseal_data_helper()
}
fn seal_data_iv(
additional_text: &[u8],
encrypt_text: &[u8],
payload_iv: &[u8],
key_request: &sgx_key_request_t,
) -> SgxResult<Self> {
let mut seal_key = rsgx_get_align_key(key_request).map_err(|ret| {
if ret != sgx_status_t::SGX_ERROR_OUT_OF_MEMORY {
sgx_status_t::SGX_ERROR_UNEXPECTED
} else {
ret
}
})?;
let mut sealed_data = SgxInternalSealedData::default();
sealed_data.payload_data.encrypt = vec![0_u8; encrypt_text.len()].into_boxed_slice();
let error = rsgx_rijndael128GCM_encrypt(
&seal_key.key,
encrypt_text,
payload_iv,
&additional_text,
&mut sealed_data.payload_data.encrypt,
&mut sealed_data.payload_data.payload_tag,
);
if error.is_err() {
seal_key.key = sgx_key_128bit_t::default();
return Err(error.unwrap_err());
}
sealed_data.payload_data.payload_size = (encrypt_text.len() + additional_text.len()) as u32;
if !additional_text.is_empty() {
sealed_data.payload_data.additional = additional_text.to_vec().into_boxed_slice();
}
seal_key.key = sgx_key_128bit_t::default();
Ok(sealed_data)
}
fn unseal_data_helper(&self) -> SgxResult<SgxInternalUnsealedData> {
let mut seal_key = rsgx_get_align_key(self.get_key_request()).map_err(|ret| {
if (ret == sgx_status_t::SGX_ERROR_INVALID_CPUSVN)
|| (ret == sgx_status_t::SGX_ERROR_INVALID_ISVSVN)
|| (ret == sgx_status_t::SGX_ERROR_OUT_OF_MEMORY)
{
ret
} else {
sgx_status_t::SGX_ERROR_MAC_MISMATCH
}
})?;
//
// code that calls sgx_unseal_data commonly does some sanity checks
// related to plain_text_offset. We add fence here since we don't
// know what crypto code does and if plain_text_offset-related
// checks mispredict the crypto code could operate on unintended data
//
rsgx_lfence();
let payload_iv = [0_u8; SGX_SEAL_IV_SIZE];
let mut unsealed_data: SgxInternalUnsealedData = SgxInternalUnsealedData::default();
unsealed_data.decrypt = vec![0_u8; self.payload_data.encrypt.len()].into_boxed_slice();
let error = rsgx_rijndael128GCM_decrypt(
&seal_key.key,
self.get_encrypt_txt(),
&payload_iv,
self.get_additional_txt(),
self.get_payload_tag(),
&mut unsealed_data.decrypt,
);
if error.is_err() {
seal_key.key = sgx_key_128bit_t::default();
return Err(error.unwrap_err());
}
if self.payload_data.additional.len() > 0 {
unsealed_data.additional = self.get_additional_txt().to_vec().into_boxed_slice();
}
unsealed_data.payload_size = self.get_payload_size();
seal_key.key = sgx_key_128bit_t::default();
Ok(unsealed_data)
}
}