Skip to content

Commit 4a6666a

Browse files
author
jul-sh
authored
Test remote attestation in UEFI app (#2703)
* add remote attestation test inside UEFI app * Stub missing symbols * improve comment spelling somewhat * Use ___chkstk_ms from go * simplify test to aid debugging: just test ring source of randomness * log random data in test * patch rdrand availability check for debuggingnd enable KVM * Add test to check that the byte array has in fact been filled * add remote attestation handshake test * Update config to match #2725 * Remoe test of ring, as remote attestation is now tested * remove debugging logs from remote attestation test * wip * Revert "wip" This reverts commit 2779e2a. * Move the UEFI remote attestation test into it's own module * remove now unneeded crate imports in the main UEFI app * finalize moving remote attestation test * redundant surplus qemu cpu flags * Add anyhow as dev dep for test * Add extra context to ring stubs * Only run remote attestation tests if the hosts supports kvm, and the kvm feature is set * improve comment for clarity * improve comment copy * disable ring default features to fix duplicate lang items * bust CI cache * toggle tests that require kvm by disabling a default flag, as xtask enables all flags for tests * Clarify comment * Improve comments for accuracy and clarity * Don't lint target subdirectories created by cargo fuzz
1 parent 3df6546 commit 4a6666a

File tree

13 files changed

+221
-11
lines changed

13 files changed

+221
-11
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ jobs:
6464
uses: actions/cache@v2
6565
env:
6666
# Increment this value to invalidate previous cache entries.
67-
CACHE_VERSION: 3
67+
CACHE_VERSION: 4
6868
with:
6969
path: |
7070
./cargo-cache/bin

experimental/uefi/app/.cargo/config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
target = "x86_64-unknown-uefi"
33

44
[target.x86_64-unknown-uefi]
5-
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"
5+
runner = "./runner"
66

77
[unstable]
88
build-std = ["core", "alloc"]

experimental/uefi/app/Cargo.lock

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

experimental/uefi/app/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ authors = ["Andri Saar <[email protected]>"]
55
edition = "2021"
66
license = "Apache-2.0"
77

8+
[features]
9+
default = ["support_emulated_runner"]
10+
support_emulated_runner = []
11+
812
[dependencies]
913
uefi = { version = "*", features = ["exts"] }
1014
uefi-services = "*"
@@ -14,4 +18,5 @@ ciborium-io = "*"
1418
oak_remote_attestation = { path = "../../../remote_attestation/rust" }
1519

1620
[dev-dependencies]
21+
anyhow = { version = "*", default-features = false }
1722
uefi-services = { version = "*", features = ["qemu"] }

experimental/uefi/app/runner

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env bash
2+
3+
# Thin shell script invoked as a cargo runner to run the compiled efi firmware
4+
# in QEMU. Detects if kvm is supported, and sets qemu flags based on that.
5+
# Instead of this single runner script it would be preferable to use a different
6+
# runner based on whether the kvm feature is set. However, cargo does not
7+
# currently allow this. Ref: https://github.com/rust-lang/cargo/issues/8170
8+
9+
readonly TARGET=$1
10+
11+
qemu_flags=(
12+
'-nodefaults'
13+
'-nographic'
14+
'-bios' '/usr/share/OVMF/OVMF_CODE.fd'
15+
'-serial' 'file:target/console.log'
16+
'-serial' 'stdio'
17+
'-machine' 'q35'
18+
'-device' 'isa-debug-exit,iobase=0xf4,iosize=0x04'
19+
)
20+
21+
# Use kvm if supported, as it is required for certain features. Note
22+
# that hosts that support kvm still need to disable the default
23+
# `support_emulated_runner` feature in cargo to include code that requires kvm
24+
# in the compiled firmware. Ideally this check would rely on the cargo
25+
# flag itself, enabling kvm if it is disabled. However cargo does not expose
26+
# which flags are set to the runner. Ref: https://doc.rust-lang.org/cargo/reference/environment-variables.html
27+
if [[ -e "/dev/kvm" ]]; then
28+
qemu_flags+=(
29+
'-enable-kvm'
30+
'-cpu' 'Broadwell-IBRS'
31+
)
32+
fi
33+
34+
qemu-system-x86_64 "${qemu_flags[@]}" -kernel "${TARGET}"
35+

experimental/uefi/app/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,6 @@ fn test_simple() {
121121
let x = 1;
122122
assert_eq!(x, 1);
123123
}
124+
125+
#[cfg(test)]
126+
mod tests;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// Copyright 2022 The Project Oak Authors
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
// Uses advanced CPU features not available when using running tests in qemu
18+
// with CPU emulation.
19+
#[cfg(not(feature = "support_emulated_runner"))]
20+
mod remote_attestation;
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//
2+
// Copyright 2022 The Project Oak Authors
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
//! Integration Test of Remote Attestation in UEFI.
18+
//!
19+
//! This tests that remote attestion works inside the UEFI app. While the test
20+
//! code is identical to (a subset of) the tests in the remote attestation crate
21+
//! they here utilize the qemu runner configured in the UEFI app. This means
22+
//! that test code actually compiled to a UEFI target, which changes the
23+
//! underlying implementation of the remote attestation crate.
24+
//! TODO(#2654): It would be preferable to remove the test here, and instead
25+
//! run the tests in the oak_remote_attestation crate itself for both standard
26+
//! and UEFI targets. Due to concerns related to the workspace this is presently
27+
//! not possible. Ref: https://github.com/project-oak/oak/issues/2654
28+
29+
extern crate alloc;
30+
31+
use alloc::{boxed::Box, sync::Arc};
32+
use oak_remote_attestation::handshaker::{AttestationBehavior, ClientHandshaker, ServerHandshaker};
33+
34+
const TEE_MEASUREMENT: &str = "Test TEE measurement";
35+
const DATA: [u8; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
36+
37+
fn create_handshakers() -> (ClientHandshaker, ServerHandshaker) {
38+
let bidirectional_attestation =
39+
AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes())
40+
.unwrap();
41+
let client_handshaker = ClientHandshaker::new(
42+
bidirectional_attestation,
43+
Box::new(|server_identity| {
44+
if !server_identity.additional_info.is_empty() {
45+
Ok(())
46+
} else {
47+
anyhow::bail!("No additional info provided.")
48+
}
49+
}),
50+
);
51+
52+
let bidirectional_attestation =
53+
AttestationBehavior::create_bidirectional_attestation(&[], TEE_MEASUREMENT.as_bytes())
54+
.unwrap();
55+
56+
let additional_info = br"Additional Info".to_vec();
57+
let server_handshaker =
58+
ServerHandshaker::new(bidirectional_attestation, Arc::new(additional_info));
59+
60+
(client_handshaker, server_handshaker)
61+
}
62+
63+
#[test_case]
64+
fn test_handshake() {
65+
let (mut client_handshaker, mut server_handshaker) = create_handshakers();
66+
67+
let client_hello = client_handshaker
68+
.create_client_hello()
69+
.expect("Couldn't create client hello message");
70+
71+
let server_identity = server_handshaker
72+
.next_step(&client_hello)
73+
.expect("Couldn't process client hello message")
74+
.expect("Empty server identity message");
75+
76+
let client_identity = client_handshaker
77+
.next_step(&server_identity)
78+
.expect("Couldn't process server identity message")
79+
.expect("Empty client identity message");
80+
assert!(client_handshaker.is_completed());
81+
82+
let result = server_handshaker
83+
.next_step(&client_identity)
84+
.expect("Couldn't process client identity message");
85+
assert_eq!(result, None);
86+
assert!(server_handshaker.is_completed());
87+
88+
let mut client_encryptor = client_handshaker
89+
.get_encryptor()
90+
.expect("Couldn't get client encryptor");
91+
let mut server_encryptor = server_handshaker
92+
.get_encryptor()
93+
.expect("Couldn't get server encryptor");
94+
95+
let encrypted_client_data = client_encryptor
96+
.encrypt(&DATA)
97+
.expect("Couldn't encrypt client data");
98+
let decrypted_client_data = server_encryptor
99+
.decrypt(&encrypted_client_data)
100+
.expect("Couldn't decrypt client data");
101+
assert_eq!(decrypted_client_data, DATA);
102+
103+
let encrypted_server_data = server_encryptor
104+
.encrypt(&DATA)
105+
.expect("Couldn't encrypt server data");
106+
let decrypted_server_data = client_encryptor
107+
.decrypt(&encrypted_server_data)
108+
.expect("Couldn't decrypt server data");
109+
assert_eq!(decrypted_server_data, DATA);
110+
}

remote_attestation/rust/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ anyhow = { version = "*", default-features = false }
1414
bytes = { version = "*", default-features = false }
1515
log = "*"
1616
prost = { version = "*", default-features = false, features = ["prost-derive"] }
17-
ring = { path = "../../third_party/ring" }
17+
ring = { path = "../../third_party/ring", default-features = false }
1818

1919
[build-dependencies]
2020
prost-build = "*"

third_party/ring/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ include = [
3333
"benches/*.rs",
3434
"build.rs",
3535

36+
"stubs.c",
37+
3638
"crypto/chacha/asm/chacha-armv4.pl",
3739
"crypto/chacha/asm/chacha-armv8.pl",
3840
"crypto/chacha/asm/chacha-x86.pl",

0 commit comments

Comments
 (0)