This is an automated email from the ASF dual-hosted git repository.
yuanz pushed a commit to branch main
in repository
https://gitbox.apache.org/repos/asf/incubator-teaclave-trustzone-sdk.git
The following commit(s) were added to refs/heads/main by this push:
new 0a0ab8a optee-utee: Enable TA-to-TA Invocation
0a0ab8a is described below
commit 0a0ab8acd0d6f74b0994a782fc309bc11fe78a10
Author: Yuan Zhuang <[email protected]>
AuthorDate: Tue Apr 8 07:23:53 2025 +0000
optee-utee: Enable TA-to-TA Invocation
This commit provides the Rust API for GP API TEE_InvokeTACommand(),
which enable the user TA calls another user TA or pseudo TA.
- Add abstraction of TeeParameters and TaSession;
- Add inter-ta example and test scripts.
Signed-off-by: Yuan Zhuang <[email protected]>
Reviewed-by: Zehui Chen <[email protected]>
---
ci/ci.sh | 1 +
ci/ci.sh => examples/inter_ta-rs/Makefile | 52 +--
ci/ci.sh => examples/inter_ta-rs/host/Cargo.toml | 52 +--
ci/ci.sh => examples/inter_ta-rs/host/Makefile | 60 ++--
examples/inter_ta-rs/host/src/main.rs | 32 ++
ci/ci.sh => examples/inter_ta-rs/proto/Cargo.toml | 49 +--
examples/inter_ta-rs/proto/src/lib.rs | 57 ++++
ci/ci.sh => examples/inter_ta-rs/ta/Cargo.toml | 56 ++--
examples/inter_ta-rs/ta/Makefile | 45 +++
ci/ci.sh => examples/inter_ta-rs/ta/Xargo.toml | 45 +--
examples/inter_ta-rs/ta/build.rs | 26 ++
examples/inter_ta-rs/ta/src/main.rs | 152 +++++++++
examples/inter_ta-rs/uuid.txt | 1 +
optee-utee/src/error.rs | 199 ++++++++----
optee-utee/src/lib.rs | 26 +-
optee-utee/src/ta_session.rs | 146 +++++++++
optee-utee/src/tee_parameter.rs | 372 ++++++++++++++++++++++
ci/ci.sh => tests/test_inter_ta.sh | 52 ++-
18 files changed, 1085 insertions(+), 338 deletions(-)
diff --git a/ci/ci.sh b/ci/ci.sh
index 6f026bc..53ada6f 100755
--- a/ci/ci.sh
+++ b/ci/ci.sh
@@ -52,6 +52,7 @@ fi
./test_tcp_client.sh
./test_udp_socket.sh
./test_client_pool.sh
+./test_inter_ta.sh
popd
diff --git a/ci/ci.sh b/examples/inter_ta-rs/Makefile
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/Makefile
index 6f026bc..a7a3dec
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/Makefile
@@ -1,5 +1,3 @@
-#!/bin/bash
-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,41 +15,25 @@
# specific language governing permissions and limitations
# under the License.
-set -xe
+# If _HOST or _TA specific compiler/target are not specified, then use common
+# compiler/target for both
+CROSS_COMPILE_HOST ?= aarch64-linux-gnu-
+CROSS_COMPILE_TA ?= aarch64-linux-gnu-
+TARGET_HOST ?= aarch64-unknown-linux-gnu
+TARGET_TA ?= aarch64-unknown-linux-gnu
-pushd ../tests
+.PHONY: host ta all clean
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
+all: host ta
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+host:
+ $(q)make -C host TARGET=$(TARGET_HOST) \
+ CROSS_COMPILE=$(CROSS_COMPILE_HOST)
+ta:
+ $(q)make -C ta TARGET=$(TARGET_TA) \
+ CROSS_COMPILE=$(CROSS_COMPILE_TA)
-popd
+clean:
+ $(q)make -C host clean
+ $(q)make -C ta clean
diff --git a/ci/ci.sh b/examples/inter_ta-rs/host/Cargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/host/Cargo.toml
index 6f026bc..c11c427
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/host/Cargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,41 +15,19 @@
# specific language governing permissions and limitations
# under the License.
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+[package]
+name = "inter_ta-rs"
+version = "0.4.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+license = "Apache-2.0"
+repository = "https://github.com/apache/incubator-teaclave-trustzone-sdk.git"
+description = "An example of Rust OP-TEE TrustZone SDK."
+edition = "2018"
+[dependencies]
+libc = "0.2.48"
+proto = { path = "../proto" }
+optee-teec = { path = "../../../optee-teec" }
-popd
+[profile.release]
+lto = true
diff --git a/ci/ci.sh b/examples/inter_ta-rs/host/Makefile
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/host/Makefile
index 6f026bc..55a5c7e
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/host/Makefile
@@ -1,5 +1,3 @@
-#!/bin/bash
-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,41 +15,23 @@
# specific language governing permissions and limitations
# under the License.
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
-
-
-popd
+NAME := inter_ta-rs
+
+TARGET ?= aarch64-unknown-linux-gnu
+CROSS_COMPILE ?= aarch64-linux-gnu-
+OBJCOPY := $(CROSS_COMPILE)objcopy
+LINKER_CFG := target.$(TARGET).linker=\"$(CROSS_COMPILE)gcc\"
+
+OUT_DIR := $(CURDIR)/target/$(TARGET)/release
+
+
+all: host strip
+
+host:
+ @cargo build --target $(TARGET_HOST) --release --config $(LINKER_CFG)
+
+strip: host
+ @$(OBJCOPY) --strip-unneeded $(OUT_DIR)/$(NAME) $(OUT_DIR)/$(NAME)
+
+clean:
+ @cargo clean
diff --git a/examples/inter_ta-rs/host/src/main.rs
b/examples/inter_ta-rs/host/src/main.rs
new file mode 100644
index 0000000..1647efd
--- /dev/null
+++ b/examples/inter_ta-rs/host/src/main.rs
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+use optee_teec::{Context, ErrorKind, Operation, ParamNone, Uuid};
+use proto::{Command, UUID};
+
+fn main() -> optee_teec::Result<()> {
+ let mut ctx = Context::new()?;
+ let uuid =
+ Uuid::parse_str(UUID).map_err(|_|
optee_teec::Error::from(ErrorKind::BadParameters))?;
+ let mut session = ctx.open_session(uuid)?;
+ let mut operation = Operation::new(0, ParamNone, ParamNone, ParamNone,
ParamNone);
+
+ // Nothing to send, just invoke the Test command
+ session.invoke_command(Command::Test as u32, &mut operation)?;
+ println!("Success");
+ Ok(())
+}
diff --git a/ci/ci.sh b/examples/inter_ta-rs/proto/Cargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/proto/Cargo.toml
index 6f026bc..91066a3
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/proto/Cargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,41 +15,14 @@
# specific language governing permissions and limitations
# under the License.
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
-
+[package]
+name = "proto"
+version = "0.4.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+license = "Apache-2.0"
+repository = "https://github.com/apache/incubator-teaclave-trustzone-sdk.git"
+description = "Data structures and functions shared by host and TA."
+edition = "2018"
-popd
+[dependencies]
+num_enum = { version = "0.7.3", default-features = false }
diff --git a/examples/inter_ta-rs/proto/src/lib.rs
b/examples/inter_ta-rs/proto/src/lib.rs
new file mode 100644
index 0000000..44583ba
--- /dev/null
+++ b/examples/inter_ta-rs/proto/src/lib.rs
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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_std]
+use num_enum::{FromPrimitive, IntoPrimitive};
+
+// For CA-TA invocation:
+#[derive(FromPrimitive, IntoPrimitive)]
+#[repr(u32)]
+pub enum Command {
+ Test,
+ #[default]
+ Unknown,
+}
+
+// If Uuid::parse_str() returns an InvalidLength error, there may be an extra
+// newline in your uuid.txt file. You can remove it by running
+// `truncate -s 36 uuid.txt`.
+pub const UUID: &str = &include_str!("../../uuid.txt");
+
+// For TA-TA invocation testcases:
+#[derive(FromPrimitive, IntoPrimitive)]
+#[repr(u32)]
+pub enum SystemPtaCommand {
+ AddRngEntropy,
+ DeriveTaUniqueKey,
+ // We omit other commands here.
+ // Full definitions can be found in optee_os system_pta.h.
+ #[default]
+ Unknown,
+}
+
+#[derive(FromPrimitive, IntoPrimitive)]
+#[repr(u32)]
+pub enum HelloWorldTaCommand {
+ IncValue,
+ DecValue,
+ #[default]
+ Unknown,
+}
+
+pub const SYSTEM_PTA_UUID: &str = "3a2f8978-5dc0-11e8-9c2d-fa7ae01bbebc";
+pub const HELLO_WORLD_USER_TA_UUID: &str =
"133af0ca-bdab-11eb-9130-43bf7873bf67";
diff --git a/ci/ci.sh b/examples/inter_ta-rs/ta/Cargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/ta/Cargo.toml
index 6f026bc..4a0f9d2
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/ta/Cargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,41 +15,25 @@
# specific language governing permissions and limitations
# under the License.
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
+[package]
+name = "ta"
+version = "0.4.0"
+authors = ["Teaclave Contributors <[email protected]>"]
+license = "Apache-2.0"
+repository = "https://github.com/apache/incubator-teaclave-trustzone-sdk.git"
+description = "An example of Rust OP-TEE TrustZone SDK."
+edition = "2018"
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+[dependencies]
+proto = { path = "../proto" }
+optee-utee-sys = { path = "../../../optee-utee/optee-utee-sys" }
+optee-utee = { path = "../../../optee-utee" }
+[build-dependencies]
+proto = { path = "../proto" }
+optee-utee-build = { path = "../../../optee-utee-build" }
-popd
+[profile.release]
+panic = "abort"
+lto = true
+opt-level = 1
diff --git a/examples/inter_ta-rs/ta/Makefile b/examples/inter_ta-rs/ta/Makefile
new file mode 100644
index 0000000..029e66d
--- /dev/null
+++ b/examples/inter_ta-rs/ta/Makefile
@@ -0,0 +1,45 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+UUID ?= $(shell cat "../uuid.txt")
+
+TARGET ?= aarch64-unknown-linux-gnu
+CROSS_COMPILE ?= aarch64-linux-gnu-
+OBJCOPY := $(CROSS_COMPILE)objcopy
+# Configure the linker to use GCC, which works on both cross-compilation and
ARM machines
+LINKER_CFG := target.$(TARGET).linker=\"$(CROSS_COMPILE)gcc\"
+
+TA_SIGN_KEY ?= $(TA_DEV_KIT_DIR)/keys/default_ta.pem
+SIGN := $(TA_DEV_KIT_DIR)/scripts/sign_encrypt.py
+OUT_DIR := $(CURDIR)/target/$(TARGET)/release
+
+BUILDER = $(if $(STD),xargo,cargo)
+
+all: ta strip sign
+
+ta:
+ @$(BUILDER) build --target $(TARGET) --release --config $(LINKER_CFG)
+
+strip: ta
+ @$(OBJCOPY) --strip-unneeded $(OUT_DIR)/ta $(OUT_DIR)/stripped_ta
+
+sign: strip
+ @$(SIGN) --uuid $(UUID) --key $(TA_SIGN_KEY) --in
$(OUT_DIR)/stripped_ta --out $(OUT_DIR)/$(UUID).ta
+ @echo "SIGN => ${UUID}"
+
+clean:
+ @cargo clean
diff --git a/ci/ci.sh b/examples/inter_ta-rs/ta/Xargo.toml
old mode 100755
new mode 100644
similarity index 50%
copy from ci/ci.sh
copy to examples/inter_ta-rs/ta/Xargo.toml
index 6f026bc..1b1a113
--- a/ci/ci.sh
+++ b/examples/inter_ta-rs/ta/Xargo.toml
@@ -1,5 +1,3 @@
-#!/bin/bash
-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,41 +15,10 @@
# specific language governing permissions and limitations
# under the License.
-set -xe
-
-pushd ../tests
-
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
-
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
-
+[dependencies.std]
+path = "../../../rust/rust/library/std"
-popd
+[patch.crates-io]
+libc = { path = "../../../rust/libc" }
+rustc-std-workspace-core = { path =
"../../../rust/rust/library/rustc-std-workspace-core" }
+rustc-std-workspace-alloc = { path =
"../../../rust/rust/library/rustc-std-workspace-alloc" }
diff --git a/examples/inter_ta-rs/ta/build.rs b/examples/inter_ta-rs/ta/build.rs
new file mode 100644
index 0000000..d492383
--- /dev/null
+++ b/examples/inter_ta-rs/ta/build.rs
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+use optee_utee_build::{Error, RustEdition, TaConfig};
+use proto;
+
+fn main() -> Result<(), Error> {
+ let config = TaConfig::new_default_with_cargo_env(proto::UUID)?
+ .ta_data_size(1 * 1024 * 1024)
+ .ta_stack_size(1 * 1024 * 1024);
+ optee_utee_build::build(RustEdition::Before2024, config)
+}
diff --git a/examples/inter_ta-rs/ta/src/main.rs
b/examples/inter_ta-rs/ta/src/main.rs
new file mode 100644
index 0000000..fe2f6d1
--- /dev/null
+++ b/examples/inter_ta-rs/ta/src/main.rs
@@ -0,0 +1,152 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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_std]
+#![no_main]
+
+use optee_utee::{
+ ta_close_session, ta_create, ta_destroy, ta_invoke_command,
ta_open_session, trace_println,
+};
+use optee_utee::{Error, ErrorKind, Parameters, Result, Uuid};
+use optee_utee::{ParamIndex, TaSessionBuilder, TeeParams};
+use proto::{
+ Command, HelloWorldTaCommand, SystemPtaCommand, HELLO_WORLD_USER_TA_UUID,
SYSTEM_PTA_UUID,
+};
+
+#[ta_create]
+fn create() -> Result<()> {
+ trace_println!("[+] TA create");
+ Ok(())
+}
+
+#[ta_open_session]
+fn open_session(_params: &mut Parameters) -> Result<()> {
+ trace_println!("[+] TA open session");
+ Ok(())
+}
+
+#[ta_close_session]
+fn close_session() {
+ trace_println!("[+] TA close session");
+}
+
+#[ta_destroy]
+fn destroy() {
+ trace_println!("[+] TA destroy");
+}
+
+fn test_invoke_system_pta() -> Result<()> {
+ let system_pta_uuid =
+ Uuid::parse_str(SYSTEM_PTA_UUID).map_err(|_|
Error::from(ErrorKind::BadFormat))?;
+ // Open a session using the default timeout (TEE_TIMEOUT_INFINITE, meaning
no timeout), and no parameters:
+ let mut session = TaSessionBuilder::new(system_pta_uuid).build()?;
+ trace_println!("[+] TA open PTA session success");
+
+ let input: [u8; 32] = [0; 32];
+ let mut output: [u8; 32] = [0; 32];
+
+ // Construct parameters using chained method calls, max 4 parameters:
+ let mut params = TeeParams::new()
+ .with_memref_in(ParamIndex::Arg0, &input)
+ .with_memref_out(ParamIndex::Arg1, &mut output);
+
+ // Invoke the command using the default timeout, meaning no timeout:
+ session.invoke_command(SystemPtaCommand::DeriveTaUniqueKey as u32, &mut
params)?;
+
+ // Get the output buffer through written_slice():
+ // Note: written_slice() returns a slice of the original output buffer,
with the length
+ // adjusted to the actual size written by the TA.
+ let written_slice = params[ParamIndex::Arg1]
+ .written_slice()
+ .ok_or(Error::new(ErrorKind::BadParameters))?;
+
+ trace_println!("[+] TA invoke PTA command, output: {:?}", written_slice);
+
+ // Check if the output is not all zeroes and has the expected length:
+ if written_slice.len() != 32 {
+ trace_println!(
+ "[-] TA invoke PTA command failed, wrong output length: {:?}",
+ written_slice.len()
+ );
+ return Err(Error::new(ErrorKind::Generic));
+ }
+
+ if written_slice.iter().all(|&x| x == 0) {
+ trace_println!("[-] TA invoke PTA command failed, output is all 0");
+ return Err(Error::new(ErrorKind::Generic));
+ }
+
+ trace_println!("[+] TA invoke System PTA command success");
+
+ Ok(())
+}
+
+fn test_invoke_hello_world_user_ta() -> Result<()> {
+ let hello_world_user_ta_uuid =
+ Uuid::parse_str(HELLO_WORLD_USER_TA_UUID).map_err(|_|
Error::from(ErrorKind::BadFormat))?;
+ // Open a session with a specified timeout in milliseconds (10 seconds).
+ // To pass parameters during session opening, use `.with_params(xxx)`.
+ let mut session = TaSessionBuilder::new(hello_world_user_ta_uuid)
+ .with_timeout(10000)
+ .build()?;
+ trace_println!("[+] TA open user TA session success");
+
+ let mut params = TeeParams::new().with_value_inout(ParamIndex::Arg0, 29,
0);
+ // Invoke the command with a specified timeout in milliseconds (10
seconds).
+ session.invoke_command_with_timeout(
+ HelloWorldTaCommand::IncValue as u32,
+ &mut params,
+ 10000,
+ )?;
+
+ // Get the output value pair through output_value():
+ let (value_a, _value_b) = params[ParamIndex::Arg0]
+ .output_value()
+ .ok_or(Error::new(ErrorKind::BadParameters))?;
+
+ // Check if the output value is as expected:
+ if value_a != 129 {
+ trace_println!(
+ "[-] TA invoke user TA command failed, wrong output value: {:?}",
+ value_a
+ );
+ return Err(Error::new(ErrorKind::Generic));
+ }
+
+ trace_println!("[+] TA invoke hello world TA command success.");
+
+ Ok(())
+}
+
+#[ta_invoke_command]
+fn invoke_command(cmd_id: u32, _params: &mut Parameters) -> Result<()> {
+ trace_println!("[+] TA invoke command");
+ match Command::from(cmd_id) {
+ Command::Test => {
+ test_invoke_system_pta()?;
+ test_invoke_hello_world_user_ta()?;
+
+ trace_println!("[+] Test passed");
+ Ok(())
+ }
+ _ => {
+ return Err(Error::new(ErrorKind::NotSupported));
+ }
+ }
+}
+
+include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs"));
diff --git a/examples/inter_ta-rs/uuid.txt b/examples/inter_ta-rs/uuid.txt
new file mode 100644
index 0000000..6c50099
--- /dev/null
+++ b/examples/inter_ta-rs/uuid.txt
@@ -0,0 +1 @@
+fa9ea860-ef3b-4d59-8457-5564a60c0379
\ No newline at end of file
diff --git a/optee-utee/src/error.rs b/optee-utee/src/error.rs
index b71c4f5..97ea941 100644
--- a/optee-utee/src/error.rs
+++ b/optee-utee/src/error.rs
@@ -15,12 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-use optee_utee_sys as raw;
+#[cfg(not(target_os = "optee"))]
+use core::error;
use core::{fmt, result};
+use optee_utee_sys as raw;
#[cfg(target_os = "optee")]
use std::error;
-#[cfg(not(target_os = "optee"))]
-use core::error;
/// A specialized
[`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
/// type for TEE operations.
@@ -34,76 +34,79 @@ use core::error;
/// ````
pub type Result<T> = result::Result<T, Error>;
+#[derive(Clone)]
pub struct Error {
- code: u32,
+ kind: ErrorKind,
+ origin: Option<ErrorOrigin>,
}
/// A list specifying general categories of TEE error and its corresponding
code
/// in OP-TEE OS.
-#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum ErrorKind {
/// Object corruption.
- CorruptObject = 0xF0100001,
+ CorruptObject = raw::TEE_ERROR_CORRUPT_OBJECT,
/// Persistent object corruption.
- CorruptObject2 = 0xF0100002,
+ CorruptObject2 = raw::TEE_ERROR_CORRUPT_OBJECT_2,
/// Object storage is not available.
- StorageNotAvailable = 0xF0100003,
+ StorageNotAvailable = raw::TEE_ERROR_STORAGE_NOT_AVAILABLE,
/// Persistent object storage is not available.
- StorageNotAvailable2 = 0xF0100004,
+ StorageNotAvailable2 = raw::TEE_ERROR_STORAGE_NOT_AVAILABLE_2,
/// Non-specific cause.
- Generic = 0xFFFF0000,
+ Generic = raw::TEE_ERROR_GENERIC,
/// Access privileges are not sufficient.
- AccessDenied = 0xFFFF0001,
+ AccessDenied = raw::TEE_ERROR_ACCESS_DENIED,
/// The operation was canceled.
- Cancel = 0xFFFF0002,
+ Cancel = raw::TEE_ERROR_CANCEL,
/// Concurrent accesses caused conflict.
- AccessConflict = 0xFFFF0003,
+ AccessConflict = raw::TEE_ERROR_ACCESS_CONFLICT,
/// Too much data for the requested operation was passed.
- ExcessData = 0xFFFF0004,
+ ExcessData = raw::TEE_ERROR_EXCESS_DATA,
/// Input data was of invalid format.
- BadFormat = 0xFFFF0005,
+ BadFormat = raw::TEE_ERROR_BAD_FORMAT,
/// Input parameters were invalid.
- BadParameters = 0xFFFF0006,
+ BadParameters = raw::TEE_ERROR_BAD_PARAMETERS,
/// Operation is not valid in the current state.
- BadState = 0xFFFF0007,
+ BadState = raw::TEE_ERROR_BAD_STATE,
/// The requested data item is not found.
- ItemNotFound = 0xFFFF0008,
+ ItemNotFound = raw::TEE_ERROR_ITEM_NOT_FOUND,
/// The requested operation should exist but is not yet implemented.
- NotImplemented = 0xFFFF0009,
+ NotImplemented = raw::TEE_ERROR_NOT_IMPLEMENTED,
/// The requested operation is valid but is not supported in this
implementation.
- NotSupported = 0xFFFF000A,
+ NotSupported = raw::TEE_ERROR_NOT_SUPPORTED,
/// Expected data was missing.
- NoData = 0xFFFF000B,
+ NoData = raw::TEE_ERROR_NO_DATA,
/// System ran out of resources.
- OutOfMemory = 0xFFFF000C,
+ OutOfMemory = raw::TEE_ERROR_OUT_OF_MEMORY,
/// The system is busy working on something else.
- Busy = 0xFFFF000D,
+ Busy = raw::TEE_ERROR_BUSY,
/// Communication with a remote party failed.
- Communication = 0xFFFF000E,
+ Communication = raw::TEE_ERROR_COMMUNICATION,
/// A security fault was detected.
- Security = 0xFFFF000F,
+ Security = raw::TEE_ERROR_SECURITY,
/// The supplied buffer is too short for the generated output.
- ShortBuffer = 0xFFFF0010,
+ ShortBuffer = raw::TEE_ERROR_SHORT_BUFFER,
/// The operation has been cancelled by an external event which occurred in
/// the REE while the function was in progress.
- ExternalCancel = 0xFFFF0011,
+ ExternalCancel = raw::TEE_ERROR_EXTERNAL_CANCEL,
/// Data overflow.
- Overflow = 0xFFFF300F,
+ Overflow = raw::TEE_ERROR_OVERFLOW,
/// Trusted Application has panicked during the operation.
- TargetDead = 0xFFFF3024,
+ TargetDead = raw::TEE_ERROR_TARGET_DEAD,
/// Insufficient space is available.
- StorageNoSpace = 0xFFFF3041,
+ StorageNoSpace = raw::TEE_ERROR_STORAGE_NO_SPACE,
/// MAC is invalid.
- MacInvalid = 0xFFFF3071,
+ MacInvalid = raw::TEE_ERROR_MAC_INVALID,
/// Signature is invalid.
- SignatureInvalid = 0xFFFF3072,
+ SignatureInvalid = raw::TEE_ERROR_SIGNATURE_INVALID,
/// The persistent time has not been set.
- TimeNotSet = 0xFFFF5000,
+ TimeNotSet = raw::TEE_ERROR_TIME_NOT_SET,
/// The persistent time has been set but may have been corrupted and SHALL
/// no longer be trusted.
- TimeNeedsReset = 0xFFFF5001,
+ TimeNeedsReset = raw::TEE_ERROR_TIME_NEEDS_RESET,
/// Unknown error.
+ #[default]
Unknown,
}
@@ -150,36 +153,15 @@ impl ErrorKind {
}
}
-impl Error {
- pub fn new(kind: ErrorKind) -> Error {
- Error { code: kind as u32 }
- }
-
- /// Creates a new instance of an `Error` from a particular TEE error code.
- ///
- /// # Examples
- ///
- /// ``` no_run
- /// use optee_utee;
- ///
- /// let error = optee_utee::Error::from_raw_error(0xFFFF000F);
- /// assert_eq!(error.kind(), optee_utee::ErrorKind::Security);
- /// ```
- pub fn from_raw_error(code: u32) -> Error {
- Error { code }
+impl From<ErrorKind> for u32 {
+ fn from(kind: ErrorKind) -> u32 {
+ kind as u32
}
+}
- /// Returns the corresponding `ErrorKind` for this error.
- ///
- /// # Examples
- ///
- /// ``` no_run
- /// use optee_utee;
- ///
- /// let error = optee_utee::Error::new(optee_utee::ErrorKind::Security);
- /// ```
- pub fn kind(&self) -> ErrorKind {
- match self.code {
+impl From<u32> for ErrorKind {
+ fn from(code: u32) -> ErrorKind {
+ match code {
raw::TEE_ERROR_CORRUPT_OBJECT => ErrorKind::CorruptObject,
raw::TEE_ERROR_CORRUPT_OBJECT_2 => ErrorKind::CorruptObject2,
raw::TEE_ERROR_STORAGE_NOT_AVAILABLE =>
ErrorKind::StorageNotAvailable,
@@ -212,11 +194,59 @@ impl Error {
_ => ErrorKind::Unknown,
}
}
+}
+
+impl Error {
+ pub fn new(kind: ErrorKind) -> Error {
+ Error { kind, origin: None }
+ }
+
+ /// Creates a new instance of an `Error` from a particular TEE error code.
+ ///
+ /// # Examples
+ ///
+ /// ``` no_run
+ /// use optee_utee;
+ ///
+ /// let error = optee_utee::Error::from_raw_error(0xFFFF000F);
+ /// assert_eq!(error.kind(), optee_utee::ErrorKind::Security);
+ /// ```
+ pub fn from_raw_error(code: u32) -> Error {
+ Error {
+ kind: ErrorKind::from(code),
+ origin: None,
+ }
+ }
+ pub fn with_origin(mut self, origin: ErrorOrigin) -> Self {
+ self.origin = Some(origin);
+ self
+ }
+
+ /// Returns the corresponding `ErrorKind` for this error.
+ ///
+ /// # Examples
+ ///
+ /// ``` no_run
+ /// use optee_utee;
+ ///
+ /// let error = optee_utee::Error::new(optee_utee::ErrorKind::Security);
+ /// ```
+ pub fn kind(&self) -> ErrorKind {
+ self.kind
+ }
+
+ /// Returns the origin of this error.
+ pub fn origin(&self) -> Option<ErrorOrigin> {
+ self.origin.clone()
+ }
+
+ /// Returns raw code of this error.
pub fn raw_code(&self) -> u32 {
- self.code
+ self.kind.into()
}
+ /// Returns corresponding error message of this error.
pub fn message(&self) -> &str {
self.kind().as_str()
}
@@ -224,13 +254,19 @@ impl Error {
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "{} (error code 0x{:x})", self.message(), self.code)
+ write!(
+ fmt,
+ "{} (error code 0x{:x}, origin 0x{:x})",
+ self.message(),
+ self.raw_code(),
+ self.origin().map(|v| v.into()).unwrap_or(0_u32),
+ )
}
}
impl fmt::Display for Error {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "{} (error code 0x{:x})", self.message(), self.code)
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self, f)
}
}
@@ -243,6 +279,35 @@ impl error::Error for Error {
impl From<ErrorKind> for Error {
#[inline]
fn from(kind: ErrorKind) -> Error {
- Error { code: kind as u32 }
+ Error { kind, origin: None }
+ }
+}
+
+#[derive(Clone, Debug, Default, Eq, PartialEq)]
+#[repr(u32)]
+pub enum ErrorOrigin {
+ API = raw::TEE_ORIGIN_API,
+ COMMS = raw::TEE_ORIGIN_COMMS,
+ TEE = raw::TEE_ORIGIN_TEE,
+ TA = raw::TEE_ORIGIN_TRUSTED_APP,
+ #[default]
+ UNKNOWN,
+}
+
+impl From<ErrorOrigin> for u32 {
+ fn from(origin: ErrorOrigin) -> u32 {
+ origin as u32
+ }
+}
+
+impl From<u32> for ErrorOrigin {
+ fn from(code: u32) -> ErrorOrigin {
+ match code {
+ raw::TEE_ORIGIN_API => ErrorOrigin::API,
+ raw::TEE_ORIGIN_COMMS => ErrorOrigin::COMMS,
+ raw::TEE_ORIGIN_TEE => ErrorOrigin::TEE,
+ raw::TEE_ORIGIN_TRUSTED_APP => ErrorOrigin::TA,
+ _ => ErrorOrigin::UNKNOWN,
+ }
}
}
diff --git a/optee-utee/src/lib.rs b/optee-utee/src/lib.rs
index af65778..795c5ca 100644
--- a/optee-utee/src/lib.rs
+++ b/optee-utee/src/lib.rs
@@ -37,18 +37,22 @@ use optee_utee_sys as raw;
#[cfg(all(not(target_os = "optee"), not(feature = "no_panic_handler")))]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
- unsafe { raw::TEE_Panic(0); }
+ unsafe {
+ raw::TEE_Panic(0);
+ }
loop {}
}
+pub use self::arithmetical::*;
+pub use self::crypto_op::*;
pub use self::error::{Error, ErrorKind, Result};
+pub use self::extension::*;
pub use self::object::*;
-pub use self::crypto_op::*;
+pub use self::parameter::{ParamType, ParamTypes, Parameter, Parameters};
+pub use self::ta_session::{TaSession, TaSessionBuilder};
+pub use self::tee_parameter::{ParamIndex, TeeParams};
pub use self::time::*;
-pub use self::arithmetical::*;
-pub use self::extension::*;
pub use self::uuid::*;
-pub use self::parameter::{ParamType, ParamTypes, Parameter, Parameters};
pub use optee_utee_macros::{
ta_close_session, ta_create, ta_destroy, ta_invoke_command,
ta_open_session,
};
@@ -56,12 +60,14 @@ pub use optee_utee_macros::{
pub mod trace;
#[macro_use]
mod macros;
+pub mod arithmetical;
+pub mod crypto_op;
mod error;
-mod parameter;
+pub mod extension;
+pub mod net;
pub mod object;
-pub mod crypto_op;
+mod parameter;
+mod ta_session;
+mod tee_parameter;
pub mod time;
-pub mod arithmetical;
-pub mod extension;
pub mod uuid;
-pub mod net;
diff --git a/optee-utee/src/ta_session.rs b/optee-utee/src/ta_session.rs
new file mode 100644
index 0000000..f50a59a
--- /dev/null
+++ b/optee-utee/src/ta_session.rs
@@ -0,0 +1,146 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+use crate::{Error, Result, TeeParams, Uuid};
+use optee_utee_sys as raw;
+
+pub struct TaSessionBuilder<'a> {
+ target_uuid: Uuid,
+ timeout: u32,
+ params: Option<TeeParams<'a>>,
+}
+
+impl<'a> TaSessionBuilder<'a> {
+ /// Creates a new builder for the given TA UUID.
+ pub fn new(uuid: Uuid) -> Self {
+ Self {
+ target_uuid: uuid,
+ timeout: raw::TEE_TIMEOUT_INFINITE,
+ params: None,
+ }
+ }
+
+ /// Sets a custom timeout for the session opening.
+ pub fn with_timeout(mut self, timeout: u32) -> Self {
+ self.timeout = timeout;
+ self
+ }
+
+ /// Sets the parameters to be passed during session opening.
+ pub fn with_params(mut self, params: TeeParams<'a>) -> Self {
+ self.params = Some(params);
+ self
+ }
+
+ /// Builds and opens the `TaSession`. Returns an error if the session
fails to open.
+ pub fn build(mut self) -> Result<TaSession> {
+ let mut err_origin: u32 = 0;
+ let mut raw_session: raw::TEE_TASessionHandle = core::ptr::null_mut();
+ // Check if the parameters are provided and prepare them for the C API
call.
+ let (raw_param_types, raw_params_ptr, raw_params_opt) =
+ if let Some(params) = &mut self.params {
+ let mut raw_params = params.as_raw();
+ let raw_ptr = raw_params.as_mut_ptr();
+ (params.raw_param_types(), raw_ptr, Some(raw_params))
+ } else {
+ (0, core::ptr::null_mut(), None)
+ };
+
+ // SAFETY:
+ // self.target_uuid.as_raw_ptr() provides a valid pointer to the UUID.
+ // raw_params.as_mut_ptr() provides a valid pointer to the parameters.
+ // The remaining arguments are either valid values or null/mut
pointers as expected by the C API.
+ // For parameters that are intended to be modified by the call, the
buffer constraints are checked later in update_from_raw().
+ match unsafe {
+ raw::TEE_OpenTASession(
+ self.target_uuid.as_raw_ptr(),
+ self.timeout,
+ raw_param_types,
+ raw_params_ptr,
+ &mut raw_session,
+ &mut err_origin,
+ )
+ } {
+ raw::TEE_SUCCESS => {
+ if let (Some(params), Some(raw_params)) = (&mut self.params,
raw_params_opt) {
+ params.update_from_raw(&raw_params)?;
+ }
+
+ Ok(TaSession { raw: raw_session })
+ }
+ code =>
Err(Error::from_raw_error(code).with_origin(err_origin.into())),
+ }
+ }
+}
+
+pub struct TaSession {
+ raw: raw::TEE_TASessionHandle,
+}
+
+impl TaSession {
+ /// Invokes a command with the provided parameters using the session's
default timeout.
+ /// Returns the result directly without allowing further method chaining.
+ pub fn invoke_command(&mut self, command_id: u32, params: &mut TeeParams)
-> Result<()> {
+ self.invoke_command_with_timeout(command_id, params,
raw::TEE_TIMEOUT_INFINITE)
+ }
+
+ pub fn invoke_command_with_timeout(
+ &mut self,
+ command_id: u32,
+ params: &mut TeeParams,
+ timeout: u32,
+ ) -> Result<()> {
+ let mut err_origin: u32 = 0;
+ let mut raw_params = params.as_raw();
+ let param_types = params.raw_param_types();
+
+ // SAFETY:
+ // self.raw is a valid pointer to an active session handle.
+ // raw_params.as_mut_ptr() yields a valid mutable pointer to the
parameters array.
+ // The remaining arguments are either valid values or null/mutable
pointers, as expected by the C API.
+ // For parameters that are intended to be modified by the call, the
buffer constraints are checked later in update_from_raw().
+ match unsafe {
+ raw::TEE_InvokeTACommand(
+ self.raw,
+ timeout,
+ command_id,
+ param_types,
+ raw_params.as_mut_ptr(),
+ &mut err_origin,
+ )
+ } {
+ raw::TEE_SUCCESS => {
+ // Update the parameters with the results
+ params.update_from_raw(&raw_params)?;
+ Ok(())
+ }
+ code =>
Err(Error::from_raw_error(code).with_origin(err_origin.into())),
+ }
+ }
+}
+
+// Drop implementation to close the session
+impl Drop for TaSession {
+ fn drop(&mut self) {
+ // SAFETY:
+ // self.raw is a valid pointer to an active session handle.
+ // The function call is expected to clean up the session resources.
+ unsafe {
+ raw::TEE_CloseTASession(self.raw);
+ }
+ }
+}
diff --git a/optee-utee/src/tee_parameter.rs b/optee-utee/src/tee_parameter.rs
new file mode 100644
index 0000000..7c91d19
--- /dev/null
+++ b/optee-utee/src/tee_parameter.rs
@@ -0,0 +1,372 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+use crate::{Error, ErrorKind, ParamType, Result};
+use core::ops::{Index, IndexMut};
+use optee_utee_sys as raw;
+
+#[derive(Copy, Clone, Debug)]
+pub enum ParamIndex {
+ Arg0,
+ Arg1,
+ Arg2,
+ Arg3,
+}
+
+impl ParamIndex {
+ fn to_usize(self) -> usize {
+ match self {
+ ParamIndex::Arg0 => 0,
+ ParamIndex::Arg1 => 1,
+ ParamIndex::Arg2 => 2,
+ ParamIndex::Arg3 => 3,
+ }
+ }
+}
+
+enum ParamContent<'a> {
+ None,
+ MemrefInput {
+ buffer: &'a [u8],
+ },
+ MemrefOutput {
+ buffer: &'a mut [u8],
+ written: usize,
+ },
+ MemrefInout {
+ buffer: &'a mut [u8],
+ written: usize,
+ },
+ ValueInput {
+ a: u32,
+ b: u32,
+ },
+ ValueOutput {
+ a: u32,
+ b: u32,
+ },
+ ValueInout {
+ a: u32,
+ b: u32,
+ },
+}
+
+pub struct Param<'a> {
+ content: ParamContent<'a>,
+}
+
+impl<'a> Param<'a> {
+ fn new() -> Self {
+ Self {
+ content: ParamContent::None,
+ }
+ }
+
+ /// Returns the written slice if available (for `MemrefOutput` or
`MemrefInout`).
+ /// Returns `None` for other types. Developers can decide whether to treat
absence as an error.
+ pub fn written_slice(&self) -> Option<&[u8]> {
+ match &self.content {
+ ParamContent::MemrefOutput { buffer, written } =>
Some(&buffer[..*written]),
+ ParamContent::MemrefInout { buffer, written } =>
Some(&buffer[..*written]),
+ _ => None,
+ }
+ }
+
+ /// Returns the output values if available (for `ValueOutput` or
`ValueInout`).
+ /// Returns `None` for other types. Caller decides how to handle missing
values.
+ pub fn output_value(&self) -> Option<(u32, u32)> {
+ match &self.content {
+ ParamContent::ValueOutput { a, b } => Some((*a, *b)),
+ ParamContent::ValueInout { a, b } => Some((*a, *b)),
+ _ => None,
+ }
+ }
+
+ fn get_type(&self) -> ParamType {
+ match &self.content {
+ ParamContent::None => ParamType::None,
+ ParamContent::MemrefInput { .. } => ParamType::MemrefInput,
+ ParamContent::MemrefOutput { .. } => ParamType::MemrefOutput,
+ ParamContent::MemrefInout { .. } => ParamType::MemrefInout,
+ ParamContent::ValueInput { .. } => ParamType::ValueInput,
+ ParamContent::ValueOutput { .. } => ParamType::ValueOutput,
+ ParamContent::ValueInout { .. } => ParamType::ValueInout,
+ }
+ }
+
+ fn get_raw_type(&self) -> u32 {
+ self.get_type() as u32
+ }
+
+ fn as_raw(&mut self) -> raw::TEE_Param {
+ match &mut self.content {
+ ParamContent::None => raw::TEE_Param {
+ memref: raw::Memref {
+ buffer: core::ptr::null_mut(),
+ size: 0,
+ },
+ },
+ ParamContent::MemrefInput { buffer } => raw::TEE_Param {
+ memref: raw::Memref {
+ buffer: (*buffer).as_ptr() as *mut core::ffi::c_void,
+ size: buffer.len(),
+ },
+ },
+ ParamContent::MemrefOutput { buffer, written: _ } =>
raw::TEE_Param {
+ memref: raw::Memref {
+ buffer: (*buffer).as_mut_ptr() as *mut core::ffi::c_void,
+ size: buffer.len(),
+ },
+ },
+ ParamContent::MemrefInout { buffer, written: _ } => raw::TEE_Param
{
+ memref: raw::Memref {
+ buffer: (*buffer).as_mut_ptr() as *mut core::ffi::c_void,
+ size: buffer.len(),
+ },
+ },
+ ParamContent::ValueInput { a, b } => raw::TEE_Param {
+ value: raw::Value { a: *a, b: *b },
+ },
+ ParamContent::ValueInout { a, b } => raw::TEE_Param {
+ value: raw::Value { a: *a, b: *b },
+ },
+ ParamContent::ValueOutput { a, b } => raw::TEE_Param {
+ value: raw::Value { a: *a, b: *b },
+ },
+ }
+ }
+
+ fn update_size_from_raw(&mut self, raw_param: &raw::TEE_Param) ->
Result<()> {
+ match &mut self.content {
+ ParamContent::MemrefOutput { buffer, written } => {
+ // SAFETY:
+ // The caller must ensure this param is of memref type and
properly initialized.
+ // This is enforced by the variant match on
`ParamContent::MemrefOutput`.
+ // Accessing `raw_param.memref.size` is safe under these
assumptions.
+ let new_size = unsafe { raw_param.memref.size };
+ if new_size > (*buffer).len() {
+ return Err(Error::new(ErrorKind::BadParameters));
+ }
+ *written = new_size;
+ Ok(())
+ }
+ ParamContent::MemrefInout { buffer, written } => {
+ // SAFETY:
+ // The caller must ensure this param is of memref type and
properly initialized.
+ // This is enforced by the variant match on
`ParamContent::MemrefOutput`.
+ // Accessing `raw_param.memref.size` is safe under these
assumptions.
+ let new_size = unsafe { raw_param.memref.size };
+ if new_size > (*buffer).len() {
+ return Err(Error::new(ErrorKind::BadParameters));
+ }
+ *written = new_size;
+ Ok(())
+ }
+ _ => {
+ return Err(Error::new(ErrorKind::BadFormat));
+ }
+ }
+ }
+
+ fn update_value_from_raw(&mut self, raw_param: &raw::TEE_Param) {
+ match &mut self.content {
+ ParamContent::ValueInout { a, b } => {
+ // SAFETY:
+ // The caller must ensure this param is of value type and
properly initialized.
+ // This is guaranteed by matching against
`ParamContent::ValueInout`.
+ // Accessing `raw_param.value.a` is safe under above
assumption.
+ *a = unsafe { raw_param.value.a };
+ // SAFETY:
+ // Accessing `raw_param.value.b` is safe under above
assumption.
+ *b = unsafe { raw_param.value.b };
+ }
+ ParamContent::ValueOutput { a, b } => {
+ // SAFETY:
+ // The caller must ensure this param is of value type and
properly initialized.
+ // This is guaranteed by matching against
`ParamContent::ValueInout`.
+ // Accessing `raw_param.value.a` is safe under above
assumption.
+ *a = unsafe { raw_param.value.a };
+ // SAFETY:
+ // Accessing `raw_param.value.b` is safe under above
assumption.
+ *b = unsafe { raw_param.value.b };
+ }
+ _ => {}
+ }
+ }
+}
+
+/// The TeeParams struct is used to manage the parameters for TEE commands.
+pub struct TeeParams<'a> {
+ params: [Param<'a>; 4],
+}
+
+impl<'a> TeeParams<'a> {
+ pub fn new() -> Self {
+ Self {
+ params: [Param::new(), Param::new(), Param::new(), Param::new()],
+ }
+ }
+
+ /// These functions allow for method-chaining to easily configure multiple
parameters at once.
+ ///
+ /// The following methods can be chained:
+ /// - `with_memref_in`: Sets a memory reference input parameter.
+ /// - `with_memref_out`: Sets a memory reference output parameter.
+ /// - `with_memref_inout`: Sets a memory reference inout parameter.
+ /// - `with_value_in`: Sets a value input parameter.
+ /// - `with_value_out`: Sets a value output parameter.
+ /// - `with_value_inout`: Sets a value inout parameter.
+ ///
+ /// Example usage:
+ /// ``` no_run
+ /// let params = TeeParams::new()
+ /// .with_memref_in(ParamIndex::Arg0, &input_buffer)
+ /// .with_memref_out(ParamIndex::Arg1, &mut output_buffer)
+ /// .with_value_in(ParamIndex::Arg2, 42, 0)
+ /// .with_value_out(ParamIndex::Arg3, 0, 0);
+ /// ```
+ pub fn with_memref_in(mut self, idx: ParamIndex, buffer: &'a [u8]) -> Self
{
+ self[idx].content = ParamContent::MemrefInput { buffer };
+ self
+ }
+
+ pub fn with_memref_out(mut self, idx: ParamIndex, buffer: &'a mut [u8]) ->
Self {
+ self[idx].content = ParamContent::MemrefOutput { buffer, written: 0 };
+ self
+ }
+
+ pub fn with_memref_inout(mut self, idx: ParamIndex, buffer: &'a mut [u8])
-> Self {
+ self[idx].content = ParamContent::MemrefInout { buffer, written: 0 };
+ self
+ }
+
+ pub fn with_value_in(mut self, idx: ParamIndex, a: u32, b: u32) -> Self {
+ self[idx].content = ParamContent::ValueInput { a, b };
+ self
+ }
+
+ pub fn with_value_out(mut self, idx: ParamIndex, a: u32, b: u32) -> Self {
+ self[idx].content = ParamContent::ValueOutput { a, b };
+ self
+ }
+
+ pub fn with_value_inout(mut self, idx: ParamIndex, a: u32, b: u32) -> Self
{
+ self[idx].content = ParamContent::ValueInout { a, b };
+ self
+ }
+
+ /// These methods allow the user to set the content at a specific index.
+ ///
+ /// Example usage:
+ /// ``` no_run
+ /// let mut params = TeeParams::new();
+ /// params.set_memref_in(ParamIndex::Arg0, &input_buffer);
+ /// params.set_memref_out(ParamIndex::Arg1, &mut output_buffer);
+ /// params.set_value_in(ParamIndex::Arg2, 42, 0);
+ /// params.set_value_out(ParamIndex::Arg3, 0, 0);
+ /// ```
+ pub fn set_memref_in(&mut self, idx: ParamIndex, buffer: &'a [u8]) -> &mut
Self {
+ self[idx].content = ParamContent::MemrefInput { buffer };
+ self
+ }
+
+ pub fn set_memref_out(&mut self, idx: ParamIndex, buffer: &'a mut [u8]) ->
&mut Self {
+ self[idx].content = ParamContent::MemrefOutput { buffer, written: 0 };
+ self
+ }
+
+ pub fn set_memref_inout(&mut self, idx: ParamIndex, buffer: &'a mut [u8])
-> &mut Self {
+ self[idx].content = ParamContent::MemrefInout { buffer, written: 0 };
+ self
+ }
+
+ pub fn set_value_in(&mut self, idx: ParamIndex, a: u32, b: u32) -> &mut
Self {
+ self[idx].content = ParamContent::ValueInput { a, b };
+ self
+ }
+
+ pub fn set_value_out(&mut self, idx: ParamIndex, a: u32, b: u32) -> &mut
Self {
+ self[idx].content = ParamContent::ValueOutput { a, b };
+ self
+ }
+
+ pub fn set_value_inout(&mut self, idx: ParamIndex, a: u32, b: u32) -> &mut
Self {
+ self[idx].content = ParamContent::ValueInout { a, b };
+ self
+ }
+
+ pub(crate) fn raw_param_types(&self) -> u32 {
+ let mut param_types = 0;
+ for (i, param) in self.params.iter().enumerate() {
+ param_types |= param.get_raw_type() << (i * 4);
+ }
+ param_types
+ }
+
+ pub(crate) fn as_raw(&mut self) -> [raw::TEE_Param; 4] {
+ [
+ self.params[0].as_raw(),
+ self.params[1].as_raw(),
+ self.params[2].as_raw(),
+ self.params[3].as_raw(),
+ ]
+ }
+
+ /// Updates the parameters with results after each TEE call.
+ ///
+ /// This function updates the content of parameters for `MemrefInout`,
`MemrefOutput`, `ValueInout`, and `ValueOutput`.
+ /// Parameters of other types are not modified.
+ pub(crate) fn update_from_raw(&mut self, raw_params: &[raw::TEE_Param; 4])
-> Result<()> {
+ // update the content for memref inout/out, and value inout/out
+ for (i, param) in self.params.iter_mut().enumerate() {
+ let raw_param = &raw_params[i];
+ match param.get_type() {
+ ParamType::MemrefOutput => {
+ param.update_size_from_raw(raw_param)?;
+ }
+ ParamType::MemrefInout => {
+ param.update_size_from_raw(raw_param)?;
+ }
+ ParamType::ValueOutput => {
+ param.update_value_from_raw(raw_param);
+ }
+ ParamType::ValueInout => {
+ param.update_value_from_raw(raw_param);
+ }
+ _ => {
+ // No action needed for other types
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+// Index trait implementations for direct parameter access
+impl<'a> Index<ParamIndex> for TeeParams<'a> {
+ type Output = Param<'a>;
+
+ fn index(&self, index: ParamIndex) -> &Self::Output {
+ &self.params[index.to_usize()]
+ }
+}
+
+impl<'a> IndexMut<ParamIndex> for TeeParams<'a> {
+ fn index_mut(&mut self, index: ParamIndex) -> &mut Self::Output {
+ &mut self.params[index.to_usize()]
+ }
+}
diff --git a/ci/ci.sh b/tests/test_inter_ta.sh
similarity index 51%
copy from ci/ci.sh
copy to tests/test_inter_ta.sh
index 6f026bc..390ecb1 100755
--- a/ci/ci.sh
+++ b/tests/test_inter_ta.sh
@@ -19,39 +19,25 @@
set -xe
-pushd ../tests
+# Include base script
+source setup.sh
-# Prioritize running specialized test suites first, as they have a higher
-# probability of detecting failures early in the pipeline.
-# Run std only tests
-if [ "$STD" ]; then
- ./test_serde.sh
- ./test_message_passing_interface.sh
- ./test_tls_client.sh
- ./test_tls_server.sh
- ./test_eth_wallet.sh
- ./test_secure_db_abstraction.sh
-else
- ./test_mnist_rs.sh
-fi
+# Copy hello_world-rs TA for testing
+cp ../examples/hello_world-rs/ta/target/$TARGET_TA/release/*.ta shared
+# Copy TA and host binary
+cp ../examples/inter_ta-rs/host/target/$TARGET_HOST/release/inter_ta-rs shared
+cp ../examples/inter_ta-rs/ta/target/$TARGET_TA/release/*.ta shared
-./test_hello_world.sh
-./test_random.sh
-./test_secure_storage.sh
-./test_aes.sh
-./test_hotp.sh
-./test_acipher.sh
-./test_big_int.sh
-./test_diffie_hellman.sh
-./test_digest.sh
-./test_authentication.sh
-./test_time.sh
-./test_signature_verification.sh
-./test_supp_plugin.sh
-./test_error_handling.sh
-./test_tcp_client.sh
-./test_udp_socket.sh
-./test_client_pool.sh
+# Run script specific commands in QEMU
+run_in_qemu "cp *.ta /lib/optee_armtz/\n"
+run_in_qemu "./inter_ta-rs\n"
+run_in_qemu "^C"
-
-popd
+# Script specific checks
+{
+ grep -q "Success" screenlog.0
+} || {
+ cat -v screenlog.0
+ cat -v /tmp/serial.log
+ false
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]