Skip to content

Commit

Permalink
pRuntime: Manually encrypted worker privkey and gk master key
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Sep 18, 2023
1 parent 7f300d0 commit dc67cd0
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/phactory/api/proto
Submodule proto updated 1 files
+4 −2 pruntime_rpc.proto
2 changes: 1 addition & 1 deletion crates/phactory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ fn new_sr25519_key() -> sr25519::Pair {
}

// TODO.kevin: Move to phactory-api when the std ready.
fn generate_random_iv() -> aead::IV {
pub fn generate_random_iv() -> aead::IV {
let mut nonce_vec = [0u8; aead::IV_BYTES];
let rand = ring::rand::SystemRandom::new();
rand.fill(&mut nonce_vec).unwrap();
Expand Down
1 change: 1 addition & 0 deletions crates/sgx-api-lite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ edition = "2021"
[dependencies]
cmac = "0.7.1"
aes = "0.8.1"
bitflags = "2"
115 changes: 115 additions & 0 deletions crates/sgx-api-lite/src/egetkey.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//! This file is copied from crate sgx_isa which is part of Fortanix, we can not directly use
//! sgx_isa because it requires compilation target=fortanix-sgx.

#![allow(dead_code)]
#![allow(clippy::enum_variant_names)]

use bitflags::bitflags;
use core::arch::asm;
use core::mem::MaybeUninit;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u16)]
enum Keyname {
Einittoken = 0,
Provision = 1,
ProvisionSeal = 2,
Report = 3,
Seal = 4,
}

bitflags! {
#[repr(C)]
struct Keypolicy: u16 {
const MRENCLAVE = 0b0000_0001;
const MRSIGNER = 0b0000_0010;
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u32)]
enum Enclu {
EReport = 0,
EGetkey = 1,
EEnter = 2,
EResume = 3,
EExit = 4,
EAccept = 5,
EModpe = 6,
EAcceptcopy = 7,
}

#[repr(align(16))]
struct Align16<T>(T);

#[repr(align(512))]
struct Align512<T>(T);

/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
unsafe {
let mut out = MaybeUninit::uninit();
let error;

asm!(
// rbx is reserved by LLVM
"xchg %rbx, {0}",
"enclu",
"mov {0}, %rbx",
inout(reg) request => _,
inlateout("eax") Enclu::EGetkey as u32 => error,
in("rcx") out.as_mut_ptr(),
options(att_syntax, nostack),
);

match error {
0 => Ok(out.assume_init()),
err => Err(err),
}
}
}

#[repr(C, align(512))]
struct Keyrequest {
keyname: u16,
keypolicy: Keypolicy,
isvsvn: u16,
_reserved1: u16,
cpusvn: [u8; 16],
attributemask: [u64; 2],
keyid: [u8; 32],
miscmask: u32,
_reserved2: [u8; 436],
}

impl Keyrequest {
fn copy(&self) -> [u8; 512] {
unsafe { *(self as *const Keyrequest as *const [u8; 512]) }
}

fn egetkey(&self) -> Result<Align16<[u8; 16]>, u32> {
egetkey(&Align512(self.copy()))
}
}

/// Derive a MRENCLAVE sealing key with the given `isvsvn`, `cpusvn` and `keyid`.
pub fn get_mrenclave_sealing_key(
isvsvn: u16,
cpusvn: [u8; 16],
keyid: [u8; 32],
) -> Result<[u8; 16], u32> {
let request = Keyrequest {
keyname: Keyname::Seal as u16,
keypolicy: Keypolicy::MRENCLAVE,
isvsvn,
_reserved1: 0,
cpusvn,
// Less mask to prevent the derived key changes during system upgrade.
attributemask: [0x03, 0x00],
keyid,
miscmask: 0,
_reserved2: [0; 436],
};
let key = request.egetkey()?;
Ok(key.0)
}
2 changes: 2 additions & 0 deletions crates/sgx-api-lite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ use std::mem::{size_of, zeroed};
pub use sys::sgx_report_data_t as ReportData;
pub use sys::sgx_report_t as Report;
pub use sys::sgx_target_info_t as TargetInfo;
pub use egetkey::get_mrenclave_sealing_key;

mod sys;
mod egetkey;

#[repr(C, align(512))]
struct SgxAligned<T>(T);
Expand Down
2 changes: 2 additions & 0 deletions standalone/pruntime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions standalone/pruntime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ phala-rocket-middleware = { path = "../../crates/phala-rocket-middleware" }
phala-types = { path = "../../crates/phala-types", features = ["enable_serde", "sgx"] }
phala-git-revision = { path = "../../crates/phala-git-revision" }
phala-clap-parsers = { path = "../../crates/phala-clap-parsers" }
phala-crypto = { path = "../../crates/phala-crypto" }
sgx-api-lite = { path = "../../crates/sgx-api-lite" }
tracing = "0.1"
hex_fmt = "0.3.0"
Expand Down
3 changes: 1 addition & 2 deletions standalone/pruntime/gramine-build/pruntime.manifest.template
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ uri = "file:{{ libdir }}"
[[fs.mounts]]
path = "/data/protected_files"
uri = "file:{{ seal_dir }}"
type = "encrypted"
key_name = "_sgx_mrenclave"

[[fs.mounts]]
type = "chroot"
Expand Down Expand Up @@ -89,4 +87,5 @@ allowed_files = [
"file:/etc/resolv.conf",
"file:Rocket.toml",
"file:{{ storage_dir }}/",
"file:{{ seal_dir }}/",
]
72 changes: 67 additions & 5 deletions standalone/pruntime/src/pal_gramine.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::anyhow;
use parity_scale_codec::Encode;
use parity_scale_codec::{Decode, Encode};
use std::alloc::System;
use tracing::info;

Expand All @@ -16,16 +16,70 @@ use phala_types::AttestationProvider;
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub(crate) struct GraminePlatform;

#[derive(Encode, Decode)]
struct SealedData {
isvsvn: u16,
cpusvn: [u8; 16],
iv: [u8; 12],
data: Vec<u8>,
}

fn get_sealing_key(isvsvn: u16, cpusvn: [u8; 16]) -> anyhow::Result<[u8; 32]> {
const KEY_ID: [u8; 32] = *b"pruntime-sealed-data-key-id\0\0\0\0\0";
let key128 = sgx_api_lite::get_mrenclave_sealing_key(isvsvn, cpusvn, KEY_ID)
.or(Err(anyhow!("Failed to get sealing key")))?;
// phala_crypto API uses AES256, so extend the key to 256 bits
let mut key256 = [0; 32];
key256[..16].copy_from_slice(&key128[..]);
Ok(key256)
}

fn sgx_seal_data(data: &[u8]) -> anyhow::Result<SealedData> {
let this_target_info =
sgx_api_lite::target_info().or(Err(anyhow!("Failed to get target info")))?;
let report = sgx_api_lite::report(&this_target_info, &[0; 64])
.or(Err(anyhow!("Failed to get SGX report")))?;
let isvsvn = report.body.isv_svn;
let cpusvn = report.body.cpu_svn.svn;
let key = get_sealing_key(isvsvn, cpusvn)
.or(Err(anyhow!("Failed to get sealing key")))?;
let iv = phactory::generate_random_iv();
let mut data = data.to_vec();
phala_crypto::aead::encrypt(&iv, &key, &mut data).or(Err(anyhow!("Failed to encrypt data")))?;
Ok(SealedData {
isvsvn,
cpusvn,
iv,
data,
})
}

fn sgx_unseal_data(data: &SealedData) -> anyhow::Result<Vec<u8>> {
let key = get_sealing_key(data.isvsvn, data.cpusvn)
.or(Err(anyhow!("Failed to get sealing key")))?;
let mut enccypted_data = data.data.clone();
let decrypted = phala_crypto::aead::decrypt(&data.iv, &key, &mut enccypted_data[..])
.or(Err(anyhow!("Failed to decrypt sealed data",)))?;
Ok(decrypted.to_vec())
}

impl Sealing for GraminePlatform {
type SealError = std::io::Error;
type UnsealError = std::io::Error;
type SealError = anyhow::Error;
type UnsealError = anyhow::Error;

fn seal_data(
&self,
path: impl AsRef<std::path::Path>,
data: &[u8],
) -> Result<(), Self::SealError> {
std::fs::write(path, data)?;
if !is_gramine() {
std::fs::write(path, data)?;
return Ok(());
}
info!("Sealing data to {:?}", path.as_ref());
let data = sgx_seal_data(data)?;
let encoded = data.encode();
std::fs::write(path, encoded)?;
Ok(())
}

Expand All @@ -35,7 +89,15 @@ impl Sealing for GraminePlatform {
) -> Result<Option<Vec<u8>>, Self::UnsealError> {
match std::fs::read(path) {
Err(err) if matches!(err.kind(), ErrorKind::NotFound) => Ok(None),
other => other.map(Some),
Ok(data) => {
if !is_gramine() {
return Ok(Some(data));
}
let data = SealedData::decode(&mut &data[..])?;
let data = sgx_unseal_data(&data)?;
Ok(Some(data))
}
Err(err) => Err(err.into()),
}
}
}
Expand Down

0 comments on commit dc67cd0

Please sign in to comment.