Skip to content

Commit

Permalink
Use zeroize to clear DICE secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
conradgrobler committed Jan 12, 2024
1 parent f85610f commit 8ddf562
Show file tree
Hide file tree
Showing 15 changed files with 48 additions and 33 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions enclave_apps/Cargo.lock

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

3 changes: 2 additions & 1 deletion oak_containers_orchestrator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ clap = { version = "*", features = ["derive"] }
coset = { version = "*", features = ["std"] }
hpke = { version = "*", default-features = false, features = [
"alloc",
"x25519"
"x25519",
] }
log = "*"
nix = "*"
Expand Down Expand Up @@ -52,6 +52,7 @@ tokio-stream = { version = "*", features = ["net"] }
tokio-util = { version = "*", default-features = false }
tonic = { workspace = true }
walkdir = "*"
zeroize = "*"

[build-dependencies]
oak_grpc_utils = { workspace = true }
9 changes: 6 additions & 3 deletions oak_containers_orchestrator/src/dice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::{
fs::OpenOptions,
io::{Read, Seek, Write},
};
use zeroize::Zeroize;

/// The path to the file where the DICE data provided by Stage 1 is stored.
const STAGE1_DICE_DATA_PATH: &str = "/oak/dice";
Expand All @@ -39,14 +40,16 @@ pub fn load_stage1_dice_data() -> anyhow::Result<DiceBuilder> {
.write(true)
.open(STAGE1_DICE_DATA_PATH)
.context("couldn't open DICE data file")?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer)
let size = file.metadata().map(|m| m.len() as usize).unwrap_or(0);

let mut buffer = Vec::with_capacity(size);
file.read(&mut buffer)
.context("couldn't read DICE data from file")?;

let result =
DiceData::decode_length_delimited(&buffer[..]).context("couldn't parse DICE data")?;

buffer.fill(0);
buffer.zeroize();
file.rewind()?;
file.write_all(&buffer)
.context("couldn't overwrite DICE data file")?;
Expand Down
1 change: 1 addition & 0 deletions oak_containers_stage1/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ tower = "*"
x86_64 = "*"
xz2 = "*"
zerocopy = "*"
zeroize = "*"
3 changes: 2 additions & 1 deletion oak_containers_stage1/src/dice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use std::{
};
use x86_64::PhysAddr;
use zerocopy::FromBytes;
use zeroize::Zeroize;

/// The expected string representation of the custom type for the reserved memory range that
/// contains the DICE data.
Expand Down Expand Up @@ -119,7 +120,7 @@ fn read_stage0_dice_data(start: PhysAddr) -> anyhow::Result<Stage0DiceData> {
.ok_or_else(|| anyhow::anyhow!("size mismatch while reading DICE data"))?;

// Zero out the source memory.
source.fill(0);
source.zeroize();
result
};

Expand Down
1 change: 1 addition & 0 deletions oak_dice/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ sha2 = { version = "*", default-features = false }
static_assertions = "*"
strum = { version = "*", default-features = false, features = ["derive"] }
zerocopy = { version = "*", features = ["derive"] }
zeroize = { version = "*", features = ["derive"] }
29 changes: 4 additions & 25 deletions oak_dice/src/evidence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::utils::PaddedCopyFromSlice;
use alloc::{format, string::String, vec::Vec};
use strum::{Display, FromRepr};
use zerocopy::{AsBytes, FromBytes, FromZeroes};
use zeroize::{Zeroize, ZeroizeOnDrop};

/// The maximum size of the signed attestation report.
pub const REPORT_SIZE: usize = 2048;
Expand Down Expand Up @@ -138,7 +139,7 @@ impl LayerEvidence {
static_assertions::assert_eq_size!([u8; CERTIFICATE_SIZE], LayerEvidence);

/// Private key that can be used by a layer to sign a certificate for the next layer.
#[derive(AsBytes, FromZeroes, FromBytes)]
#[derive(AsBytes, FromZeroes, FromBytes, Zeroize, ZeroizeOnDrop)]
#[repr(C)]
pub struct CertificateAuthority {
/// The RAW bytes representing an ECDSA private key.
Expand All @@ -147,15 +148,8 @@ pub struct CertificateAuthority {

static_assertions::assert_eq_size!([u8; PRIVATE_KEY_SIZE], CertificateAuthority);

impl Drop for CertificateAuthority {
fn drop(&mut self) {
// Zero out the ECA private key.
self.eca_private_key.fill(0);
}
}

// A derived compound device identifier for a layer.
#[derive(AsBytes, FromZeroes, FromBytes)]
#[derive(AsBytes, FromZeroes, FromBytes, Zeroize, ZeroizeOnDrop)]
#[repr(C)]
pub struct CompoundDeviceIdentifier {
/// The RAW bytes representing the CDI.
Expand All @@ -164,13 +158,6 @@ pub struct CompoundDeviceIdentifier {

static_assertions::assert_eq_size!([u8; CDI_SIZE], CompoundDeviceIdentifier);

impl Drop for CompoundDeviceIdentifier {
fn drop(&mut self) {
// Zero out the CDI.
self.cdi.fill(0);
}
}

/// Wrapper for passing DICE info from Stage0 to the next layer (Stage 1 or the Restricted Kernel).
#[derive(AsBytes, FromZeroes, FromBytes)]
#[repr(C, align(4096))]
Expand Down Expand Up @@ -215,7 +202,7 @@ impl ApplicationKeys {
static_assertions::assert_eq_size!([u8; 2048], ApplicationKeys);

/// ECDSA private keys that can be used for an application for signing or encryption.
#[derive(AsBytes, FromZeroes, FromBytes)]
#[derive(AsBytes, FromZeroes, FromBytes, Zeroize, ZeroizeOnDrop)]
#[repr(C)]
pub struct ApplicationPrivateKeys {
/// The RAW bytes representing an ECDSA private key that can be used to sign arbitrary data.
Expand All @@ -226,14 +213,6 @@ pub struct ApplicationPrivateKeys {

static_assertions::assert_eq_size!([u8; 128], ApplicationPrivateKeys);

impl Drop for ApplicationPrivateKeys {
fn drop(&mut self) {
// Zero out the private keys.
self.signing_private_key.fill(0);
self.encryption_private_key.fill(0);
}
}

/// Wrapper for passing the attestation evidence from the Restricted Kernel to the application.
#[derive(AsBytes, FromZeroes, FromBytes, Clone)]
#[repr(C)]
Expand Down
1 change: 1 addition & 0 deletions oak_remote_attestation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ rand_core = { version = "*", default-features = false, features = [
"getrandom",
] }
sha2 = { version = "*", default-features = false }
zeroize = "*"

[build-dependencies]
micro_rpc_build = { workspace = true }
3 changes: 2 additions & 1 deletion oak_remote_attestation/src/dice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use oak_dice::{
evidence::Stage0DiceData,
};
use p256::ecdsa::{SigningKey, VerifyingKey};
use zeroize::Zeroize;

/// Builds the DICE evidence and certificate authority for the next DICE layer.
pub struct DiceBuilder {
Expand Down Expand Up @@ -147,7 +148,7 @@ impl Drop for DiceData {
fn drop(&mut self) {
// Zero out the ECA private key if it was set.
if let Some(certificate_authority) = &mut self.certificate_authority {
certificate_authority.eca_private_key.fill(0);
certificate_authority.eca_private_key.zeroize();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions oak_restricted_kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ oak_virtio = { workspace = true, optional = true }
virtio-drivers = { version = "*", optional = true }
x86_64 = "*"
zerocopy = "*"
zeroize = "*"

[dev-dependencies]
assertables = "*"
3 changes: 2 additions & 1 deletion oak_restricted_kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ use x86_64::{
PhysAddr, VirtAddr,
};
use zerocopy::FromBytes;
use zeroize::Zeroize;

/// A derived sealing key.
type DerivedKey = [u8; 32];
Expand Down Expand Up @@ -291,7 +292,7 @@ pub fn start_kernel(info: &BootParams) -> ! {
.expect("failed to read dice data");

// Overwrite the dice data provided by stage0 after reading.
dice_memory_slice.fill(0);
dice_memory_slice.zeroize();

if dice_data.magic != oak_dice::evidence::STAGE0_MAGIC {
panic!("dice data loaded from stage0 failed validation");
Expand Down
3 changes: 2 additions & 1 deletion oak_restricted_kernel/src/syscall/dice_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use super::fd::{copy_max_slice, FileDescriptor};
use alloc::boxed::Box;
use oak_dice::evidence::RestrictedKernelDiceData as DiceData;
use oak_restricted_kernel_interface::{Errno, DICE_DATA_FD};
use zeroize::Zeroize;

struct DiceDataDescriptor {
data: DiceData,
Expand All @@ -37,7 +38,7 @@ impl FileDescriptor for DiceDataDescriptor {

// destroy the data that was read, to ensure that it can only be read once
let slice_to_read = &mut data_as_slice[self.index..(self.index + length)];
slice_to_read.fill(0);
slice_to_read.zeroize();

self.index += length;
Ok(length as isize)
Expand Down
2 changes: 2 additions & 0 deletions oak_restricted_kernel_bin/Cargo.lock

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

15 changes: 15 additions & 0 deletions stage0_bin/Cargo.lock

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

0 comments on commit 8ddf562

Please sign in to comment.