From 57a735a93aade5157368d339b5082ee78e6981f5 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 7 Sep 2023 11:14:51 -0700 Subject: [PATCH 01/15] Stage0 attestation * Generate Stage0 and Stage1 CA keys * Sign Stage1 CA keys with Stage0 keys * Package the data in CWT format --- Cargo.lock | 60 ++++ stage0/Cargo.toml | 5 + stage0/src/lib.rs | 109 ++++++++ stage0_bin/Cargo.lock | 256 ++++++++++++++++++ .../Cargo.lock | 67 +++++ 5 files changed, 497 insertions(+) create mode 100644 third_party/rust-hypervisor-firmware-virtio/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index cc87e0667ff..650aae93e0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -430,6 +430,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -556,6 +583,16 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "coset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c765a4e852cef25c69a48e9fcd60995a7fecabf0134a0021e7181452c4a60f95" +dependencies = [ + "ciborium", + "ciborium-io", +] + [[package]] name = "cpufeatures" version = "0.2.8" @@ -1033,6 +1070,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hashbrown" version = "0.12.3" @@ -2248,12 +2291,17 @@ name = "oak_stage0" version = "0.1.0" dependencies = [ "bitflags 2.3.3", + "coset", "elf", + "hex", + "hkdf", "linked_list_allocator", "log", "oak_core", "oak_linux_boot_params", "oak_sev_guest", + "p384", + "rand_core 0.6.4", "sev_serial", "sha2", "spinning_top", @@ -2356,6 +2404,18 @@ dependencies = [ "sha2", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "paste" version = "1.0.12" diff --git a/stage0/Cargo.toml b/stage0/Cargo.toml index cc062758ee9..76c8a0faae1 100644 --- a/stage0/Cargo.toml +++ b/stage0/Cargo.toml @@ -20,3 +20,8 @@ static_assertions = "*" strum = { version = "*", default-features = false, features = ["derive"] } x86_64 = "*" zerocopy = "*" +p384 = { version = "0.13.0", default-features = false, features = ["ecdsa"]} +hkdf = {version = "0.12.3", default-features = false} +rand_core = {version = "0.6.4", default-features = false, features = ["getrandom"]} +hex = { version = "0.4", default-features = false, features = ["alloc"] } +coset = {version = "0.3.4", default-features = false} \ No newline at end of file diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 49e0e052820..2ae71766a6e 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -38,6 +38,12 @@ use x86_64::{ }; use zerocopy::AsBytes; +use alloc::{string::String, vec::Vec}; +use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; +use hkdf::Hkdf; +use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; +use rand_core::OsRng; + mod acpi; mod acpi_tables; mod allocator; @@ -59,6 +65,9 @@ type Measurement = [u8; 32]; // Reserve 128K for boot data structures that will outlive Stage 0. static BOOT_ALLOC: allocator::BumpAllocator<0x20000> = allocator::BumpAllocator::uninit(); +pub const ID_SALT: &str = "DICE_ID_SALT"; +pub const SIGNATURE_LENGTH: usize = 20; + // Heap for short-term allocations. These allocations are not expected to outlive Stage 0. #[cfg_attr(not(test), global_allocator)] static SHORT_TERM_ALLOC: LockedHeap = LockedHeap::empty(); @@ -118,6 +127,104 @@ pub fn sev_status() -> SevStatus { unsafe { SEV_STATUS } } +/// Attestation related functions +/// +/// Returns Signed Stage1 key and measurments +struct Stage0Signer { + signing_key: SigningKey, +} + +// Signer implementation. +impl Stage0Signer { + fn sign(&self, data: &[u8]) -> Vec { + let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); + Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) + } +} + +fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { + let hkdf = Hkdf::::new(Some(&(ID_SALT.as_bytes().to_vec())), &ikm); + let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + hkdf.expand(info.unwrap_or(&[]), &mut okm) + .expect("20 is a valid length for Sha256 to output"); + + okm +} + +fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { + let key = SigningKey::random(&mut OsRng); + let public_key = VerifyingKey::from(&key); + let key_id = derive_id( + public_key.to_encoded_point(false).as_bytes(), + Some(info.as_bytes()), + ); + (key, key_id) +} + +fn generate_stage1_ca_cwt( + stage0_eca_key: SigningKey, + stage0_cert_id_hex: String, +) -> Result, CoseError> { + // Generate Stage 1 keys and Signer. + let info_str = "ID"; + let stage1_ca_key = generate_ecdsa_keys(info_str); + let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); + let stage0_signer = Stage0Signer { + signing_key: stage0_eca_key, + }; + + // Generate claims + let claims = cwt::ClaimsSetBuilder::new() + .issuer(stage0_cert_id_hex) + .subject(hex::encode(stage1_ca_key.1)) + .cwt_id(Vec::from(stage1_ca_key.1)) + // Add additional private-use claim. + .private_claim( + -4670552, + Value::Bytes(Vec::from( + stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), + )), + ) + .build(); + + let aad = b""; + + // Build a `CoseSign1` object. + let protected = coset::HeaderBuilder::new() + .algorithm(iana::Algorithm::ES384) + .build(); + let unprotected = coset::HeaderBuilder::new() + .key_id((*b"AsymmetricECDSA384").into()) + .build(); + let sign1 = coset::CoseSign1Builder::new() + .protected(protected) + .unprotected(unprotected) + .payload(claims.clone().to_vec()?) + .create_signature(aad, |data| stage0_signer.sign(data)) + .build(); + sign1.to_vec() +} + +pub fn generate_stage1_attestation() { + // Generate Stage0 keys. This key will be used to sign Stage1 + // measurement+config and the stage1_ca_key + let info_str = "ID"; + let stage0_ca_key = generate_ecdsa_keys(info_str); + let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); + + // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. + log::debug!( + "Stage0 Verification key: {}", + hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) + ); + + // Generate Stage1 CWT + let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); + if stage1_cwt.is_ok() { + // Call code that transmits the serialized cwt to Stage1 + } +} + /// Entry point for the Rust code in the stage0 BIOS. /// /// # Arguments @@ -231,6 +338,8 @@ pub fn rust64_start(encrypted: u64) -> ! { }) .unwrap_or_default(); + generate_stage1_attestation(); + let kernel_info = kernel::try_load_kernel_image(&mut fwcfg, zero_page.e820_table()) .unwrap_or(kernel::KernelInfo::default()); let mut entry = kernel_info.entry; diff --git a/stage0_bin/Cargo.lock b/stage0_bin/Cargo.lock index 955a36f66bb..07305eea785 100644 --- a/stage0_bin/Cargo.lock +++ b/stage0_bin/Cargo.lock @@ -8,6 +8,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "bit_field" version = "0.10.2" @@ -47,6 +53,49 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "coset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c765a4e852cef25c69a48e9fcd60995a7fecabf0134a0021e7181452c4a60f95" +dependencies = [ + "ciborium", + "ciborium-io", +] + [[package]] name = "cpufeatures" version = "0.2.9" @@ -56,6 +105,18 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -66,6 +127,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -73,7 +144,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -82,12 +155,53 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "elf" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2b183d6ce6ca4cf30e3db37abf5b52568b5f9015c97d9fbdd7026aa5dcdd758" +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -96,6 +210,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -109,12 +224,53 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "heck" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "libc" version = "0.2.144" @@ -186,12 +342,17 @@ name = "oak_stage0" version = "0.1.0" dependencies = [ "bitflags 2.4.0", + "coset", "elf", + "hex", + "hkdf", "linked_list_allocator", "log", "oak_core", "oak_linux_boot_params", "oak_sev_guest", + "p384", + "rand_core", "sev_serial", "sha2", "spinning_top", @@ -208,6 +369,27 @@ dependencies = [ "oak_stage0", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "primeorder" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.63" @@ -226,6 +408,25 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -238,6 +439,39 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sev_serial" version = "0.1.0" @@ -257,6 +491,16 @@ dependencies = [ "digest", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "snafu" version = "0.7.1" @@ -316,6 +560,12 @@ dependencies = [ "syn", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.101" @@ -407,3 +657,9 @@ dependencies = [ "syn", "synstructure", ] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/third_party/rust-hypervisor-firmware-virtio/Cargo.lock b/third_party/rust-hypervisor-firmware-virtio/Cargo.lock new file mode 100644 index 00000000000..281fcbeaaed --- /dev/null +++ b/third_party/rust-hypervisor-firmware-virtio/Cargo.lock @@ -0,0 +1,67 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atomic_refcell" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112ef6b3f6cb3cb6fc5b6b494ef7a848492cff1ab0ef4de10b0f7d572861c905" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "rust-hypervisor-firmware-virtio" +version = "0.1.0" +dependencies = [ + "atomic_refcell", + "bitflags 2.4.0", + "log", + "x86_64", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "volatile" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" + +[[package]] +name = "x86_64" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" +dependencies = [ + "bit_field", + "bitflags 1.3.2", + "rustversion", + "volatile", +] From 452d52c160170578f51e2083828f2f0310562240 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 7 Sep 2023 11:14:51 -0700 Subject: [PATCH 02/15] Stage0 attestation * Generate Stage0 and Stage1 CA keys * Sign Stage1 CA keys with Stage0 keys * Package the data in CWT format --- Cargo.lock | 60 ++++ stage0/Cargo.toml | 5 + stage0/src/lib.rs | 109 ++++++++ stage0_bin/Cargo.lock | 256 ++++++++++++++++++ stage0_bin/build.rs | 2 +- .../Cargo.lock | 67 +++++ 6 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 third_party/rust-hypervisor-firmware-virtio/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index cc87e0667ff..650aae93e0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -430,6 +430,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -556,6 +583,16 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "coset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c765a4e852cef25c69a48e9fcd60995a7fecabf0134a0021e7181452c4a60f95" +dependencies = [ + "ciborium", + "ciborium-io", +] + [[package]] name = "cpufeatures" version = "0.2.8" @@ -1033,6 +1070,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hashbrown" version = "0.12.3" @@ -2248,12 +2291,17 @@ name = "oak_stage0" version = "0.1.0" dependencies = [ "bitflags 2.3.3", + "coset", "elf", + "hex", + "hkdf", "linked_list_allocator", "log", "oak_core", "oak_linux_boot_params", "oak_sev_guest", + "p384", + "rand_core 0.6.4", "sev_serial", "sha2", "spinning_top", @@ -2356,6 +2404,18 @@ dependencies = [ "sha2", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "paste" version = "1.0.12" diff --git a/stage0/Cargo.toml b/stage0/Cargo.toml index cc062758ee9..76c8a0faae1 100644 --- a/stage0/Cargo.toml +++ b/stage0/Cargo.toml @@ -20,3 +20,8 @@ static_assertions = "*" strum = { version = "*", default-features = false, features = ["derive"] } x86_64 = "*" zerocopy = "*" +p384 = { version = "0.13.0", default-features = false, features = ["ecdsa"]} +hkdf = {version = "0.12.3", default-features = false} +rand_core = {version = "0.6.4", default-features = false, features = ["getrandom"]} +hex = { version = "0.4", default-features = false, features = ["alloc"] } +coset = {version = "0.3.4", default-features = false} \ No newline at end of file diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 49e0e052820..7dcea5e6cd1 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -38,6 +38,12 @@ use x86_64::{ }; use zerocopy::AsBytes; +use alloc::{string::String, vec::Vec}; +use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; +use hkdf::Hkdf; +use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; +use rand_core::OsRng; + mod acpi; mod acpi_tables; mod allocator; @@ -59,6 +65,9 @@ type Measurement = [u8; 32]; // Reserve 128K for boot data structures that will outlive Stage 0. static BOOT_ALLOC: allocator::BumpAllocator<0x20000> = allocator::BumpAllocator::uninit(); +pub const ID_SALT: &str = "DICE_ID_SALT"; +pub const SIGNATURE_LENGTH: usize = 20; + // Heap for short-term allocations. These allocations are not expected to outlive Stage 0. #[cfg_attr(not(test), global_allocator)] static SHORT_TERM_ALLOC: LockedHeap = LockedHeap::empty(); @@ -118,6 +127,104 @@ pub fn sev_status() -> SevStatus { unsafe { SEV_STATUS } } +/// Attestation related functions +/// +/// Returns Signed Stage1 key and measurments +struct Stage0Signer { + signing_key: SigningKey, +} + +// Signer implementation. +impl Stage0Signer { + fn sign(&self, data: &[u8]) -> Vec { + let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); + Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) + } +} + +fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { + let hkdf = Hkdf::::new(Some(&(ID_SALT.as_bytes())), ikm); + let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + hkdf.expand(info.unwrap_or(&[]), &mut okm) + .expect("20 is a valid length for Sha256 to output"); + + okm +} + +fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { + let key = SigningKey::random(&mut OsRng); + let public_key = VerifyingKey::from(&key); + let key_id = derive_id( + public_key.to_encoded_point(false).as_bytes(), + Some(info.as_bytes()), + ); + (key, key_id) +} + +fn generate_stage1_ca_cwt( + stage0_eca_key: SigningKey, + stage0_cert_id_hex: String, +) -> Result, CoseError> { + // Generate Stage 1 keys and Signer. + let info_str = "ID"; + let stage1_ca_key = generate_ecdsa_keys(info_str); + let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); + let stage0_signer = Stage0Signer { + signing_key: stage0_eca_key, + }; + + // Generate claims + let claims = cwt::ClaimsSetBuilder::new() + .issuer(stage0_cert_id_hex) + .subject(hex::encode(stage1_ca_key.1)) + .cwt_id(Vec::from(stage1_ca_key.1)) + // Add additional private-use claim. + .private_claim( + -4670552, + Value::Bytes(Vec::from( + stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), + )), + ) + .build(); + + let aad = b""; + + // Build a `CoseSign1` object. + let protected = coset::HeaderBuilder::new() + .algorithm(iana::Algorithm::ES384) + .build(); + let unprotected = coset::HeaderBuilder::new() + .key_id((*b"AsymmetricECDSA384").into()) + .build(); + let sign1 = coset::CoseSign1Builder::new() + .protected(protected) + .unprotected(unprotected) + .payload(claims.clone().to_vec()?) + .create_signature(aad, |data| stage0_signer.sign(data)) + .build(); + sign1.to_vec() +} + +pub fn generate_stage1_attestation() { + // Generate Stage0 keys. This key will be used to sign Stage1 + // measurement+config and the stage1_ca_key + let info_str = "ID"; + let stage0_ca_key = generate_ecdsa_keys(info_str); + let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); + + // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. + log::debug!( + "Stage0 Verification key: {}", + hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) + ); + + // Generate Stage1 CWT + let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); + if stage1_cwt.is_ok() { + // Call code that transmits the serialized cwt to Stage1 + } +} + /// Entry point for the Rust code in the stage0 BIOS. /// /// # Arguments @@ -231,6 +338,8 @@ pub fn rust64_start(encrypted: u64) -> ! { }) .unwrap_or_default(); + generate_stage1_attestation(); + let kernel_info = kernel::try_load_kernel_image(&mut fwcfg, zero_page.e820_table()) .unwrap_or(kernel::KernelInfo::default()); let mut entry = kernel_info.entry; diff --git a/stage0_bin/Cargo.lock b/stage0_bin/Cargo.lock index 955a36f66bb..07305eea785 100644 --- a/stage0_bin/Cargo.lock +++ b/stage0_bin/Cargo.lock @@ -8,6 +8,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "bit_field" version = "0.10.2" @@ -47,6 +53,49 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "coset" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c765a4e852cef25c69a48e9fcd60995a7fecabf0134a0021e7181452c4a60f95" +dependencies = [ + "ciborium", + "ciborium-io", +] + [[package]] name = "cpufeatures" version = "0.2.9" @@ -56,6 +105,18 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -66,6 +127,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -73,7 +144,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -82,12 +155,53 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + [[package]] name = "elf" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2b183d6ce6ca4cf30e3db37abf5b52568b5f9015c97d9fbdd7026aa5dcdd758" +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -96,6 +210,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -109,12 +224,53 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "heck" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "libc" version = "0.2.144" @@ -186,12 +342,17 @@ name = "oak_stage0" version = "0.1.0" dependencies = [ "bitflags 2.4.0", + "coset", "elf", + "hex", + "hkdf", "linked_list_allocator", "log", "oak_core", "oak_linux_boot_params", "oak_sev_guest", + "p384", + "rand_core", "sev_serial", "sha2", "spinning_top", @@ -208,6 +369,27 @@ dependencies = [ "oak_stage0", ] +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "primeorder" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.63" @@ -226,6 +408,25 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -238,6 +439,39 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sev_serial" version = "0.1.0" @@ -257,6 +491,16 @@ dependencies = [ "digest", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "snafu" version = "0.7.1" @@ -316,6 +560,12 @@ dependencies = [ "syn", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.101" @@ -407,3 +657,9 @@ dependencies = [ "syn", "synstructure", ] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/stage0_bin/build.rs b/stage0_bin/build.rs index db7de761a57..a20d4cac2ca 100644 --- a/stage0_bin/build.rs +++ b/stage0_bin/build.rs @@ -21,7 +21,7 @@ fn main() { println!("cargo:rustc-link-arg=--script=layout.ld"); if env::var("PROFILE").unwrap() == "release" { - println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=128K"); + println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=384K"); } else { println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=512K"); } diff --git a/third_party/rust-hypervisor-firmware-virtio/Cargo.lock b/third_party/rust-hypervisor-firmware-virtio/Cargo.lock new file mode 100644 index 00000000000..281fcbeaaed --- /dev/null +++ b/third_party/rust-hypervisor-firmware-virtio/Cargo.lock @@ -0,0 +1,67 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atomic_refcell" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112ef6b3f6cb3cb6fc5b6b494ef7a848492cff1ab0ef4de10b0f7d572861c905" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "rust-hypervisor-firmware-virtio" +version = "0.1.0" +dependencies = [ + "atomic_refcell", + "bitflags 2.4.0", + "log", + "x86_64", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "volatile" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" + +[[package]] +name = "x86_64" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" +dependencies = [ + "bit_field", + "bitflags 1.3.2", + "rustversion", + "volatile", +] From 3710dc757a562680485461471214ba12d014d98e Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 7 Sep 2023 15:35:35 -0700 Subject: [PATCH 03/15] Move the attestation related code to different file. --- stage0/src/dice_attestation.rs | 129 +++++++++++++++++++++++++++++++++ stage0/src/lib.rs | 110 +--------------------------- 2 files changed, 131 insertions(+), 108 deletions(-) create mode 100644 stage0/src/dice_attestation.rs diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs new file mode 100644 index 00000000000..9ba849e9b25 --- /dev/null +++ b/stage0/src/dice_attestation.rs @@ -0,0 +1,129 @@ +// +// Copyright 2022 The Project Oak Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +extern crate alloc; + +use alloc::{string::String, vec::Vec}; +use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; +use hkdf::Hkdf; +use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; +use rand_core::OsRng; +use sha2::Sha256; + + +pub const ID_SALT: &str = "DICE_ID_SALT"; +pub const SIGNATURE_LENGTH: usize = 20; + +/// Attestation related functions +/// +/// Returns Signed Stage1 key and measurments +struct Stage0Signer { + signing_key: SigningKey, +} + +// Signer implementation. +impl Stage0Signer { + fn sign(&self, data: &[u8]) -> Vec { + let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); + Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) + } +} + +fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { + let hkdf = Hkdf::::new(Some(&(ID_SALT.as_bytes())), ikm); + let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + hkdf.expand(info.unwrap_or(&[]), &mut okm) + .expect("20 is a valid length for Sha256 to output"); + + okm +} + +fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { + let key = SigningKey::random(&mut OsRng); + let public_key = VerifyingKey::from(&key); + let key_id = derive_id( + public_key.to_encoded_point(false).as_bytes(), + Some(info.as_bytes()), + ); + (key, key_id) +} + +fn generate_stage1_ca_cwt( + stage0_eca_key: SigningKey, + stage0_cert_id_hex: String, +) -> Result, CoseError> { + // Generate Stage 1 keys and Signer. + let info_str = "ID"; + let stage1_ca_key = generate_ecdsa_keys(info_str); + let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); + let stage0_signer = Stage0Signer { + signing_key: stage0_eca_key, + }; + + // Generate claims + let claims = cwt::ClaimsSetBuilder::new() + .issuer(stage0_cert_id_hex) + .subject(hex::encode(stage1_ca_key.1)) + .cwt_id(Vec::from(stage1_ca_key.1)) + // Add additional private-use claim. + .private_claim( + -4670552, + Value::Bytes(Vec::from( + stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), + )), + ) + .build(); + + let aad = b""; + + // Build a `CoseSign1` object. + let protected = coset::HeaderBuilder::new() + .algorithm(iana::Algorithm::ES384) + .build(); + let unprotected = coset::HeaderBuilder::new() + .key_id((*b"AsymmetricECDSA384").into()) + .build(); + let sign1 = coset::CoseSign1Builder::new() + .protected(protected) + .unprotected(unprotected) + .payload(claims.clone().to_vec()?) + .create_signature(aad, |data| stage0_signer.sign(data)) + .build(); + sign1.to_vec() +} + +pub fn generate_stage1_attestation() { + // Generate Stage0 keys. This key will be used to sign Stage1 + // measurement+config and the stage1_ca_key + let info_str = "ID"; + let stage0_ca_key = generate_ecdsa_keys(info_str); + let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); + + // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. + log::debug!( + "Stage0 Verification key: {}", + hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) + ); + + // Generate Stage1 CWT + let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); + if stage1_cwt.is_ok() { + // Call code that transmits the serialized cwt to Stage1 + log::debug!("Signing was successful.."); + return; + } + log::debug!("Error in signing: {}", stage1_cwt.unwrap_err()) +} \ No newline at end of file diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 7dcea5e6cd1..9fe6859770d 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -38,12 +38,6 @@ use x86_64::{ }; use zerocopy::AsBytes; -use alloc::{string::String, vec::Vec}; -use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; -use hkdf::Hkdf; -use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; -use rand_core::OsRng; - mod acpi; mod acpi_tables; mod allocator; @@ -59,15 +53,13 @@ mod pic; mod sev; mod smp; mod zero_page; +mod dice_attestation; type Measurement = [u8; 32]; // Reserve 128K for boot data structures that will outlive Stage 0. static BOOT_ALLOC: allocator::BumpAllocator<0x20000> = allocator::BumpAllocator::uninit(); -pub const ID_SALT: &str = "DICE_ID_SALT"; -pub const SIGNATURE_LENGTH: usize = 20; - // Heap for short-term allocations. These allocations are not expected to outlive Stage 0. #[cfg_attr(not(test), global_allocator)] static SHORT_TERM_ALLOC: LockedHeap = LockedHeap::empty(); @@ -127,104 +119,6 @@ pub fn sev_status() -> SevStatus { unsafe { SEV_STATUS } } -/// Attestation related functions -/// -/// Returns Signed Stage1 key and measurments -struct Stage0Signer { - signing_key: SigningKey, -} - -// Signer implementation. -impl Stage0Signer { - fn sign(&self, data: &[u8]) -> Vec { - let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); - Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) - } -} - -fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { - let hkdf = Hkdf::::new(Some(&(ID_SALT.as_bytes())), ikm); - let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - hkdf.expand(info.unwrap_or(&[]), &mut okm) - .expect("20 is a valid length for Sha256 to output"); - - okm -} - -fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { - let key = SigningKey::random(&mut OsRng); - let public_key = VerifyingKey::from(&key); - let key_id = derive_id( - public_key.to_encoded_point(false).as_bytes(), - Some(info.as_bytes()), - ); - (key, key_id) -} - -fn generate_stage1_ca_cwt( - stage0_eca_key: SigningKey, - stage0_cert_id_hex: String, -) -> Result, CoseError> { - // Generate Stage 1 keys and Signer. - let info_str = "ID"; - let stage1_ca_key = generate_ecdsa_keys(info_str); - let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); - let stage0_signer = Stage0Signer { - signing_key: stage0_eca_key, - }; - - // Generate claims - let claims = cwt::ClaimsSetBuilder::new() - .issuer(stage0_cert_id_hex) - .subject(hex::encode(stage1_ca_key.1)) - .cwt_id(Vec::from(stage1_ca_key.1)) - // Add additional private-use claim. - .private_claim( - -4670552, - Value::Bytes(Vec::from( - stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), - )), - ) - .build(); - - let aad = b""; - - // Build a `CoseSign1` object. - let protected = coset::HeaderBuilder::new() - .algorithm(iana::Algorithm::ES384) - .build(); - let unprotected = coset::HeaderBuilder::new() - .key_id((*b"AsymmetricECDSA384").into()) - .build(); - let sign1 = coset::CoseSign1Builder::new() - .protected(protected) - .unprotected(unprotected) - .payload(claims.clone().to_vec()?) - .create_signature(aad, |data| stage0_signer.sign(data)) - .build(); - sign1.to_vec() -} - -pub fn generate_stage1_attestation() { - // Generate Stage0 keys. This key will be used to sign Stage1 - // measurement+config and the stage1_ca_key - let info_str = "ID"; - let stage0_ca_key = generate_ecdsa_keys(info_str); - let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); - - // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. - log::debug!( - "Stage0 Verification key: {}", - hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) - ); - - // Generate Stage1 CWT - let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); - if stage1_cwt.is_ok() { - // Call code that transmits the serialized cwt to Stage1 - } -} - /// Entry point for the Rust code in the stage0 BIOS. /// /// # Arguments @@ -338,7 +232,7 @@ pub fn rust64_start(encrypted: u64) -> ! { }) .unwrap_or_default(); - generate_stage1_attestation(); + dice_attestation::generate_stage1_attestation(); let kernel_info = kernel::try_load_kernel_image(&mut fwcfg, zero_page.e820_table()) .unwrap_or(kernel::KernelInfo::default()); From 4f6d3e29d2b3a912df01681e94627e3becf394d9 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 7 Sep 2023 15:35:35 -0700 Subject: [PATCH 04/15] Move the attestation related code to different file. --- stage0/src/dice_attestation.rs | 129 +++++++++++++++++++++++++++++++++ stage0/src/lib.rs | 110 +--------------------------- 2 files changed, 131 insertions(+), 108 deletions(-) create mode 100644 stage0/src/dice_attestation.rs diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs new file mode 100644 index 00000000000..303c5a034e2 --- /dev/null +++ b/stage0/src/dice_attestation.rs @@ -0,0 +1,129 @@ +// +// Copyright 2022 The Project Oak Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +extern crate alloc; + +use alloc::{string::String, vec::Vec}; +use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; +use hkdf::Hkdf; +use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; +use rand_core::OsRng; +use sha2::Sha256; + + +pub const ID_SALT: &str = "DICE_ID_SALT"; +pub const SIGNATURE_LENGTH: usize = 20; + +/// Attestation related functions +/// +/// Returns Signed Stage1 key and measurments +struct Stage0Signer { + signing_key: SigningKey, +} + +// Signer implementation. +impl Stage0Signer { + fn sign(&self, data: &[u8]) -> Vec { + let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); + Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) + } +} + +fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { + let hkdf = Hkdf::::new(Some(ID_SALT.as_bytes()), ikm); + let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + hkdf.expand(info.unwrap_or(&[]), &mut okm) + .expect("20 is a valid length for Sha256 to output"); + + okm +} + +fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { + let key = SigningKey::random(&mut OsRng); + let public_key = VerifyingKey::from(&key); + let key_id = derive_id( + public_key.to_encoded_point(false).as_bytes(), + Some(info.as_bytes()), + ); + (key, key_id) +} + +fn generate_stage1_ca_cwt( + stage0_eca_key: SigningKey, + stage0_cert_id_hex: String, +) -> Result, CoseError> { + // Generate Stage 1 keys and Signer. + let info_str = "ID"; + let stage1_ca_key = generate_ecdsa_keys(info_str); + let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); + let stage0_signer = Stage0Signer { + signing_key: stage0_eca_key, + }; + + // Generate claims + let claims = cwt::ClaimsSetBuilder::new() + .issuer(stage0_cert_id_hex) + .subject(hex::encode(stage1_ca_key.1)) + .cwt_id(Vec::from(stage1_ca_key.1)) + // Add additional private-use claim. + .private_claim( + -4670552, + Value::Bytes(Vec::from( + stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), + )), + ) + .build(); + + let aad = b""; + + // Build a `CoseSign1` object. + let protected = coset::HeaderBuilder::new() + .algorithm(iana::Algorithm::ES384) + .build(); + let unprotected = coset::HeaderBuilder::new() + .key_id((*b"AsymmetricECDSA384").into()) + .build(); + let sign1 = coset::CoseSign1Builder::new() + .protected(protected) + .unprotected(unprotected) + .payload(claims.clone().to_vec()?) + .create_signature(aad, |data| stage0_signer.sign(data)) + .build(); + sign1.to_vec() +} + +pub fn generate_stage1_attestation() { + // Generate Stage0 keys. This key will be used to sign Stage1 + // measurement+config and the stage1_ca_key + let info_str = "ID"; + let stage0_ca_key = generate_ecdsa_keys(info_str); + let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); + + // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. + log::debug!( + "Stage0 Verification key: {}", + hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) + ); + + // Generate Stage1 CWT + let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); + if stage1_cwt.is_ok() { + // Call code that transmits the serialized cwt to Stage1 + log::debug!("Signing was successful.."); + return; + } + log::debug!("Error in signing: {}", stage1_cwt.unwrap_err()) +} \ No newline at end of file diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 7dcea5e6cd1..9fe6859770d 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -38,12 +38,6 @@ use x86_64::{ }; use zerocopy::AsBytes; -use alloc::{string::String, vec::Vec}; -use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; -use hkdf::Hkdf; -use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; -use rand_core::OsRng; - mod acpi; mod acpi_tables; mod allocator; @@ -59,15 +53,13 @@ mod pic; mod sev; mod smp; mod zero_page; +mod dice_attestation; type Measurement = [u8; 32]; // Reserve 128K for boot data structures that will outlive Stage 0. static BOOT_ALLOC: allocator::BumpAllocator<0x20000> = allocator::BumpAllocator::uninit(); -pub const ID_SALT: &str = "DICE_ID_SALT"; -pub const SIGNATURE_LENGTH: usize = 20; - // Heap for short-term allocations. These allocations are not expected to outlive Stage 0. #[cfg_attr(not(test), global_allocator)] static SHORT_TERM_ALLOC: LockedHeap = LockedHeap::empty(); @@ -127,104 +119,6 @@ pub fn sev_status() -> SevStatus { unsafe { SEV_STATUS } } -/// Attestation related functions -/// -/// Returns Signed Stage1 key and measurments -struct Stage0Signer { - signing_key: SigningKey, -} - -// Signer implementation. -impl Stage0Signer { - fn sign(&self, data: &[u8]) -> Vec { - let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); - Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) - } -} - -fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { - let hkdf = Hkdf::::new(Some(&(ID_SALT.as_bytes())), ikm); - let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - hkdf.expand(info.unwrap_or(&[]), &mut okm) - .expect("20 is a valid length for Sha256 to output"); - - okm -} - -fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { - let key = SigningKey::random(&mut OsRng); - let public_key = VerifyingKey::from(&key); - let key_id = derive_id( - public_key.to_encoded_point(false).as_bytes(), - Some(info.as_bytes()), - ); - (key, key_id) -} - -fn generate_stage1_ca_cwt( - stage0_eca_key: SigningKey, - stage0_cert_id_hex: String, -) -> Result, CoseError> { - // Generate Stage 1 keys and Signer. - let info_str = "ID"; - let stage1_ca_key = generate_ecdsa_keys(info_str); - let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); - let stage0_signer = Stage0Signer { - signing_key: stage0_eca_key, - }; - - // Generate claims - let claims = cwt::ClaimsSetBuilder::new() - .issuer(stage0_cert_id_hex) - .subject(hex::encode(stage1_ca_key.1)) - .cwt_id(Vec::from(stage1_ca_key.1)) - // Add additional private-use claim. - .private_claim( - -4670552, - Value::Bytes(Vec::from( - stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), - )), - ) - .build(); - - let aad = b""; - - // Build a `CoseSign1` object. - let protected = coset::HeaderBuilder::new() - .algorithm(iana::Algorithm::ES384) - .build(); - let unprotected = coset::HeaderBuilder::new() - .key_id((*b"AsymmetricECDSA384").into()) - .build(); - let sign1 = coset::CoseSign1Builder::new() - .protected(protected) - .unprotected(unprotected) - .payload(claims.clone().to_vec()?) - .create_signature(aad, |data| stage0_signer.sign(data)) - .build(); - sign1.to_vec() -} - -pub fn generate_stage1_attestation() { - // Generate Stage0 keys. This key will be used to sign Stage1 - // measurement+config and the stage1_ca_key - let info_str = "ID"; - let stage0_ca_key = generate_ecdsa_keys(info_str); - let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); - - // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. - log::debug!( - "Stage0 Verification key: {}", - hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) - ); - - // Generate Stage1 CWT - let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); - if stage1_cwt.is_ok() { - // Call code that transmits the serialized cwt to Stage1 - } -} - /// Entry point for the Rust code in the stage0 BIOS. /// /// # Arguments @@ -338,7 +232,7 @@ pub fn rust64_start(encrypted: u64) -> ! { }) .unwrap_or_default(); - generate_stage1_attestation(); + dice_attestation::generate_stage1_attestation(); let kernel_info = kernel::try_load_kernel_image(&mut fwcfg, zero_page.e820_table()) .unwrap_or(kernel::KernelInfo::default()); From 3f66c9d75230b1db54a41c707109471ca6d4980e Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Tue, 12 Sep 2023 10:23:58 -0700 Subject: [PATCH 05/15] Add code for signing measurements --- stage0/src/dice_attestation.rs | 44 ++++++++++++++++++++++++++++++---- stage0/src/lib.rs | 15 +++++++++--- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index 303c5a034e2..d9845219da7 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -23,7 +23,6 @@ use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; use rand_core::OsRng; use sha2::Sha256; - pub const ID_SALT: &str = "DICE_ID_SALT"; pub const SIGNATURE_LENGTH: usize = 20; @@ -33,6 +32,15 @@ pub const SIGNATURE_LENGTH: usize = 20; struct Stage0Signer { signing_key: SigningKey, } +// Measurements of various components in Stage1 +pub struct Measurements { + pub kernel_measurement: [u8; 32], + pub cmdline_measurement: [u8; 32], + pub setup_data_measurement: [u8; 32], + pub ram_disk_measurement: [u8; 32], + pub memory_map_measurement: [u8; 32], + pub acpi_measurement: [u8; 32], +} // Signer implementation. impl Stage0Signer { @@ -64,6 +72,7 @@ fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { fn generate_stage1_ca_cwt( stage0_eca_key: SigningKey, stage0_cert_id_hex: String, + measurements: &Measurements, ) -> Result, CoseError> { // Generate Stage 1 keys and Signer. let info_str = "ID"; @@ -73,7 +82,7 @@ fn generate_stage1_ca_cwt( signing_key: stage0_eca_key, }; - // Generate claims + // Generate claims and add the Stage1 CA key. let claims = cwt::ClaimsSetBuilder::new() .issuer(stage0_cert_id_hex) .subject(hex::encode(stage1_ca_key.1)) @@ -85,6 +94,30 @@ fn generate_stage1_ca_cwt( stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), )), ) + .private_claim( + -4670555, + Value::Bytes(Vec::from(measurements.kernel_measurement)), + ) + .private_claim( + -4670556, + Value::Bytes(Vec::from(measurements.kernel_measurement)), + ) + .private_claim( + -4670557, + Value::Bytes(Vec::from(measurements.setup_data_measurement)), + ) + .private_claim( + -4670558, + Value::Bytes(Vec::from(measurements.ram_disk_measurement)), + ) + .private_claim( + -4670559, + Value::Bytes(Vec::from(measurements.memory_map_measurement)), + ) + .private_claim( + -4670560, + Value::Bytes(Vec::from(measurements.acpi_measurement)), + ) .build(); let aad = b""; @@ -105,7 +138,7 @@ fn generate_stage1_ca_cwt( sign1.to_vec() } -pub fn generate_stage1_attestation() { +pub fn generate_stage1_attestation(measurements: &Measurements) { // Generate Stage0 keys. This key will be used to sign Stage1 // measurement+config and the stage1_ca_key let info_str = "ID"; @@ -119,11 +152,12 @@ pub fn generate_stage1_attestation() { ); // Generate Stage1 CWT - let stage1_cwt = generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1)); + let stage1_cwt = + generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1), measurements); if stage1_cwt.is_ok() { // Call code that transmits the serialized cwt to Stage1 log::debug!("Signing was successful.."); return; } log::debug!("Error in signing: {}", stage1_cwt.unwrap_err()) -} \ No newline at end of file +} diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 9fe6859770d..5fa3c32eba9 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -43,6 +43,7 @@ mod acpi_tables; mod allocator; mod apic; mod cmos; +mod dice_attestation; mod fw_cfg; mod initramfs; mod kernel; @@ -53,7 +54,6 @@ mod pic; mod sev; mod smp; mod zero_page; -mod dice_attestation; type Measurement = [u8; 32]; @@ -232,8 +232,6 @@ pub fn rust64_start(encrypted: u64) -> ! { }) .unwrap_or_default(); - dice_attestation::generate_stage1_attestation(); - let kernel_info = kernel::try_load_kernel_image(&mut fwcfg, zero_page.e820_table()) .unwrap_or(kernel::KernelInfo::default()); let mut entry = kernel_info.entry; @@ -307,6 +305,17 @@ pub fn rust64_start(encrypted: u64) -> ! { log::debug!("ACPI table generation digest: {:?}", acpi_measurement); log::debug!("E820 table digest: {:?}", memory_map_measurement); + let measurements = dice_attestation::Measurements { + acpi_measurement: acpi_measurement, + kernel_measurement: kernel_info.measurement, + cmdline_measurement: cmdline_measurement, + ram_disk_measurement: ram_disk_measurement, + setup_data_measurement: setup_data_measurement, + memory_map_measurement: memory_map_measurement, + }; + + dice_attestation::generate_stage1_attestation(&measurements); + log::info!("jumping to kernel at {:#018x}", entry.as_u64()); // Clean-ups we need to do just before we jump to the kernel proper: clean up the early GHCB and From 9fb044e4d73b6f10379c7fcf1777000ad5d1a760 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 21 Sep 2023 00:20:43 -0700 Subject: [PATCH 06/15] Address many of the review comments. --- stage0/Cargo.toml | 12 ++-- stage0/src/dice_attestation.rs | 127 +++++++++++++++++++++++---------- 2 files changed, 95 insertions(+), 44 deletions(-) diff --git a/stage0/Cargo.toml b/stage0/Cargo.toml index 76c8a0faae1..102c6c1cff8 100644 --- a/stage0/Cargo.toml +++ b/stage0/Cargo.toml @@ -20,8 +20,10 @@ static_assertions = "*" strum = { version = "*", default-features = false, features = ["derive"] } x86_64 = "*" zerocopy = "*" -p384 = { version = "0.13.0", default-features = false, features = ["ecdsa"]} -hkdf = {version = "0.12.3", default-features = false} -rand_core = {version = "0.6.4", default-features = false, features = ["getrandom"]} -hex = { version = "0.4", default-features = false, features = ["alloc"] } -coset = {version = "0.3.4", default-features = false} \ No newline at end of file +p384 = { version = "*", default-features = false, features = ["ecdsa"] } +hkdf = { version = "*", default-features = false } +rand_core = { version = "*", default-features = false, features = [ + "getrandom" +] } +hex = { version = "*", default-features = false, features = ["alloc"] } +coset = { version = "*", default-features = false } diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index d9845219da7..b83f2c9486e 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -1,5 +1,5 @@ // -// Copyright 2022 The Project Oak Authors +// Copyright 2023 The Project Oak Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,23 +16,42 @@ extern crate alloc; -use alloc::{string::String, vec::Vec}; -use coset::{cbor::value::Value, cwt, iana, CborSerializable, CoseError}; +use alloc::{string::String, vec, vec::Vec}; +use coset::{ + cbor::value::Value, cwt, iana, Algorithm, CborSerializable, CoseError, CoseKey, KeyOperation, + KeyType, Label, +}; use hkdf::Hkdf; use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; use rand_core::OsRng; use sha2::Sha256; +/// String to be used as salt for generating Key IDs. pub const ID_SALT: &str = "DICE_ID_SALT"; -pub const SIGNATURE_LENGTH: usize = 20; +/// ID for the CWT private claim corresponding to the Subject of the CWT. +pub const SUBJECT_PUBLIC_KEY_ID: i64 = -4670552; +/// ID for the CWT private claim corresponding to the VM kernel measurement. +pub const KERNEL_MEASUREMENT_ID: i64 = -4670555; +/// ID for the CWT private claim corresponding to the VM kernel commandline measurement. +pub const KERNEL_COMMANDLINE_MEASUREMENT_ID: i64 = -4670556; +/// ID for the CWT private claim corresponding to the VM kernel setup data measurement. +pub const SETUP_DATA_MEASUREMENT_ID: i64 = -4670557; +/// ID for the CWT private claim corresponding to the initial ramdisk measurement. +pub const INITRD_MEASUREMENT_ID: i64 = -4670558; +/// ID for the CWT private claim corresponding to the physical memory map (e820 table). +pub const MEMORY_MAP_MEASUREMENT_ID: i64 = -4670559; +/// ID for the CWT private claim corresponding to the hash of the commands for building the ACPI tables. +pub const ACPI_MEASUREMENT_ID: i64 = -4670560; +/// Length of the unique ID for ECDSA keys generated. +pub const KEY_ID_LENGTH: usize = 20; -/// Attestation related functions +/// Attestation related functions. /// -/// Returns Signed Stage1 key and measurments +/// Returns Signed Stage1 key and measurments. struct Stage0Signer { signing_key: SigningKey, } -// Measurements of various components in Stage1 +/// Measurements of various components in Stage1. pub struct Measurements { pub kernel_measurement: [u8; 32], pub cmdline_measurement: [u8; 32], @@ -42,7 +61,7 @@ pub struct Measurements { pub acpi_measurement: [u8; 32], } -// Signer implementation. +/// Signer implementation. impl Stage0Signer { fn sign(&self, data: &[u8]) -> Vec { let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); @@ -50,16 +69,16 @@ impl Stage0Signer { } } -fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; SIGNATURE_LENGTH] { +fn derive_id(ikm: &[u8], info: Option<&[u8]>) -> [u8; KEY_ID_LENGTH] { let hkdf = Hkdf::::new(Some(ID_SALT.as_bytes()), ikm); - let mut okm: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + let mut okm: [u8; KEY_ID_LENGTH] = [0u8; KEY_ID_LENGTH]; hkdf.expand(info.unwrap_or(&[]), &mut okm) - .expect("20 is a valid length for Sha256 to output"); + .expect("invalid length for HKDF output"); okm } -fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { +fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; KEY_ID_LENGTH]) { let key = SigningKey::random(&mut OsRng); let public_key = VerifyingKey::from(&key); let key_id = derive_id( @@ -69,53 +88,78 @@ fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; SIGNATURE_LENGTH]) { (key, key_id) } -fn generate_stage1_ca_cwt( +fn generate_stage1_eca_cwt( stage0_eca_key: SigningKey, - stage0_cert_id_hex: String, + stage0_cert_issuer: String, measurements: &Measurements, ) -> Result, CoseError> { // Generate Stage 1 keys and Signer. let info_str = "ID"; - let stage1_ca_key = generate_ecdsa_keys(info_str); - let stage1_ca_verifying_key = VerifyingKey::from(&stage1_ca_key.0); + let stage1_eca_key = generate_ecdsa_keys(info_str); + let stage1_eca_verifying_key = VerifyingKey::from(&stage1_eca_key.0); let stage0_signer = Stage0Signer { signing_key: stage0_eca_key, }; + let encoded_point = stage1_eca_verifying_key.to_encoded_point(false); + let x = encoded_point.x(); + let y = encoded_point.y(); + + let stage1_eca_verifying_cose_key = CoseKey { + kty: KeyType::Assigned(iana::KeyType::EC2), + key_id: Vec::from(stage1_eca_key.1), + alg: Some(Algorithm::Assigned(iana::Algorithm::ES384)), + key_ops: vec![KeyOperation::Assigned(iana::KeyOperation::Verify)] + .into_iter() + .collect(), + params: vec![ + ( + Label::Int(iana::Ec2KeyParameter::Crv as i64), + Value::from(iana::EllipticCurve::P_384 as u64), + ), + ( + Label::Int(iana::Ec2KeyParameter::X as i64), + Value::Bytes(x.unwrap().to_vec()), + ), + ( + Label::Int(iana::Ec2KeyParameter::Y as i64), + Value::Bytes(y.unwrap().to_vec()), + ), + ], + ..Default::default() + }; + // Generate claims and add the Stage1 CA key. let claims = cwt::ClaimsSetBuilder::new() - .issuer(stage0_cert_id_hex) - .subject(hex::encode(stage1_ca_key.1)) - .cwt_id(Vec::from(stage1_ca_key.1)) + .issuer(stage0_cert_issuer) + .subject(hex::encode(stage1_eca_key.1)) // Add additional private-use claim. .private_claim( - -4670552, - Value::Bytes(Vec::from( - stage1_ca_verifying_key.to_encoded_point(false).as_bytes(), - )), + SUBJECT_PUBLIC_KEY_ID, + Value::Bytes(stage1_eca_verifying_cose_key.to_vec().unwrap()), ) .private_claim( - -4670555, + KERNEL_MEASUREMENT_ID, Value::Bytes(Vec::from(measurements.kernel_measurement)), ) .private_claim( - -4670556, - Value::Bytes(Vec::from(measurements.kernel_measurement)), + KERNEL_COMMANDLINE_MEASUREMENT_ID, + Value::Bytes(Vec::from(measurements.cmdline_measurement)), ) .private_claim( - -4670557, + SETUP_DATA_MEASUREMENT_ID, Value::Bytes(Vec::from(measurements.setup_data_measurement)), ) .private_claim( - -4670558, + INITRD_MEASUREMENT_ID, Value::Bytes(Vec::from(measurements.ram_disk_measurement)), ) .private_claim( - -4670559, + MEMORY_MAP_MEASUREMENT_ID, Value::Bytes(Vec::from(measurements.memory_map_measurement)), ) .private_claim( - -4670560, + ACPI_MEASUREMENT_ID, Value::Bytes(Vec::from(measurements.acpi_measurement)), ) .build(); @@ -138,24 +182,29 @@ fn generate_stage1_ca_cwt( sign1.to_vec() } +/// Generate signed attestation for the 'measurements' of all Stage 1 components. pub fn generate_stage1_attestation(measurements: &Measurements) { // Generate Stage0 keys. This key will be used to sign Stage1 - // measurement+config and the stage1_ca_key + // measurement+config and the stage1_ca_key. let info_str = "ID"; - let stage0_ca_key = generate_ecdsa_keys(info_str); - let stage0_ca_verifying_key = VerifyingKey::from(&stage0_ca_key.0); + let stage0_eca_key = generate_ecdsa_keys(info_str); + let stage0_eca_verifying_key = VerifyingKey::from(&stage0_eca_key.0); - // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation report. + // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation + // report. log::debug!( "Stage0 Verification key: {}", - hex::encode(stage0_ca_verifying_key.to_encoded_point(false).as_bytes()) + hex::encode(stage0_eca_verifying_key.to_encoded_point(false).as_bytes()) ); - // Generate Stage1 CWT - let stage1_cwt = - generate_stage1_ca_cwt(stage0_ca_key.0, hex::encode(stage0_ca_key.1), measurements); + // Generate Stage1 CWT. + let stage1_cwt = generate_stage1_eca_cwt( + stage0_eca_key.0, + hex::encode(stage0_eca_key.1), + measurements, + ); if stage1_cwt.is_ok() { - // Call code that transmits the serialized cwt to Stage1 + // Call code that transmits the serialized cwt to Stage1. log::debug!("Signing was successful.."); return; } From 9fb7bc7bb77cede566af430438e80223af2ee62c Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Fri, 22 Sep 2023 10:12:42 -0700 Subject: [PATCH 07/15] Address additional review comments. --- stage0/src/dice_attestation.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index b83f2c9486e..d93de482806 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -30,6 +30,8 @@ use sha2::Sha256; pub const ID_SALT: &str = "DICE_ID_SALT"; /// ID for the CWT private claim corresponding to the Subject of the CWT. pub const SUBJECT_PUBLIC_KEY_ID: i64 = -4670552; +/// ID for bitstring used to describe the intended usage for the key represented by the certificate. +pub const KEY_USAGE_ID: i64 = -4670553; /// ID for the CWT private claim corresponding to the VM kernel measurement. pub const KERNEL_MEASUREMENT_ID: i64 = -4670555; /// ID for the CWT private claim corresponding to the VM kernel commandline measurement. @@ -44,6 +46,8 @@ pub const MEMORY_MAP_MEASUREMENT_ID: i64 = -4670559; pub const ACPI_MEASUREMENT_ID: i64 = -4670560; /// Length of the unique ID for ECDSA keys generated. pub const KEY_ID_LENGTH: usize = 20; +/// Info string for HKDF generator. +pub const INFO_STR: &str = "ID"; /// Attestation related functions. /// @@ -88,14 +92,13 @@ fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; KEY_ID_LENGTH]) { (key, key_id) } -fn generate_stage1_eca_cwt( +fn generate_stage1_certificate( stage0_eca_key: SigningKey, stage0_cert_issuer: String, measurements: &Measurements, ) -> Result, CoseError> { // Generate Stage 1 keys and Signer. - let info_str = "ID"; - let stage1_eca_key = generate_ecdsa_keys(info_str); + let stage1_eca_key = generate_ecdsa_keys(INFO_STR); let stage1_eca_verifying_key = VerifyingKey::from(&stage1_eca_key.0); let stage0_signer = Stage0Signer { signing_key: stage0_eca_key, @@ -129,6 +132,9 @@ fn generate_stage1_eca_cwt( ..Default::default() }; + // Setting bit 5 in little-endian order to 1 for keyCertSign usage. For more details + // refer: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 + let key_usage: [u8; 2] = [0x20, 0x00]; // Generate claims and add the Stage1 CA key. let claims = cwt::ClaimsSetBuilder::new() .issuer(stage0_cert_issuer) @@ -138,6 +144,7 @@ fn generate_stage1_eca_cwt( SUBJECT_PUBLIC_KEY_ID, Value::Bytes(stage1_eca_verifying_cose_key.to_vec().unwrap()), ) + .private_claim(KEY_USAGE_ID, Value::Bytes(Vec::from(key_usage))) .private_claim( KERNEL_MEASUREMENT_ID, Value::Bytes(Vec::from(measurements.kernel_measurement)), @@ -186,8 +193,7 @@ fn generate_stage1_eca_cwt( pub fn generate_stage1_attestation(measurements: &Measurements) { // Generate Stage0 keys. This key will be used to sign Stage1 // measurement+config and the stage1_ca_key. - let info_str = "ID"; - let stage0_eca_key = generate_ecdsa_keys(info_str); + let stage0_eca_key = generate_ecdsa_keys(INFO_STR); let stage0_eca_verifying_key = VerifyingKey::from(&stage0_eca_key.0); // Call generate_attestation_report() to get 'stage0_ca_verifying_key' added to attestation @@ -198,15 +204,15 @@ pub fn generate_stage1_attestation(measurements: &Measurements) { ); // Generate Stage1 CWT. - let stage1_cwt = generate_stage1_eca_cwt( + let stage1_eca = generate_stage1_certificate( stage0_eca_key.0, hex::encode(stage0_eca_key.1), - measurements, + measurements ); - if stage1_cwt.is_ok() { + if stage1_eca.is_ok() { // Call code that transmits the serialized cwt to Stage1. log::debug!("Signing was successful.."); return; } - log::debug!("Error in signing: {}", stage1_cwt.unwrap_err()) + log::debug!("Error in signing: {}", stage1_eca.unwrap_err()) } From 3e8a6645ab09f6ffbd978737f72342ce9ac5a0cd Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Wed, 11 Oct 2023 10:26:54 -0700 Subject: [PATCH 08/15] Made changes to fix the checks that were failing. --- stage0/src/dice_attestation.rs | 23 ++++++++++++++--------- stage0/src/lib.rs | 10 +++++----- stage0_bin/deny.toml | 8 +++++++- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index d93de482806..7a36189ec43 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -42,7 +42,8 @@ pub const SETUP_DATA_MEASUREMENT_ID: i64 = -4670557; pub const INITRD_MEASUREMENT_ID: i64 = -4670558; /// ID for the CWT private claim corresponding to the physical memory map (e820 table). pub const MEMORY_MAP_MEASUREMENT_ID: i64 = -4670559; -/// ID for the CWT private claim corresponding to the hash of the commands for building the ACPI tables. +/// ID for the CWT private claim corresponding to the hash of the commands for building the ACPI +/// tables. pub const ACPI_MEASUREMENT_ID: i64 = -4670560; /// Length of the unique ID for ECDSA keys generated. pub const KEY_ID_LENGTH: usize = 20; @@ -52,7 +53,7 @@ pub const INFO_STR: &str = "ID"; /// Attestation related functions. /// /// Returns Signed Stage1 key and measurments. -struct Stage0Signer { +struct Signer { signing_key: SigningKey, } /// Measurements of various components in Stage1. @@ -66,7 +67,7 @@ pub struct Measurements { } /// Signer implementation. -impl Stage0Signer { +impl Signer { fn sign(&self, data: &[u8]) -> Vec { let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) @@ -91,16 +92,17 @@ fn generate_ecdsa_keys(info: &str) -> (SigningKey, [u8; KEY_ID_LENGTH]) { ); (key, key_id) } - +/// +/// Generates Stage1 attestation evidence and ECA fn generate_stage1_certificate( stage0_eca_key: SigningKey, stage0_cert_issuer: String, measurements: &Measurements, -) -> Result, CoseError> { +) -> Result, SigningKey, CoseError> { // Generate Stage 1 keys and Signer. let stage1_eca_key = generate_ecdsa_keys(INFO_STR); let stage1_eca_verifying_key = VerifyingKey::from(&stage1_eca_key.0); - let stage0_signer = Stage0Signer { + let stage0_signer = Signer { signing_key: stage0_eca_key, }; @@ -186,7 +188,7 @@ fn generate_stage1_certificate( .payload(claims.clone().to_vec()?) .create_signature(aad, |data| stage0_signer.sign(data)) .build(); - sign1.to_vec() + (sign1.to_vec(), stage1_eca_key.0) } /// Generate signed attestation for the 'measurements' of all Stage 1 components. @@ -207,10 +209,13 @@ pub fn generate_stage1_attestation(measurements: &Measurements) { let stage1_eca = generate_stage1_certificate( stage0_eca_key.0, hex::encode(stage0_eca_key.1), - measurements + measurements, ); if stage1_eca.is_ok() { - // Call code that transmits the serialized cwt to Stage1. + // Call code that transmits the following to Stage1. + // 1. stage0_eca_verifying_key + // 2. stage1_eca.0 (the Stage 1 evidence) + // 3. stage1_eca.1 (the Stage 1 ECA private key) log::debug!("Signing was successful.."); return; } diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 5fa3c32eba9..66c9125e45d 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -306,12 +306,12 @@ pub fn rust64_start(encrypted: u64) -> ! { log::debug!("E820 table digest: {:?}", memory_map_measurement); let measurements = dice_attestation::Measurements { - acpi_measurement: acpi_measurement, + acpi_measurement, kernel_measurement: kernel_info.measurement, - cmdline_measurement: cmdline_measurement, - ram_disk_measurement: ram_disk_measurement, - setup_data_measurement: setup_data_measurement, - memory_map_measurement: memory_map_measurement, + cmdline_measurement, + ram_disk_measurement, + setup_data_measurement, + memory_map_measurement, }; dice_attestation::generate_stage1_attestation(&measurements); diff --git a/stage0_bin/deny.toml b/stage0_bin/deny.toml index 1917cc6b059..d3b2afd3421 100644 --- a/stage0_bin/deny.toml +++ b/stage0_bin/deny.toml @@ -24,5 +24,11 @@ unknown-git = "allow" # List of allowed licenses. # For more detailed information see http://go/thirdpartylicenses. [licenses] -allow = ["Apache-2.0", "BSD-2-Clause", "MIT", "Unicode-DFS-2016"] +allow = [ + "Apache-2.0", + "BSD-2-Clause", + "BSD-3-Clause", + "MIT", + "Unicode-DFS-2016" +] copyleft = "deny" From 6ff80474078f04b5714c1ad4beed1b2dfaddcffa Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Wed, 11 Oct 2023 10:52:35 -0700 Subject: [PATCH 09/15] Reverting name changed for Stage 0 signer class due to check failure. --- stage0/src/dice_attestation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index 7a36189ec43..38584d28ebd 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -53,7 +53,7 @@ pub const INFO_STR: &str = "ID"; /// Attestation related functions. /// /// Returns Signed Stage1 key and measurments. -struct Signer { +struct Stage0Signer { signing_key: SigningKey, } /// Measurements of various components in Stage1. @@ -67,7 +67,7 @@ pub struct Measurements { } /// Signer implementation. -impl Signer { +impl Stage0Signer { fn sign(&self, data: &[u8]) -> Vec { let signed_stage1_ca_verifying_key: Signature = self.signing_key.sign(data); Vec::from(signed_stage1_ca_verifying_key.to_bytes().as_slice()) @@ -102,7 +102,7 @@ fn generate_stage1_certificate( // Generate Stage 1 keys and Signer. let stage1_eca_key = generate_ecdsa_keys(INFO_STR); let stage1_eca_verifying_key = VerifyingKey::from(&stage1_eca_key.0); - let stage0_signer = Signer { + let stage0_signer = Stage0Signer { signing_key: stage0_eca_key, }; From 90be88f8263c7c753da536469af7ba3a8e9e1915 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Wed, 11 Oct 2023 12:49:58 -0700 Subject: [PATCH 10/15] Fixing the return type to pass checks --- stage0/src/dice_attestation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index 38584d28ebd..0461f56f635 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -98,7 +98,7 @@ fn generate_stage1_certificate( stage0_eca_key: SigningKey, stage0_cert_issuer: String, measurements: &Measurements, -) -> Result, SigningKey, CoseError> { +) -> Result, CoseError> { // Generate Stage 1 keys and Signer. let stage1_eca_key = generate_ecdsa_keys(INFO_STR); let stage1_eca_verifying_key = VerifyingKey::from(&stage1_eca_key.0); @@ -188,7 +188,7 @@ fn generate_stage1_certificate( .payload(claims.clone().to_vec()?) .create_signature(aad, |data| stage0_signer.sign(data)) .build(); - (sign1.to_vec(), stage1_eca_key.0) + sign1.to_vec() } /// Generate signed attestation for the 'measurements' of all Stage 1 components. From 0602f0111ac42f3217476184fe2288c9aff1fdd5 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Wed, 25 Oct 2023 10:59:33 -0700 Subject: [PATCH 11/15] DICE related changes to existing code --- stage0/Cargo.toml | 1 + stage0/src/dice_attestation.rs | 38 ++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/stage0/Cargo.toml b/stage0/Cargo.toml index 102c6c1cff8..77e8f4239c3 100644 --- a/stage0/Cargo.toml +++ b/stage0/Cargo.toml @@ -27,3 +27,4 @@ rand_core = { version = "*", default-features = false, features = [ ] } hex = { version = "*", default-features = false, features = ["alloc"] } coset = { version = "*", default-features = false } +oak_dice = { path = "../oak_dice", default-features = false } diff --git a/stage0/src/dice_attestation.rs b/stage0/src/dice_attestation.rs index 0461f56f635..2afc630b435 100644 --- a/stage0/src/dice_attestation.rs +++ b/stage0/src/dice_attestation.rs @@ -22,9 +22,14 @@ use coset::{ KeyType, Label, }; use hkdf::Hkdf; +use oak_dice::{ + self, + evidence::{CertificateAuthority, RootLayerEvidence, Stage0DiceData, TeePlatform, LayerEvidence}, +}; use p384::ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey}; use rand_core::OsRng; use sha2::Sha256; +use zerocopy::AsBytes; /// String to be used as salt for generating Key IDs. pub const ID_SALT: &str = "DICE_ID_SALT"; @@ -98,7 +103,7 @@ fn generate_stage1_certificate( stage0_eca_key: SigningKey, stage0_cert_issuer: String, measurements: &Measurements, -) -> Result, CoseError> { +) -> Result { // Generate Stage 1 keys and Signer. let stage1_eca_key = generate_ecdsa_keys(INFO_STR); let stage1_eca_verifying_key = VerifyingKey::from(&stage1_eca_key.0); @@ -182,13 +187,34 @@ fn generate_stage1_certificate( let unprotected = coset::HeaderBuilder::new() .key_id((*b"AsymmetricECDSA384").into()) .build(); - let sign1 = coset::CoseSign1Builder::new() + let serialized_sign1_certificate = coset::CoseSign1Builder::new() .protected(protected) .unprotected(unprotected) .payload(claims.clone().to_vec()?) .create_signature(aad, |data| stage0_signer.sign(data)) - .build(); - sign1.to_vec() + .build() + .to_vec(); + if serialized_sign1_certificate.is_err() { + return Err(serialized_sign1_certificate.err().unwrap()); + } + let returned_data = Stage0DiceData { + layer_1_certifcate_authority: CertificateAuthority { + eca_private_key: stage1_eca_key.0.to_bytes().as_slice(), + }, + root_layer_evidence: RootLayerEvidence { + tee_platform: TeePlatform::AmdSevSnp as u64, + eca_public_key: VerifyingKey::from(&stage0_eca_key) + .to_encoded_point(false) + .as_bytes(), + // 'remote_attestation_report' to be added later. + ..Default::default() + }, + layer_1_evidence: LayerEvidence { + eca_certificate: serialized_sign1_certificate.unwrap().as_bytes(), + }, + ..Default::default() + }; + return Ok(returned_data); } /// Generate signed attestation for the 'measurements' of all Stage 1 components. @@ -211,6 +237,10 @@ pub fn generate_stage1_attestation(measurements: &Measurements) { hex::encode(stage0_eca_key.1), measurements, ); + log::debug!( + "Stage1 certificate: {}", + hex::encode(stage1_eca.unwrap().as_bytes()) + ); if stage1_eca.is_ok() { // Call code that transmits the following to Stage1. // 1. stage0_eca_verifying_key From 1d00236d1bc317b070618c867e36e309c21f5c4c Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Wed, 25 Oct 2023 15:57:00 -0700 Subject: [PATCH 12/15] syncing with head --- stage0/Cargo.toml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/stage0/Cargo.toml b/stage0/Cargo.toml index a2290c8bbf2..45d7bb46d6d 100644 --- a/stage0/Cargo.toml +++ b/stage0/Cargo.toml @@ -28,14 +28,3 @@ static_assertions = "*" strum = { version = "*", default-features = false, features = ["derive"] } x86_64 = "*" zerocopy = "*" -<<<<<<< HEAD -p384 = { version = "*", default-features = false, features = ["ecdsa"] } -hkdf = { version = "*", default-features = false } -rand_core = { version = "*", default-features = false, features = [ - "getrandom" -] } -hex = { version = "*", default-features = false, features = ["alloc"] } -coset = { version = "*", default-features = false } -oak_dice = { path = "../oak_dice", default-features = false } -======= ->>>>>>> 5b81c518019530e1153d864e7650f88af6e2cac6 From 56cddbc37eae22e46a86c78ebab1f406d3fbad16 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Wed, 1 May 2024 10:26:03 -0700 Subject: [PATCH 13/15] Eventlog proto for stage 0 --- Cargo.lock | 3 + stage0/Cargo.toml | 5 + stage0/build.rs | 8 + stage0/src/eventlog.proto | 23 +++ stage0/src/lib.rs | 17 +- stage0_bin/Cargo.lock | 416 +++++++++++++++++++++++++++++++++++++- stage0_bin/build.rs | 2 +- 7 files changed, 471 insertions(+), 3 deletions(-) create mode 100644 stage0/build.rs create mode 100644 stage0/src/eventlog.proto diff --git a/Cargo.lock b/Cargo.lock index e3f1b7f5c4d..726697cf5fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3154,6 +3154,9 @@ dependencies = [ "oak_sev_snp_attestation_report", "oak_stage0_dice", "p256", + "prost", + "prost-build", + "prost-types", "rand_core", "sev_serial", "sha2", diff --git a/stage0/Cargo.toml b/stage0/Cargo.toml index ab4a1950916..b9484e3f6f1 100644 --- a/stage0/Cargo.toml +++ b/stage0/Cargo.toml @@ -5,6 +5,9 @@ authors = ["Andri Saar "] edition = "2021" license = "Apache-2.0" +[build-dependencies] +prost-build = { version = "*" } + [dependencies] bitflags = "*" coset = { version = "*", default-features = false } @@ -23,6 +26,8 @@ p256 = { version = "*", default-features = false, features = ["ecdsa"] } rand_core = { version = "*", default-features = false, features = [ "getrandom", ] } +prost = {version = "*", default-features = false, features = ["prost-derive"]} +prost-types = {version = "*", default-features = false} sev_serial = { path = "../sev_serial" } sha2 = { version = "*", default-features = false, features = ["force-soft"] } spinning_top = "*" diff --git a/stage0/build.rs b/stage0/build.rs new file mode 100644 index 00000000000..4b28760cc21 --- /dev/null +++ b/stage0/build.rs @@ -0,0 +1,8 @@ +extern crate prost_build; + +fn main() { + let mut config = prost_build::Config::new(); + config.btree_map(&["."]); + prost_build::compile_protos(&["src/eventlog.proto"], + &["src/"]).unwrap(); +} \ No newline at end of file diff --git a/stage0/src/eventlog.proto b/stage0/src/eventlog.proto new file mode 100644 index 00000000000..3dc32fc7340 --- /dev/null +++ b/stage0/src/eventlog.proto @@ -0,0 +1,23 @@ +syntax = "proto2"; + +package eventlog; + +import "google/protobuf/any.proto"; + +// Represents an event intended for inclusion in attestation. +// For example, in an attested measured boot, each event is a reference to the +// code identity of the boot layer being launched next. +// An Event message must have a canonical serialization and contain what's +// necessary for an attestation verifier to verify the Event against a Reference +// Value. +message Event { + // Represents what is contains in the event. For example, the tag for + // TaskConfig for the Layer 2 is "layer2". + optional string tag = 1; + optional google.protobuf.Any event = 2; +} + +// A sequence of Events intended for inclusion in attestation evidence. +message EventLog { + repeated Event events = 1; +} diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 01b4a3da56b..67e8e3b2a55 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -21,7 +21,7 @@ extern crate alloc; -use alloc::{boxed::Box, format}; +use alloc::{boxed::Box, format , string::String}; use core::{arch::asm, ffi::c_void, mem::MaybeUninit, panic::PanicInfo}; use linked_list_allocator::LockedHeap; @@ -41,6 +41,7 @@ use x86_64::{ PhysAddr, VirtAddr, }; use zerocopy::AsBytes; +// use prost::Message; use crate::{alloc::string::ToString, kernel::KernelType, sev::GHCB_WRAPPER, smp::AP_JUMP_TABLE}; @@ -61,6 +62,10 @@ mod sev; mod smp; mod zero_page; +pub mod eventlog { + include!(concat!(env!("OUT_DIR"), "/eventlog.rs")); +} + type Measurement = [u8; 32]; // Reserve 128K for boot data structures that will outlive Stage 0. @@ -339,6 +344,8 @@ pub fn rust64_start(encrypted: u64) -> ! { ), &crate::BOOT_ALLOC, )); + let event = generate_event_log(); + log::info!("event tage = {}", event.tag.unwrap()); // Reserve the memory containing the DICE data. zero_page.insert_e820_entry(BootE820Entry::new( dice_data.as_bytes().as_ptr() as usize, @@ -414,3 +421,11 @@ fn io_port_factory() -> PortFactoryWrapper { PortFactoryWrapper::new_raw() } } + +fn generate_event_log(/*measurement: Measurement*/) -> eventlog::Event { + let mut event = eventlog::Event::default(); + let str = String::new(); + let m = Some(str); + event.tag = m; + event +} \ No newline at end of file diff --git a/stage0_bin/Cargo.lock b/stage0_bin/Cargo.lock index d562052d637..7ee9b87787a 100644 --- a/stage0_bin/Cargo.lock +++ b/stage0_bin/Cargo.lock @@ -37,6 +37,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" + [[package]] name = "autocfg" version = "1.1.0" @@ -82,6 +97,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "cfg-if" version = "1.0.0" @@ -222,6 +243,12 @@ dependencies = [ "signature", ] +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + [[package]] name = "elf" version = "0.7.2" @@ -246,6 +273,31 @@ dependencies = [ "zeroize", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "ff" version = "0.13.0" @@ -256,6 +308,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "generic-array" version = "0.14.7" @@ -305,12 +363,24 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" @@ -335,6 +405,16 @@ dependencies = [ "digest", ] +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.3" @@ -344,6 +424,35 @@ dependencies = [ "generic-array", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "libc" version = "0.2.144" @@ -359,6 +468,12 @@ dependencies = [ "spinning_top", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "lock_api" version = "0.4.9" @@ -378,6 +493,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "oak_core" version = "0.1.0" @@ -434,7 +561,7 @@ dependencies = [ name = "oak_sev_snp_attestation_report" version = "0.0.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "static_assertions", "strum", "zerocopy", @@ -458,6 +585,9 @@ dependencies = [ "oak_sev_snp_attestation_report", "oak_stage0_dice", "p256", + "prost", + "prost-build", + "prost-types", "rand_core", "sev_serial", "sha2", @@ -491,6 +621,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -509,6 +645,16 @@ dependencies = [ "sha2", ] +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "polyval" version = "0.6.1" @@ -521,6 +667,16 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.38", +] + [[package]] name = "primeorder" version = "0.13.2" @@ -539,6 +695,59 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +dependencies = [ + "bytes", + "heck", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.38", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "prost-types" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +dependencies = [ + "prost", +] + [[package]] name = "quote" version = "1.0.33" @@ -557,6 +766,44 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + [[package]] name = "rfc6979" version = "0.4.0" @@ -567,6 +814,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustversion" version = "1.0.9" @@ -728,6 +989,20 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +dependencies = [ + "autocfg", + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "typenum" version = "1.16.0" @@ -768,6 +1043,145 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "x86_64" version = "0.14.10" diff --git a/stage0_bin/build.rs b/stage0_bin/build.rs index e526062d6ab..cd7d6dcf08e 100644 --- a/stage0_bin/build.rs +++ b/stage0_bin/build.rs @@ -23,7 +23,7 @@ fn main() { #[allow(clippy::if_same_then_else)] if env::var("PROFILE").unwrap() == "release" { - println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=2M"); + println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=256K"); } else { println!("cargo:rustc-link-arg=--defsym=BIOS_SIZE=2M"); } From b7de5116d56217d77b44c0e4cfd61109ad3dfc08 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 2 May 2024 17:37:19 -0700 Subject: [PATCH 14/15] Add all measurements and generate eventlog --- stage0/src/eventlog.proto | 16 +++++++++++ stage0/src/lib.rs | 57 +++++++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/stage0/src/eventlog.proto b/stage0/src/eventlog.proto index 3dc32fc7340..0d21d04cc88 100644 --- a/stage0/src/eventlog.proto +++ b/stage0/src/eventlog.proto @@ -4,6 +4,22 @@ package eventlog; import "google/protobuf/any.proto"; +// All the related measurements for Stage 0. +message Stage0Measurements { + // Kernel setup data digest. + optional bytes setup_data_digest = 1; + // Kernel digest. + optional bytes kernel_measurement = 2; + // Initial RAM disk digest. + optional bytes ram_disk_digest = 3; + // E820 table digest + optional bytes memory_map_digest = 4; + // ACPI table generation digest + optional bytes acpi_digest = 5; + // Kernel Command line. + optional string kernel_cmdline = 6; +} + // Represents an event intended for inclusion in attestation. // For example, in an attested measured boot, each event is a reference to the // code identity of the boot layer being launched next. diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 67e8e3b2a55..3cbd0770405 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -21,7 +21,7 @@ extern crate alloc; -use alloc::{boxed::Box, format , string::String}; +use alloc::{boxed::Box, format, string::String}; use core::{arch::asm, ffi::c_void, mem::MaybeUninit, panic::PanicInfo}; use linked_list_allocator::LockedHeap; @@ -29,6 +29,8 @@ use oak_core::sync::OnceCell; use oak_dice::evidence::{TeePlatform, DICE_DATA_CMDLINE_PARAM}; use oak_linux_boot_params::{BootE820Entry, E820EntryType}; use oak_sev_guest::{io::PortFactoryWrapper, msr::SevStatus}; +use prost::Name; +use prost_types::Any; use sha2::{Digest, Sha256}; use x86_64::{ instructions::{hlt, interrupts::int3}, @@ -41,7 +43,6 @@ use x86_64::{ PhysAddr, VirtAddr, }; use zerocopy::AsBytes; -// use prost::Message; use crate::{alloc::string::ToString, kernel::KernelType, sev::GHCB_WRAPPER, smp::AP_JUMP_TABLE}; @@ -313,6 +314,19 @@ pub fn rust64_start(encrypted: u64) -> ! { log::debug!("ACPI table generation digest: sha2-256:{}", hex::encode(acpi_sha2_256_digest)); log::debug!("E820 table digest: sha2-256:{}", hex::encode(memory_map_sha2_256_digest)); + let mut stage0event = eventlog::Stage0Measurements::default(); + stage0event.kernel_measurement = Some(kernel_info.measurement.as_bytes().to_vec()); + stage0event.acpi_digest = Some(acpi_sha2_256_digest.as_bytes().to_vec()); + stage0event.memory_map_digest = Some(memory_map_sha2_256_digest.as_bytes().to_vec()); + stage0event.ram_disk_digest = Some(ram_disk_sha2_256_digest.as_bytes().to_vec()); + stage0event.setup_data_digest = Some(setup_data_sha2_256_digest.as_bytes().to_vec()); + stage0event.kernel_cmdline = Some(cmdline); + let event_log = Box::leak(Box::new_in( + generate_event_log(stage0event), + &crate::BOOT_ALLOC, + )); + log::info!("event tag = {:?}", event_log); + // TODO: b/331252282 - Remove temporary workaround for cmd line length. let cmdline_max_len = 256; let measurements = oak_stage0_dice::Measurements { @@ -344,14 +358,19 @@ pub fn rust64_start(encrypted: u64) -> ! { ), &crate::BOOT_ALLOC, )); - let event = generate_event_log(); - log::info!("event tage = {}", event.tag.unwrap()); + // Reserve the memory containing the DICE data. zero_page.insert_e820_entry(BootE820Entry::new( dice_data.as_bytes().as_ptr() as usize, dice_data.as_bytes().len(), E820EntryType::RESERVED, )); + // Reserve memory containing Eventlog Data. + zero_page.insert_e820_entry(BootE820Entry::new( + event_log.as_bytes().as_ptr() as usize, + event_log.as_bytes().len(), + E820EntryType::RESERVED, + )); // Append the DICE data address to the kernel command-line. let extra = format!("--{DICE_DATA_CMDLINE_PARAM}={dice_data:p}"); @@ -422,10 +441,32 @@ fn io_port_factory() -> PortFactoryWrapper { } } -fn generate_event_log(/*measurement: Measurement*/) -> eventlog::Event { +const PACKAGE: &str = "google.protobuf"; + +/// Compute the type URL for the given `google.protobuf` type, using +/// `type.googleapis.com` as the authority for the URL. +fn type_url_for() -> String { + format!("type.googleapis.com/{}.{}", T::PACKAGE, T::NAME) +} + +impl Name for eventlog::Stage0Measurements { + const PACKAGE: &'static str = PACKAGE; + const NAME: &'static str = "Stage0"; + + fn type_url() -> String { + type_url_for::() + } +} + +fn generate_event_log(measurements: eventlog::Stage0Measurements) -> eventlog::EventLog { let mut event = eventlog::Event::default(); - let str = String::new(); + let mut str = String::new(); + let any = Any::from_msg(&measurements); + str.push_str("Stage0"); let m = Some(str); event.tag = m; - event -} \ No newline at end of file + event.event = Some(any.unwrap()); + let mut eventlog = eventlog::EventLog::default(); + eventlog.events.push(event); + eventlog +} From 3a103c98c185edb922173464a6789ed3e5b316a5 Mon Sep 17 00:00:00 2001 From: Sourav Dasgupta Date: Thu, 2 May 2024 17:53:12 -0700 Subject: [PATCH 15/15] Fix errors due to previous changes. --- stage0/src/lib.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/stage0/src/lib.rs b/stage0/src/lib.rs index 3cbd0770405..b1b20bc0ad2 100644 --- a/stage0/src/lib.rs +++ b/stage0/src/lib.rs @@ -29,7 +29,7 @@ use oak_core::sync::OnceCell; use oak_dice::evidence::{TeePlatform, DICE_DATA_CMDLINE_PARAM}; use oak_linux_boot_params::{BootE820Entry, E820EntryType}; use oak_sev_guest::{io::PortFactoryWrapper, msr::SevStatus}; -use prost::Name; +use prost::{Message, Name}; use prost_types::Any; use sha2::{Digest, Sha256}; use x86_64::{ @@ -314,19 +314,6 @@ pub fn rust64_start(encrypted: u64) -> ! { log::debug!("ACPI table generation digest: sha2-256:{}", hex::encode(acpi_sha2_256_digest)); log::debug!("E820 table digest: sha2-256:{}", hex::encode(memory_map_sha2_256_digest)); - let mut stage0event = eventlog::Stage0Measurements::default(); - stage0event.kernel_measurement = Some(kernel_info.measurement.as_bytes().to_vec()); - stage0event.acpi_digest = Some(acpi_sha2_256_digest.as_bytes().to_vec()); - stage0event.memory_map_digest = Some(memory_map_sha2_256_digest.as_bytes().to_vec()); - stage0event.ram_disk_digest = Some(ram_disk_sha2_256_digest.as_bytes().to_vec()); - stage0event.setup_data_digest = Some(setup_data_sha2_256_digest.as_bytes().to_vec()); - stage0event.kernel_cmdline = Some(cmdline); - let event_log = Box::leak(Box::new_in( - generate_event_log(stage0event), - &crate::BOOT_ALLOC, - )); - log::info!("event tag = {:?}", event_log); - // TODO: b/331252282 - Remove temporary workaround for cmd line length. let cmdline_max_len = 256; let measurements = oak_stage0_dice::Measurements { @@ -365,10 +352,24 @@ pub fn rust64_start(encrypted: u64) -> ! { dice_data.as_bytes().len(), E820EntryType::RESERVED, )); + + // Generate Stage0 Event Log data. + let mut stage0event = eventlog::Stage0Measurements::default(); + stage0event.kernel_measurement = Some(kernel_info.measurement.as_bytes().to_vec()); + stage0event.acpi_digest = Some(acpi_sha2_256_digest.as_bytes().to_vec()); + stage0event.memory_map_digest = Some(memory_map_sha2_256_digest.as_bytes().to_vec()); + stage0event.ram_disk_digest = Some(ram_disk_sha2_256_digest.as_bytes().to_vec()); + stage0event.setup_data_digest = Some(setup_data_sha2_256_digest.as_bytes().to_vec()); + stage0event.kernel_cmdline = Some(cmdline.clone()); + let event_log = Box::leak(Box::new_in( + generate_event_log(stage0event), + &crate::BOOT_ALLOC, + )); + log::info!("event tag = {:?}", event_log); // Reserve memory containing Eventlog Data. zero_page.insert_e820_entry(BootE820Entry::new( - event_log.as_bytes().as_ptr() as usize, - event_log.as_bytes().len(), + event_log.encode_to_vec().as_bytes().as_ptr() as usize, + event_log.encode_to_vec().as_bytes().len(), E820EntryType::RESERVED, ));