[tee_manager] Support new fuchsia.tee protocols
This change accomplishes the following:
* Adds support for board-specific configuration files to specify which
trusted application UUIDs are available on a given environment.
* Passes through the new `fuchsia.tee.DeviceInfo`.
* Passes through a config-determined number of different
`fuchsia.tee.Application` protocols, based on the board config.
Bug: 44664
Test: fx test optee_smoke_test tee-manager-tests
Change-Id: I7e1ca15a4a2799cce9e198cf6be28d5ab501d904
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/364594
Reviewed-by: Chris Tam <godtamit@google.com>
Commit-Queue: RJ Ascani <rjascani@google.com>
Testability-Review: Austin Foxley <afoxley@google.com>
diff --git a/src/security/tee_manager/BUILD.gn b/src/security/tee_manager/BUILD.gn
index ad3a6f0..276711e 100644
--- a/src/security/tee_manager/BUILD.gn
+++ b/src/security/tee_manager/BUILD.gn
@@ -54,7 +54,11 @@
"//src/lib/zircon/rust:fuchsia-zircon",
"//third_party/rust_crates:anyhow",
"//third_party/rust_crates:futures",
+ "//third_party/rust_crates:serde",
+ "//third_party/rust_crates:serde_derive",
+ "//third_party/rust_crates:serde_json",
"//third_party/rust_crates:thiserror",
+ "//third_party/rust_crates:uuid",
]
test_deps = [
@@ -74,6 +78,7 @@
]
}
+# TODO(44664): Remove this config when transition to board-specific configs is complete.
config_data("config") {
for_pkg = "sysmgr"
sources = [ "tee_manager.config" ]
diff --git a/src/security/tee_manager/meta/tee_manager.cmx b/src/security/tee_manager/meta/tee_manager.cmx
index fc308fe..7e4d7c1 100644
--- a/src/security/tee_manager/meta/tee_manager.cmx
+++ b/src/security/tee_manager/meta/tee_manager.cmx
@@ -7,6 +7,7 @@
"class/tee"
],
"features": [
+ "config-data",
"isolated-persistent-storage"
],
"services": [
diff --git a/src/security/tee_manager/src/config.rs b/src/security/tee_manager/src/config.rs
new file mode 100644
index 0000000..4cd0240
--- /dev/null
+++ b/src/security/tee_manager/src/config.rs
@@ -0,0 +1,27 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+ anyhow::{Context, Error},
+ serde_derive::Deserialize,
+ serde_json,
+ std::{fs::File, io::BufReader},
+ uuid::Uuid,
+};
+
+const CONFIG_FILE: &'static str = "/config/data/tee_manager.config";
+
+#[derive(Deserialize)]
+pub struct Config {
+ pub application_uuids: Vec<Uuid>,
+}
+
+impl Config {
+ pub fn from_file() -> Result<Self, Error> {
+ Ok(serde_json::from_reader(BufReader::new(
+ File::open(CONFIG_FILE).context("Unable to open config")?,
+ ))
+ .context("Unable to parse config")?)
+ }
+}
diff --git a/src/security/tee_manager/src/device_server.rs b/src/security/tee_manager/src/device_server.rs
index 13b9fe35..8ed0dd0 100644
--- a/src/security/tee_manager/src/device_server.rs
+++ b/src/security/tee_manager/src/device_server.rs
@@ -7,7 +7,7 @@
anyhow::{Context as _, Error},
fidl::endpoints::{ClientEnd, ServerEnd},
fidl_fuchsia_hardware_tee::DeviceConnectorProxy,
- fuchsia_async as fasync, fuchsia_zircon as zx,
+ fidl_fuchsia_tee as fuchsia_tee, fuchsia_async as fasync, fuchsia_zircon as zx,
std::path::PathBuf,
};
@@ -27,7 +27,45 @@
device_connector
.connect_tee(Some(ClientEnd::new(zx_provider_client_end)), ServerEnd::new(channel))
- .context("Could not connect to TEE over DeviceConnectorProxy")?;
+ .context("Could not connect to fuchsia.tee.Device over DeviceConnectorProxy")?;
provider.serve(provider_server_chan).await
}
+
+/// Serves a `fuchsia.tee.Application` protocol request by passing it through the
+/// `TeeDeviceConnection` and specifying the application UUID.
+pub async fn serve_application_passthrough(
+ mut uuid: fuchsia_tee::Uuid,
+ device_connector: DeviceConnectorProxy,
+ channel: zx::Channel,
+) -> Result<(), Error> {
+ // Create a ProviderServer to support the TEE driver
+ let provider = ProviderServer::try_new(PathBuf::new().join(STORAGE_DIR))?;
+ let (zx_provider_server_end, zx_provider_client_end) =
+ zx::Channel::create().context("Could not create Provider channel pair")?;
+
+ let provider_server_chan = fasync::Channel::from_channel(zx_provider_server_end)?;
+
+ device_connector
+ .connect_to_application(
+ &mut uuid,
+ Some(ClientEnd::new(zx_provider_client_end)),
+ ServerEnd::new(channel),
+ )
+ .context("Could not connect to fuchsia.tee.Application over DeviceConnectorProxy")?;
+
+ provider.serve(provider_server_chan).await
+}
+
+/// Serves a `fuchsia.tee.DeviceInfo` protocol request by passing it through the
+/// `TeeDeviceConnection`.
+pub async fn serve_device_info_passthrough(
+ device_connector: DeviceConnectorProxy,
+ channel: zx::Channel,
+) -> Result<(), Error> {
+ device_connector
+ .connect_to_device_info(ServerEnd::new(channel))
+ .context("Could not connect to fuchsia.tee.DeviceInfo over DeviceConnectorProxy")?;
+
+ Ok(())
+}
diff --git a/src/security/tee_manager/src/main.rs b/src/security/tee_manager/src/main.rs
index 6d87f00..3ecceeb4 100644
--- a/src/security/tee_manager/src/main.rs
+++ b/src/security/tee_manager/src/main.rs
@@ -4,15 +4,19 @@
#![recursion_limit = "128"]
+mod config;
mod device_server;
mod provider_server;
use {
- crate::device_server::serve_passthrough,
+ crate::config::Config,
+ crate::device_server::{
+ serve_application_passthrough, serve_device_info_passthrough, serve_passthrough,
+ },
anyhow::{format_err, Context as _, Error},
fidl::endpoints::ServiceMarker,
fidl_fuchsia_hardware_tee::{DeviceConnectorMarker, DeviceConnectorProxy},
- fidl_fuchsia_tee::DeviceMarker,
+ fidl_fuchsia_tee::{self as fuchsia_tee, DeviceInfoMarker, DeviceMarker},
fuchsia_async as fasync,
fuchsia_component::server::ServiceFs,
fuchsia_syslog as syslog,
@@ -21,12 +25,15 @@
futures::{prelude::*, select, stream::FusedStream},
io_util::{open_directory_in_namespace, OPEN_RIGHT_READABLE},
std::path::PathBuf,
+ uuid::Uuid,
};
const DEV_TEE_PATH: &str = "/dev/class/tee";
enum IncomingRequest {
Device(zx::Channel),
+ Application(zx::Channel, fuchsia_tee::Uuid),
+ DeviceInfo(zx::Channel),
}
#[fasync::run_singlethreaded]
@@ -49,7 +56,26 @@
let mut fs = ServiceFs::new_local();
fs.dir("svc")
- .add_service_at(DeviceMarker::NAME, |channel| Some(IncomingRequest::Device(channel)));
+ .add_service_at(DeviceMarker::NAME, |channel| Some(IncomingRequest::Device(channel)))
+ .add_service_at(DeviceInfoMarker::NAME, |channel| {
+ Some(IncomingRequest::DeviceInfo(channel))
+ });
+
+ match Config::from_file() {
+ Ok(config) => {
+ for app_uuid in config.application_uuids {
+ let service_name =
+ format!("fuchsia.tee.Application.{}", app_uuid.to_hyphenated_ref());
+ fx_log_debug!("Serving {}", service_name);
+ let fidl_uuid = uuid_to_fuchsia_tee_uuid(&app_uuid);
+ fs.dir("svc").add_service_at(service_name, move |channel| {
+ Some(IncomingRequest::Application(channel, fidl_uuid))
+ });
+ }
+ }
+ Err(error) => fx_log_warn!("Unable to serve applications: {:?}", error),
+ }
+
fs.take_and_serve_directory_handle()?;
serve(dev_connector_proxy, fs.fuse()).await
@@ -66,6 +92,13 @@
IncomingRequest::Device(channel) => {
serve_passthrough(dev_connector_proxy.clone(), channel).await
}
+ IncomingRequest::Application(channel, uuid) => {
+ fx_log_trace!("Connecting application: {:?}", uuid);
+ serve_application_passthrough(uuid, dev_connector_proxy.clone(), channel).await
+ }
+ IncomingRequest::DeviceInfo(channel) => {
+ serve_device_info_passthrough(dev_connector_proxy.clone(), channel).await
+ }
}
.unwrap_or_else(|e| fx_log_err!("{:?}", e));
});
@@ -111,6 +144,18 @@
Ok(proxy)
}
+/// Converts a `uuid::Uuid` to a `fidl_fuchsia_tee::Uuid`.
+fn uuid_to_fuchsia_tee_uuid(uuid: &Uuid) -> fuchsia_tee::Uuid {
+ let (time_low, time_mid, time_hi_and_version, clock_seq_and_node) = uuid.as_fields();
+
+ fuchsia_tee::Uuid {
+ time_low,
+ time_mid,
+ time_hi_and_version,
+ clock_seq_and_node: *clock_seq_and_node,
+ }
+}
+
#[cfg(test)]
mod tests {
use {
@@ -118,6 +163,7 @@
fidl::{endpoints, Error},
fidl_fuchsia_hardware_tee::DeviceConnectorRequest,
fidl_fuchsia_io as fio,
+ fidl_fuchsia_tee::ApplicationMarker,
fidl_fuchsia_tee_manager::ProviderProxy,
fuchsia_zircon::HandleBased,
fuchsia_zircon_status::Status,
@@ -163,13 +209,14 @@
}
}
- async fn is_valid_storage(storage_proxy: &fio::DirectoryProxy) {
+ async fn assert_is_valid_storage(storage_proxy: &fio::DirectoryProxy) {
let maybe_node_info = storage_proxy.describe().await;
assert!(maybe_node_info.is_ok());
let node_info = maybe_node_info.unwrap();
assert!(is_directory(&node_info));
}
+ // TODO(44664): Remove once ConnectTee is deprecated
#[fasync::run_singlethreaded(test)]
async fn connect() {
let dev_connector = spawn_device_connector(|request| async move {
@@ -187,7 +234,7 @@
.into_proxy()
.expect("Failed to convert ClientEnd to ProviderProxy");
- is_valid_storage(&get_storage(&provider_proxy)).await;
+ assert_is_valid_storage(&get_storage(&provider_proxy)).await;
tee_request
.close_with_epitaph(Status::OK)
@@ -221,6 +268,103 @@
}
#[fasync::run_singlethreaded(test)]
+ async fn connect_to_application() {
+ let app_uuid = uuid_to_fuchsia_tee_uuid(
+ &Uuid::parse_str("8aaaf200-2450-11e4-abe2-0002a5d5c51b").unwrap(),
+ );
+
+ let dev_connector = spawn_device_connector(move |request| async move {
+ match request {
+ DeviceConnectorRequest::ConnectToApplication {
+ application_uuid,
+ service_provider,
+ application_request,
+ control_handle: _,
+ } => {
+ assert_eq!(application_uuid, app_uuid);
+ assert!(service_provider.is_some());
+ assert!(!application_request.channel().is_invalid_handle());
+
+ let provider_proxy = service_provider
+ .unwrap()
+ .into_proxy()
+ .expect("Failed to convert ClientEnd to ProviderProxy");
+
+ assert_is_valid_storage(&get_storage(&provider_proxy)).await;
+
+ application_request
+ .close_with_epitaph(Status::OK)
+ .expect("Unable to close tee_request");
+ }
+ _ => {
+ assert!(false);
+ }
+ }
+ });
+
+ let (mut sender, receiver) = mpsc::channel::<IncomingRequest>(1);
+
+ fasync::spawn_local(async move {
+ let result = serve(dev_connector, receiver.fuse()).await;
+ assert!(result.is_ok(), "{}", result.unwrap_err());
+ });
+
+ let (app_client, app_server) = endpoints::create_endpoints::<ApplicationMarker>()
+ .expect("Failed to create Device endpoints");
+
+ let app_proxy =
+ app_client.into_proxy().expect("Failed to convert ClientEnd to DeviceProxy");
+ sender
+ .try_send(IncomingRequest::Application(app_server.into_channel(), app_uuid))
+ .expect("Unable to send Application Request");
+
+ let (result, _) = app_proxy.take_event_stream().into_future().await;
+ assert!(is_closed_with_status(result.unwrap().unwrap_err(), Status::OK));
+ }
+
+ #[fasync::run_singlethreaded(test)]
+ async fn connect_to_device_info() {
+ let dev_connector = spawn_device_connector(|request| async move {
+ match request {
+ DeviceConnectorRequest::ConnectToDeviceInfo {
+ device_info_request,
+ control_handle: _,
+ } => {
+ assert!(!device_info_request.channel().is_invalid_handle());
+ device_info_request
+ .close_with_epitaph(Status::OK)
+ .expect("Unable to close device_info_request");
+ }
+ _ => {
+ assert!(false);
+ }
+ }
+ });
+
+ let (mut sender, receiver) = mpsc::channel::<IncomingRequest>(1);
+
+ fasync::spawn_local(async move {
+ let result = serve(dev_connector, receiver.fuse()).await;
+ assert!(result.is_ok(), "{}", result.unwrap_err());
+ });
+
+ let (device_info_client, device_info_server) =
+ endpoints::create_endpoints::<DeviceInfoMarker>()
+ .expect("Failed to create DeviceInfo endpoints");
+
+ let device_info_proxy = device_info_client
+ .into_proxy()
+ .expect("Failed to convert ClientEnd to DeviceInfoProxy");
+
+ sender
+ .try_send(IncomingRequest::DeviceInfo(device_info_server.into_channel()))
+ .expect("Unable to send DeviceInfo Request");
+
+ let (result, _) = device_info_proxy.take_event_stream().into_future().await;
+ assert!(is_closed_with_status(result.unwrap().unwrap_err(), Status::OK));
+ }
+
+ #[fasync::run_singlethreaded(test)]
async fn tee_device_closed() {
let (dev_connector_proxy, dev_connector_server) =
fidl::endpoints::create_proxy::<DeviceConnectorMarker>()
diff --git a/src/security/tee_manager/tee_manager_config.gni b/src/security/tee_manager/tee_manager_config.gni
new file mode 100644
index 0000000..a281b9f
--- /dev/null
+++ b/src/security/tee_manager/tee_manager_config.gni
@@ -0,0 +1,55 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config.gni")
+import("//build/json/validate_json.gni")
+
+# Validates a tee manager configuration file against a schema.
+#
+# Parameters
+# config (required)
+# This is the tee manager config file that needs to be validated.
+template("tee_manager_config_validate") {
+ validate_json(target_name) {
+ forward_variables_from(invoker,
+ [
+ "deps",
+ "public_deps",
+ "testonly",
+ "visibility",
+ ])
+
+ data = invoker.config
+ schema = "//src/security/tee_manager/tee_manager_config_schema.json"
+ }
+}
+
+# Packages a tee manager configuration after validating it.
+#
+# Parameters
+# config (required)
+# A file containing a configuration for the tee manager.
+template("tee_manager_config") {
+ validate_target = target_name + "_validate"
+
+ tee_manager_config_validate(validate_target) {
+ forward_variables_from(invoker,
+ [
+ "deps",
+ "testonly",
+ "visibility",
+ ])
+
+ config = invoker.config
+ }
+
+ config_data(target_name) {
+ for_pkg = "tee_manager"
+ sources = [ rebase_path(invoker.config) ]
+
+ outputs = [ "tee_manager.config" ]
+
+ deps = [ ":${validate_target}" ]
+ }
+}
diff --git a/src/security/tee_manager/tee_manager_config_schema.json b/src/security/tee_manager/tee_manager_config_schema.json
new file mode 100644
index 0000000..53584c9
--- /dev/null
+++ b/src/security/tee_manager/tee_manager_config_schema.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "http://json-schema.org/schema#",
+ "title": "Schema for tee manager configuration",
+ "definitions": {
+ "uuid": {
+ "type": "string",
+ "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ }
+ },
+ "type": "object",
+ "properties": {
+ "application_uuids": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/uuid"
+ }
+ }
+ },
+ "required": [
+ "application_uuids"
+ ],
+ "additionalProperties": false
+}