Skip to content

Commit

Permalink
Allow setting path of the State Key (AES) (#1324)
Browse files Browse the repository at this point in the history
* [itp-sgx-crypto] add `ToPubkey` and `AccessPubkey` traits

* [itp-sgx-crypto] refactor the Rsa3072 stuff to no longer use static file IO.

* [itp-sgx-crypto] set-base-path to the PWD

* [enclave-runtime] more explanation about using the PWD

* [enclave-runtime] add todo for replacing the once-cell.

* taplo fmt

* add some doc

* typo

* [sgx-crypto] log full path instead of just filename.

* [itp-sgx-io] fix standalone compilation

* [itp-sgx-crypto] put some functions behind a trait.

* [enclave-runtime/attestation_handler] add signing key repo to struct

* [itp-sgx-crypto] impl `ToPubkey` for `ed25511::Pair`

* introduce `SigningKeyRepository` and remove all instances of `StaticFile` IO.

* [itp-sgx-crypto] add base path to AESSeal

* [itp-state-handler] wip update tests

* [itp-state-handler] add debug log for existing files in shard

* [itp-state-handler] fix tests by creating a unique key-repo per test

* fix merge errors

* [itp-sgx-crypto] add tests for aes

* taplo fmt

* clippy

* move aes key file name constant to the aes module

* [stf-state-handle] rename `TestKeyRepositoryMock` to `TestKeyRepositoryMock` to reflect that it is no longer the mock

* [itp-sgx-crypto] more accurate name for the AES key file
  • Loading branch information
clangenb authored May 26, 2023
1 parent a01f476 commit ab52658
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 62 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3628,6 +3628,7 @@ dependencies = [
"itp-sgx-crypto",
"itp-sgx-externalities",
"itp-sgx-io",
"itp-sgx-temp-dir",
"itp-stf-interface",
"itp-stf-state-observer",
"itp-time-utils",
Expand Down
1 change: 0 additions & 1 deletion core-primitives/settings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ pub mod files {
pub static SIDECHAIN_PURGE_LIMIT: u64 = 100; // keep the last.. sidechainblocks when purging

// used by enclave
pub const AES_KEY_FILE_AND_INIT_V: &str = "aes_key_sealed.bin";
pub const LIGHT_CLIENT_DB: &str = "light_client_db.bin";

pub const RA_DUMP_CERT_DER_FILE: &str = "ra_dump_cert.der";
Expand Down
131 changes: 102 additions & 29 deletions core-primitives/sgx/crypto/src/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@ use crate::{
};
use aes::Aes128;
use codec::{Decode, Encode};
use derive_more::Display;
use ofb::{
cipher::{NewStreamCipher, SyncStreamCipher},
Ofb,
};
use std::convert::{TryFrom, TryInto};
use std::{
convert::{TryFrom, TryInto},
path::PathBuf,
};

type AesOfb = Ofb<Aes128>;

/// File name of the sealed AES key data.
pub const AES_KEY_FILE_AND_INIT_V: &str = "aes_key_and_iv_sealed_data.bin";

#[derive(Debug, Default, Encode, Decode, Clone, Copy, PartialEq, Eq)]
pub struct Aes {
pub key: [u8; 16],
Expand All @@ -42,8 +47,20 @@ impl Aes {
}
}

#[derive(Copy, Clone, Debug, Display)]
pub struct AesSeal;
#[derive(Clone, Debug)]
pub struct AesSeal {
base_path: PathBuf,
}

impl AesSeal {
pub fn new(base_path: PathBuf) -> Self {
Self { base_path }
}

pub fn path(&self) -> PathBuf {
self.base_path.join(AES_KEY_FILE_AND_INIT_V)
}
}

impl StateCrypto for Aes {
type Error = Error;
Expand All @@ -70,29 +87,63 @@ pub fn de_or_encrypt(aes: &Aes, data: &mut [u8]) -> Result<()> {
aes.try_into().map(|mut ofb: AesOfb| ofb.apply_keystream(data))
}

pub trait AesSealing {
fn unseal_key(&self) -> Result<Aes>;

fn exists(&self) -> bool;

fn create_sealed_if_absent(&self) -> Result<()>;

fn create_sealed(&self) -> Result<()>;
}

#[cfg(feature = "sgx")]
pub use sgx::*;

#[cfg(feature = "sgx")]
pub mod sgx {

use super::*;
use itp_settings::files::AES_KEY_FILE_AND_INIT_V;
use itp_sgx_io::{seal, unseal, SealedIO, StaticSealedIO};
use crate::key_repository::KeyRepository;
use itp_sgx_io::{seal, unseal, SealedIO};
use log::info;
use sgx_rand::{Rng, StdRng};
use std::sgxfs::SgxFile;

impl StaticSealedIO for AesSeal {
type Error = Error;
type Unsealed = Aes;
/// Gets a repository for an AES key and initializes
/// a fresh key if it doesn't exist at `path`.
pub fn get_aes_repository(path: PathBuf) -> Result<KeyRepository<Aes, AesSeal>> {
let aes_seal = AesSeal::new(path);
aes_seal.create_sealed_if_absent()?;
let aes_key = aes_seal.unseal_key()?;
Ok(KeyRepository::new(aes_key, aes_seal.into()))
}

impl AesSealing for AesSeal {
fn unseal_key(&self) -> Result<Aes> {
self.unseal()
}

fn unseal_from_static_file() -> Result<Self::Unsealed> {
Ok(unseal(AES_KEY_FILE_AND_INIT_V).map(|b| Decode::decode(&mut b.as_slice()))??)
fn exists(&self) -> bool {
SgxFile::open(self.path()).is_ok()
}

fn seal_to_static_file(unsealed: &Self::Unsealed) -> Result<()> {
Ok(unsealed.using_encoded(|bytes| seal(bytes, AES_KEY_FILE_AND_INIT_V))?)
fn create_sealed_if_absent(&self) -> Result<()> {
if !self.exists() {
info!("Keyfile not found, creating new! {}", self.path().display());
return self.create_sealed()
}
Ok(())
}

fn create_sealed(&self) -> Result<()> {
let mut key = [0u8; 16];
let mut iv = [0u8; 16];
let mut rand = StdRng::new()?;

rand.fill_bytes(&mut key);
rand.fill_bytes(&mut iv);

Ok(self.seal(&Aes::new(key, iv))?)
}
}

Expand All @@ -101,30 +152,52 @@ pub mod sgx {
type Unsealed = Aes;

fn unseal(&self) -> Result<Self::Unsealed> {
Self::unseal_from_static_file()
Ok(unseal(self.path()).map(|b| Decode::decode(&mut b.as_slice()))??)
}

fn seal(&self, unsealed: &Self::Unsealed) -> Result<()> {
Self::seal_to_static_file(&unsealed)
Ok(unsealed.using_encoded(|bytes| seal(bytes, self.path()))?)
}
}
}

pub fn create_sealed_if_absent() -> Result<()> {
if SgxFile::open(AES_KEY_FILE_AND_INIT_V).is_err() {
info!("[Enclave] Keyfile not found, creating new! {}", AES_KEY_FILE_AND_INIT_V);
return create_sealed()
}
Ok(())
#[cfg(feature = "test")]
pub mod sgx_tests {
use super::sgx::*;
use crate::{key_repository::AccessKey, AesSeal, AesSealing};
use itp_sgx_temp_dir::TempDir;

pub fn using_get_aes_repository_twice_initializes_key_only_once() {
let temp_dir =
TempDir::with_prefix("using_get_aes_repository_twice_initializes_key_only_once")
.unwrap();
let temp_path = temp_dir.path().to_path_buf();
let key1 = get_aes_repository(temp_path.clone()).unwrap().retrieve_key().unwrap();
let key2 = get_aes_repository(temp_path).unwrap().retrieve_key().unwrap();
assert_eq!(key1, key2);
}

pub fn create_sealed() -> Result<()> {
let mut key = [0u8; 16];
let mut iv = [0u8; 16];
pub fn aes_sealing_works() {
let temp_dir = TempDir::with_prefix("aes_sealing_works").unwrap();
let seal = AesSeal::new(temp_dir.path().to_path_buf());

// Create new sealed keys and unseal them
assert!(!seal.exists());
seal.create_sealed_if_absent().unwrap();
let key = seal.unseal_key().unwrap();

assert!(seal.exists());

// Should not change anything because the key is already there.
seal.create_sealed_if_absent().unwrap();
let key_same = seal.unseal_key().unwrap();

assert_eq!(key, key_same);

let mut rand = StdRng::new()?;
// Should overwrite previous keys.
seal.create_sealed().unwrap();
let key_different = seal.unseal_key().unwrap();

rand.fill_bytes(&mut key);
rand.fill_bytes(&mut iv);
AesSeal::seal_to_static_file(&Aes::new(key, iv))
assert_ne!(key_different, key);
}
}
4 changes: 4 additions & 0 deletions core-primitives/sgx/crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,8 @@ pub mod tests {
pub use super::rsa3072::sgx_tests::{
rsa3072_sealing_works, using_get_rsa3072_repository_twice_initializes_key_only_once,
};

pub use super::aes::sgx_tests::{
aes_sealing_works, using_get_aes_repository_twice_initializes_key_only_once,
};
}
4 changes: 4 additions & 0 deletions core-primitives/stf-state-handler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ itp-stf-state-observer = { path = "../stf-state-observer", default-features = fa
itp-time-utils = { path = "../../core-primitives/time-utils", default-features = false }
itp-types = { path = "../types", default-features = false }

# for tests
itp-sgx-temp-dir = { version = "0.1", default-features = false, optional = true, path = "../../core-primitives/sgx/temp-dir" }

# sgx enabled external libraries
rust-base58_sgx = { package = "rust-base58", rev = "sgx_1.1.3", git = "https://github.com/mesalock-linux/rust-base58-sgx", optional = true, default-features = false, features = ["mesalock_sgx"] }
thiserror_sgx = { package = "thiserror", git = "https://github.com/mesalock-linux/thiserror-sgx", tag = "sgx_1.1.3", optional = true }
Expand Down Expand Up @@ -71,4 +74,5 @@ sgx = [
test = [
"itp-sgx-crypto/mocks",
"itp-stf-interface/mocks",
"itp-sgx-temp-dir",
]
Loading

0 comments on commit ab52658

Please sign in to comment.