From 9f71461ecf856cc1d87b98fb7c787104e40cecb1 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Mon, 11 Apr 2022 10:07:37 +0000 Subject: [PATCH 01/29] add remote attestation test inside UEFI app --- experimental/uefi/app/Cargo.lock | 1 + experimental/uefi/app/Cargo.toml | 1 + experimental/uefi/app/src/main.rs | 87 +++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/experimental/uefi/app/Cargo.lock b/experimental/uefi/app/Cargo.lock index 6345fbbc9ef..39f225d5daf 100644 --- a/experimental/uefi/app/Cargo.lock +++ b/experimental/uefi/app/Cargo.lock @@ -372,6 +372,7 @@ dependencies = [ name = "uefi-simple" version = "0.1.0" dependencies = [ + "anyhow", "log", "oak_remote_attestation", "uefi", diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index 4e47574c818..e5f7ad725e1 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -10,6 +10,7 @@ uefi = { version = "*", features = ["exts"] } uefi-services = "*" log = { version = "*" } oak_remote_attestation = { path = "../../../remote_attestation/rust" } +anyhow = { version = "*", default-features = false } [dev-dependencies] uefi-services = { version = "*", features = ["qemu"] } diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index 12bdcf69e8c..5204448b34c 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -26,7 +26,13 @@ #[macro_use] extern crate log; +extern crate alloc; +extern crate anyhow; +#[cfg(test)] +use alloc::{boxed::Box, sync::Arc}; +#[cfg(test)] +use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; use uefi::{ prelude::*, proto::console::serial::Serial, @@ -130,3 +136,84 @@ fn test_simple() { let x = 1; assert_eq!(x, 1); } + +#[cfg(test)] +const TEE_MEASUREMENT: &str = "Test TEE measurement"; +#[cfg(test)] +const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + +#[cfg(test)] +fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + let client_handshaker = ClientHandshaker::new( + bidirectional_attestation, + Box::new(|server_identity| { + if !server_identity.additional_info.is_empty() { + Ok(()) + } else { + anyhow::bail!("No additional info provided.") + } + }), + ); + + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + + let additional_info = br"Additional Info".to_vec(); + let server_handshaker = + ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); + + (client_handshaker, server_handshaker) +} + +#[test_case] +fn test_handshake() { + let (mut client_handshaker, mut server_handshaker) = create_handshakers(); + + let client_hello = client_handshaker + .create_client_hello() + .expect("Couldn't create client hello message"); + + let server_identity = server_handshaker + .next_step(&client_hello) + .expect("Couldn't process client hello message") + .expect("Empty server identity message"); + + let client_identity = client_handshaker + .next_step(&server_identity) + .expect("Couldn't process server identity message") + .expect("Empty client identity message"); + assert!(client_handshaker.is_completed()); + + let result = server_handshaker + .next_step(&client_identity) + .expect("Couldn't process client identity message"); + assert_eq!(result, None); + assert!(server_handshaker.is_completed()); + + let mut client_encryptor = client_handshaker + .get_encryptor() + .expect("Couldn't get client encryptor"); + let mut server_encryptor = server_handshaker + .get_encryptor() + .expect("Couldn't get server encryptor"); + + let encrypted_client_data = client_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt client data"); + let decrypted_client_data = server_encryptor + .decrypt(&encrypted_client_data) + .expect("Couldn't decrypt client data"); + assert_eq!(decrypted_client_data, DATA); + + let encrypted_server_data = server_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt server data"); + let decrypted_server_data = client_encryptor + .decrypt(&encrypted_server_data) + .expect("Couldn't decrypt server data"); + assert_eq!(decrypted_server_data, DATA); +} From fb4f9050c9d62820a6aa66653811bb0596641fab Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Mon, 11 Apr 2022 15:16:50 +0000 Subject: [PATCH 02/29] Stub missing symbols --- third_party/ring/Cargo.toml | 2 ++ third_party/ring/build.rs | 1 + third_party/ring/stubs.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) create mode 100644 third_party/ring/stubs.c diff --git a/third_party/ring/Cargo.toml b/third_party/ring/Cargo.toml index 81b800b51f9..05fedf0fbca 100644 --- a/third_party/ring/Cargo.toml +++ b/third_party/ring/Cargo.toml @@ -33,6 +33,8 @@ include = [ "benches/*.rs", "build.rs", + "stubs.c", + "crypto/chacha/asm/chacha-armv4.pl", "crypto/chacha/asm/chacha-armv8.pl", "crypto/chacha/asm/chacha-x86.pl", diff --git a/third_party/ring/build.rs b/third_party/ring/build.rs index 4e569b42f72..bf134fda63e 100644 --- a/third_party/ring/build.rs +++ b/third_party/ring/build.rs @@ -55,6 +55,7 @@ const RING_SRCS: &[(&[&str], &str)] = &[ (&[X86], "crypto/chacha/asm/chacha-x86.pl"), (&[X86], "crypto/fipsmodule/modes/asm/ghash-x86.pl"), + (&[X86_64], "stubs.c"), (&[X86_64], "crypto/chacha/asm/chacha-x86_64.pl"), (&[X86_64], "crypto/fipsmodule/aes/asm/aesni-x86_64.pl"), (&[X86_64], "crypto/fipsmodule/aes/asm/vpaes-x86_64.pl"), diff --git a/third_party/ring/stubs.c b/third_party/ring/stubs.c new file mode 100644 index 00000000000..d234842d3e0 --- /dev/null +++ b/third_party/ring/stubs.c @@ -0,0 +1,30 @@ +#include + +/** + * + Stub function for win64 error handler API call inserted by nasm. + Stubbed as it unavailable in UEFI. + Ref: https://github.com/openssl/openssl/issues/12712. + Inspired by: https://github.com/tianocore/edk2/blob/7c0ad2c33810ead45b7919f8f8d0e282dae52e71/CryptoPkg/Library/OpensslLib/X64/ApiHooks.c +**/ +void * +__imp_RtlVirtualUnwind ( + void *Args + ) +{ + return NULL; +} + +/** + Stub function for win64 routine used for exceedomgy large variable calls. + Inserted MinGW, stubbed as it unavailable in UEFI. + Ref: https://metricpanda.com/rival-fortress-update-45-dealing-with-__chkstk-__chkstk_ms-when-cross-compiling-for-windows/ +**/ +void * +___chkstk_ms ( + void *Args + ) +{ + return NULL; +} + From c4b2bea0244f3f89876813fe1b6f413bb0e7b6e1 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Mon, 11 Apr 2022 15:51:45 +0000 Subject: [PATCH 03/29] improve comment spelling somewhat --- third_party/ring/stubs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/third_party/ring/stubs.c b/third_party/ring/stubs.c index d234842d3e0..c1cf2ddf4fd 100644 --- a/third_party/ring/stubs.c +++ b/third_party/ring/stubs.c @@ -3,7 +3,7 @@ /** * Stub function for win64 error handler API call inserted by nasm. - Stubbed as it unavailable in UEFI. + Stubbed as it is unavailable in UEFI. Ref: https://github.com/openssl/openssl/issues/12712. Inspired by: https://github.com/tianocore/edk2/blob/7c0ad2c33810ead45b7919f8f8d0e282dae52e71/CryptoPkg/Library/OpensslLib/X64/ApiHooks.c **/ @@ -16,8 +16,8 @@ __imp_RtlVirtualUnwind ( } /** - Stub function for win64 routine used for exceedomgy large variable calls. - Inserted MinGW, stubbed as it unavailable in UEFI. + Stub function for win64 routine used for exceedingly large variables. + Inserted Mby inGW, stubbed as it is unavailable in UEFI. Ref: https://metricpanda.com/rival-fortress-update-45-dealing-with-__chkstk-__chkstk_ms-when-cross-compiling-for-windows/ **/ void * From 63c22a9f1562075edda5701705cb510637d609dd Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Mon, 11 Apr 2022 16:15:15 +0000 Subject: [PATCH 04/29] Use ___chkstk_ms from go --- third_party/ring/stubs.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/third_party/ring/stubs.c b/third_party/ring/stubs.c index c1cf2ddf4fd..6765ccec1ce 100644 --- a/third_party/ring/stubs.c +++ b/third_party/ring/stubs.c @@ -18,13 +18,11 @@ __imp_RtlVirtualUnwind ( /** Stub function for win64 routine used for exceedingly large variables. Inserted Mby inGW, stubbed as it is unavailable in UEFI. - Ref: https://metricpanda.com/rival-fortress-update-45-dealing-with-__chkstk-__chkstk_ms-when-cross-compiling-for-windows/ + Ref 1: https://metricpanda.com/rival-fortress-update-45-dealing-with-__chkstk-__chkstk_ms-when-cross-compiling-for-windows/ + Ref 2: https://github.com/golang/go/issues/6305 + Inspired by: https://android.googlesource.com/platform/external/compiler-rt/+/ccaafe6%5E%21/#F1 **/ -void * -___chkstk_ms ( - void *Args - ) +void ___chkstk_ms(void) { - return NULL; } From 8c49af0c7c747938c10d3bc7c7f73dc78341bbc2 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Mon, 11 Apr 2022 16:34:24 +0000 Subject: [PATCH 05/29] simplify test to aid debugging: just test ring source of randomness --- experimental/uefi/app/Cargo.lock | 231 +----------------------------- experimental/uefi/app/Cargo.toml | 2 +- experimental/uefi/app/src/main.rs | 90 ++---------- 3 files changed, 10 insertions(+), 313 deletions(-) diff --git a/experimental/uefi/app/Cargo.lock b/experimental/uefi/app/Cargo.lock index 39f225d5daf..b7fd4a68404 100644 --- a/experimental/uefi/app/Cargo.lock +++ b/experimental/uefi/app/Cargo.lock @@ -8,12 +8,6 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "bit_field" version = "0.10.1" @@ -26,12 +20,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - [[package]] name = "cc" version = "1.0.73" @@ -44,82 +32,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cmake" -version = "0.1.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" -dependencies = [ - "cc", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fixedbitset" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.121" @@ -135,40 +47,12 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "oak_remote_attestation" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "log", - "prost", - "prost-build", - "ring", -] - [[package]] name = "once_cell" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" -[[package]] -name = "petgraph" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" -dependencies = [ - "fixedbitset", - "indexmap", -] - [[package]] name = "proc-macro2" version = "1.0.36" @@ -178,61 +62,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "prost" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd5316aa8f5c82add416dfbc25116b84b748a21153f512917e8143640a71bbd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328f9f29b82409216decb172d81e936415d21245befa79cd34c3f29d87d1c50b" -dependencies = [ - "bytes", - "cfg-if", - "cmake", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost", - "prost-types", - "regex", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df35198f0777b75e9ff669737c6da5136b59dba33cf5a010a6d1cc4d56defc6f" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-types" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926681c118ae6e512a3ccefd4abbe5521a14f4cc1e207356d4d00c0b7f2006fd" -dependencies = [ - "bytes", - "prost", -] - [[package]] name = "qemu-exit" version = "3.0.1" @@ -248,39 +77,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "ring" version = "0.17.0-not-released-yet" @@ -310,20 +106,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - [[package]] name = "ucs2" version = "0.3.2" @@ -374,7 +156,7 @@ version = "0.1.0" dependencies = [ "anyhow", "log", - "oak_remote_attestation", + "ring", "uefi", "uefi-services", ] @@ -391,17 +173,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "which" -version = "4.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" -dependencies = [ - "either", - "lazy_static", - "libc", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index e5f7ad725e1..c0da9db4046 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -9,7 +9,7 @@ license = "Apache-2.0" uefi = { version = "*", features = ["exts"] } uefi-services = "*" log = { version = "*" } -oak_remote_attestation = { path = "../../../remote_attestation/rust" } +ring = { path = "../../../third_party/ring" } anyhow = { version = "*", default-features = false } [dev-dependencies] diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index 5204448b34c..fe481246521 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -29,10 +29,6 @@ extern crate log; extern crate alloc; extern crate anyhow; -#[cfg(test)] -use alloc::{boxed::Box, sync::Arc}; -#[cfg(test)] -use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; use uefi::{ prelude::*, proto::console::serial::Serial, @@ -42,6 +38,9 @@ use uefi::{ }, }; +#[cfg(test)] +use ring::rand::SecureRandom; + // The main entry point of the UEFI application. // // The choice of name (`_start`) is entirely arbitrary; what matters is that @@ -137,83 +136,10 @@ fn test_simple() { assert_eq!(x, 1); } -#[cfg(test)] -const TEE_MEASUREMENT: &str = "Test TEE measurement"; -#[cfg(test)] -const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - -#[cfg(test)] -fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - let client_handshaker = ClientHandshaker::new( - bidirectional_attestation, - Box::new(|server_identity| { - if !server_identity.additional_info.is_empty() { - Ok(()) - } else { - anyhow::bail!("No additional info provided.") - } - }), - ); - - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - - let additional_info = br"Additional Info".to_vec(); - let server_handshaker = - ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); - - (client_handshaker, server_handshaker) -} - +// Simple test source of randomness, for more straightforward debugging #[test_case] -fn test_handshake() { - let (mut client_handshaker, mut server_handshaker) = create_handshakers(); - - let client_hello = client_handshaker - .create_client_hello() - .expect("Couldn't create client hello message"); - - let server_identity = server_handshaker - .next_step(&client_hello) - .expect("Couldn't process client hello message") - .expect("Empty server identity message"); - - let client_identity = client_handshaker - .next_step(&server_identity) - .expect("Couldn't process server identity message") - .expect("Empty client identity message"); - assert!(client_handshaker.is_completed()); - - let result = server_handshaker - .next_step(&client_identity) - .expect("Couldn't process client identity message"); - assert_eq!(result, None); - assert!(server_handshaker.is_completed()); - - let mut client_encryptor = client_handshaker - .get_encryptor() - .expect("Couldn't get client encryptor"); - let mut server_encryptor = server_handshaker - .get_encryptor() - .expect("Couldn't get server encryptor"); - - let encrypted_client_data = client_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt client data"); - let decrypted_client_data = server_encryptor - .decrypt(&encrypted_client_data) - .expect("Couldn't decrypt client data"); - assert_eq!(decrypted_client_data, DATA); - - let encrypted_server_data = server_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt server data"); - let decrypted_server_data = client_encryptor - .decrypt(&encrypted_server_data) - .expect("Couldn't decrypt server data"); - assert_eq!(decrypted_server_data, DATA); +fn random_test() { + let rng = ring::rand::SystemRandom::new(); + let mut buf = alloc::vec::Vec::with_capacity(8); + assert_eq!(rng.fill(&mut buf).is_err(), false); } From d73e8480ccb0cfc340119b6b72ac2d20b8391f80 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Tue, 12 Apr 2022 17:20:58 +0000 Subject: [PATCH 06/29] log random data in test --- experimental/uefi/app/src/main.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index fe481246521..b68b3a2cc8d 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -140,6 +140,8 @@ fn test_simple() { #[test_case] fn random_test() { let rng = ring::rand::SystemRandom::new(); - let mut buf = alloc::vec::Vec::with_capacity(8); - assert_eq!(rng.fill(&mut buf).is_err(), false); + let mut buf = [0u8; 8]; + let result = rng.fill(&mut buf).is_err(); + log::info!("{:?}", buf); + assert_eq!(result, false); } From d8111c859c7678391321d6cc300d557e964bd2c7 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Wed, 13 Apr 2022 13:31:26 +0100 Subject: [PATCH 07/29] patch rdrand availability check for debuggingnd enable KVM --- experimental/uefi/app/.cargo/config.toml | 2 +- third_party/ring/src/rand.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/experimental/uefi/app/.cargo/config.toml b/experimental/uefi/app/.cargo/config.toml index 33a5210dcce..b25fbccd921 100644 --- a/experimental/uefi/app/.cargo/config.toml +++ b/experimental/uefi/app/.cargo/config.toml @@ -7,7 +7,7 @@ runner = "qemu-system-x86_64 -nodefaults -nographic -bios /usr/share/OVMF/OVMF_C # Otherwise, (a) the first serial port gets routed to a log, and (b) the second serial gets attached to stdio. [target.'cfg(not(test))'] -runner = "qemu-system-x86_64 -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial file:target/console.log -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" +runner = "qemu-system-x86_64 -enable-kvm -cpu Broadwell-IBRS,vme=on,f16c=on,rdrand=on -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial file:target/console.log -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" [unstable] build-std = ["core", "alloc"] diff --git a/third_party/ring/src/rand.rs b/third_party/ring/src/rand.rs index 4377b0699de..71e4417d5dc 100644 --- a/third_party/ring/src/rand.rs +++ b/third_party/ring/src/rand.rs @@ -452,7 +452,11 @@ mod uefi { static mut OPENSSL_ia32cap_P: [u32; 4]; } const FLAG: u32 = 1 << 30; - unsafe { OPENSSL_ia32cap_P[1] & FLAG == FLAG } + // Somehow this check continues to require patching, regardless + // of qemu CPU config. :/. That is even though RDRAND is in fact + // available and working. + // unsafe { OPENSSL_ia32cap_P[1] & FLAG == FLAG } + true } // We must make sure current cpu support `rdrand` From 837660c1006c4037cb7d7b5e85ae4528d14a867e Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 10:53:46 +0100 Subject: [PATCH 08/29] Add test to check that the byte array has in fact been filled --- experimental/uefi/app/src/main.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index b68b3a2cc8d..bea8dfde774 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -136,12 +136,14 @@ fn test_simple() { assert_eq!(x, 1); } +#[cfg(test)] +const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + // Simple test source of randomness, for more straightforward debugging #[test_case] fn random_test() { let rng = ring::rand::SystemRandom::new(); - let mut buf = [0u8; 8]; - let result = rng.fill(&mut buf).is_err(); - log::info!("{:?}", buf); - assert_eq!(result, false); + let mut array = EMPTY_ARRAY.clone(); + assert_eq!(rng.fill(&mut array).is_err(), false); + assert_ne!(array, EMPTY_ARRAY); } From 3227a63ec7dcc8da0bf20887fadcdbc56a5b2610 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 11:19:51 +0100 Subject: [PATCH 09/29] add remote attestation handshake test --- experimental/uefi/app/.cargo/config.toml | 3 - experimental/uefi/app/Cargo.lock | 230 +++++++++++++++++++++++ experimental/uefi/app/Cargo.toml | 1 + experimental/uefi/app/src/main.rs | 89 +++++++++ 4 files changed, 320 insertions(+), 3 deletions(-) diff --git a/experimental/uefi/app/.cargo/config.toml b/experimental/uefi/app/.cargo/config.toml index b25fbccd921..b7fc19be6b3 100644 --- a/experimental/uefi/app/.cargo/config.toml +++ b/experimental/uefi/app/.cargo/config.toml @@ -1,9 +1,6 @@ [build] target = "x86_64-unknown-uefi" -# Test runners get only one serial port, routed to stdio. -[target.'cfg(test)'] -runner = "qemu-system-x86_64 -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" # Otherwise, (a) the first serial port gets routed to a log, and (b) the second serial gets attached to stdio. [target.'cfg(not(test))'] diff --git a/experimental/uefi/app/Cargo.lock b/experimental/uefi/app/Cargo.lock index b7fd4a68404..f09e4fae1f7 100644 --- a/experimental/uefi/app/Cargo.lock +++ b/experimental/uefi/app/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bit_field" version = "0.10.1" @@ -20,6 +26,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cc" version = "1.0.73" @@ -32,6 +44,82 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fixedbitset" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +dependencies = [ + "either", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.121" @@ -47,12 +135,40 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "oak_remote_attestation" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "log", + "prost", + "prost-build", + "ring", +] + [[package]] name = "once_cell" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +[[package]] +name = "petgraph" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "proc-macro2" version = "1.0.36" @@ -62,6 +178,61 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "prost" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07b0857a71a8cb765763950499cae2413c3f9cede1133478c43600d9e146890" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120fbe7988713f39d780a58cf1a7ef0d7ef66c6d87e5aa3438940c05357929f4" +dependencies = [ + "bytes", + "cfg-if", + "cmake", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost", +] + [[package]] name = "qemu-exit" version = "3.0.1" @@ -77,6 +248,39 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + [[package]] name = "ring" version = "0.17.0-not-released-yet" @@ -106,6 +310,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "ucs2" version = "0.3.2" @@ -156,6 +374,7 @@ version = "0.1.0" dependencies = [ "anyhow", "log", + "oak_remote_attestation", "ring", "uefi", "uefi-services", @@ -173,6 +392,17 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "which" +version = "4.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae" +dependencies = [ + "either", + "lazy_static", + "libc", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index c0da9db4046..0d53d7de258 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -11,6 +11,7 @@ uefi-services = "*" log = { version = "*" } ring = { path = "../../../third_party/ring" } anyhow = { version = "*", default-features = false } +oak_remote_attestation = { path = "../../../remote_attestation/rust" } [dev-dependencies] uefi-services = { version = "*", features = ["qemu"] } diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index bea8dfde774..055adb2180c 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -29,6 +29,11 @@ extern crate log; extern crate alloc; extern crate anyhow; +#[cfg(test)] +use alloc::{boxed::Box, sync::Arc}; +#[cfg(test)] +use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; + use uefi::{ prelude::*, proto::console::serial::Serial, @@ -147,3 +152,87 @@ fn random_test() { assert_eq!(rng.fill(&mut array).is_err(), false); assert_ne!(array, EMPTY_ARRAY); } + +#[cfg(test)] +const TEE_MEASUREMENT: &str = "Test TEE measurement"; +#[cfg(test)] +const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + +#[cfg(test)] +fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + let client_handshaker = ClientHandshaker::new( + bidirectional_attestation, + Box::new(|server_identity| { + if !server_identity.additional_info.is_empty() { + Ok(()) + } else { + anyhow::bail!("No additional info provided.") + } + }), + ); + + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + + let additional_info = br"Additional Info".to_vec(); + let server_handshaker = + ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); + + (client_handshaker, server_handshaker) +} + +#[test_case] +fn test_handshake() { + let (mut client_handshaker, mut server_handshaker) = create_handshakers(); + + let client_hello = client_handshaker + .create_client_hello() + .expect("Couldn't create client hello message"); + + let server_identity = server_handshaker + .next_step(&client_hello) + .expect("Couldn't process client hello message") + .expect("Empty server identity message"); + + let client_identity = client_handshaker + .next_step(&server_identity) + .expect("Couldn't process server identity message") + .expect("Empty client identity message"); + assert!(client_handshaker.is_completed()); + + let result = server_handshaker + .next_step(&client_identity) + .expect("Couldn't process client identity message"); + assert_eq!(result, None); + assert!(server_handshaker.is_completed()); + + let mut client_encryptor = client_handshaker + .get_encryptor() + .expect("Couldn't get client encryptor"); + let mut server_encryptor = server_handshaker + .get_encryptor() + .expect("Couldn't get server encryptor"); + + let encrypted_client_data = client_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt client data"); + let decrypted_client_data = server_encryptor + .decrypt(&encrypted_client_data) + .expect("Couldn't decrypt client data"); + assert_eq!(decrypted_client_data, DATA); + + let encrypted_server_data = server_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt server data"); + let decrypted_server_data = client_encryptor + .decrypt(&encrypted_server_data) + .expect("Couldn't decrypt server data"); + assert_eq!(decrypted_server_data, DATA); + + log::info!("{:?}", decrypted_server_data); + log::info!("hallelujah"); +} From d2009a399f2b5f9ef00d30290c0add6dd872b4c1 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 12:34:15 +0100 Subject: [PATCH 10/29] Update config to match #2725 --- experimental/uefi/app/.cargo/config.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/experimental/uefi/app/.cargo/config.toml b/experimental/uefi/app/.cargo/config.toml index b7fc19be6b3..477ae52ec72 100644 --- a/experimental/uefi/app/.cargo/config.toml +++ b/experimental/uefi/app/.cargo/config.toml @@ -1,9 +1,7 @@ [build] target = "x86_64-unknown-uefi" - -# Otherwise, (a) the first serial port gets routed to a log, and (b) the second serial gets attached to stdio. -[target.'cfg(not(test))'] +[target.x86_64-unknown-uefi] runner = "qemu-system-x86_64 -enable-kvm -cpu Broadwell-IBRS,vme=on,f16c=on,rdrand=on -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial file:target/console.log -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" [unstable] From d8de7d6786749d6f61884a50966dfcba6b260427 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 12:34:34 +0100 Subject: [PATCH 11/29] Remoe test of ring, as remote attestation is now tested --- experimental/uefi/app/Cargo.lock | 1 - experimental/uefi/app/Cargo.toml | 1 - experimental/uefi/app/src/main.rs | 12 ------------ 3 files changed, 14 deletions(-) diff --git a/experimental/uefi/app/Cargo.lock b/experimental/uefi/app/Cargo.lock index f09e4fae1f7..3de87178250 100644 --- a/experimental/uefi/app/Cargo.lock +++ b/experimental/uefi/app/Cargo.lock @@ -375,7 +375,6 @@ dependencies = [ "anyhow", "log", "oak_remote_attestation", - "ring", "uefi", "uefi-services", ] diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index 0d53d7de258..e469af4c856 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -9,7 +9,6 @@ license = "Apache-2.0" uefi = { version = "*", features = ["exts"] } uefi-services = "*" log = { version = "*" } -ring = { path = "../../../third_party/ring" } anyhow = { version = "*", default-features = false } oak_remote_attestation = { path = "../../../remote_attestation/rust" } diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index 055adb2180c..a808e09593c 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -43,9 +43,6 @@ use uefi::{ }, }; -#[cfg(test)] -use ring::rand::SecureRandom; - // The main entry point of the UEFI application. // // The choice of name (`_start`) is entirely arbitrary; what matters is that @@ -144,15 +141,6 @@ fn test_simple() { #[cfg(test)] const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; -// Simple test source of randomness, for more straightforward debugging -#[test_case] -fn random_test() { - let rng = ring::rand::SystemRandom::new(); - let mut array = EMPTY_ARRAY.clone(); - assert_eq!(rng.fill(&mut array).is_err(), false); - assert_ne!(array, EMPTY_ARRAY); -} - #[cfg(test)] const TEE_MEASUREMENT: &str = "Test TEE measurement"; #[cfg(test)] From 7a94c05b5099d975e6f7524c9cd7ed685751a704 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 12:35:14 +0100 Subject: [PATCH 12/29] remove debugging logs from remote attestation test --- experimental/uefi/app/src/main.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index a808e09593c..c0cbe664ce7 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -220,7 +220,4 @@ fn test_handshake() { .decrypt(&encrypted_server_data) .expect("Couldn't decrypt server data"); assert_eq!(decrypted_server_data, DATA); - - log::info!("{:?}", decrypted_server_data); - log::info!("hallelujah"); } From 2779e2a7cf2d9d39b7a3ece1c51e3145ae8b6323 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 12:50:10 +0100 Subject: [PATCH 13/29] wip --- experimental/uefi/app/src/main.rs | 91 ---------- .../uefi/app/tests/remote_attestation.rs | 156 ++++++++++++++++++ 2 files changed, 156 insertions(+), 91 deletions(-) create mode 100644 experimental/uefi/app/tests/remote_attestation.rs diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index c0cbe664ce7..12bdcf69e8c 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -26,13 +26,6 @@ #[macro_use] extern crate log; -extern crate alloc; -extern crate anyhow; - -#[cfg(test)] -use alloc::{boxed::Box, sync::Arc}; -#[cfg(test)] -use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; use uefi::{ prelude::*, @@ -137,87 +130,3 @@ fn test_simple() { let x = 1; assert_eq!(x, 1); } - -#[cfg(test)] -const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; - -#[cfg(test)] -const TEE_MEASUREMENT: &str = "Test TEE measurement"; -#[cfg(test)] -const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - -#[cfg(test)] -fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - let client_handshaker = ClientHandshaker::new( - bidirectional_attestation, - Box::new(|server_identity| { - if !server_identity.additional_info.is_empty() { - Ok(()) - } else { - anyhow::bail!("No additional info provided.") - } - }), - ); - - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - - let additional_info = br"Additional Info".to_vec(); - let server_handshaker = - ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); - - (client_handshaker, server_handshaker) -} - -#[test_case] -fn test_handshake() { - let (mut client_handshaker, mut server_handshaker) = create_handshakers(); - - let client_hello = client_handshaker - .create_client_hello() - .expect("Couldn't create client hello message"); - - let server_identity = server_handshaker - .next_step(&client_hello) - .expect("Couldn't process client hello message") - .expect("Empty server identity message"); - - let client_identity = client_handshaker - .next_step(&server_identity) - .expect("Couldn't process server identity message") - .expect("Empty client identity message"); - assert!(client_handshaker.is_completed()); - - let result = server_handshaker - .next_step(&client_identity) - .expect("Couldn't process client identity message"); - assert_eq!(result, None); - assert!(server_handshaker.is_completed()); - - let mut client_encryptor = client_handshaker - .get_encryptor() - .expect("Couldn't get client encryptor"); - let mut server_encryptor = server_handshaker - .get_encryptor() - .expect("Couldn't get server encryptor"); - - let encrypted_client_data = client_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt client data"); - let decrypted_client_data = server_encryptor - .decrypt(&encrypted_client_data) - .expect("Couldn't decrypt client data"); - assert_eq!(decrypted_client_data, DATA); - - let encrypted_server_data = server_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt server data"); - let decrypted_server_data = client_encryptor - .decrypt(&encrypted_server_data) - .expect("Couldn't decrypt server data"); - assert_eq!(decrypted_server_data, DATA); -} diff --git a/experimental/uefi/app/tests/remote_attestation.rs b/experimental/uefi/app/tests/remote_attestation.rs new file mode 100644 index 00000000000..acddecefdf9 --- /dev/null +++ b/experimental/uefi/app/tests/remote_attestation.rs @@ -0,0 +1,156 @@ +// +// 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. +// + +#![no_main] +#![no_std] +#![feature(abi_efiapi)] +#![feature(never_type)] +#![feature(custom_test_frameworks)] +// As we're in a `no_std` environment, testing requires special handling. This +// approach was inspired by https://os.phil-opp.com/testing/. +#![test_runner(crate::test_runner)] +#![reexport_test_harness_main = "test_main"] + +#[macro_use] +extern crate log; +extern crate alloc; +extern crate anyhow; + +use alloc::{boxed::Box, sync::Arc}; +use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; + +use uefi::{ + prelude::*, + proto::console::serial::Serial, + table::{ + boot::{OpenProtocolAttributes, OpenProtocolParams}, + runtime::ResetType, + }, +}; + +// The main entry point of the UEFI application. +// +// The choice of name (`_start`) is entirely arbitrary; what matters is that +// there's exactly one function with the `#[entry]` attribute in the +// dependency graph. +#[entry] +fn _start(_handle: Handle, mut system_table: SystemTable) -> Status { + uefi_services::init(&mut system_table).unwrap(); + + // As we're not relying on the normal Rust test harness, we need to call + // the tests ourselves. + test_main(); + Status::SUCCESS + + // After we're done running our code, we also tell the UEFI runtime to shut + // down the machine, otherwise we'd go back to the UEFI shell. + system_table + .runtime_services() + .reset(ResetType::Shutdown, status, None); +} + +fn test_runner(tests: &[&dyn Fn()]) { + for test in tests { + test(); + } +} + +// Simple silly test just to prove that the test infrastructure works. +#[test_case] +fn test_simple() { + let x = 1; + assert_eq!(x, 1); +} + +const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + +const TEE_MEASUREMENT: &str = "Test TEE measurement"; +const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + +fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + let client_handshaker = ClientHandshaker::new( + bidirectional_attestation, + Box::new(|server_identity| { + if !server_identity.additional_info.is_empty() { + Ok(()) + } else { + anyhow::bail!("No additional info provided.") + } + }), + ); + + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + + let additional_info = br"Additional Info".to_vec(); + let server_handshaker = + ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); + + (client_handshaker, server_handshaker) +} + +#[test_case] +fn test_handshake() { + let (mut client_handshaker, mut server_handshaker) = create_handshakers(); + + let client_hello = client_handshaker + .create_client_hello() + .expect("Couldn't create client hello message"); + + let server_identity = server_handshaker + .next_step(&client_hello) + .expect("Couldn't process client hello message") + .expect("Empty server identity message"); + + let client_identity = client_handshaker + .next_step(&server_identity) + .expect("Couldn't process server identity message") + .expect("Empty client identity message"); + assert!(client_handshaker.is_completed()); + + let result = server_handshaker + .next_step(&client_identity) + .expect("Couldn't process client identity message"); + assert_eq!(result, None); + assert!(server_handshaker.is_completed()); + + let mut client_encryptor = client_handshaker + .get_encryptor() + .expect("Couldn't get client encryptor"); + let mut server_encryptor = server_handshaker + .get_encryptor() + .expect("Couldn't get server encryptor"); + + let encrypted_client_data = client_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt client data"); + let decrypted_client_data = server_encryptor + .decrypt(&encrypted_client_data) + .expect("Couldn't decrypt client data"); + assert_eq!(decrypted_client_data, DATA); + + let encrypted_server_data = server_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt server data"); + let decrypted_server_data = client_encryptor + .decrypt(&encrypted_server_data) + .expect("Couldn't decrypt server data"); + assert_eq!(decrypted_server_data, DATA); +} From 17960fd5d3cea42f19826685a0dcc3fcf9011021 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 15:34:48 +0100 Subject: [PATCH 14/29] Revert "wip" This reverts commit 2779e2a7cf2d9d39b7a3ece1c51e3145ae8b6323. --- experimental/uefi/app/src/main.rs | 91 ++++++++++ .../uefi/app/tests/remote_attestation.rs | 156 ------------------ 2 files changed, 91 insertions(+), 156 deletions(-) delete mode 100644 experimental/uefi/app/tests/remote_attestation.rs diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index 12bdcf69e8c..c0cbe664ce7 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -26,6 +26,13 @@ #[macro_use] extern crate log; +extern crate alloc; +extern crate anyhow; + +#[cfg(test)] +use alloc::{boxed::Box, sync::Arc}; +#[cfg(test)] +use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; use uefi::{ prelude::*, @@ -130,3 +137,87 @@ fn test_simple() { let x = 1; assert_eq!(x, 1); } + +#[cfg(test)] +const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; + +#[cfg(test)] +const TEE_MEASUREMENT: &str = "Test TEE measurement"; +#[cfg(test)] +const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + +#[cfg(test)] +fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + let client_handshaker = ClientHandshaker::new( + bidirectional_attestation, + Box::new(|server_identity| { + if !server_identity.additional_info.is_empty() { + Ok(()) + } else { + anyhow::bail!("No additional info provided.") + } + }), + ); + + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + + let additional_info = br"Additional Info".to_vec(); + let server_handshaker = + ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); + + (client_handshaker, server_handshaker) +} + +#[test_case] +fn test_handshake() { + let (mut client_handshaker, mut server_handshaker) = create_handshakers(); + + let client_hello = client_handshaker + .create_client_hello() + .expect("Couldn't create client hello message"); + + let server_identity = server_handshaker + .next_step(&client_hello) + .expect("Couldn't process client hello message") + .expect("Empty server identity message"); + + let client_identity = client_handshaker + .next_step(&server_identity) + .expect("Couldn't process server identity message") + .expect("Empty client identity message"); + assert!(client_handshaker.is_completed()); + + let result = server_handshaker + .next_step(&client_identity) + .expect("Couldn't process client identity message"); + assert_eq!(result, None); + assert!(server_handshaker.is_completed()); + + let mut client_encryptor = client_handshaker + .get_encryptor() + .expect("Couldn't get client encryptor"); + let mut server_encryptor = server_handshaker + .get_encryptor() + .expect("Couldn't get server encryptor"); + + let encrypted_client_data = client_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt client data"); + let decrypted_client_data = server_encryptor + .decrypt(&encrypted_client_data) + .expect("Couldn't decrypt client data"); + assert_eq!(decrypted_client_data, DATA); + + let encrypted_server_data = server_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt server data"); + let decrypted_server_data = client_encryptor + .decrypt(&encrypted_server_data) + .expect("Couldn't decrypt server data"); + assert_eq!(decrypted_server_data, DATA); +} diff --git a/experimental/uefi/app/tests/remote_attestation.rs b/experimental/uefi/app/tests/remote_attestation.rs deleted file mode 100644 index acddecefdf9..00000000000 --- a/experimental/uefi/app/tests/remote_attestation.rs +++ /dev/null @@ -1,156 +0,0 @@ -// -// 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. -// - -#![no_main] -#![no_std] -#![feature(abi_efiapi)] -#![feature(never_type)] -#![feature(custom_test_frameworks)] -// As we're in a `no_std` environment, testing requires special handling. This -// approach was inspired by https://os.phil-opp.com/testing/. -#![test_runner(crate::test_runner)] -#![reexport_test_harness_main = "test_main"] - -#[macro_use] -extern crate log; -extern crate alloc; -extern crate anyhow; - -use alloc::{boxed::Box, sync::Arc}; -use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; - -use uefi::{ - prelude::*, - proto::console::serial::Serial, - table::{ - boot::{OpenProtocolAttributes, OpenProtocolParams}, - runtime::ResetType, - }, -}; - -// The main entry point of the UEFI application. -// -// The choice of name (`_start`) is entirely arbitrary; what matters is that -// there's exactly one function with the `#[entry]` attribute in the -// dependency graph. -#[entry] -fn _start(_handle: Handle, mut system_table: SystemTable) -> Status { - uefi_services::init(&mut system_table).unwrap(); - - // As we're not relying on the normal Rust test harness, we need to call - // the tests ourselves. - test_main(); - Status::SUCCESS - - // After we're done running our code, we also tell the UEFI runtime to shut - // down the machine, otherwise we'd go back to the UEFI shell. - system_table - .runtime_services() - .reset(ResetType::Shutdown, status, None); -} - -fn test_runner(tests: &[&dyn Fn()]) { - for test in tests { - test(); - } -} - -// Simple silly test just to prove that the test infrastructure works. -#[test_case] -fn test_simple() { - let x = 1; - assert_eq!(x, 1); -} - -const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; - -const TEE_MEASUREMENT: &str = "Test TEE measurement"; -const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - -fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - let client_handshaker = ClientHandshaker::new( - bidirectional_attestation, - Box::new(|server_identity| { - if !server_identity.additional_info.is_empty() { - Ok(()) - } else { - anyhow::bail!("No additional info provided.") - } - }), - ); - - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - - let additional_info = br"Additional Info".to_vec(); - let server_handshaker = - ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); - - (client_handshaker, server_handshaker) -} - -#[test_case] -fn test_handshake() { - let (mut client_handshaker, mut server_handshaker) = create_handshakers(); - - let client_hello = client_handshaker - .create_client_hello() - .expect("Couldn't create client hello message"); - - let server_identity = server_handshaker - .next_step(&client_hello) - .expect("Couldn't process client hello message") - .expect("Empty server identity message"); - - let client_identity = client_handshaker - .next_step(&server_identity) - .expect("Couldn't process server identity message") - .expect("Empty client identity message"); - assert!(client_handshaker.is_completed()); - - let result = server_handshaker - .next_step(&client_identity) - .expect("Couldn't process client identity message"); - assert_eq!(result, None); - assert!(server_handshaker.is_completed()); - - let mut client_encryptor = client_handshaker - .get_encryptor() - .expect("Couldn't get client encryptor"); - let mut server_encryptor = server_handshaker - .get_encryptor() - .expect("Couldn't get server encryptor"); - - let encrypted_client_data = client_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt client data"); - let decrypted_client_data = server_encryptor - .decrypt(&encrypted_client_data) - .expect("Couldn't decrypt client data"); - assert_eq!(decrypted_client_data, DATA); - - let encrypted_server_data = server_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt server data"); - let decrypted_server_data = client_encryptor - .decrypt(&encrypted_server_data) - .expect("Couldn't decrypt server data"); - assert_eq!(decrypted_server_data, DATA); -} From b458198ddce8047e2984d12c952a899d907409b2 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 15:54:37 +0100 Subject: [PATCH 15/29] Move the UEFI remote attestation test into it's own module --- experimental/uefi/app/src/main.rs | 88 +------------- experimental/uefi/app/src/tests/mod.rs | 17 +++ .../uefi/app/src/tests/remote_attestation.rs | 109 ++++++++++++++++++ 3 files changed, 127 insertions(+), 87 deletions(-) create mode 100644 experimental/uefi/app/src/tests/mod.rs create mode 100644 experimental/uefi/app/src/tests/remote_attestation.rs diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index c0cbe664ce7..3d2a825d64c 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -29,11 +29,6 @@ extern crate log; extern crate alloc; extern crate anyhow; -#[cfg(test)] -use alloc::{boxed::Box, sync::Arc}; -#[cfg(test)] -use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; - use uefi::{ prelude::*, proto::console::serial::Serial, @@ -139,85 +134,4 @@ fn test_simple() { } #[cfg(test)] -const EMPTY_ARRAY: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0]; - -#[cfg(test)] -const TEE_MEASUREMENT: &str = "Test TEE measurement"; -#[cfg(test)] -const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - -#[cfg(test)] -fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - let client_handshaker = ClientHandshaker::new( - bidirectional_attestation, - Box::new(|server_identity| { - if !server_identity.additional_info.is_empty() { - Ok(()) - } else { - anyhow::bail!("No additional info provided.") - } - }), - ); - - let bidirectional_attestation = - AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) - .unwrap(); - - let additional_info = br"Additional Info".to_vec(); - let server_handshaker = - ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); - - (client_handshaker, server_handshaker) -} - -#[test_case] -fn test_handshake() { - let (mut client_handshaker, mut server_handshaker) = create_handshakers(); - - let client_hello = client_handshaker - .create_client_hello() - .expect("Couldn't create client hello message"); - - let server_identity = server_handshaker - .next_step(&client_hello) - .expect("Couldn't process client hello message") - .expect("Empty server identity message"); - - let client_identity = client_handshaker - .next_step(&server_identity) - .expect("Couldn't process server identity message") - .expect("Empty client identity message"); - assert!(client_handshaker.is_completed()); - - let result = server_handshaker - .next_step(&client_identity) - .expect("Couldn't process client identity message"); - assert_eq!(result, None); - assert!(server_handshaker.is_completed()); - - let mut client_encryptor = client_handshaker - .get_encryptor() - .expect("Couldn't get client encryptor"); - let mut server_encryptor = server_handshaker - .get_encryptor() - .expect("Couldn't get server encryptor"); - - let encrypted_client_data = client_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt client data"); - let decrypted_client_data = server_encryptor - .decrypt(&encrypted_client_data) - .expect("Couldn't decrypt client data"); - assert_eq!(decrypted_client_data, DATA); - - let encrypted_server_data = server_encryptor - .encrypt(&DATA) - .expect("Couldn't encrypt server data"); - let decrypted_server_data = client_encryptor - .decrypt(&encrypted_server_data) - .expect("Couldn't decrypt server data"); - assert_eq!(decrypted_server_data, DATA); -} +mod tests; diff --git a/experimental/uefi/app/src/tests/mod.rs b/experimental/uefi/app/src/tests/mod.rs new file mode 100644 index 00000000000..7724cdb4350 --- /dev/null +++ b/experimental/uefi/app/src/tests/mod.rs @@ -0,0 +1,17 @@ +// +// 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. +// + +mod remote_attestation; diff --git a/experimental/uefi/app/src/tests/remote_attestation.rs b/experimental/uefi/app/src/tests/remote_attestation.rs new file mode 100644 index 00000000000..e0b1e705ff3 --- /dev/null +++ b/experimental/uefi/app/src/tests/remote_attestation.rs @@ -0,0 +1,109 @@ +// +// 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. +// + +//! Integration Test of Remote Attestation in UEFI +//! This tests that remote attestion works inside the UEFI app. While the test +//! code is identical to (a subset of) the tests in the remote attestation crate +//! they here utilize the qemu runner configured in the UEFI app. This means +//! that test code actually compiled to a UEFI target, which changes the +//! underlying implementation of the remote attestation crate. +//! TODO(#2654): It would be preferable to remove the test here, and instead +//! run the tests in the oak_remote_attestation crate itself for both standard +//! and UEFI targets. Due to concerns related to the workspace this is presently +//! not possible. Ref: https://github.com/project-oak/oak/issues/2654 + +use alloc::{boxed::Box, sync::Arc}; +use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; + +const TEE_MEASUREMENT: &str = "Test TEE measurement"; +const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + +fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + let client_handshaker = ClientHandshaker::new( + bidirectional_attestation, + Box::new(|server_identity| { + if !server_identity.additional_info.is_empty() { + Ok(()) + } else { + anyhow::bail!("No additional info provided.") + } + }), + ); + + let bidirectional_attestation = + AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes()) + .unwrap(); + + let additional_info = br"Additional Info".to_vec(); + let server_handshaker = + ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info)); + + (client_handshaker, server_handshaker) +} + +#[test_case] +fn test_handshake() { + log::info!("henlo"); + + let (mut client_handshaker, mut server_handshaker) = create_handshakers(); + + let client_hello = client_handshaker + .create_client_hello() + .expect("Couldn't create client hello message"); + + let server_identity = server_handshaker + .next_step(&client_hello) + .expect("Couldn't process client hello message") + .expect("Empty server identity message"); + + let client_identity = client_handshaker + .next_step(&server_identity) + .expect("Couldn't process server identity message") + .expect("Empty client identity message"); + assert!(client_handshaker.is_completed()); + + let result = server_handshaker + .next_step(&client_identity) + .expect("Couldn't process client identity message"); + assert_eq!(result, None); + assert!(server_handshaker.is_completed()); + + let mut client_encryptor = client_handshaker + .get_encryptor() + .expect("Couldn't get client encryptor"); + let mut server_encryptor = server_handshaker + .get_encryptor() + .expect("Couldn't get server encryptor"); + + let encrypted_client_data = client_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt client data"); + let decrypted_client_data = server_encryptor + .decrypt(&encrypted_client_data) + .expect("Couldn't decrypt client data"); + assert_eq!(decrypted_client_data, DATA); + + let encrypted_server_data = server_encryptor + .encrypt(&DATA) + .expect("Couldn't encrypt server data"); + let decrypted_server_data = client_encryptor + .decrypt(&encrypted_server_data) + .expect("Couldn't decrypt server data"); + assert_eq!(decrypted_server_data, DATA); +} From 9d43182a86a8c55baa7398b4be802d7f6ced09d3 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 15:55:25 +0100 Subject: [PATCH 16/29] remove now unneeded crate imports in the main UEFI app --- experimental/uefi/app/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/experimental/uefi/app/src/main.rs b/experimental/uefi/app/src/main.rs index 3d2a825d64c..7a95dd57c02 100644 --- a/experimental/uefi/app/src/main.rs +++ b/experimental/uefi/app/src/main.rs @@ -26,8 +26,6 @@ #[macro_use] extern crate log; -extern crate alloc; -extern crate anyhow; use uefi::{ prelude::*, From 2e0bc9ad89d8a18c832e93e084377da84da750ab Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 15:57:45 +0100 Subject: [PATCH 17/29] finalize moving remote attestation test --- experimental/uefi/app/Cargo.toml | 1 - experimental/uefi/app/src/tests/remote_attestation.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index e469af4c856..4e47574c818 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -9,7 +9,6 @@ license = "Apache-2.0" uefi = { version = "*", features = ["exts"] } uefi-services = "*" log = { version = "*" } -anyhow = { version = "*", default-features = false } oak_remote_attestation = { path = "../../../remote_attestation/rust" } [dev-dependencies] diff --git a/experimental/uefi/app/src/tests/remote_attestation.rs b/experimental/uefi/app/src/tests/remote_attestation.rs index e0b1e705ff3..78478d89048 100644 --- a/experimental/uefi/app/src/tests/remote_attestation.rs +++ b/experimental/uefi/app/src/tests/remote_attestation.rs @@ -25,6 +25,8 @@ //! and UEFI targets. Due to concerns related to the workspace this is presently //! not possible. Ref: https://github.com/project-oak/oak/issues/2654 +extern crate alloc; + use alloc::{boxed::Box, sync::Arc}; use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker}; @@ -59,8 +61,6 @@ fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) { #[test_case] fn test_handshake() { - log::info!("henlo"); - let (mut client_handshaker, mut server_handshaker) = create_handshakers(); let client_hello = client_handshaker From 7f0889b7adec92072f07afa37310d24e3977c189 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 16:06:03 +0100 Subject: [PATCH 18/29] redundant surplus qemu cpu flags --- experimental/uefi/app/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experimental/uefi/app/.cargo/config.toml b/experimental/uefi/app/.cargo/config.toml index 477ae52ec72..6080f75ba29 100644 --- a/experimental/uefi/app/.cargo/config.toml +++ b/experimental/uefi/app/.cargo/config.toml @@ -2,7 +2,7 @@ target = "x86_64-unknown-uefi" [target.x86_64-unknown-uefi] -runner = "qemu-system-x86_64 -enable-kvm -cpu Broadwell-IBRS,vme=on,f16c=on,rdrand=on -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial file:target/console.log -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" +runner = "qemu-system-x86_64 -enable-kvm -cpu Broadwell-IBRS -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial file:target/console.log -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" [unstable] build-std = ["core", "alloc"] From 7bb238121544e9caab6f32abbc0bcc870838bd90 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 16:09:45 +0100 Subject: [PATCH 19/29] Add anyhow as dev dep for test --- experimental/uefi/app/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index 4e47574c818..6995a67bb64 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -12,4 +12,5 @@ log = { version = "*" } oak_remote_attestation = { path = "../../../remote_attestation/rust" } [dev-dependencies] +anyhow = { version = "*", default-features = false } uefi-services = { version = "*", features = ["qemu"] } From 56e0e253de88ee5245dde8e75f6cf428d2da6b88 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 16:18:39 +0100 Subject: [PATCH 20/29] Add extra context to ring stubs --- third_party/ring/stubs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/third_party/ring/stubs.c b/third_party/ring/stubs.c index 6765ccec1ce..2bfefd255ab 100644 --- a/third_party/ring/stubs.c +++ b/third_party/ring/stubs.c @@ -3,7 +3,8 @@ /** * Stub function for win64 error handler API call inserted by nasm. - Stubbed as it is unavailable in UEFI. + Stubbed as it is unavailable in UEFI. It appears unlikely this call will + ever be invoked in deployment. Ref: https://github.com/openssl/openssl/issues/12712. Inspired by: https://github.com/tianocore/edk2/blob/7c0ad2c33810ead45b7919f8f8d0e282dae52e71/CryptoPkg/Library/OpensslLib/X64/ApiHooks.c **/ @@ -17,9 +18,10 @@ __imp_RtlVirtualUnwind ( /** Stub function for win64 routine used for exceedingly large variables. - Inserted Mby inGW, stubbed as it is unavailable in UEFI. - Ref 1: https://metricpanda.com/rival-fortress-update-45-dealing-with-__chkstk-__chkstk_ms-when-cross-compiling-for-windows/ - Ref 2: https://github.com/golang/go/issues/6305 + Inserted Mby inGW, stubbed as it is unavailable in UEFI. Given that this + routine is used for very large variable it appears unlikely to ever be + invoked in deployment. + Ref: https://github.com/golang/go/issues/6305 Inspired by: https://android.googlesource.com/platform/external/compiler-rt/+/ccaafe6%5E%21/#F1 **/ void ___chkstk_ms(void) From 6f66c522b05b60cb0edec4f99856e3b0824e4ffd Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 18:31:04 +0000 Subject: [PATCH 21/29] Only run remote attestation tests if the hosts supports kvm, and the kvm feature is set --- experimental/uefi/app/.cargo/config.toml | 2 +- experimental/uefi/app/Cargo.toml | 4 +++ experimental/uefi/app/runner | 33 ++++++++++++++++++++++++ experimental/uefi/app/src/tests/mod.rs | 3 +++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100755 experimental/uefi/app/runner diff --git a/experimental/uefi/app/.cargo/config.toml b/experimental/uefi/app/.cargo/config.toml index 6080f75ba29..0bb001dca52 100644 --- a/experimental/uefi/app/.cargo/config.toml +++ b/experimental/uefi/app/.cargo/config.toml @@ -2,7 +2,7 @@ target = "x86_64-unknown-uefi" [target.x86_64-unknown-uefi] -runner = "qemu-system-x86_64 -enable-kvm -cpu Broadwell-IBRS -nodefaults -nographic -bios /usr/share/OVMF/OVMF_CODE.fd -serial file:target/console.log -serial stdio -machine q35 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -kernel" +runner = "./runner" [unstable] build-std = ["core", "alloc"] diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index 6995a67bb64..27b0a14f929 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -5,6 +5,10 @@ authors = ["Andri Saar "] edition = "2021" license = "Apache-2.0" +[features] +default = [] +kvm = [] + [dependencies] uefi = { version = "*", features = ["exts"] } uefi-services = "*" diff --git a/experimental/uefi/app/runner b/experimental/uefi/app/runner new file mode 100755 index 00000000000..d2f62e9913a --- /dev/null +++ b/experimental/uefi/app/runner @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# Thin shell script invoked as a cargo runner to run the compiled efi firmware +# in QEMU. Detects if kvm is supported, and sets qemu flags based on that. +# Instead of this single runner script it would be preferable to use a different +# runner based on whether the kvm feature is set. However, cargo does not +# currently allow this. Ref: https://github.com/rust-lang/cargo/issues/8170 + +readonly TARGET=$1 + +qemu_flags=( + '-nodefaults' + '-nographic' + '-bios' '/usr/share/OVMF/OVMF_CODE.fd' + '-serial' 'file:target/console.log' + '-serial' 'stdio' + '-machine' 'q35' + '-device' 'isa-debug-exit,iobase=0xf4,iosize=0x04' +) + +# If the host supports KVM, allow the image to use it. Ideally this check +# should be based on whether the kvm cargo feature is available. However, cargo +# does not expose this information to the runner. +# Ref: https://doc.rust-lang.org/cargo/reference/environment-variables.html +if [[ -e "/dev/kvm" ]]; then + qemu_flags+=( + '-enable-kvm' + '-cpu' 'Broadwell-IBRS' + ) +fi + +qemu-system-x86_64 "${qemu_flags[@]}" -kernel "${TARGET}" + diff --git a/experimental/uefi/app/src/tests/mod.rs b/experimental/uefi/app/src/tests/mod.rs index 7724cdb4350..4ef494ef238 100644 --- a/experimental/uefi/app/src/tests/mod.rs +++ b/experimental/uefi/app/src/tests/mod.rs @@ -14,4 +14,7 @@ // limitations under the License. // +// Requires advanced CPU features that are unavailable when running using +// emulation. +#[cfg(feature = "kvm")] mod remote_attestation; From ca2cea7fee773ffe91b4088fd62e5e8b546f3305 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 18:41:35 +0000 Subject: [PATCH 22/29] improve comment for clarity --- experimental/uefi/app/runner | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/experimental/uefi/app/runner b/experimental/uefi/app/runner index d2f62e9913a..f663831d02c 100755 --- a/experimental/uefi/app/runner +++ b/experimental/uefi/app/runner @@ -18,9 +18,12 @@ qemu_flags=( '-device' 'isa-debug-exit,iobase=0xf4,iosize=0x04' ) -# If the host supports KVM, allow the image to use it. Ideally this check -# should be based on whether the kvm cargo feature is available. However, cargo -# does not expose this information to the runner. +# Use kvm if supported, as it is required for certain features (that are gated +# behind the cargo `kvm` feature flag. Note that systems that support kvm still +# need to enable the cargo `kvm` feature for this crate in order to include +# code that requires kvm in the compiled firmware. Ideally this check would +# check the cargo `kvm` flag itself. However, cargo does not expose this +# information to the runner. # Ref: https://doc.rust-lang.org/cargo/reference/environment-variables.html if [[ -e "/dev/kvm" ]]; then qemu_flags+=( From 0c424d5de35be4f40b6f00992bbb8d5499292783 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 18:44:10 +0000 Subject: [PATCH 23/29] improve comment copy --- experimental/uefi/app/runner | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/experimental/uefi/app/runner b/experimental/uefi/app/runner index f663831d02c..33b4f90cc06 100755 --- a/experimental/uefi/app/runner +++ b/experimental/uefi/app/runner @@ -18,11 +18,10 @@ qemu_flags=( '-device' 'isa-debug-exit,iobase=0xf4,iosize=0x04' ) -# Use kvm if supported, as it is required for certain features (that are gated -# behind the cargo `kvm` feature flag. Note that systems that support kvm still -# need to enable the cargo `kvm` feature for this crate in order to include -# code that requires kvm in the compiled firmware. Ideally this check would -# check the cargo `kvm` flag itself. However, cargo does not expose this +# Use kvm if supported, as it is required for certain features. Note +# that hosts that support kvm still need to enable the `kvm` feature in cargo +# to include code that requires kvm in the compiled firmware. Ideally this check +# would rely on the cargo `kvm` flag itself. However, cargo does not expose this # information to the runner. # Ref: https://doc.rust-lang.org/cargo/reference/environment-variables.html if [[ -e "/dev/kvm" ]]; then From 8d258a55f056469a953e20a158829ceb16dd741f Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 21:23:46 +0100 Subject: [PATCH 24/29] disable ring default features to fix duplicate lang items --- remote_attestation/rust/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote_attestation/rust/Cargo.toml b/remote_attestation/rust/Cargo.toml index 87692263b70..f15064be569 100644 --- a/remote_attestation/rust/Cargo.toml +++ b/remote_attestation/rust/Cargo.toml @@ -14,7 +14,7 @@ anyhow = { version = "*", default-features = false } bytes = { version = "*", default-features = false } log = "*" prost = { version = "*", default-features = false, features = ["prost-derive"] } -ring = { path = "../../third_party/ring" } +ring = { path = "../../third_party/ring", default-features = false } [build-dependencies] prost-build = "*" From 26082d07e820d9c5efacde4acb01b1ec9b17c819 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 21:24:42 +0100 Subject: [PATCH 25/29] bust CI cache --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 128fb9ba3c1..74fd71db4df 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -64,7 +64,7 @@ jobs: uses: actions/cache@v2 env: # Increment this value to invalidate previous cache entries. - CACHE_VERSION: 3 + CACHE_VERSION: 4 with: path: | ./cargo-cache/bin From eebf47c1f55dac75bab9ee36f85b02c89b8d3c01 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 23:00:26 +0100 Subject: [PATCH 26/29] toggle tests that require kvm by disabling a default flag, as xtask enables all flags for tests --- experimental/uefi/app/Cargo.toml | 4 ++-- experimental/uefi/app/runner | 10 +++++----- experimental/uefi/app/src/tests/mod.rs | 5 ++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/experimental/uefi/app/Cargo.toml b/experimental/uefi/app/Cargo.toml index 2a7d0c2ecd5..a251d6b37a0 100644 --- a/experimental/uefi/app/Cargo.toml +++ b/experimental/uefi/app/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" license = "Apache-2.0" [features] -default = [] -kvm = [] +default = ["support_emulated_runner"] +support_emulated_runner = [] [dependencies] uefi = { version = "*", features = ["exts"] } diff --git a/experimental/uefi/app/runner b/experimental/uefi/app/runner index 33b4f90cc06..50a0529bad1 100755 --- a/experimental/uefi/app/runner +++ b/experimental/uefi/app/runner @@ -19,11 +19,11 @@ qemu_flags=( ) # Use kvm if supported, as it is required for certain features. Note -# that hosts that support kvm still need to enable the `kvm` feature in cargo -# to include code that requires kvm in the compiled firmware. Ideally this check -# would rely on the cargo `kvm` flag itself. However, cargo does not expose this -# information to the runner. -# Ref: https://doc.rust-lang.org/cargo/reference/environment-variables.html +# that hosts that support kvm still need to disable the default +# `support_emulated_runner` feature in cargo to include code that requires kvm +# in the compiled firmware. Ideally this check would rely on the cargo +# flag itself, enabling kvm if it is disabled. However cargo does not expose +# which flags are set to the runner. Ref: https://doc.rust-lang.org/cargo/reference/environment-variables.html if [[ -e "/dev/kvm" ]]; then qemu_flags+=( '-enable-kvm' diff --git a/experimental/uefi/app/src/tests/mod.rs b/experimental/uefi/app/src/tests/mod.rs index 4ef494ef238..eda732722ed 100644 --- a/experimental/uefi/app/src/tests/mod.rs +++ b/experimental/uefi/app/src/tests/mod.rs @@ -14,7 +14,6 @@ // limitations under the License. // -// Requires advanced CPU features that are unavailable when running using -// emulation. -#[cfg(feature = "kvm")] +// Uses advanced CPU features not available +#[cfg(not(feature = "support_emulated_runner"))] mod remote_attestation; From 6c27bf0a074567a110b7988656e120bb92e89c93 Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Thu, 14 Apr 2022 23:01:26 +0100 Subject: [PATCH 27/29] Clarify comment --- experimental/uefi/app/src/tests/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/experimental/uefi/app/src/tests/mod.rs b/experimental/uefi/app/src/tests/mod.rs index eda732722ed..5000bc72246 100644 --- a/experimental/uefi/app/src/tests/mod.rs +++ b/experimental/uefi/app/src/tests/mod.rs @@ -14,6 +14,7 @@ // limitations under the License. // -// Uses advanced CPU features not available +// Uses advanced CPU features not available when using running tests in qemu +// with CPU emulation. #[cfg(not(feature = "support_emulated_runner"))] mod remote_attestation; From 23a3508b8790a0b4979aaabdda64fa25b7aff2ca Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Tue, 19 Apr 2022 13:59:26 +0000 Subject: [PATCH 28/29] Improve comments for accuracy and clarity --- experimental/uefi/app/src/tests/remote_attestation.rs | 3 ++- third_party/ring/stubs.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/experimental/uefi/app/src/tests/remote_attestation.rs b/experimental/uefi/app/src/tests/remote_attestation.rs index 78478d89048..63bc1e473dd 100644 --- a/experimental/uefi/app/src/tests/remote_attestation.rs +++ b/experimental/uefi/app/src/tests/remote_attestation.rs @@ -14,7 +14,8 @@ // limitations under the License. // -//! Integration Test of Remote Attestation in UEFI +//! Integration Test of Remote Attestation in UEFI. +//! //! This tests that remote attestion works inside the UEFI app. While the test //! code is identical to (a subset of) the tests in the remote attestation crate //! they here utilize the qemu runner configured in the UEFI app. This means diff --git a/third_party/ring/stubs.c b/third_party/ring/stubs.c index 2bfefd255ab..0141367c2be 100644 --- a/third_party/ring/stubs.c +++ b/third_party/ring/stubs.c @@ -18,7 +18,7 @@ __imp_RtlVirtualUnwind ( /** Stub function for win64 routine used for exceedingly large variables. - Inserted Mby inGW, stubbed as it is unavailable in UEFI. Given that this + Inserted nasm, stubbed as it is unavailable in UEFI. Given that this routine is used for very large variable it appears unlikely to ever be invoked in deployment. Ref: https://github.com/golang/go/issues/6305 From 9e0312346ddf84d421a643d60b975a34b2a4ecbf Mon Sep 17 00:00:00 2001 From: Juliette Pretot Date: Tue, 19 Apr 2022 15:58:26 +0000 Subject: [PATCH 29/29] Don't lint target subdirectories created by cargo fuzz --- xtask/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index bb3db6de03e..e8b3bea6470 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -585,6 +585,9 @@ fn run_clang_format(mode: FormatMode) -> Step { "--recursive", "--exclude", "*/node_modules", + // TODO(#2654): Remove once all crates are part of the same workspace again + "--exclude", + "*/target", "--exclude", "third_party", "oak_functions",