api_impl/
props.rs

1// Copyright 2024 The Fuchsia Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Implementation of TEE Internal Core API Specification 4.4 Property Access Functions
6// Functions return specific error codes where applicable and panic on all other errors.
7use std::cmp::min;
8use std::collections::HashMap;
9use std::path::Path;
10use std::sync::atomic::{AtomicU64, Ordering};
11use std::sync::Arc;
12
13use tee_internal::{
14    Error, Identity, PropSetHandle, Result as TeeResult, Uuid, TEE_PROPSET_CURRENT_CLIENT,
15    TEE_PROPSET_CURRENT_TA, TEE_PROPSET_TEE_IMPLEMENTATION,
16};
17use tee_properties::{PropEnumerator, PropSet, PropertyError};
18
19fn write_c_string_to_buffer<'a>(string_val: &str, buffer: &'a mut [u8]) -> &'a str {
20    if buffer.len() == 0 {
21        return std::str::from_utf8(buffer).unwrap();
22    }
23    // buffer.len() - 1 accounts for the NUL byte we need to write at the end.
24    let bytes_to_write = min(buffer.len() - 1, string_val.len());
25    buffer[..bytes_to_write].clone_from_slice(&string_val.as_bytes()[..bytes_to_write]);
26    buffer[bytes_to_write] = 0;
27
28    std::str::from_utf8(&buffer[..bytes_to_write]).unwrap()
29}
30
31// The public surface of this module calls into a PropSets singleton.
32
33// A `PropSetHandle` input into the API can be either:
34// 1. A handle to an enumerator on a property set, OR
35// 2. A pseudo-handle which designates a specific property set: TEE Implementation, Client, or TA.
36// This helper fn aims to easily distinguish between the two for easier processing.
37pub fn is_propset_pseudo_handle(handle: PropSetHandle) -> bool {
38    handle == TEE_PROPSET_TEE_IMPLEMENTATION
39        || handle == TEE_PROPSET_CURRENT_CLIENT
40        || handle == TEE_PROPSET_CURRENT_TA
41}
42
43pub struct GetStringError<'a> {
44    pub error: Error,
45    pub written: &'a str,
46    pub actual_length: usize,
47}
48
49pub struct GetBinaryBlockError<'a> {
50    pub error: Error,
51    pub written: &'a [u8],
52    pub actual_length: usize,
53}
54
55pub struct Properties {
56    prop_sets: PropSets,
57}
58
59impl Properties {
60    pub fn new() -> Self {
61        Self { prop_sets: PropSets::load_prop_sets() }
62    }
63
64    pub fn get_property_as_string<'a>(
65        &self,
66        handle: PropSetHandle,
67        name: &str,
68        buffer: &'a mut [u8],
69    ) -> Result<&'a str, GetStringError<'a>> {
70        let string_val = self
71            .prop_sets
72            .get_string_property(handle, name)
73            .map_err(|error| GetStringError { error, written: "", actual_length: 0 })?;
74        let buffer_len = buffer.len();
75        let string_written = write_c_string_to_buffer(string_val.as_str(), buffer);
76        // We're writing a NUL byte to the buffer which is not captured in string_val.len().
77        if buffer_len < string_val.len() + 1 {
78            return Err(GetStringError {
79                error: Error::ShortBuffer,
80                written: string_written,
81                actual_length: string_val.len(),
82            });
83        }
84        Ok(string_written)
85    }
86
87    pub fn get_property_as_bool(&self, handle: PropSetHandle, name: &str) -> TeeResult<bool> {
88        self.prop_sets.get_bool_property(handle, name)
89    }
90
91    pub fn get_property_as_u32(&self, handle: PropSetHandle, name: &str) -> TeeResult<u32> {
92        self.prop_sets.get_uint32_property(handle, name)
93    }
94
95    pub fn get_property_as_u64(&self, handle: PropSetHandle, name: &str) -> TeeResult<u64> {
96        self.prop_sets.get_uint64_property(handle, name)
97    }
98
99    pub fn get_property_as_binary_block<'a>(
100        &self,
101        handle: PropSetHandle,
102        name: &str,
103        buffer: &'a mut [u8],
104    ) -> Result<&'a [u8], GetBinaryBlockError<'a>> {
105        let bytes = self
106            .prop_sets
107            .get_binary_block_property(handle, name)
108            .map_err(|error| GetBinaryBlockError { error, written: &[], actual_length: 0 })?;
109
110        let buffer_len = buffer.len();
111        let bytes_to_write = min(buffer.len(), bytes.len());
112        let written = &mut buffer[..bytes_to_write];
113        written.clone_from_slice(&bytes[..bytes_to_write]);
114
115        if buffer_len < bytes.len() {
116            return Err(GetBinaryBlockError {
117                error: Error::ShortBuffer,
118                written,
119                actual_length: bytes.len(),
120            });
121        }
122        Ok(written)
123    }
124
125    pub fn get_property_as_uuid(&self, handle: PropSetHandle, name: &str) -> TeeResult<Uuid> {
126        self.prop_sets.get_uuid_property(handle, name)
127    }
128
129    pub fn get_property_as_identity(
130        &self,
131        handle: PropSetHandle,
132        name: &str,
133    ) -> TeeResult<Identity> {
134        self.prop_sets.get_identity_property(handle, name)
135    }
136
137    pub fn allocate_property_enumerator(&mut self) -> PropSetHandle {
138        self.prop_sets.allocate_property_enumerator()
139    }
140
141    pub fn free_property_enumerator(&mut self, handle: PropSetHandle) {
142        self.prop_sets.free_property_enumerator(handle);
143    }
144
145    pub fn start_property_enumerator(&mut self, handle: PropSetHandle, prop_set: PropSetHandle) {
146        self.prop_sets.start_property_enumerator(handle, prop_set);
147    }
148
149    pub fn reset_property_enumerator(&mut self, handle: PropSetHandle) {
150        self.prop_sets.reset_property_enumerator(handle);
151    }
152
153    pub fn get_property_name<'a>(
154        &self,
155        handle: PropSetHandle,
156        buffer: &'a mut [u8],
157    ) -> Result<&'a str, GetStringError<'a>> {
158        let string_val = self
159            .prop_sets
160            .get_property_name(handle)
161            .map_err(|error| GetStringError { error, written: "", actual_length: 0 })?;
162
163        let buffer_len = buffer.len();
164        let string_written = write_c_string_to_buffer(string_val.as_str(), buffer);
165        // We're writing a NUL byte to the buffer which is not captured in string_val.len().
166        if buffer_len < string_val.len() + 1 {
167            return Err(GetStringError {
168                error: Error::ShortBuffer,
169                written: string_written,
170                actual_length: string_val.len(),
171            });
172        }
173        Ok(string_written)
174    }
175
176    pub fn get_next_property(&mut self, handle: PropSetHandle) -> TeeResult<()> {
177        self.prop_sets.get_next_property(handle)
178    }
179}
180
181struct PropSets {
182    tee_implementation_props: Arc<PropSet>,
183    ta_props: Arc<PropSet>,
184    client_props: Arc<PropSet>,
185    // TODO: Scope write locking to this hashmap only.
186    prop_enums: HashMap<u64, PropEnumerator>,
187    enumerator_handle_id_counter: AtomicU64,
188}
189
190impl PropSets {
191    fn load_prop_sets() -> Self {
192        let tee_impl_props_path = Path::new("/properties/system_properties");
193        let tee_impl_props = PropSet::from_config_file(&tee_impl_props_path)
194            .expect("TEE prop set loads successfully");
195
196        let ta_props_path = Path::new("/pkg/data/ta_properties");
197        let ta_props =
198            PropSet::from_config_file(&ta_props_path).expect("TA prop set loads successfully");
199
200        // TODO(b/369916290): Handle this properly.
201        let fake_client_props_str: &str = r#"
202        [
203            {
204                name: "gpd.client.identity",
205                prop_type: "identity",
206                value: "0:9cccff19-13b5-4d4c-aa9e-5c8901a52e2f",
207            },
208        ]
209        "#;
210        let client_props = PropSet::from_config_string(fake_client_props_str)
211            .expect("load fake client props successfully");
212
213        Self {
214            tee_implementation_props: Arc::new(tee_impl_props),
215            ta_props: Arc::new(ta_props),
216            client_props: Arc::new(client_props),
217            prop_enums: HashMap::new(),
218            // Handles cannot be 0, as that value is reserved for TEE_HANDLE_NULL, so we start at 1.
219            // There are reserved values at 0xFFFFFFFD-0xFFFFFFFF; not expecting allocations to reach them.
220            enumerator_handle_id_counter: AtomicU64::new(1),
221        }
222    }
223
224    fn get_prop_set_from_pseudo_handle(
225        &self,
226        maybe_pseudo_handle: PropSetHandle,
227    ) -> Option<Arc<PropSet>> {
228        match maybe_pseudo_handle {
229            TEE_PROPSET_TEE_IMPLEMENTATION => Some(self.tee_implementation_props.clone()),
230            TEE_PROPSET_CURRENT_CLIENT => Some(self.client_props.clone()),
231            TEE_PROPSET_CURRENT_TA => Some(self.ta_props.clone()),
232            _ => None,
233        }
234    }
235
236    // TODO(https://fxbug.dev/376130726): Use &str as return value instead of String.
237    fn get_string_property(
238        &self,
239        handle: PropSetHandle,
240        name: &str,
241    ) -> Result<String, tee_internal::Error> {
242        assert!(!handle.is_null());
243        let string_val = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
244            prop_set
245                .get_string_property(name.to_string())
246                .map_err(|_| tee_internal::Error::ItemNotFound)?
247        } else {
248            self.prop_enums
249                .get(&handle)
250                .expect("enumerator handle must be valid")
251                .get_property_as_string()
252                .map_err(|_| tee_internal::Error::ItemNotFound)?
253        };
254        Ok(string_val)
255    }
256
257    fn get_bool_property(
258        &self,
259        handle: PropSetHandle,
260        name: &str,
261    ) -> Result<bool, tee_internal::Error> {
262        assert!(!handle.is_null());
263        let bool_val = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
264            prop_set
265                .get_boolean_property(name.to_string())
266                .map_err(|_| tee_internal::Error::ItemNotFound)?
267        } else {
268            self.prop_enums
269                .get(&handle)
270                .expect("enumerator handle must be valid")
271                .get_property_as_bool()
272                .map_err(|_| tee_internal::Error::ItemNotFound)?
273        };
274        Ok(bool_val)
275    }
276
277    fn get_uint32_property(
278        &self,
279        handle: PropSetHandle,
280        name: &str,
281    ) -> Result<u32, tee_internal::Error> {
282        assert!(!handle.is_null());
283        let u32_val = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
284            prop_set
285                .get_uint32_property(name.to_string())
286                .map_err(|_| tee_internal::Error::ItemNotFound)?
287        } else {
288            self.prop_enums
289                .get(&handle)
290                .expect("enumerator handle must be valid")
291                .get_property_as_u32()
292                .map_err(|_| tee_internal::Error::ItemNotFound)?
293        };
294        Ok(u32_val)
295    }
296
297    fn get_uint64_property(
298        &self,
299        handle: PropSetHandle,
300        name: &str,
301    ) -> Result<u64, tee_internal::Error> {
302        assert!(!handle.is_null());
303        let u64_val = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
304            prop_set
305                .get_uint64_property(name.to_string())
306                .map_err(|_| tee_internal::Error::ItemNotFound)?
307        } else {
308            self.prop_enums
309                .get(&handle)
310                .expect("enumerator handle must be valid")
311                .get_property_as_u64()
312                .map_err(|_| tee_internal::Error::ItemNotFound)?
313        };
314        Ok(u64_val)
315    }
316
317    // TODO(https://fxbug.dev/376130726): Use &[u8] as return value instead of Vec<u8>.
318    fn get_binary_block_property(
319        &self,
320        handle: PropSetHandle,
321        name: &str,
322    ) -> Result<Vec<u8>, tee_internal::Error> {
323        assert!(!handle.is_null());
324        let bytes = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
325            prop_set.get_binary_block_property(name.to_string()).map_err(
326                |error: PropertyError| match error {
327                    PropertyError::BadFormat { .. } => tee_internal::Error::BadFormat,
328                    PropertyError::ItemNotFound { .. } => return tee_internal::Error::ItemNotFound,
329                    PropertyError::Generic { msg } => {
330                        panic!("Error getting property as binary block: {:?}", msg)
331                    }
332                },
333            )?
334        } else {
335            self.prop_enums
336                .get(&handle)
337                .expect("enumerator handle must be valid")
338                .get_property_as_binary_block()
339                .map_err(|error: PropertyError| match error {
340                    PropertyError::BadFormat { .. } => tee_internal::Error::BadFormat,
341                    PropertyError::ItemNotFound { .. } => return tee_internal::Error::ItemNotFound,
342                    PropertyError::Generic { msg } => {
343                        panic!("Error getting property as binary block: {:?}", msg)
344                    }
345                })?
346        };
347
348        Ok(bytes)
349    }
350
351    fn get_uuid_property(
352        &self,
353        handle: PropSetHandle,
354        name: &str,
355    ) -> Result<Uuid, tee_internal::Error> {
356        assert!(!handle.is_null());
357        let uuid = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
358            prop_set.get_uuid_property(name.to_string()).map_err(|error| match error {
359                PropertyError::BadFormat { .. } => tee_internal::Error::BadFormat,
360                PropertyError::ItemNotFound { .. } => return tee_internal::Error::ItemNotFound,
361                PropertyError::Generic { msg } => {
362                    panic!("Error getting property as uuid: {:?}", msg)
363                }
364            })?
365        } else {
366            self.prop_enums
367                .get(&handle)
368                .expect("enumerator handle must be valid")
369                .get_property_as_uuid()
370                .map_err(|error| match error {
371                    PropertyError::BadFormat { .. } => tee_internal::Error::BadFormat,
372                    PropertyError::ItemNotFound { .. } => return tee_internal::Error::ItemNotFound,
373                    PropertyError::Generic { msg } => {
374                        panic!("Error getting property as uuid: {:?}", msg)
375                    }
376                })?
377        };
378
379        Ok(uuid)
380    }
381
382    fn get_identity_property(
383        &self,
384        handle: PropSetHandle,
385        name: &str,
386    ) -> Result<Identity, tee_internal::Error> {
387        assert!(!handle.is_null());
388        let identity = if let Some(prop_set) = self.get_prop_set_from_pseudo_handle(handle) {
389            prop_set.get_identity_property(name.to_string()).map_err(|error: PropertyError| {
390                match error {
391                    PropertyError::BadFormat { .. } => tee_internal::Error::BadFormat,
392                    PropertyError::ItemNotFound { .. } => return tee_internal::Error::ItemNotFound,
393                    PropertyError::Generic { msg } => {
394                        panic!("Error getting property as identity: {:?}", msg)
395                    }
396                }
397            })?
398        } else {
399            self.prop_enums
400                .get(&handle)
401                .expect("enumerator handle must be valid")
402                .get_property_as_identity()
403                .map_err(|error| match error {
404                    PropertyError::BadFormat { .. } => tee_internal::Error::BadFormat,
405                    PropertyError::ItemNotFound { .. } => return tee_internal::Error::ItemNotFound,
406                    PropertyError::Generic { msg } => {
407                        panic!("Error getting property as identity: {:?}", msg)
408                    }
409                })?
410        };
411
412        Ok(identity)
413    }
414
415    fn new_enumerator_handle(&mut self) -> u64 {
416        assert!(
417            self.enumerator_handle_id_counter.load(Ordering::Relaxed)
418                <= *TEE_PROPSET_TEE_IMPLEMENTATION
419        );
420        self.enumerator_handle_id_counter.fetch_add(1, Ordering::Relaxed)
421    }
422
423    fn allocate_property_enumerator(&mut self) -> PropSetHandle {
424        // TODO(b/369916290): Check for out-of-memory conditions to return TEE_ERROR_OUT_OF_MEMORY.
425        let handle = self.new_enumerator_handle();
426        let _ = self.prop_enums.insert(handle, PropEnumerator::new());
427        PropSetHandle::from_value(handle)
428    }
429
430    fn free_property_enumerator(&mut self, handle: PropSetHandle) {
431        assert!(!handle.is_null());
432        let _ = self.prop_enums.remove_entry(&handle);
433    }
434
435    fn start_property_enumerator(&mut self, handle: PropSetHandle, prop_set: PropSetHandle) {
436        assert!(!handle.is_null());
437        let Some(prop_set) = self.get_prop_set_from_pseudo_handle(prop_set) else {
438            panic!("Invalid TEE_PropSetHandle pseudo-handle provided");
439        };
440
441        let Some(prop_enumerator) = self.prop_enums.get_mut(&handle) else {
442            panic!("Invalid enumerator handle provided");
443        };
444
445        prop_enumerator.start(prop_set);
446    }
447
448    fn reset_property_enumerator(&mut self, handle: PropSetHandle) {
449        assert!(!handle.is_null());
450        let Some(prop_enumerator) = self.prop_enums.get_mut(&handle) else {
451            panic!("Invalid enumerator handle provided");
452        };
453        prop_enumerator.reset();
454    }
455
456    fn get_property_name(&self, handle: PropSetHandle) -> Result<String, tee_internal::Error> {
457        assert!(!handle.is_null());
458        let Some(prop_enumerator) = self.prop_enums.get(&handle) else {
459            panic!("Invalid enumerator handle provided");
460        };
461        prop_enumerator.get_property_name().map_err(|_| tee_internal::Error::ItemNotFound)
462    }
463
464    fn get_next_property(&mut self, handle: PropSetHandle) -> Result<(), tee_internal::Error> {
465        assert!(!handle.is_null());
466        let Some(prop_enumerator) = self.prop_enums.get_mut(&handle) else {
467            panic!("Invalid enumerator handle provided");
468        };
469
470        prop_enumerator.next().map_err(|_| tee_internal::Error::ItemNotFound)
471    }
472}
473
474#[cfg(test)]
475pub mod tests {
476    use super::*;
477
478    // TODO: Re-use test values from //src/tee/lib/tee_properties tests to avoid duplicating these.
479    const TEST_TEE_IMPL_PROPS_STR: &str = r#"[
480        {
481            name: "gpd.tee.test.string",
482            prop_type: "string",
483            value: "asdf",
484        },
485        {
486            name: "gpd.tee.test.bool",
487            prop_type: "boolean",
488            value: "true",
489        },
490        {
491            name: "gpd.tee.test.u32",
492            prop_type: "unsigned_int32",
493            value: "57",
494        },
495        {
496            name: "gpd.tee.test.u64",
497            prop_type: "unsigned_int64",
498            value: "4294967296",
499        },
500        {
501            name: "gpd.tee.test.binaryBlock",
502            prop_type: "binary_block",
503            value: "ZnVjaHNpYQ==",
504        },
505        {
506            name: "gpd.tee.test.uuid",
507            prop_type: "uuid",
508            value: "9cccff19-13b5-4d4c-aa9e-5c8901a52e2f",
509        },
510        {
511            name: "gpd.tee.test.identity",
512            prop_type: "identity",
513            value: "4026531840:9cccff19-13b5-4d4c-aa9e-5c8901a52e2f",
514        },
515    ]
516    "#;
517
518    const TEST_TA_PROPS_STR: &str = r#"[
519        {
520            name: "gpd.ta.appID",
521            prop_type: "uuid",
522            value: "9cccff19-13b5-4d4c-aa9e-5c8901a52e2f",
523        },
524        {
525            name: "gpd.ta.singleInstance",
526            prop_type: "boolean",
527            value: "true",
528        },
529        {
530            name: "gpd.ta.multiSession",
531            prop_type: "boolean",
532            value: "true",
533        },
534        {
535            name: "gpd.ta.instanceKeepAlive",
536            prop_type: "boolean",
537            value: "false",
538        },
539    ]
540    "#;
541
542    const TEST_CLIENT_PROPS_STR: &str = r#"
543    [
544        {
545            name: "gpd.client.identity",
546            prop_type: "identity",
547            value: "0:9cccff19-13b5-4d4c-aa9e-5c8901a52e2f",
548        },
549    ]
550    "#;
551
552    fn init_test_tee_impl_props() -> PropSets {
553        let test_props = PropSet::from_config_string(TEST_TEE_IMPL_PROPS_STR)
554            .expect("load fake tee props successfully");
555        let ta_props = PropSet::from_config_string(TEST_TA_PROPS_STR)
556            .expect("load fake ta props successfully");
557        let client_props = PropSet::from_config_string(TEST_CLIENT_PROPS_STR)
558            .expect("load fake client props successfully");
559
560        PropSets {
561            tee_implementation_props: Arc::new(test_props),
562            ta_props: Arc::new(ta_props),
563            client_props: Arc::new(client_props),
564            prop_enums: HashMap::new(),
565            enumerator_handle_id_counter: AtomicU64::new(1),
566        }
567    }
568
569    #[fuchsia::test]
570    pub fn test_get_string_property() {
571        let prop_sets = init_test_tee_impl_props();
572        let value = prop_sets
573            .get_string_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.string")
574            .unwrap();
575        assert_eq!("asdf".to_string(), value);
576    }
577
578    #[fuchsia::test]
579    pub fn test_get_string_property_not_found() {
580        let prop_sets = init_test_tee_impl_props();
581        let value =
582            prop_sets.get_string_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
583        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
584    }
585
586    #[fuchsia::test]
587    pub fn test_get_bool_property() {
588        let prop_sets = init_test_tee_impl_props();
589        let value = prop_sets
590            .get_bool_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.bool")
591            .unwrap();
592        assert!(value);
593    }
594
595    #[fuchsia::test]
596    pub fn test_get_bool_property_not_found() {
597        let prop_sets = init_test_tee_impl_props();
598        let value = prop_sets.get_bool_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
599        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
600    }
601
602    #[fuchsia::test]
603    pub fn test_get_u32_property() {
604        let prop_sets = init_test_tee_impl_props();
605        let value = prop_sets
606            .get_uint32_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.u32")
607            .unwrap();
608        assert_eq!(57, value);
609    }
610
611    #[fuchsia::test]
612    pub fn test_get_u32_property_not_found() {
613        let prop_sets = init_test_tee_impl_props();
614        let value =
615            prop_sets.get_uint32_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
616        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
617    }
618
619    #[fuchsia::test]
620    pub fn test_get_u64_property() {
621        let prop_sets = init_test_tee_impl_props();
622        let value = prop_sets
623            .get_uint64_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.u64")
624            .unwrap();
625        assert_eq!(4294967296, value);
626    }
627
628    #[fuchsia::test]
629    pub fn test_get_u64_property_not_found() {
630        let prop_sets = init_test_tee_impl_props();
631        let value =
632            prop_sets.get_uint64_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
633        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
634    }
635
636    #[fuchsia::test]
637    pub fn test_get_binary_block_property() {
638        let prop_sets = init_test_tee_impl_props();
639        let value = prop_sets
640            .get_binary_block_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.binaryBlock")
641            .unwrap();
642
643        // base64 string ZnVjaHNpYQ== resolves to hex [66 75 63 68 73 69 61], which is len 7.
644        // This maps to [102, 117, 99, 104, 115, 105, 97] as u8 bytes.
645        let expected_val_as_u8: Vec<u8> = vec![102, 117, 99, 104, 115, 105, 97];
646        assert_eq!(7, value.len());
647        assert_eq!(expected_val_as_u8, value);
648    }
649
650    #[fuchsia::test]
651    pub fn test_get_binary_block_property_not_found() {
652        let prop_sets = init_test_tee_impl_props();
653        let value =
654            prop_sets.get_binary_block_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
655        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
656    }
657
658    #[fuchsia::test]
659    pub fn test_get_binary_block_property_bad_format() {
660        let prop_sets = init_test_tee_impl_props();
661        let value =
662            prop_sets.get_binary_block_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.u32");
663        assert_eq!(tee_internal::Error::BadFormat, value.err().unwrap());
664    }
665
666    #[fuchsia::test]
667    pub fn test_get_uuid_property() {
668        let prop_sets = init_test_tee_impl_props();
669        let value = prop_sets
670            .get_uuid_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.uuid")
671            .unwrap();
672
673        assert_eq!(0x9cccff19, value.time_low);
674        assert_eq!(0x13b5, value.time_mid);
675        assert_eq!(0x4d4c, value.time_hi_and_version);
676        assert_eq!([0xaa, 0x9e, 0x5c, 0x89, 0x01, 0xa5, 0x2e, 0x2f], value.clock_seq_and_node);
677    }
678
679    #[fuchsia::test]
680    pub fn test_get_uuid_property_not_found() {
681        let prop_sets = init_test_tee_impl_props();
682        let value = prop_sets.get_uuid_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
683        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
684    }
685
686    #[fuchsia::test]
687    pub fn test_get_uuid_property_bad_format() {
688        let prop_sets = init_test_tee_impl_props();
689        let value = prop_sets.get_uuid_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.u32");
690        assert_eq!(tee_internal::Error::BadFormat, value.err().unwrap());
691    }
692
693    #[fuchsia::test]
694    pub fn test_get_identity_property() {
695        let prop_sets = init_test_tee_impl_props();
696        let value = prop_sets
697            .get_identity_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.identity")
698            .unwrap();
699
700        // Login::TrustedApp = TEE_LOGIN_TRUSTED_APP = 4026531840, as encoded in TEST_TEE_IMPL_PROPS_STR.
701        assert_eq!(tee_internal::Login::TrustedApp, value.login);
702
703        assert_eq!(0x9cccff19, value.uuid.time_low);
704        assert_eq!(0x13b5, value.uuid.time_mid);
705        assert_eq!(0x4d4c, value.uuid.time_hi_and_version);
706        assert_eq!([0xaa, 0x9e, 0x5c, 0x89, 0x01, 0xa5, 0x2e, 0x2f], value.uuid.clock_seq_and_node);
707    }
708
709    #[fuchsia::test]
710    pub fn test_get_identity_property_not_found() {
711        let prop_sets = init_test_tee_impl_props();
712        let value =
713            prop_sets.get_identity_property(TEE_PROPSET_TEE_IMPLEMENTATION, "name_not_in_set");
714        assert_eq!(tee_internal::Error::ItemNotFound, value.err().unwrap());
715    }
716
717    #[fuchsia::test]
718    pub fn test_get_identity_property_bad_format() {
719        let prop_sets = init_test_tee_impl_props();
720        let value =
721            prop_sets.get_identity_property(TEE_PROPSET_TEE_IMPLEMENTATION, "gpd.tee.test.uuid");
722        assert_eq!(tee_internal::Error::BadFormat, value.err().unwrap());
723    }
724
725    #[fuchsia::test]
726    pub fn test_enumerator_allocate() {
727        let mut prop_sets = init_test_tee_impl_props();
728        assert_eq!(0, prop_sets.prop_enums.len());
729        let handle = prop_sets.allocate_property_enumerator();
730        assert!(prop_sets.prop_enums.get(&handle).is_some());
731    }
732
733    #[fuchsia::test]
734    pub fn test_enumerator_free() {
735        let mut prop_sets = init_test_tee_impl_props();
736        assert_eq!(0, prop_sets.prop_enums.len());
737        let handle = prop_sets.allocate_property_enumerator();
738        assert!(prop_sets.prop_enums.get(&handle).is_some());
739        prop_sets.free_property_enumerator(handle);
740        assert_eq!(0, prop_sets.prop_enums.len());
741    }
742
743    #[fuchsia::test]
744    pub fn test_enumerator_start() {
745        let mut prop_sets = init_test_tee_impl_props();
746        let handle = prop_sets.allocate_property_enumerator();
747        // We can't inspect the internal state of the enumerator, so this tests not panicking.
748        prop_sets.start_property_enumerator(handle, TEE_PROPSET_TEE_IMPLEMENTATION);
749    }
750
751    #[fuchsia::test]
752    #[should_panic]
753    pub fn test_enumerator_start_bad_handle() {
754        let mut prop_sets = init_test_tee_impl_props();
755        let _handle = prop_sets.allocate_property_enumerator();
756        // Handle value of 0 corresponds to TEE_HANDLE_NULL, which is not valid for this API.
757        let bad_handle = PropSetHandle::from_value(0);
758        prop_sets.start_property_enumerator(bad_handle, TEE_PROPSET_TEE_IMPLEMENTATION);
759    }
760
761    #[fuchsia::test]
762    #[should_panic(expected = "Invalid TEE_PropSetHandle pseudo-handle provided")]
763    pub fn test_enumerator_start_bad_prop_set_pseudo_handle() {
764        let mut prop_sets = init_test_tee_impl_props();
765        let handle = prop_sets.allocate_property_enumerator();
766        // Pseudo handle is not one of the 3 reserved values.
767        prop_sets.start_property_enumerator(handle, PropSetHandle::from_value(0));
768    }
769
770    #[fuchsia::test]
771    pub fn test_enumerator_get_name() {
772        let mut prop_sets = init_test_tee_impl_props();
773        let handle = prop_sets.allocate_property_enumerator();
774
775        prop_sets.start_property_enumerator(handle, TEE_PROPSET_TEE_IMPLEMENTATION);
776        let name = prop_sets.get_property_name(handle).unwrap();
777        assert_eq!("gpd.tee.test.string".to_string(), name);
778    }
779
780    #[fuchsia::test]
781    pub fn test_enumerator_next_property() {
782        let mut prop_sets = init_test_tee_impl_props();
783        let handle = prop_sets.allocate_property_enumerator();
784
785        prop_sets.start_property_enumerator(handle, TEE_PROPSET_TEE_IMPLEMENTATION);
786        let name = prop_sets.get_property_name(handle).unwrap();
787        assert_eq!("gpd.tee.test.string".to_string(), name);
788
789        prop_sets.get_next_property(handle).unwrap();
790        let name = prop_sets.get_property_name(handle).unwrap();
791        assert_eq!("gpd.tee.test.bool".to_string(), name);
792    }
793
794    #[fuchsia::test]
795    pub fn test_enumerator_reset() {
796        let mut prop_sets = init_test_tee_impl_props();
797        let handle = prop_sets.allocate_property_enumerator();
798
799        prop_sets.start_property_enumerator(handle, TEE_PROPSET_TEE_IMPLEMENTATION);
800        let name = prop_sets.get_property_name(handle).unwrap();
801        assert_eq!("gpd.tee.test.string".to_string(), name);
802
803        prop_sets.get_next_property(handle).unwrap();
804        let name = prop_sets.get_property_name(handle).unwrap();
805        assert_eq!("gpd.tee.test.bool".to_string(), name);
806
807        prop_sets.reset_property_enumerator(handle);
808        let name = prop_sets.get_property_name(handle).unwrap();
809        assert_eq!("gpd.tee.test.string".to_string(), name);
810    }
811
812    #[fuchsia::test]
813    pub fn test_enumerator_get_name_ta_prop_set() {
814        let mut prop_sets = init_test_tee_impl_props();
815        let handle = prop_sets.allocate_property_enumerator();
816
817        prop_sets.start_property_enumerator(handle, TEE_PROPSET_CURRENT_TA);
818        let name = prop_sets.get_property_name(handle).unwrap();
819        assert_eq!("gpd.ta.appID".to_string(), name);
820    }
821
822    #[fuchsia::test]
823    pub fn test_enumerator_get_name_client_prop_set() {
824        let mut prop_sets = init_test_tee_impl_props();
825        let handle = prop_sets.allocate_property_enumerator();
826
827        prop_sets.start_property_enumerator(handle, TEE_PROPSET_CURRENT_CLIENT);
828        let name = prop_sets.get_property_name(handle).unwrap();
829        assert_eq!("gpd.client.identity".to_string(), name);
830    }
831
832    #[fuchsia::test]
833    pub fn test_enumerator_all_prop_types() {
834        // This test uses the enumerator to run through all the test types in the following order:
835        // string -> bool -> u32 -> u64 -> binary block -> uuid -> identity
836        let mut prop_sets = init_test_tee_impl_props();
837        let handle = prop_sets.allocate_property_enumerator();
838
839        prop_sets.start_property_enumerator(handle, TEE_PROPSET_TEE_IMPLEMENTATION);
840        let string_val = prop_sets.get_string_property(handle, "").unwrap();
841        assert_eq!("asdf".to_string(), string_val);
842
843        prop_sets.get_next_property(handle).unwrap();
844        let bool_val = prop_sets.get_bool_property(handle, "").unwrap();
845        assert!(bool_val);
846
847        prop_sets.get_next_property(handle).unwrap();
848        let u32_val = prop_sets.get_uint32_property(handle, "").unwrap();
849        assert_eq!(57, u32_val);
850
851        prop_sets.get_next_property(handle).unwrap();
852        let u64_val = prop_sets.get_uint64_property(handle, "").unwrap();
853        assert_eq!(4294967296, u64_val);
854
855        prop_sets.get_next_property(handle).unwrap();
856        let binary_block = prop_sets.get_binary_block_property(handle, "").unwrap();
857        let expected_val_as_u8: Vec<u8> = vec![102, 117, 99, 104, 115, 105, 97];
858        assert_eq!(7, binary_block.len());
859        assert_eq!(expected_val_as_u8, binary_block);
860
861        prop_sets.get_next_property(handle).unwrap();
862        let uuid_val = prop_sets.get_uuid_property(handle, "").unwrap();
863        assert_eq!(0x9cccff19, uuid_val.time_low);
864        assert_eq!(0x13b5, uuid_val.time_mid);
865        assert_eq!(0x4d4c, uuid_val.time_hi_and_version);
866        assert_eq!([0xaa, 0x9e, 0x5c, 0x89, 0x01, 0xa5, 0x2e, 0x2f], uuid_val.clock_seq_and_node);
867
868        prop_sets.get_next_property(handle).unwrap();
869        let identity_val = prop_sets.get_identity_property(handle, "").unwrap();
870        assert_eq!(tee_internal::Login::TrustedApp, identity_val.login);
871        assert_eq!(0x9cccff19, identity_val.uuid.time_low);
872        assert_eq!(0x13b5, identity_val.uuid.time_mid);
873        assert_eq!(0x4d4c, identity_val.uuid.time_hi_and_version);
874        assert_eq!(
875            [0xaa, 0x9e, 0x5c, 0x89, 0x01, 0xa5, 0x2e, 0x2f],
876            identity_val.uuid.clock_seq_and_node
877        );
878
879        let res = prop_sets.get_next_property(handle);
880        assert_eq!(tee_internal::Error::ItemNotFound, res.err().unwrap())
881    }
882}