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
commit e12359b9612a4a9bf1bd345fe3d34cf49eac2a6b Author: Yuan Zhuang <[email protected]> AuthorDate: Thu Feb 27 10:25:40 2025 +0000 examples: Add secure_db_abstraction (std-only) Add reference implementation for TA that simplifies interaction with secure storage. It provides basic methods for database operations, including `get()`, `put()`, `delete_entries()`, and `list_entries()`, making it easier for developers to store and retrieve data based on Rust Type constraints. The example is std-only for now. Signed-off-by: Yuan Zhuang <[email protected]> Reviewed-by: Zehui Chen <[email protected]> --- ci/ci.sh | 1 + .../secure_db_abstraction-rs/Makefile | 47 ++++---- .../secure_db_abstraction-rs/host/Cargo.toml | 44 +++----- .../secure_db_abstraction-rs/host/Makefile | 59 +++++----- examples/secure_db_abstraction-rs/host/src/main.rs | 32 ++++++ .../secure_db_abstraction-rs/proto/Cargo.toml | 42 ++------ examples/secure_db_abstraction-rs/proto/src/lib.rs | 31 ++++++ .../secure_db_abstraction-rs/ta/Cargo.toml | 52 ++++----- examples/secure_db_abstraction-rs/ta/Makefile | 50 +++++++++ .../secure_db_abstraction-rs/ta/Xargo.toml | 38 ++----- examples/secure_db_abstraction-rs/ta/build.rs | 24 +++++ examples/secure_db_abstraction-rs/ta/src/main.rs | 120 +++++++++++++++++++++ .../ta/src/secure_db/backend.rs | 86 +++++++++++++++ .../ta/src/secure_db/client.rs | 102 ++++++++++++++++++ .../ta/src/secure_db/db.rs | 113 +++++++++++++++++++ .../ta/src/secure_db/mod.rs | 25 +++++ .../ta/src/secure_db/storable.rs | 52 +++++++++ examples/secure_db_abstraction-rs/uuid.txt | 1 + ci/ci.sh => tests/test_secure_db_abstraction.sh | 45 ++++---- 19 files changed, 751 insertions(+), 213 deletions(-) diff --git a/ci/ci.sh b/ci/ci.sh index e10916f..7556757 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -45,6 +45,7 @@ if [ "$STD" ]; then ./test_tls_client.sh ./test_tls_server.sh ./test_eth_wallet.sh + ./test_secure_db_abstraction.sh fi popd diff --git a/ci/ci.sh b/examples/secure_db_abstraction-rs/Makefile old mode 100755 new mode 100644 similarity index 58% copy from ci/ci.sh copy to examples/secure_db_abstraction-rs/Makefile index e10916f..a7a3dec --- a/ci/ci.sh +++ b/examples/secure_db_abstraction-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,34 +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 + +.PHONY: host ta all clean -pushd ../tests +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 +host: + $(q)make -C host TARGET=$(TARGET_HOST) \ + CROSS_COMPILE=$(CROSS_COMPILE_HOST) -# 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 -fi +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/secure_db_abstraction-rs/host/Cargo.toml old mode 100755 new mode 100644 similarity index 58% copy from ci/ci.sh copy to examples/secure_db_abstraction-rs/host/Cargo.toml index e10916f..c199ce8 --- a/ci/ci.sh +++ b/examples/secure_db_abstraction-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,34 +15,18 @@ # specific language governing permissions and limitations # under the License. -set -xe - -pushd ../tests - -./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 +[package] +name = "secure_db_abstraction-rs" +version = "0.1.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" -# 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 -fi +[dependencies] +proto = { path = "../proto" } +optee-teec = { path = "../../../optee-teec" } -popd +[profile.release] +lto = true diff --git a/ci/ci.sh b/examples/secure_db_abstraction-rs/host/Makefile old mode 100755 new mode 100644 similarity index 57% copy from ci/ci.sh copy to examples/secure_db_abstraction-rs/host/Makefile index e10916f..c8b90ce --- a/ci/ci.sh +++ b/examples/secure_db_abstraction-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,34 +15,29 @@ # specific language governing permissions and limitations # under the License. -set -xe - -pushd ../tests - -./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 - -# 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 -fi - -popd +# STD-ONLY example + +NAME := secure_db_abstraction-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 + +ifeq ($(STD),) +all: + @echo "Please \`export STD=y\` then rerun \`source environment\` to build the STD version" +else +all: host strip +endif + +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/secure_db_abstraction-rs/host/src/main.rs b/examples/secure_db_abstraction-rs/host/src/main.rs new file mode 100644 index 0000000..1647efd --- /dev/null +++ b/examples/secure_db_abstraction-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/secure_db_abstraction-rs/proto/Cargo.toml old mode 100755 new mode 100644 similarity index 58% copy from ci/ci.sh copy to examples/secure_db_abstraction-rs/proto/Cargo.toml index e10916f..e30aef8 --- a/ci/ci.sh +++ b/examples/secure_db_abstraction-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,34 +15,14 @@ # specific language governing permissions and limitations # under the License. -set -xe - -pushd ../tests - -./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 - -# 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 -fi +[package] +name = "proto" +version = "0.1.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/secure_db_abstraction-rs/proto/src/lib.rs b/examples/secure_db_abstraction-rs/proto/src/lib.rs new file mode 100644 index 0000000..76bf57f --- /dev/null +++ b/examples/secure_db_abstraction-rs/proto/src/lib.rs @@ -0,0 +1,31 @@ +// 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 num_enum::{FromPrimitive, IntoPrimitive}; + +#[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"); diff --git a/ci/ci.sh b/examples/secure_db_abstraction-rs/ta/Cargo.toml old mode 100755 new mode 100644 similarity index 53% copy from ci/ci.sh copy to examples/secure_db_abstraction-rs/ta/Cargo.toml index e10916f..40e2e9d --- a/ci/ci.sh +++ b/examples/secure_db_abstraction-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,34 +15,28 @@ # specific language governing permissions and limitations # under the License. -set -xe - -pushd ../tests +[package] +name = "ta" +version = "0.1.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 +[dependencies] +proto = { path = "../proto" } +optee-utee-sys = { path = "../../../optee-utee/optee-utee-sys" } +optee-utee = { path = "../../../optee-utee" } +bincode = "1.3.3" +anyhow = "1.0" +serde = { version = "1.0", features = ["derive"] } -# 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 -fi +[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/secure_db_abstraction-rs/ta/Makefile b/examples/secure_db_abstraction-rs/ta/Makefile new file mode 100644 index 0000000..42d9236 --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/Makefile @@ -0,0 +1,50 @@ +# 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. + +# STD-ONLY example + +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 + +ifeq ($(STD),) +all: + @echo "Please \`export STD=y\` then rerun \`source environment\` to build the STD version" +else +all: ta strip sign +endif + +ta: + @xargo 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/secure_db_abstraction-rs/ta/Xargo.toml old mode 100755 new mode 100644 similarity index 58% copy from ci/ci.sh copy to examples/secure_db_abstraction-rs/ta/Xargo.toml index e10916f..1b1a113 --- a/ci/ci.sh +++ b/examples/secure_db_abstraction-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,34 +15,10 @@ # specific language governing permissions and limitations # under the License. -set -xe - -pushd ../tests - -./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 - -# 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 -fi +[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/secure_db_abstraction-rs/ta/build.rs b/examples/secure_db_abstraction-rs/ta/build.rs new file mode 100644 index 0000000..34ae5fa --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/build.rs @@ -0,0 +1,24 @@ +// 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 ta_config = TaConfig::new_default_with_cargo_env(proto::UUID)?; + optee_utee_build::build(RustEdition::Before2024, ta_config) +} diff --git a/examples/secure_db_abstraction-rs/ta/src/main.rs b/examples/secure_db_abstraction-rs/ta/src/main.rs new file mode 100644 index 0000000..adc61bf --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/src/main.rs @@ -0,0 +1,120 @@ +// 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_main] + +mod secure_db; + +extern crate alloc; + +use alloc::vec; +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}; +use proto::Command; +use secure_db::{SecureStorageClient, Storable}; +use serde::{Deserialize, Serialize}; + +#[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"); +} + +#[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 => match test() { + Ok(_) => { + trace_println!("[+] Test passed"); + Ok(()) + } + Err(e) => { + trace_println!("[-] Test failed: {:?}", e); + Err(Error::new(ErrorKind::Generic)) + } + }, + _ => { + return Err(Error::new(ErrorKind::NotSupported)); + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct ExampleData { + pub id: String, + pub data: Vec<u8>, +} + +// Any structure that implements Storable can be stored in the secure db. +// Any Key type can be used as unique id as long as it implements +// TryFrom<String> + Into<String> + Clone +impl Storable for ExampleData { + type Key = String; + + fn unique_id(&self) -> Self::Key { + self.id.clone() + } +} + +pub fn test() -> anyhow::Result<()> { + // Assume this is the data that we want to store + let example_data = ExampleData { + id: "example_data".to_string(), + data: vec![1, 2, 3, 4, 5], + }; + + // Initialize secure storage db client with a db name + let db_client = SecureStorageClient::open("secure_db")?; + + // Now, we can do common db interactions using the db_client: + // Store data in db using put() + db_client.put(&example_data)?; + // Load data from db using get() + let loaded_example_data = db_client.get::<ExampleData>(&example_data.id)?; + anyhow::ensure!( + loaded_example_data == example_data, + "Loaded example_data is not equal to the original example_data" + ); + // List all entries in db + let entries = db_client.list_entries::<ExampleData>()?; + trace_println!("Entries: {:?}", entries); + // Delete entry from db + db_client.delete_entry::<ExampleData>(&example_data.id)?; + + Ok(()) +} + +include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs")); diff --git a/examples/secure_db_abstraction-rs/ta/src/secure_db/backend.rs b/examples/secure_db_abstraction-rs/ta/src/secure_db/backend.rs new file mode 100644 index 0000000..ab40dcd --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/src/secure_db/backend.rs @@ -0,0 +1,86 @@ +// 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 anyhow::{anyhow, bail, Result}; +use optee_utee::{DataFlag, ObjectStorageConstants, PersistentObject}; + +// Wrapper functions for OP-TEE raw API + +pub fn save_in_secure_storage(obj_id: &[u8], data: &[u8]) -> Result<()> { + let obj_data_flag = DataFlag::ACCESS_READ + | DataFlag::ACCESS_WRITE + | DataFlag::ACCESS_WRITE_META + | DataFlag::OVERWRITE; + + PersistentObject::create( + ObjectStorageConstants::Private, + obj_id, + obj_data_flag, + None, + data, + ) + .map_err(|e| anyhow!("[-] {:?}: failed to create object: {:?}", &obj_id, e))?; + + Ok(()) +} + +pub fn load_from_secure_storage(obj_id: &[u8]) -> Result<Option<Vec<u8>>> { + match PersistentObject::open( + ObjectStorageConstants::Private, + obj_id, + DataFlag::ACCESS_READ | DataFlag::SHARE_READ, + ) { + Err(e) => match e.kind() { + optee_utee::ErrorKind::ItemNotFound => { + return Ok(None); + } + _ => { + bail!("[-] {:?}: failed to open object: {:?}", &obj_id, e); + } + }, + + Ok(object) => { + let obj_info = object.info()?; + let mut buf = vec![0u8; obj_info.data_size() as usize]; + + let read_bytes = object.read(&mut buf)?; + if read_bytes != obj_info.data_size() as u32 { + bail!("[-] {:?}: failed to read data", &obj_id); + } + + return Ok(Some(buf)); + } + } +} + +pub fn delete_from_secure_storage(obj_id: &[u8]) -> Result<()> { + match PersistentObject::open( + ObjectStorageConstants::Private, + &obj_id, + DataFlag::ACCESS_READ | DataFlag::ACCESS_WRITE_META, + ) { + Err(e) => { + bail!("[-] {:?}: failed to open object: {:?}", &obj_id, e); + } + + Ok(mut object) => { + object.close_and_delete()?; + std::mem::forget(object); + return Ok(()); + } + } +} diff --git a/examples/secure_db_abstraction-rs/ta/src/secure_db/client.rs b/examples/secure_db_abstraction-rs/ta/src/secure_db/client.rs new file mode 100644 index 0000000..d6d649e --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/src/secure_db/client.rs @@ -0,0 +1,102 @@ +// 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::secure_db::SecureStorageDb; +use crate::Storable; +use anyhow::{anyhow, Result}; +use std::{ + collections::HashMap, + convert::TryFrom, + hash::Hash, + sync::{Arc, RwLock}, +}; + +// SecureStorageClient is a client to interact with SecureStorageDb. +// Bound operations to Structure that implements Storable trait. + +pub struct SecureStorageClient { + db: Arc<RwLock<SecureStorageDb>>, +} + +impl SecureStorageClient { + pub fn open(db_name: &str) -> Result<Self> { + Ok(Self { + db: Arc::new(RwLock::new(SecureStorageDb::open(db_name.to_string())?)), + }) + } + + pub fn get<V>(&self, key: &V::Key) -> Result<V> + where + V: Storable + serde::de::DeserializeOwned, + V::Key: Into<String> + Clone, + { + let key: String = key.clone().into(); + let storage_key = V::concat_key(&key); + let value = self + .db + .read() + .map_err(|_| anyhow!("Failed to acquire read lock"))? + .get(&storage_key)?; + Ok(bincode::deserialize(&value)?) + } + + pub fn put<V>(&self, value: &V) -> Result<()> + where + V: Storable + serde::Serialize, + { + let key = value.storage_key(); + let value = bincode::serialize(value)?; + self.db + .write() + .map_err(|_| anyhow!("Failed to acquire write lock"))? + .put(key, value)?; + Ok(()) + } + + pub fn delete_entry<V>(&self, key: &V::Key) -> Result<()> + where + V: Storable, + V::Key: Into<String> + Clone, + { + let key: String = key.clone().into(); + let storage_key = V::concat_key(&key); + self.db + .write() + .map_err(|_| anyhow!("Failed to acquire write lock"))? + .delete(&storage_key)?; + Ok(()) + } + + pub fn list_entries<V>(&self) -> Result<HashMap<V::Key, V>> + where + V: Storable + serde::de::DeserializeOwned, + V::Key: TryFrom<String> + Eq + Hash, + { + let map = self + .db + .read() + .map_err(|_| anyhow!("Failed to acquire read lock"))? + .list_entries_with_prefix(V::table_name())?; + let mut result = HashMap::new(); + for (_k, v) in map { + let value: V = bincode::deserialize(&v)?; + let key = value.unique_id(); + result.insert(key, value); + } + Ok(result) + } +} diff --git a/examples/secure_db_abstraction-rs/ta/src/secure_db/db.rs b/examples/secure_db_abstraction-rs/ta/src/secure_db/db.rs new file mode 100644 index 0000000..580601a --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/src/secure_db/db.rs @@ -0,0 +1,113 @@ +// 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::secure_db::{ + delete_from_secure_storage, load_from_secure_storage, save_in_secure_storage, +}; +use anyhow::{bail, ensure, Result}; +use std::collections::{HashMap, HashSet}; + +// SecureStorageDb is a key-value storage for TA to easily store and retrieve data. +// First we store the key list in the secure storage, named as db_name. +// Then we store the each key-value pairs in the secure storage. + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SecureStorageDb { + name: String, + key_list: HashSet<String>, +} + +impl SecureStorageDb { + pub fn open(name: String) -> Result<Self> { + match load_from_secure_storage(name.as_bytes())? { + Some(data) => { + let key_list = bincode::deserialize(&data)?; + Ok(Self { name, key_list }) + } + None => { + // create new db + Ok(Self { + name, + key_list: HashSet::new(), + }) + } + } + } + + pub fn put(&mut self, key: String, value: Vec<u8>) -> Result<()> { + match save_in_secure_storage(key.as_bytes(), &value) { + Ok(_) => { + self.key_list.insert(key); + self.store_key_list()?; + } + Err(e) => { + bail!("[+] SecureStorage::insert(): save error: {}", e); + } + }; + Ok(()) + } + + pub fn get(&self, key: &str) -> Result<Vec<u8>> { + ensure!(self.key_list.contains(key), "Key not found in key list"); + match load_from_secure_storage(key.as_bytes()) { + Ok(Some(data)) => Ok(data), + Ok(None) => bail!("[+] SecureStorage::get(): object not found in db"), + Err(e) => { + bail!("[+] SecureStorage::get(): load error: {}", e); + } + } + } + + pub fn delete(&mut self, key: &str) -> Result<()> { + // ensure key must exist + ensure!(self.key_list.contains(key), "Key not found in key list"); + match delete_from_secure_storage(key.as_bytes()) { + Ok(_) => { + self.key_list.remove(key); + self.store_key_list()?; + } + Err(e) => { + bail!("[+] SecureStorage::delete(): delete error: {}", e); + } + }; + Ok(()) + } + + pub fn clear(&mut self) -> Result<()> { + for key in self.key_list.clone() { + self.delete(&key)?; + } + Ok(()) + } + + pub fn list_entries_with_prefix(&self, prefix: &str) -> Result<HashMap<String, Vec<u8>>> { + let mut result = HashMap::new(); + for key in &self.key_list { + if key.starts_with(prefix) { + let value = self.get(key)?; + result.insert(key.clone(), value); + } + } + Ok(result) + } + + fn store_key_list(&self) -> Result<()> { + let key_list = bincode::serialize(&self.key_list)?; + save_in_secure_storage(self.name.as_bytes(), &key_list)?; + Ok(()) + } +} diff --git a/examples/secure_db_abstraction-rs/ta/src/secure_db/mod.rs b/examples/secure_db_abstraction-rs/ta/src/secure_db/mod.rs new file mode 100644 index 0000000..7b34551 --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/src/secure_db/mod.rs @@ -0,0 +1,25 @@ +// 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. + +mod backend; +pub use backend::*; +mod client; +pub use client::*; +mod db; +pub use db::*; +mod storable; +pub use storable::*; diff --git a/examples/secure_db_abstraction-rs/ta/src/secure_db/storable.rs b/examples/secure_db_abstraction-rs/ta/src/secure_db/storable.rs new file mode 100644 index 0000000..afe063b --- /dev/null +++ b/examples/secure_db_abstraction-rs/ta/src/secure_db/storable.rs @@ -0,0 +1,52 @@ +// 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 std::{convert::TryFrom, hash::Hash}; + +// For each key-value data, the storage key is "$TABLE_NAME#$KEY" +// For example, if we store the Data whose type is Structure named +// ExampleData, with id "123", +// the storage key will be "ExampleData#123" + +const CONCAT: &str = "#"; + +pub trait Storable { + type Key: Into<String> + Clone + TryFrom<String> + Eq + Hash; // Associated type `Key` + + fn unique_id(&self) -> Self::Key; + + fn table_name() -> &'static str { + // keeps the last part of the path + std::any::type_name::<Self>() + .split("::") + .last() + .unwrap_or("WRONG_TABLE_NAME") + } + + fn storage_key(&self) -> String { + format!( + "{}{}{}", + Self::table_name(), + CONCAT, + Into::<String>::into(self.unique_id()) + ) + } + + fn concat_key(key: &str) -> String { + format!("{}{}{}", Self::table_name(), CONCAT, key) + } +} diff --git a/examples/secure_db_abstraction-rs/uuid.txt b/examples/secure_db_abstraction-rs/uuid.txt new file mode 100644 index 0000000..8467254 --- /dev/null +++ b/examples/secure_db_abstraction-rs/uuid.txt @@ -0,0 +1 @@ +e55291e1-521c-4dca-aa24-51e34ab32ad9 \ No newline at end of file diff --git a/ci/ci.sh b/tests/test_secure_db_abstraction.sh similarity index 60% copy from ci/ci.sh copy to tests/test_secure_db_abstraction.sh index e10916f..6bb0637 100755 --- a/ci/ci.sh +++ b/tests/test_secure_db_abstraction.sh @@ -19,32 +19,25 @@ set -xe -pushd ../tests +# Include base script +source setup.sh -./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 +# Copy TA and host binary +cp ../examples/secure_db_abstraction-rs/ta/target/$TARGET_TA/release/*.ta shared +cp ../examples/secure_db_abstraction-rs/host/target/$TARGET_HOST/release/secure_db_abstraction-rs shared -# 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 -fi +# Run script specific commands in QEMU +run_in_qemu "cp *.ta /lib/optee_armtz/\n" +run_in_qemu "./secure_db_abstraction-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 +} + +rm screenlog.0 \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
