Skip to content

Commit

Permalink
Merge branch 'project-oak:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
waywardgeek authored Feb 19, 2024
2 parents 0573bdf + 5d1f9dc commit a83d353
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 31 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions oak_attestation_verification/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ zerocopy = "*"

[dev-dependencies]
prost = { workspace = true }
oak_restricted_kernel_sdk = { workspace = true, features = [
"mock_attestation"
] }
oak_attestation = { workspace = true }
94 changes: 86 additions & 8 deletions oak_attestation_verification/tests/verifier_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,22 @@

use std::fs;

use oak_attestation::dice::evidence_to_proto;
use oak_attestation_verification::{
util::convert_pem_to_raw,
verifier::{to_attestation_results, verify},
verifier::{to_attestation_results, verify, verify_dice_chain},
};
use oak_proto_rust::oak::attestation::v1::{
attestation_results::Status, binary_reference_value, reference_values, AmdSevReferenceValues,
BinaryReferenceValue, ContainerLayerEndorsements, ContainerLayerReferenceValues,
EndorsementReferenceValue, Endorsements, Evidence, InsecureReferenceValues,
KernelLayerEndorsements, KernelLayerReferenceValues, OakContainersEndorsements,
OakContainersReferenceValues, ReferenceValues, RootLayerEndorsements, RootLayerReferenceValues,
SkipVerification, StringReferenceValue, SystemLayerEndorsements, SystemLayerReferenceValues,
TransparentReleaseEndorsement,
attestation_results::Status, binary_reference_value, endorsements, reference_values,
AmdSevReferenceValues, ApplicationLayerReferenceValues, BinaryReferenceValue,
ContainerLayerEndorsements, ContainerLayerReferenceValues, EndorsementReferenceValue,
Endorsements, Evidence, InsecureReferenceValues, KernelLayerEndorsements,
KernelLayerReferenceValues, OakContainersEndorsements, OakContainersReferenceValues,
OakRestrictedKernelEndorsements, OakRestrictedKernelReferenceValues, ReferenceValues,
RootLayerEndorsements, RootLayerReferenceValues, SkipVerification, StringReferenceValue,
SystemLayerEndorsements, SystemLayerReferenceValues, TransparentReleaseEndorsement,
};
use oak_restricted_kernel_sdk::EvidenceProvider;
use prost::Message;

const ENDORSEMENT_PATH: &str = "testdata/endorsement.json";
Expand Down Expand Up @@ -181,6 +184,81 @@ fn verify_succeeds() {
assert!(p.status() == Status::Success);
}

#[test]
fn verify_mock_dice_chain() {
let mock_evidence_provider =
oak_restricted_kernel_sdk::mock_attestation::MockEvidenceProvider::create()
.expect("failed to create mock provider");
let mock_evidence = mock_evidence_provider.get_evidence();

let result = verify_dice_chain(
&evidence_to_proto(mock_evidence.clone()).expect("could not convert evidence to proto"),
);

assert!(result.is_ok());
let evidence_values: oak_proto_rust::oak::attestation::v1::extracted_evidence::EvidenceValues =
result.unwrap().evidence_values.unwrap();
assert!(matches!(evidence_values, oak_proto_rust::oak::attestation::v1::extracted_evidence::EvidenceValues::OakRestrictedKernel{..}))
}

#[test]
fn verify_mock_evidence() {
let mock_evidence_provider =
oak_restricted_kernel_sdk::mock_attestation::MockEvidenceProvider::create()
.expect("failed to create mock provider");
let evidence = evidence_to_proto(mock_evidence_provider.get_evidence().clone())
.expect("failed to convert evidence to proto");

let endorsements = Endorsements {
r#type: Some(endorsements::Type::OakRestrictedKernel(
OakRestrictedKernelEndorsements {
root_layer: Some(RootLayerEndorsements::default()),
..Default::default()
},
)),
};

// reference values that skip everything.
let reference_values = {
let skip = BinaryReferenceValue {
r#type: Some(binary_reference_value::Type::Skip(
SkipVerification::default(),
)),
};
ReferenceValues {
r#type: Some(reference_values::Type::OakRestrictedKernel(
OakRestrictedKernelReferenceValues {
root_layer: Some(RootLayerReferenceValues {
insecure: Some(InsecureReferenceValues::default()),
..Default::default()
}),
kernel_layer: Some(KernelLayerReferenceValues {
kernel_image: Some(skip.clone()),
kernel_cmd_line: Some(skip.clone()),
kernel_setup_data: Some(skip.clone()),
init_ram_fs: Some(skip.clone()),
memory_map: Some(skip.clone()),
acpi: Some(skip.clone()),
}),
application_layer: Some(ApplicationLayerReferenceValues {
binary: Some(skip.clone()),
configuration: Some(skip.clone()),
}),
},
)),
}
};

let r = verify(NOW_UTC_MILLIS, &evidence, &endorsements, &reference_values);
let p = to_attestation_results(&r);

eprintln!("======================================");
eprintln!("code={} reason={}", p.status as i32, p.reason);
eprintln!("======================================");
assert!(r.is_ok());
assert!(p.status() == Status::Success);
}

#[test]
fn verify_fake_evidence() {
let evidence = create_fake_evidence();
Expand Down
2 changes: 1 addition & 1 deletion oak_containers_orchestrator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct Args {
#[arg(default_value = "http://10.0.2.100:8080")]
launcher_addr: String,

#[arg(default_value = "127.0.0.1:4000")]
#[arg(default_value = "0.0.0.0:4000")]
orchestrator_addr: String,

#[arg(long, default_value = "/oak_container")]
Expand Down
25 changes: 22 additions & 3 deletions oak_restricted_kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ use core::{marker::Sync, option::Option, panic::PanicInfo, str::FromStr};
use linked_list_allocator::LockedHeap;
use log::{error, info};
use mm::{
frame_allocator::PhysicalMemoryAllocator, page_tables::CurrentRootPageTable,
virtual_address_allocator::VirtualAddressAllocator,
encrypted_mapper::MemoryEncryption, frame_allocator::PhysicalMemoryAllocator,
page_tables::CurrentRootPageTable, virtual_address_allocator::VirtualAddressAllocator,
};
use oak_channel::Channel;
use oak_core::sync::OnceCell;
Expand All @@ -81,7 +81,7 @@ use strum::{EnumIter, EnumString, IntoEnumIterator};
#[cfg(not(feature = "initrd"))]
use x86_64::structures::paging::{PageSize, Size4KiB};
use x86_64::{
structures::paging::{Page, Size2MiB},
structures::paging::{Page, PageTable, Size2MiB},
PhysAddr, VirtAddr,
};
use zerocopy::FromBytes;
Expand All @@ -105,6 +105,11 @@ pub static GUEST_HOST_HEAP: OnceCell<LockedHeap> = OnceCell::new();
pub static PAGE_TABLES: Spinlock<CurrentRootPageTable> =
Spinlock::new(CurrentRootPageTable::empty());

/// Level 4 page table that is free in application space, but has all entries for kernel space
/// populated. It can be used to create free page tables for applications, that maintain correct
/// mapping in kernel space.
pub static BASE_L4_PAGE_TABLE: OnceCell<(PageTable, MemoryEncryption)> = OnceCell::new();

/// Allocator for long-lived pages in the kernel.
pub static VMA_ALLOCATOR: Spinlock<VirtualAddressAllocator<Size2MiB>> =
Spinlock::new(VirtualAddressAllocator::new(Page::range(
Expand Down Expand Up @@ -187,6 +192,20 @@ pub fn start_kernel(info: &BootParams) -> ! {
prev_page_table.is_none(),
"there should be no previous page table during initialization"
);

// Safety: We just created a page table at this location.
let pml4: &PageTable = unsafe {
&*(PAGE_TABLES
.lock()
.get()
.unwrap()
.translate_physical(PhysAddr::new(pml4_frame.start_address().as_u64()))
.expect("page table must map to virtual address"))
.as_ptr()
};
BASE_L4_PAGE_TABLE
.set((pml4.clone(), encrypted))
.expect("base pml4 not unset");
};

// Re-map boot params to the new virtual address.
Expand Down
21 changes: 19 additions & 2 deletions oak_restricted_kernel/src/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use x86_64::{
structures::paging::{
mapper::{FlagUpdateError, MapToError, MapperFlush, UnmapError},
FrameAllocator, Page, PageSize, PageTable, PageTableFlags as BasePageTableFlags, PhysFrame,
Size2MiB,
Size2MiB, Size4KiB,
},
PhysAddr, VirtAddr,
};
Expand Down Expand Up @@ -290,7 +290,7 @@ pub fn initial_pml4(
// Safety: this expects the frame allocator to be initialized and the memory region it's handing
// memory out of to be identity mapped. This is true for the lower 2 GiB after we boot.
// This reference will no longer be valid after we reload the page tables!
let pml4_frame = FRAME_ALLOCATOR
let pml4_frame: PhysFrame<Size4KiB> = FRAME_ALLOCATOR
.lock()
.allocate_frame()
.ok_or("couldn't allocate a frame for PML4")?;
Expand All @@ -307,6 +307,23 @@ pub fn initial_pml4(
MemoryEncryption::NoEncryption
};

// Populate all the kernel space entries of the level 4 page table. This means that these
// entries should never change, memory allocation will happen on lower level page tables. This
// is done to permit the kernel to switch between different level 4 page tables in the future.
// All page tables that include these mappings will point to the same lower level page tables /
// memory in kernel space.
{
let mut fa = FRAME_ALLOCATOR.lock();
for entry in pml4.iter_mut().skip(256) {
let pml3_frame: PhysFrame<Size4KiB> = fa
.allocate_frame()
.ok_or("couldn't allocate a frame for PML3")?;
let pml3 = unsafe { &mut *(pml3_frame.start_address().as_u64() as *mut PageTable) };
pml3.zero();
entry.set_frame(pml3_frame, PageTableFlags::PRESENT.into());
}
};

let mut page_table = EncryptedPageTable::new(pml4, VirtAddr::new(0), encrypted);

// Safety: these operations are safe as they're not done on active page tables.
Expand Down
13 changes: 5 additions & 8 deletions oak_restricted_kernel/src/syscall/switch_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,11 @@ pub fn syscall_unstable_switch_proccess(buf: *mut c_void, count: c_size_t) -> !
let application = crate::payload::Application::new(copied_elf_binary.into_boxed_slice())
.expect("failed to parse application");

// Ensure the page table is not dropped.
let pml4 = Box::leak(Box::new(PageTable::new()));
let encryption = crate::PAGE_TABLES
.lock()
let (base_pml4, encrypted) = crate::BASE_L4_PAGE_TABLE
.get()
.expect("page tables must exist to switch applications")
.inner()
.copy_kernel_space(pml4);
.expect("base l4 table should be set");
// Ensure the new page table is not dropped.
let pml4 = Box::leak(Box::new(base_pml4.clone()));

let pml4_frame = {
let phys_addr = {
Expand All @@ -61,7 +58,7 @@ pub fn syscall_unstable_switch_proccess(buf: *mut c_void, count: c_size_t) -> !
};

// Safety: the new page table maintains the same mappings for kernel space.
unsafe { crate::PAGE_TABLES.lock().replace(pml4_frame, encryption) };
unsafe { crate::PAGE_TABLES.lock().replace(pml4_frame, *encrypted) };
// Safety: we've loaded the Restricted Application. Whether that's valid or not is no longer
// under the kernel's control.
unsafe { application.run() }
Expand Down
35 changes: 26 additions & 9 deletions oak_restricted_kernel_dice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,15 @@

extern crate alloc;

use alloc::vec;

use coset::{cbor::Value, cwt::ClaimName, CborSerializable};
use hkdf::Hkdf;
use oak_crypto::encryption_key::generate_encryption_key_pair;
use oak_dice::cert::{ENCLAVE_APPLICATION_LAYER_ID, LAYER_2_CODE_MEASUREMENT_ID, SHA2_256_ID};
use oak_dice::cert::{
ENCLAVE_APPLICATION_LAYER_ID, FINAL_LAYER_CONFIG_MEASUREMENT_ID, LAYER_2_CODE_MEASUREMENT_ID,
SHA2_256_ID,
};
use sha2::{Digest, Sha256};

/// A derived sealing key.
Expand Down Expand Up @@ -85,15 +90,27 @@ pub fn generate_dice_data(
let (application_private_signing_key, application_public_verifying_key) =
oak_dice::cert::generate_ecdsa_key_pair();

let additional_claims = alloc::vec![(
let additional_claims = vec![(
ClaimName::PrivateUse(ENCLAVE_APPLICATION_LAYER_ID),
Value::Map(alloc::vec![(
Value::Integer(LAYER_2_CODE_MEASUREMENT_ID.into()),
Value::Map(alloc::vec![(
Value::Integer(SHA2_256_ID.into()),
Value::Bytes(app_digest.into()),
)]),
),]),
Value::Map(vec![
(
Value::Integer(LAYER_2_CODE_MEASUREMENT_ID.into()),
Value::Map(vec![(
Value::Integer(SHA2_256_ID.into()),
Value::Bytes(app_digest.into()),
)]),
),
(
Value::Integer(FINAL_LAYER_CONFIG_MEASUREMENT_ID.into()),
Value::Map(vec![(
Value::Integer(SHA2_256_ID.into()),
// There currently exists no application config for enclave
// applications. Hence this field should
// always be empty.
Value::Bytes([0; 0].into()),
)]),
),
]),
)];

let application_signing_public_key_certificate =
Expand Down

0 comments on commit a83d353

Please sign in to comment.