Skip to content

Commit dc67cd0

Browse files
committed
pRuntime: Manually encrypted worker privkey and gk master key
1 parent 7f300d0 commit dc67cd0

File tree

10 files changed

+192
-9
lines changed

10 files changed

+192
-9
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/phactory/api/proto

crates/phactory/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ fn new_sr25519_key() -> sr25519::Pair {
840840
}
841841

842842
// TODO.kevin: Move to phactory-api when the std ready.
843-
fn generate_random_iv() -> aead::IV {
843+
pub fn generate_random_iv() -> aead::IV {
844844
let mut nonce_vec = [0u8; aead::IV_BYTES];
845845
let rand = ring::rand::SystemRandom::new();
846846
rand.fill(&mut nonce_vec).unwrap();

crates/sgx-api-lite/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ edition = "2021"
66
[dependencies]
77
cmac = "0.7.1"
88
aes = "0.8.1"
9+
bitflags = "2"

crates/sgx-api-lite/src/egetkey.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//! This file is copied from crate sgx_isa which is part of Fortanix, we can not directly use
2+
//! sgx_isa because it requires compilation target=fortanix-sgx.
3+
4+
#![allow(dead_code)]
5+
#![allow(clippy::enum_variant_names)]
6+
7+
use bitflags::bitflags;
8+
use core::arch::asm;
9+
use core::mem::MaybeUninit;
10+
11+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12+
#[repr(u16)]
13+
enum Keyname {
14+
Einittoken = 0,
15+
Provision = 1,
16+
ProvisionSeal = 2,
17+
Report = 3,
18+
Seal = 4,
19+
}
20+
21+
bitflags! {
22+
#[repr(C)]
23+
struct Keypolicy: u16 {
24+
const MRENCLAVE = 0b0000_0001;
25+
const MRSIGNER = 0b0000_0010;
26+
}
27+
}
28+
29+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30+
#[repr(u32)]
31+
enum Enclu {
32+
EReport = 0,
33+
EGetkey = 1,
34+
EEnter = 2,
35+
EResume = 3,
36+
EExit = 4,
37+
EAccept = 5,
38+
EModpe = 6,
39+
EAcceptcopy = 7,
40+
}
41+
42+
#[repr(align(16))]
43+
struct Align16<T>(T);
44+
45+
#[repr(align(512))]
46+
struct Align512<T>(T);
47+
48+
/// Call the `EGETKEY` instruction to obtain a 128-bit secret key.
49+
fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> {
50+
unsafe {
51+
let mut out = MaybeUninit::uninit();
52+
let error;
53+
54+
asm!(
55+
// rbx is reserved by LLVM
56+
"xchg %rbx, {0}",
57+
"enclu",
58+
"mov {0}, %rbx",
59+
inout(reg) request => _,
60+
inlateout("eax") Enclu::EGetkey as u32 => error,
61+
in("rcx") out.as_mut_ptr(),
62+
options(att_syntax, nostack),
63+
);
64+
65+
match error {
66+
0 => Ok(out.assume_init()),
67+
err => Err(err),
68+
}
69+
}
70+
}
71+
72+
#[repr(C, align(512))]
73+
struct Keyrequest {
74+
keyname: u16,
75+
keypolicy: Keypolicy,
76+
isvsvn: u16,
77+
_reserved1: u16,
78+
cpusvn: [u8; 16],
79+
attributemask: [u64; 2],
80+
keyid: [u8; 32],
81+
miscmask: u32,
82+
_reserved2: [u8; 436],
83+
}
84+
85+
impl Keyrequest {
86+
fn copy(&self) -> [u8; 512] {
87+
unsafe { *(self as *const Keyrequest as *const [u8; 512]) }
88+
}
89+
90+
fn egetkey(&self) -> Result<Align16<[u8; 16]>, u32> {
91+
egetkey(&Align512(self.copy()))
92+
}
93+
}
94+
95+
/// Derive a MRENCLAVE sealing key with the given `isvsvn`, `cpusvn` and `keyid`.
96+
pub fn get_mrenclave_sealing_key(
97+
isvsvn: u16,
98+
cpusvn: [u8; 16],
99+
keyid: [u8; 32],
100+
) -> Result<[u8; 16], u32> {
101+
let request = Keyrequest {
102+
keyname: Keyname::Seal as u16,
103+
keypolicy: Keypolicy::MRENCLAVE,
104+
isvsvn,
105+
_reserved1: 0,
106+
cpusvn,
107+
// Less mask to prevent the derived key changes during system upgrade.
108+
attributemask: [0x03, 0x00],
109+
keyid,
110+
miscmask: 0,
111+
_reserved2: [0; 436],
112+
};
113+
let key = request.egetkey()?;
114+
Ok(key.0)
115+
}

crates/sgx-api-lite/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ use std::mem::{size_of, zeroed};
2525
pub use sys::sgx_report_data_t as ReportData;
2626
pub use sys::sgx_report_t as Report;
2727
pub use sys::sgx_target_info_t as TargetInfo;
28+
pub use egetkey::get_mrenclave_sealing_key;
2829

2930
mod sys;
31+
mod egetkey;
3032

3133
#[repr(C, align(512))]
3234
struct SgxAligned<T>(T);

standalone/pruntime/Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

standalone/pruntime/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ phala-rocket-middleware = { path = "../../crates/phala-rocket-middleware" }
3939
phala-types = { path = "../../crates/phala-types", features = ["enable_serde", "sgx"] }
4040
phala-git-revision = { path = "../../crates/phala-git-revision" }
4141
phala-clap-parsers = { path = "../../crates/phala-clap-parsers" }
42+
phala-crypto = { path = "../../crates/phala-crypto" }
4243
sgx-api-lite = { path = "../../crates/sgx-api-lite" }
4344
tracing = "0.1"
4445
hex_fmt = "0.3.0"

standalone/pruntime/gramine-build/pruntime.manifest.template

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ uri = "file:{{ libdir }}"
4747
[[fs.mounts]]
4848
path = "/data/protected_files"
4949
uri = "file:{{ seal_dir }}"
50-
type = "encrypted"
51-
key_name = "_sgx_mrenclave"
5250

5351
[[fs.mounts]]
5452
type = "chroot"
@@ -89,4 +87,5 @@ allowed_files = [
8987
"file:/etc/resolv.conf",
9088
"file:Rocket.toml",
9189
"file:{{ storage_dir }}/",
90+
"file:{{ seal_dir }}/",
9291
]

standalone/pruntime/src/pal_gramine.rs

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::anyhow;
2-
use parity_scale_codec::Encode;
2+
use parity_scale_codec::{Decode, Encode};
33
use std::alloc::System;
44
use tracing::info;
55

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

19+
#[derive(Encode, Decode)]
20+
struct SealedData {
21+
isvsvn: u16,
22+
cpusvn: [u8; 16],
23+
iv: [u8; 12],
24+
data: Vec<u8>,
25+
}
26+
27+
fn get_sealing_key(isvsvn: u16, cpusvn: [u8; 16]) -> anyhow::Result<[u8; 32]> {
28+
const KEY_ID: [u8; 32] = *b"pruntime-sealed-data-key-id\0\0\0\0\0";
29+
let key128 = sgx_api_lite::get_mrenclave_sealing_key(isvsvn, cpusvn, KEY_ID)
30+
.or(Err(anyhow!("Failed to get sealing key")))?;
31+
// phala_crypto API uses AES256, so extend the key to 256 bits
32+
let mut key256 = [0; 32];
33+
key256[..16].copy_from_slice(&key128[..]);
34+
Ok(key256)
35+
}
36+
37+
fn sgx_seal_data(data: &[u8]) -> anyhow::Result<SealedData> {
38+
let this_target_info =
39+
sgx_api_lite::target_info().or(Err(anyhow!("Failed to get target info")))?;
40+
let report = sgx_api_lite::report(&this_target_info, &[0; 64])
41+
.or(Err(anyhow!("Failed to get SGX report")))?;
42+
let isvsvn = report.body.isv_svn;
43+
let cpusvn = report.body.cpu_svn.svn;
44+
let key = get_sealing_key(isvsvn, cpusvn)
45+
.or(Err(anyhow!("Failed to get sealing key")))?;
46+
let iv = phactory::generate_random_iv();
47+
let mut data = data.to_vec();
48+
phala_crypto::aead::encrypt(&iv, &key, &mut data).or(Err(anyhow!("Failed to encrypt data")))?;
49+
Ok(SealedData {
50+
isvsvn,
51+
cpusvn,
52+
iv,
53+
data,
54+
})
55+
}
56+
57+
fn sgx_unseal_data(data: &SealedData) -> anyhow::Result<Vec<u8>> {
58+
let key = get_sealing_key(data.isvsvn, data.cpusvn)
59+
.or(Err(anyhow!("Failed to get sealing key")))?;
60+
let mut enccypted_data = data.data.clone();
61+
let decrypted = phala_crypto::aead::decrypt(&data.iv, &key, &mut enccypted_data[..])
62+
.or(Err(anyhow!("Failed to decrypt sealed data",)))?;
63+
Ok(decrypted.to_vec())
64+
}
65+
1966
impl Sealing for GraminePlatform {
20-
type SealError = std::io::Error;
21-
type UnsealError = std::io::Error;
67+
type SealError = anyhow::Error;
68+
type UnsealError = anyhow::Error;
2269

2370
fn seal_data(
2471
&self,
2572
path: impl AsRef<std::path::Path>,
2673
data: &[u8],
2774
) -> Result<(), Self::SealError> {
28-
std::fs::write(path, data)?;
75+
if !is_gramine() {
76+
std::fs::write(path, data)?;
77+
return Ok(());
78+
}
79+
info!("Sealing data to {:?}", path.as_ref());
80+
let data = sgx_seal_data(data)?;
81+
let encoded = data.encode();
82+
std::fs::write(path, encoded)?;
2983
Ok(())
3084
}
3185

@@ -35,7 +89,15 @@ impl Sealing for GraminePlatform {
3589
) -> Result<Option<Vec<u8>>, Self::UnsealError> {
3690
match std::fs::read(path) {
3791
Err(err) if matches!(err.kind(), ErrorKind::NotFound) => Ok(None),
38-
other => other.map(Some),
92+
Ok(data) => {
93+
if !is_gramine() {
94+
return Ok(Some(data));
95+
}
96+
let data = SealedData::decode(&mut &data[..])?;
97+
let data = sgx_unseal_data(&data)?;
98+
Ok(Some(data))
99+
}
100+
Err(err) => Err(err.into()),
39101
}
40102
}
41103
}

0 commit comments

Comments
 (0)