Skip to content

Commit 98e9f9d

Browse files
author
Juliette Pretot
committed
Implement simple remote attestion for the UEFI app
1 parent 7c0b815 commit 98e9f9d

File tree

5 files changed

+149
-1
lines changed

5 files changed

+149
-1
lines changed

experimental/uefi/app/Cargo.lock

Lines changed: 47 additions & 0 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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ log = { version = "*" }
1616
ciborium = { version = "*", default-features = false }
1717
ciborium-io = "*"
1818
oak_remote_attestation = { path = "../../../remote_attestation/rust" }
19+
oak_remote_attestation_sessions = { path = "../../../remote_attestation_sessions" }
20+
lru = "*"
21+
anyhow = { version = "*", default-features = false }
1922

2023
[dev-dependencies]
2124
anyhow = { version = "*", default-features = false }

experimental/uefi/app/src/main.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
extern crate log;
2929
extern crate alloc;
3030

31+
use crate::remote_attestation::AttestationHandler;
3132
use ciborium::{de, ser};
3233
use uefi::{prelude::*, table::runtime::ResetType};
3334

35+
mod remote_attestation;
3436
mod serial;
3537

3638
// The main entry point of the UEFI application.
@@ -71,6 +73,8 @@ fn main(handle: Handle, system_table: &mut SystemTable<Boot>) -> Status {
7173
serial_echo(handle, system_table.boot_services(), ECHO_SERIAL_PORT_INDEX).unwrap();
7274
}
7375

76+
const MOCK_SESSION_ID: [u8; 8] = [0; 8];
77+
7478
// Opens the index-th serial port on the system and echoes back all frames sent over the serial
7579
// port.
7680
//
@@ -85,6 +89,7 @@ fn main(handle: Handle, system_table: &mut SystemTable<Boot>) -> Status {
8589
// Normally does not return, unless an error is raised.
8690
fn serial_echo(handle: Handle, bt: &BootServices, index: usize) -> Result<!, uefi::Error<()>> {
8791
let mut serial = serial::Serial::get(handle, bt, index)?;
92+
let attestation_handler = &mut AttestationHandler::create(|v| v);
8893
loop {
8994
let msg: alloc::vec::Vec<u8> = de::from_reader(&mut serial).map_err(|err| match err {
9095
de::Error::Io(err) => err,
@@ -98,7 +103,8 @@ fn serial_echo(handle: Handle, bt: &BootServices, index: usize) -> Result<!, uef
98103
}
99104
de::Error::RecursionLimitExceeded => uefi::Error::from(Status::ABORTED),
100105
})?;
101-
ser::into_writer(&msg, &mut serial).map_err(|err| match err {
106+
let response = attestation_handler.message(MOCK_SESSION_ID, msg);
107+
ser::into_writer(&response, &mut serial).map_err(|err| match err {
102108
ser::Error::Io(err) => err,
103109
ser::Error::Value(msg) => {
104110
error!("Error serializing value: {}", msg);
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
//! Server-side implementation of the bidirectional gRPC remote attestation handshake
18+
//! protocol.
19+
//!
20+
//! A simplified version of the implementation from the `grpc_unary_attestation`
21+
//! crate. TODO(#2741): Refactor this to share more code between the two runtimes.
22+
23+
use alloc::{boxed::Box, sync::Arc, vec::Vec};
24+
use lru::LruCache;
25+
use oak_remote_attestation::handshaker::{
26+
Encryptor, ServerHandshaker, SessionId, SessionState, SessionTracker,
27+
};
28+
29+
pub struct AttestationHandler<F> {
30+
session_tracker: SessionTracker,
31+
request_handler: F,
32+
}
33+
34+
const MOCK_TEE_CERTIFICATE: [u8; 0] = [];
35+
const MOCK_ADDITIONAL_INFO: [u8; 0] = [];
36+
37+
impl<F> AttestationHandler<F>
38+
where
39+
F: Send + Sync + Clone + FnOnce(Vec<u8>) -> Vec<u8>,
40+
{
41+
pub fn create(request_handler: F) -> Self {
42+
let session_tracker =
43+
SessionTracker::create(MOCK_TEE_CERTIFICATE.to_vec(), MOCK_ADDITIONAL_INFO.to_vec());
44+
45+
Self {
46+
session_tracker,
47+
request_handler,
48+
}
49+
}
50+
51+
pub fn message(&mut self, session_id: SessionId, request: Vec<u8>) -> Vec<u8> {
52+
let mut session_state = {
53+
self.session_tracker
54+
.pop_session_state(session_id)
55+
.expect("Couldn't pop session state")
56+
};
57+
let response_body = match session_state {
58+
SessionState::HandshakeInProgress(ref mut handshaker) => {
59+
handshaker
60+
.next_step(&request)
61+
.expect("Couldn't process handshake message")
62+
// After receiving a valid `ClientIdentity` message
63+
// (the last step of the key exchange)
64+
// ServerHandshaker.next_step returns `None`. For unary
65+
// request we do want to send an explicit confirmation in
66+
// the form of a status message. Hence in case of `None`
67+
// fallback to a default (empty) response.
68+
.unwrap_or_default()
69+
}
70+
SessionState::EncryptedMessageExchange(ref mut encryptor) => {
71+
let decrypted_request = encryptor
72+
.decrypt(&request)
73+
.expect("Couldn't decrypt response");
74+
75+
let response = (self.request_handler.clone())(decrypted_request);
76+
77+
encryptor
78+
.encrypt(&response)
79+
.expect("Couldn't encrypt response")
80+
}
81+
};
82+
83+
self.session_tracker
84+
.put_session_state(session_id, session_state);
85+
86+
response_body
87+
}
88+
}

experimental/uefi/loader/src/qemu.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ impl Qemu {
7171
// Construct the command-line arguments for `qemu`. See
7272
// https://www.qemu.org/docs/master/system/invocation.html for all available options.
7373

74+
// Needed to expose advanced CPU features to the UEFI app. Specifically
75+
// RDRAND which is required for remote attestation.
76+
cmd.arg("-enable-kvm");
77+
cmd.args(&["-cpu", "Broadwell-IBRS"]);
7478
// We're going to run qemu as a noninteractive embedded program, so disable any
7579
// graphical outputs.
7680
cmd.arg("-nographic");

0 commit comments

Comments
 (0)