optee_utee/
property.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::{Error, ErrorKind, Result};
19use crate::{Identity, Uuid};
20use alloc::{ffi::CString, string::String, vec::Vec};
21use optee_utee_sys as raw;
22
23/// Represents a TEE property set according to the TEE Internal API.
24/// The property set is a collection of properties that can be
25/// queried from the TEE. The property set is identified by a
26/// handle, which is a pointer to a TEE_PropSetHandle structure.
27pub enum PropertySet {
28    TeeImplementation,
29    CurrentClient,
30    CurrentTa,
31}
32
33impl PropertySet {
34    fn as_raw(&self) -> raw::TEE_PropSetHandle {
35        match self {
36            PropertySet::TeeImplementation => raw::TEE_PROPSET_TEE_IMPLEMENTATION,
37            PropertySet::CurrentClient => raw::TEE_PROPSET_CURRENT_CLIENT,
38            PropertySet::CurrentTa => raw::TEE_PROPSET_CURRENT_TA,
39        }
40    }
41}
42
43/// Represents a TEE property value.
44/// The property value can be of different types, such as
45/// string, bool, u32, TEE_UUID, TEE_Identity, etc.
46/// The property value is obtained from the TEE
47/// property set using the TEE_GetPropertyAs* functions.
48pub trait PropertyValue: Sized {
49    /// # Safety
50    /// This function is unsafe because it dereferences raw pointers from the TEE API.
51    /// The caller must ensure that the `set` handle is valid and that the TEE environment
52    /// is properly initialized.
53    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self>;
54}
55
56/// Implements the PropertyValue trait for all return types:
57/// String, Bool, u32, u64, BinaryBlock, UUID, Identity.
58impl PropertyValue for String {
59    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
60        let mut out_size = 0;
61
62        // The first call is to get the size of the string
63        // So we pass a null pointer and a size of 0
64        let res = unsafe {
65            raw::TEE_GetPropertyAsString(
66                set,
67                key.as_ptr() as *const _,
68                core::ptr::null_mut(),
69                &mut out_size,
70            )
71        };
72        match res {
73            raw::TEE_SUCCESS => {
74                if out_size == 0 {
75                    // return an empty string
76                    Ok(String::new())
77                } else {
78                    Err(Error::new(ErrorKind::Generic))
79                }
80            }
81            raw::TEE_ERROR_SHORT_BUFFER => {
82                // Resize the string to the actual size
83                let mut out_buffer = vec![0; out_size];
84                let res = unsafe {
85                    raw::TEE_GetPropertyAsString(
86                        set,
87                        key.as_ptr() as *const _,
88                        out_buffer.as_mut_ptr() as *mut _,
89                        &mut out_size,
90                    )
91                };
92                if res != raw::TEE_SUCCESS {
93                    return Err(Error::from_raw_error(res));
94                }
95
96                // Convert the char buffer with null terminator to a C string
97                let c_str = core::ffi::CStr::from_bytes_with_nul(&out_buffer)
98                    .map_err(|_| Error::new(ErrorKind::BadFormat))?;
99                // Convert the C string to a Rust string
100                let result = c_str.to_string_lossy().into_owned();
101
102                Ok(result)
103            }
104            _ => Err(Error::from_raw_error(res)),
105        }
106    }
107}
108
109impl PropertyValue for bool {
110    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
111        let mut b: bool = false;
112
113        let res = unsafe { raw::TEE_GetPropertyAsBool(set, key.as_ptr() as *const _, &mut b) };
114        if res != 0 {
115            return Err(Error::from_raw_error(res));
116        }
117
118        Ok(b)
119    }
120}
121
122impl PropertyValue for u32 {
123    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
124        let mut value = 0;
125
126        let res = unsafe { raw::TEE_GetPropertyAsU32(set, key.as_ptr() as *const _, &mut value) };
127        if res != 0 {
128            return Err(Error::from_raw_error(res));
129        }
130
131        Ok(value)
132    }
133}
134
135impl PropertyValue for u64 {
136    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
137        let mut value = 0;
138
139        let res = unsafe { raw::TEE_GetPropertyAsU64(set, key.as_ptr() as *const _, &mut value) };
140        if res != 0 {
141            return Err(Error::from_raw_error(res));
142        }
143
144        Ok(value)
145    }
146}
147
148impl PropertyValue for Vec<u8> {
149    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
150        let mut out_size = 0;
151
152        // The first call is to get the size of the binary block
153        // So we pass a null pointer and a size of 0
154        let res = unsafe {
155            raw::TEE_GetPropertyAsBinaryBlock(
156                set,
157                key.as_ptr() as *const _,
158                core::ptr::null_mut(),
159                &mut out_size,
160            )
161        };
162
163        match res {
164            raw::TEE_SUCCESS => {
165                if out_size == 0 {
166                    // return an empty buffer
167                    Ok(vec![])
168                } else {
169                    Err(Error::new(ErrorKind::Generic))
170                }
171            }
172            raw::TEE_ERROR_SHORT_BUFFER => {
173                let mut buf = vec![0; out_size];
174
175                let res = unsafe {
176                    raw::TEE_GetPropertyAsBinaryBlock(
177                        set,
178                        key.as_ptr() as *const _,
179                        buf.as_mut_ptr() as *mut _,
180                        &mut out_size,
181                    )
182                };
183                if res != raw::TEE_SUCCESS {
184                    Err(Error::from_raw_error(res))
185                } else {
186                    Ok(buf)
187                }
188            }
189            _ => Err(Error::from_raw_error(res)),
190        }
191    }
192}
193
194impl PropertyValue for Uuid {
195    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
196        let mut raw_uuid = raw::TEE_UUID {
197            timeLow: 0,
198            timeMid: 0,
199            timeHiAndVersion: 0,
200            clockSeqAndNode: [0; 8],
201        };
202
203        let res =
204            unsafe { raw::TEE_GetPropertyAsUUID(set, key.as_ptr() as *const _, &mut raw_uuid) };
205        if res != 0 {
206            return Err(Error::from_raw_error(res));
207        }
208
209        Ok(Uuid::from(raw_uuid))
210    }
211}
212
213impl PropertyValue for Identity {
214    unsafe fn from_raw(set: raw::TEE_PropSetHandle, key: CString) -> Result<Self> {
215        // Allocate a buffer for the raw identity
216        let mut raw_id = raw::TEE_Identity {
217            login: 0,
218            uuid: raw::TEE_UUID {
219                timeLow: 0,
220                timeMid: 0,
221                timeHiAndVersion: 0,
222                clockSeqAndNode: [0; 8],
223            },
224        };
225
226        let res =
227            unsafe { raw::TEE_GetPropertyAsIdentity(set, key.as_ptr() as *const _, &mut raw_id) };
228        if res != 0 {
229            return Err(Error::from_raw_error(res));
230        }
231
232        Ok(Identity::from(raw_id))
233    }
234}
235
236/// Represents a TEE property key.
237/// The property key is used to identify a specific property
238/// within a property set. The property key is a string that
239/// is used to query the property value from the TEE property
240/// set. The property key is defined in the TEE Internal API,
241/// such as "gpd.client.identity" or "gpd.tee.apiversion".
242pub trait PropertyKey {
243    type Output: PropertyValue;
244    fn key(&self) -> CString;
245    fn set(&self) -> PropertySet;
246
247    fn get(&self) -> Result<Self::Output> {
248        unsafe { Self::Output::from_raw(self.set().as_raw(), self.key()) }
249    }
250}
251
252/// Macro to define a property key.
253/// This macro generates a struct that implements the
254/// PropertyKey trait.
255macro_rules! define_property_key {
256    (
257        $name:ident,
258        $set:ident,
259        $key:literal,
260        $output:ty
261    ) => {
262        pub struct $name;
263
264        impl PropertyKey for $name {
265            type Output = $output;
266
267            fn key(&self) -> CString {
268                CString::new($key).unwrap_or_default()
269            }
270
271            fn set(&self) -> PropertySet {
272                PropertySet::$set
273            }
274        }
275    };
276}
277
278// Define all existing property keys for the TEE property set.
279// The format is:
280// `define_property_key!(Name, Set, "key", OutputType);`
281// The `Set` is one of the PropertySet it belongs to.
282// The `key` is the raw property key string.
283// The `OutputType` is the type of the property value.
284//
285// To get the property value, use the `get` method.
286// Example usage:
287//
288// ``` no_run
289// use optee_utee::{PropertyKey, TaAppId};
290//
291// let my_property = TaAppId.get()?;
292// ```
293define_property_key!(TaAppId, CurrentTa, "gpd.ta.appID", Uuid);
294define_property_key!(TaSingleInstance, CurrentTa, "gpd.ta.singleInstance", bool);
295define_property_key!(TaMultiSession, CurrentTa, "gpd.ta.multiSession", bool);
296define_property_key!(
297    TaInstanceKeepAlive,
298    CurrentTa,
299    "gpd.ta.instanceKeepAlive",
300    bool
301);
302define_property_key!(
303    TaInstanceKeepCrashed,
304    CurrentTa,
305    "gpd.ta.instanceKeepCrashed",
306    bool
307);
308define_property_key!(TaDataSize, CurrentTa, "gpd.ta.dataSize", u32);
309define_property_key!(TaStackSize, CurrentTa, "gpd.ta.stackSize", u32);
310define_property_key!(TaVersion, CurrentTa, "gpd.ta.version", String);
311define_property_key!(TaDescription, CurrentTa, "gpd.ta.description", String);
312define_property_key!(TaEndian, CurrentTa, "gpd.ta.endian", u32);
313define_property_key!(
314    TaDoesNotCloseHandleOnCorruptObject,
315    CurrentTa,
316    "gpd.ta.doesNotCloseHandleOnCorruptObject",
317    bool
318);
319define_property_key!(
320    ClientIdentity,
321    CurrentClient,
322    "gpd.client.identity",
323    Identity
324);
325define_property_key!(ClientEndian, CurrentClient, "gpd.client.endian", u32);
326define_property_key!(
327    TeeApiVersion,
328    TeeImplementation,
329    "gpd.tee.apiversion",
330    String
331);
332define_property_key!(
333    TeeInternalCoreVersion,
334    TeeImplementation,
335    "gpd.tee.internalCore.version",
336    u32
337);
338define_property_key!(
339    TeeDescription,
340    TeeImplementation,
341    "gpd.tee.description",
342    String
343);
344define_property_key!(TeeDeviceId, TeeImplementation, "gpd.tee.deviceID", Uuid);
345define_property_key!(
346    TeeSystemTimeProtectionLevel,
347    TeeImplementation,
348    "gpd.tee.systemTime.protectionLevel",
349    u32
350);
351define_property_key!(
352    TeeTaPersistentTimeProtectionLevel,
353    TeeImplementation,
354    "gpd.tee.TAPersistentTime.protectionLevel",
355    u32
356);
357define_property_key!(
358    TeeArithMaxBigIntSize,
359    TeeImplementation,
360    "gpd.tee.arith.maxBigIntSize",
361    u32
362);
363define_property_key!(
364    TeeCryptographyEcc,
365    TeeImplementation,
366    "gpd.tee.cryptography.ecc",
367    bool
368);
369define_property_key!(
370    TeeCryptographyNist,
371    TeeImplementation,
372    "gpd.tee.cryptography.nist",
373    bool
374);
375define_property_key!(
376    TeeCryptographyBsiR,
377    TeeImplementation,
378    "gpd.tee.cryptography.bsi-r",
379    bool
380);
381define_property_key!(
382    TeeCryptographyBsiT,
383    TeeImplementation,
384    "gpd.tee.cryptography.bsi-t",
385    bool
386);
387define_property_key!(
388    TeeCryptographyIetf,
389    TeeImplementation,
390    "gpd.tee.cryptography.ietf",
391    bool
392);
393define_property_key!(
394    TeeCryptographyOcta,
395    TeeImplementation,
396    "gpd.tee.cryptography.octa",
397    bool
398);
399define_property_key!(
400    TeeTrustedStoragePrivateRollbackProtection,
401    TeeImplementation,
402    "gpd.tee.trustedStorage.private.rollbackProtection",
403    u32
404);
405define_property_key!(
406    TeeTrustedStoragePersoRollbackProtection,
407    TeeImplementation,
408    "gpd.tee.trustedStorage.perso.rollbackProtection",
409    u32
410);
411define_property_key!(
412    TeeTrustedStorageProtectedRollbackProtection,
413    TeeImplementation,
414    "gpd.tee.trustedStorage.protected.rollbackProtection",
415    u32
416);
417define_property_key!(
418    TeeTrustedStorageAntiRollbackProtectionLevel,
419    TeeImplementation,
420    "gpd.tee.trustedStorage.antiRollback.protectionLevel",
421    u32
422);
423define_property_key!(
424    TeeTrustedStorageRollbackDetectionProtectionLevel,
425    TeeImplementation,
426    "gpd.tee.trustedStorage.rollbackDetection.protectionLevel",
427    u32
428);
429define_property_key!(
430    TeeTrustedOsImplementationVersion,
431    TeeImplementation,
432    "gpd.tee.trustedos.implementation.version",
433    String
434);
435define_property_key!(
436    TeeTrustedOsImplementationBinaryVersion,
437    TeeImplementation,
438    "gpd.tee.trustedos.implementation.binaryversion",
439    u32
440);
441define_property_key!(
442    TeeTrustedOsManufacturer,
443    TeeImplementation,
444    "gpd.tee.trustedos.manufacturer",
445    String
446);
447define_property_key!(
448    TeeFirmwareImplementationVersion,
449    TeeImplementation,
450    "gpd.tee.firmware.implementation.version",
451    String
452);
453define_property_key!(
454    TeeFirmwareImplementationBinaryVersion,
455    TeeImplementation,
456    "gpd.tee.firmware.implementation.binaryversion",
457    u32
458);
459define_property_key!(
460    TeeFirmwareManufacturer,
461    TeeImplementation,
462    "gpd.tee.firmware.manufacturer",
463    String
464);
465define_property_key!(
466    TeeEventMaxSources,
467    TeeImplementation,
468    "gpd.tee.event.maxSources",
469    u32
470);