m4sterchain commented on code in PR #190:
URL: 
https://github.com/apache/incubator-teaclave-trustzone-sdk/pull/190#discussion_r2099135431


##########
optee-utee/src/property.rs:
##########
@@ -0,0 +1,481 @@
+// 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, Result};
+use crate::{Identity, Uuid};
+use alloc::{ffi::CString, string::{String, ToString}, vec::Vec};
+use optee_utee_sys as raw;
+
+/// Represents a TEE property set according to the TEE Internal API.
+/// The property set is a collection of properties that can be
+/// queried from the TEE. The property set is identified by a
+/// handle, which is a pointer to a TEE_PropSetHandle structure.
+pub enum PropertySet {
+    TeeImplementation,
+    CurrentClient,
+    CurrentTa,
+}
+
+impl PropertySet {
+    fn as_raw(&self) -> raw::TEE_PropSetHandle {
+        match self {
+            PropertySet::TeeImplementation => 
raw::TEE_PROPSET_TEE_IMPLEMENTATION,
+            PropertySet::CurrentClient => raw::TEE_PROPSET_CURRENT_CLIENT,
+            PropertySet::CurrentTa => raw::TEE_PROPSET_CURRENT_TA,
+        }
+    }
+}
+
+/// Represents a TEE property value.
+/// The property value can be of different types, such as
+/// string, bool, u32, TEE_UUID, TEE_Identity, etc.
+/// The property value is obtained from the TEE
+/// property set using the TEE_GetPropertyAs* functions.
+pub trait PropertyValue: Sized {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self>;
+}
+
+/// Implements the PropertyValue trait for all return types:
+/// String, Bool, u32, u64, BinaryBlock, UUID, Identity.
+impl PropertyValue for String {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        let mut out_size = 0;
+
+        // The first call is to get the size of the string
+        // So we pass a null pointer and a size of 0
+        let res = unsafe {
+            raw::TEE_GetPropertyAsString(
+                set,
+                key.as_ptr() as *const core::ffi::c_char,
+                core::ptr::null_mut(),
+                &mut out_size,
+            )
+        };
+        match res {
+            raw::TEE_SUCCESS => {
+                if out_size == 0 {
+                    // return an empty string
+                    return Ok(String::new());
+                }
+                else {
+                    return Err(Error::new(ErrorKind::Generic));
+                }
+            }
+            raw::TEE_ERROR_SHORT_BUFFER => {
+                // Resize the string to the actual size
+                let mut out_buffer = vec![0; out_size as usize];
+                let res = unsafe {
+                    raw::TEE_GetPropertyAsString(
+                        set,
+                        key.as_ptr() as *const core::ffi::c_char,
+                        out_buffer.as_mut_ptr() as *mut core::ffi::c_char,
+                        &mut out_size,
+                    )
+                };
+                if res != raw::TEE_SUCCESS {
+                    return Err(Error::from_raw_error(res));
+                }
+
+                Ok(String::from_utf8_lossy(&out_buffer).to_string())
+            }
+            _ => {
+                return Err(Error::from_raw_error(res));
+            }
+        }
+    }
+}
+
+impl PropertyValue for bool {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        let mut b: bool = false;
+
+        let res = unsafe { raw::TEE_GetPropertyAsBool(set, key.as_ptr() as 
*const core::ffi::c_char, &mut b) };
+        if res != 0 {
+            return Err(Error::from_raw_error(res));
+        }
+
+        Ok(b)
+    }
+}
+
+impl PropertyValue for u32 {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        let mut value = 0;
+
+        let res = unsafe { raw::TEE_GetPropertyAsU32(set, key.as_ptr() as 
*const core::ffi::c_char, &mut value) };
+        if res != 0 {
+            return Err(Error::from_raw_error(res));
+        }
+
+        Ok(value)
+    }
+}
+
+impl PropertyValue for u64 {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        let mut value = 0;
+
+        let res = unsafe { raw::TEE_GetPropertyAsU64(set, key.as_ptr() as 
*const core::ffi::c_char, &mut value) };
+        if res != 0 {
+            return Err(Error::from_raw_error(res));
+        }
+
+        Ok(value)
+    }
+}
+
+impl PropertyValue for Vec<u8> {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        let mut out_size = 0;
+
+        // The first call is to get the size of the binary block
+        // So we pass a null pointer and a size of 0
+        let res = unsafe {
+            raw::TEE_GetPropertyAsBinaryBlock(
+                set,
+                key.as_ptr() as *const core::ffi::c_char,
+                core::ptr::null_mut(),
+                &mut out_size,
+            )
+        };
+
+        match res {
+            raw::TEE_SUCCESS => {
+                if out_size == 0 {
+                    // return an empty buffer
+                    return Ok(vec![]);
+                }
+                else {
+                    return Err(Error::new(ErrorKind::Generic));
+                }
+            }
+            raw::TEE_ERROR_SHORT_BUFFER => {
+                let mut buf = vec![0; out_size as usize];
+
+                let res = unsafe {
+                    raw::TEE_GetPropertyAsBinaryBlock(
+                        set,
+                        key.as_ptr() as *const core::ffi::c_char,
+                        buf.as_mut_ptr() as *mut core::ffi::c_void,
+                        &mut out_size,
+                    )
+                };
+                if res != raw::TEE_SUCCESS {
+                    return Err(Error::from_raw_error(res));
+                }
+
+                Ok(buf)
+            }
+            _ => {
+                return Err(Error::from_raw_error(res));
+            }
+        }
+    }
+}
+
+impl PropertyValue for Uuid {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        let mut raw_uuid = raw::TEE_UUID {
+            timeLow: 0,
+            timeMid: 0,
+            timeHiAndVersion: 0,
+            clockSeqAndNode: [0; 8],
+        };
+
+        let res =
+            unsafe { raw::TEE_GetPropertyAsUUID(set, key.as_ptr() as *const 
core::ffi::c_char, &mut raw_uuid) };
+        if res != 0 {
+            return Err(Error::from_raw_error(res));
+        }
+
+        Ok(Uuid::from_raw(raw_uuid))
+    }
+}
+
+impl PropertyValue for Identity {
+    fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
+        // Allocate a buffer for the raw identity
+        let mut raw_id = raw::TEE_Identity {
+            login: 0,
+            uuid: raw::TEE_UUID {
+                timeLow: 0,
+                timeMid: 0,
+                timeHiAndVersion: 0,
+                clockSeqAndNode: [0; 8],
+            },
+        };
+
+        let res = unsafe {
+            raw::TEE_GetPropertyAsIdentity(set, key.as_ptr() as *const 
core::ffi::c_char, &mut raw_id)
+        };
+        if res != 0 {
+            return Err(Error::from_raw_error(res));
+        }
+
+        Ok(Identity::from_raw(raw_id))
+    }
+}
+
+/// Represents a TEE property key.
+/// The property key is used to identify a specific property
+/// within a property set. The property key is a string that
+/// is used to query the property value from the TEE property
+/// set. The property key is defined in the TEE Internal API,
+/// such as "gpd.client.identity" or "gpd.tee.apiversion".
+pub trait PropertyKey {
+    type Output: PropertyValue;
+    fn key(&self) -> CString;
+    fn set(&self) -> PropertySet;
+
+    fn get(&self) -> Result<Self::Output> {
+        Self::Output::from_raw(self.set().as_raw(), self.key())
+    }
+}
+
+/// Macro to define a property key.
+/// This macro generates a struct that implements the
+/// PropertyKey trait.
+macro_rules! define_property_key {
+    (
+        $name:ident,
+        $set:ident,
+        $key:literal,
+        $output:ty
+    ) => {
+        pub struct $name;
+
+        impl PropertyKey for $name {
+            type Output = $output;
+
+            fn key(&self) -> CString {
+                CString::new($key).unwrap_or_default()
+            }
+
+            fn set(&self) -> PropertySet {
+                PropertySet::$set
+            }
+        }
+    };
+}
+
+// Define all existing property keys for the TEE property set.
+// The format is:
+// `define_property_key!(Name, Set, "key", OutputType);`
+// The `Set` is one of the PropertySet it belongs to.
+// The `key` is the raw property key string.
+// The `OutputType` is the type of the property value.
+// 
+// To get the property value, use the `get` method.
+// Example usage:
+// 
+// ``` no_run
+// use optee_utee::{PropertyKey, CurrentTaAppId};
+// 
+// let my_property = CurrentTaAppId.get()?;
+// ```
+define_property_key!(CurrentTaAppId, CurrentTa, "gpd.ta.appID", Uuid);

Review Comment:
   The idea here is to abstract the complexity of fetching properties under 
Property Sets by introducing dedicated types. The main concern is the naming 
convention used for these newly introduced types.
   
   The suggested approach is to map type names directly from the corresponding 
property keys (or their suffixes). For example:
   
   gpd.ta.doesNotCloseHandleOnCorruptObject → 
TaDoesNotCloseHandleOnCorruptObject
   
   gpd.tee.apiversion → TeeApiVersion
   
   gpd.ta.dataSize → TaDataSize
   
   This naming convention allows developers to intuitively derive the type name 
from the GlobalPlatform documentation without needing to inspect the 
implementation details. It significantly improves developer experience and code 
readability.



##########
examples/property-rs/ta/src/main.rs:
##########
@@ -0,0 +1,91 @@
+// 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::{
+    CurrentClientIdentity, CurrentTaDescription, CurrentTaMultiSession, 
PropertyKey,
+    TeeImplementationInternalCoreVersion,
+};
+use optee_utee::{Error, ErrorKind, Parameters, Result};
+use proto::Command;
+
+#[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 get_properties() -> Result<()> {
+    // check caller
+    let client_identity = CurrentClientIdentity.get()?;
+    trace_println!(
+        "[+] TA get caller identity: login: {}, uuid: {}",
+        client_identity.login_type(),
+        client_identity.uuid()
+    );
+
+    // test the other property:
+    let core_version = TeeImplementationInternalCoreVersion.get()?;

Review Comment:
   - As this logic serves as test case. Can we add assertion to the return 
value?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscr...@teaclave.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@teaclave.apache.org
For additional commands, e-mail: dev-h...@teaclave.apache.org

Reply via email to