optee_utee/object/
transient_object.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 alloc::vec::Vec;
19
20use optee_utee_sys as raw;
21
22use super::{Attribute, GenericObject, ObjectHandle};
23use crate::{Error, Result};
24
25/// Define types of [TransientObject](crate::TransientObject) with
26/// predefined maximum sizes.
27#[repr(u32)]
28pub enum TransientObjectType {
29    /// 128, 192, or 256 bits
30    Aes = 0xA0000010,
31    /// Always 64 bits including the parity bits. This gives an effective key
32    /// size of 56 bits
33    Des = 0xA0000011,
34    /// 128 or 192 bits including the parity bits. This gives effective key
35    /// sizes of 112 or 168 bits
36    Des3 = 0xA0000013,
37    /// Between 64 and 512 bits, multiple of 8 bits
38    HmacMd5 = 0xA0000001,
39    /// Between 80 and 512 bits, multiple of 8 bits
40    HmacSha1 = 0xA0000002,
41    /// Between 112 and 512 bits, multiple of 8 bits
42    HmacSha224 = 0xA0000003,
43    /// Between 192 and 1024 bits, multiple of 8 bits
44    HmacSha256 = 0xA0000004,
45    /// Between 256 and 1024 bits, multiple of 8 bits
46    HmacSha384 = 0xA0000005,
47    /// Between 256 and 1024 bits, multiple of 8 bits
48    HmacSha512 = 0xA0000006,
49    /// The number of bits in the modulus. 256, 512, 768, 1024, 1536 and
50    /// 2048-bit keys SHALL be supported.
51    /// Support for other key sizes including bigger key sizes is
52    /// implementation-dependent. Minimum key size is 256 bits
53    RsaPublicKey = 0xA0000030,
54    /// Same as [RsaPublicKey](crate::TransientObjectType::RsaPublicKey) key
55    /// size.
56    RsaKeypair = 0xA1000030,
57    /// Depends on Algorithm:
58    /// 1) [DsaSha1](crate::AlgorithmId::DsaSha1):
59    ///    Between 512 and 1024 bits, multiple of 64 bits
60    /// 2) [DsaSha224](crate::AlgorithmId::DsaSha224): 2048 bits
61    /// 3) [DsaSha256](crate::AlgorithmId::DsaSha256): 2048 or 3072 bits
62    DsaPublicKey = 0xA0000031,
63    /// Same as [DsaPublicKey](crate::TransientObjectType::DsaPublicKey) key
64    /// size.
65    DsaKeypair = 0xA1000031,
66    /// From 256 to 2048 bits, multiple of 8 bits.
67    DhKeypair = 0xA1000032,
68    /// Between 160 and 521 bits. Conditional: Available only if at least
69    /// one of the ECC the curves defined in Table 6-14 with "generic"
70    /// equal to "Y" is supported.
71    EcdsaPublicKey = 0xA0000041,
72    /// Between 160 and 521 bits. Conditional: Available only if at least
73    /// one of the ECC curves defined in Table 6-14 with "generic" equal to
74    /// "Y" is supported. SHALL be same value as for ECDSA public key size.
75    EcdsaKeypair = 0xA1000041,
76    /// Between 160 and 521 bits. Conditional: Available only if at least
77    /// one of the ECC curves defined in Table 6-14 with "generic" equal to
78    /// "Y" is supported.
79    EcdhPublicKey = 0xA0000042,
80    /// Between 160 and 521 bits. Conditional: Available only if at least
81    /// one of the ECC curves defined in Table 6-14 with "generic" equal to
82    /// "Y" is supported. SHALL be same value as for ECDH public key size
83    EcdhKeypair = 0xA1000042,
84    /// 256 bits. Conditional: Available only if TEE_ECC_CURVE_25519
85    /// defined in Table 6-14 is supported.
86    Ed25519PublicKey = 0xA0000043,
87    /// 256 bits. Conditional: Available only if TEE_ECC_CURVE_25519
88    /// defined in Table 6-14 is supported.
89    Ed25519Keypair = 0xA1000043,
90    /// 256 bits. Conditional: Available only if TEE_ECC_CURVE_25519
91    /// defined in Table 6-14 is supported.
92    X25519PublicKey = 0xA0000044,
93    /// 256 bits. Conditional: Available only if TEE_ECC_CURVE_25519
94    /// defined in Table 6-14 is supported.
95    X25519Keypair = 0xA1000044,
96    /// Multiple of 8 bits, up to 4096 bits. This type is intended for secret
97    /// data that has been derived from a key derivation scheme.
98    GenericSecret = 0xA0000000,
99    /// Object is corrupted.
100    CorruptedObject = 0xA00000BE,
101    /// 0 – All data is in the associated data stream.
102    Data = 0xA00000BF,
103}
104
105/// An object containing attributes but no data stream, which is reclaimed
106/// when closed or when the TA instance is destroyed.
107/// Transient objects are used to hold a cryptographic object (key or key-pair).
108///
109/// Contrast [PersistentObject](crate::PersistentObject).
110#[derive(Debug)]
111pub struct TransientObject(ObjectHandle);
112
113impl TransientObject {
114    /// Create an object with a null handle which points to nothing.
115    //
116    // TODO: This function is only used in examples and should be removed when
117    // TransientObject is fully refactored in the future. Keep it for now and
118    // leave it for future PR.
119    pub fn null_object() -> Self {
120        Self(ObjectHandle::new_null())
121    }
122
123    /// Check if current object is created with null handle.
124    ///
125    /// # See Also
126    ///
127    /// - [Self::null_object](Self::null_object).
128    pub fn is_null_object(&self) -> bool {
129        self.0.is_null()
130    }
131
132    /// Allocate an uninitialized object, i.e. a container for attributes.
133    ///
134    /// As allocated, the object is uninitialized.
135    /// It can be initialized by subsequently importing the object material,
136    /// generating an object, deriving an object, or loading an object from the
137    /// Trusted Storage.
138    ///
139    /// # Parameters
140    ///
141    /// 1) `object_type`: Type of uninitialized object container to be created
142    ///    as defined in [TransientObjectType](crate::TransientObjectType).
143    /// 2) `max_object_size`: Key Size of the object. Valid values depend on the
144    ///    object type and are defined in
145    ///    [TransientObjectType](crate::TransientObjectType).
146    ///
147    /// # Example
148    ///
149    /// ``` rust,no_run
150    /// # use optee_utee::{TransientObject, TransientObjectType};
151    /// # fn main() -> optee_utee::Result<()> {
152    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
153    ///     Ok(object) =>
154    ///     {
155    ///         // ...
156    ///         Ok(())
157    ///     }
158    ///     Err(e) => Err(e),
159    /// }
160    /// # }
161    /// ```
162    ///
163    /// # Errors
164    ///
165    /// 1) `OutOfMemory`: If not enough resources are available to allocate the
166    ///    object handle.
167    /// 2) `NotSupported`: If the key size is not supported or the object type
168    ///    is not supported.
169    ///
170    /// # Panics
171    ///
172    /// 1) If the Implementation detects any error associated with this function
173    ///    which is not explicitly associated with a defined return code for
174    ///    this function.
175    pub fn allocate(object_type: TransientObjectType, max_object_size: usize) -> Result<Self> {
176        let mut handle: raw::TEE_ObjectHandle = core::ptr::null_mut();
177        // Move as much code as possible out of unsafe blocks to maximize Rust’s
178        // safety checks.
179        let handle_mut = &mut handle;
180        match unsafe {
181            raw::TEE_AllocateTransientObject(object_type as u32, max_object_size as u32, handle_mut)
182        } {
183            raw::TEE_SUCCESS => Ok(Self(ObjectHandle::from_raw(handle)?)),
184            code => Err(Error::from_raw_error(code)),
185        }
186    }
187
188    /// Reset the object to its initial state after allocation.
189    /// If the object is currently initialized, the function clears the object
190    /// of all its material.
191    /// The object is then uninitialized again.
192    pub fn reset(&mut self) {
193        unsafe {
194            raw::TEE_ResetTransientObject(*self.as_raw_ref());
195        }
196    }
197
198    /// Populate an uninitialized object container with object attributes passed
199    /// by the TA in the `attrs` parameter.
200    /// When this function is called, the object SHALL be uninitialized.
201    /// If the object is initialized, the caller SHALL first clear it using the
202    /// function reset.
203    /// Note that if the object type is a key-pair, then this function sets both
204    /// the private and public attributes of the keypair.
205    ///
206    /// # Parameters
207    ///
208    /// 1) `attrs`: Array of object attributes.
209    ///
210    /// # Example
211    ///
212    /// ``` rust,no_run
213    /// # use optee_utee::{
214    /// #     TransientObject,
215    /// #     TransientObjectType,
216    /// #     AttributeMemref,
217    /// #     AttributeId,
218    /// # };
219    /// # fn main() -> optee_utee::Result<()> {
220    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
221    ///     Ok(mut object) =>
222    ///     {
223    ///         let attrs = [AttributeMemref::from_ref(AttributeId::SecretValue, &[0u8;1]).into()];
224    ///         object.populate(&attrs);
225    ///         Ok(())
226    ///     }
227    ///     Err(e) => Err(e),
228    /// }
229    /// # }
230    /// ```
231    ///
232    /// # Errors
233    ///
234    /// 1) `BadParameters`: If an incorrect or inconsistent attribute value is
235    ///    detected. In this case, the content of the object SHALL remain
236    ///    uninitialized.
237    ///
238    /// # Panics
239    ///
240    /// 1) If object is not a valid opened object that is transient and
241    ///    uninitialized.
242    /// 2) If some mandatory attribute is missing.
243    /// 3) If an attribute which is not defined for the object’s type is
244    ///    present in attrs.
245    /// 4) If an attribute value is too big to fit within the maximum object
246    ///    size specified when the object was created.
247    /// 5) If the Implementation detects any other error associated with this
248    ///    function which is not explicitly associated with a defined return
249    ///    code for this function.
250    pub fn populate(&mut self, attrs: &[Attribute]) -> Result<()> {
251        let p: Vec<raw::TEE_Attribute> = attrs.iter().map(|p| p.raw()).collect();
252        match unsafe {
253            raw::TEE_PopulateTransientObject(
254                *self.0.as_raw_ref(),
255                p.as_ptr() as _,
256                attrs.len() as u32,
257            )
258        } {
259            raw::TEE_SUCCESS => Ok(()),
260            code => Err(Error::from_raw_error(code)),
261        }
262    }
263
264    /// Populates an uninitialized object handle with the attributes of another
265    /// object handle;
266    /// that is, it populates the attributes of this handle with the attributes
267    /// of src_handle.
268    /// It is most useful in the following situations:
269    /// 1) To extract the public key attributes from a key-pair object.
270    /// 2) To copy the attributes from a
271    ///    [PersistentObject](crate::PersistentObject) into a
272    ///    [TransientObject](crate::TransientObject).
273    ///
274    /// # Parameters
275    ///
276    /// 1) `src_object`: Can be either a
277    ///    [TransientObject](crate::TransientObject) or
278    ///    [PersistentObject](crate::PersistentObject).
279    ///
280    /// # Example
281    ///
282    /// ``` rust,no_run
283    /// # use optee_utee::{TransientObject, TransientObjectType};
284    /// # fn main() -> optee_utee::Result<()> {
285    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
286    ///     Ok(mut object1) =>
287    ///     {
288    ///         match TransientObject::allocate(TransientObjectType::Aes, 256) {
289    ///             Ok(object2) => {
290    ///                 object1.copy_attribute_from(&object2);
291    ///                 Ok(())
292    ///             }
293    ///             Err(e) => Err(e),
294    ///         }
295    ///     }
296    ///     Err(e) => Err(e),
297    /// }
298    /// # }
299    /// ```
300    ///
301    /// # Errors
302    ///
303    /// 1) `CorruptObject`: If the persistent object is corrupt. The object
304    ///    handle SHALL behave based on the
305    ///    `gpd.ta.doesNotCloseHandleOnCorruptObject` property.
306    /// 2) `StorageNotAvailable`: If the persistent object is stored in a
307    ///    storage area which is currently inaccessible.
308    ///
309    /// # Panics
310    ///
311    /// 1) If src_object is not initialized.
312    /// 2) If self is initialized.
313    /// 3) If the type and size of src_object and self are not compatible.
314    /// 4) If the Implementation detects any other error associated with this
315    ///    function which is not explicitly associated with a defined return
316    ///    code for this function.
317    pub fn copy_attribute_from<T: GenericObject>(&mut self, src_object: &T) -> Result<()> {
318        match unsafe {
319            raw::TEE_CopyObjectAttributes1(*self.as_raw_ref(), *src_object.as_raw_ref())
320        } {
321            raw::TEE_SUCCESS => Ok(()),
322            code => Err(Error::from_raw_error(code)),
323        }
324    }
325
326    /// Generates a random key or a key-pair and populates a transient key
327    /// object with the generated key material.
328    ///
329    /// # Parameters
330    ///
331    /// 1) `key_size`: the size of the desired key. It SHALL be less than or
332    ///    equal to the maximum key size specified when the transient object
333    ///    was created.
334    ///
335    /// # Example
336    ///
337    /// ``` rust,no_run
338    /// # use optee_utee::{TransientObject, TransientObjectType};
339    /// # fn main() -> optee_utee::Result<()> {
340    /// match TransientObject::allocate(TransientObjectType::Aes, 128) {
341    ///     Ok(object) =>
342    ///     {
343    ///         object.generate_key(128, &[])?;
344    ///         Ok(())
345    ///     }
346    ///     Err(e) => Err(e),
347    /// }
348    /// # }
349    /// ```
350    ///
351    /// # Errors
352    ///
353    /// 1) `BadParameters`: If an incorrect or inconsistent attribute value is detected. In this
354    ///    case, the content of the object SHALL remain uninitialized.
355    ///
356    /// # Panics
357    ///
358    /// 1) If object is not a valid opened object.
359    /// 2) If some mandatory attribute is missing.
360    /// 3) If an attribute which is not defined for the object’s type is present
361    ///    in attrs.
362    /// 4) If an attribute value is too big to fit within the maximum object
363    ///    size specified when the object was created.
364    /// 5) If the Implementation detects any other error associated with this
365    ///    function which is not explicitly associated with a defined return
366    ///    code for this function.
367    pub fn generate_key(&self, key_size: usize, params: &[Attribute]) -> Result<()> {
368        let p: Vec<raw::TEE_Attribute> = params.iter().map(|p| p.raw()).collect();
369        unsafe {
370            match raw::TEE_GenerateKey(
371                *self.as_raw_ref(),
372                key_size as u32,
373                p.as_slice().as_ptr() as _,
374                p.len() as u32,
375            ) {
376                raw::TEE_SUCCESS => Ok(()),
377                code => Err(Error::from_raw_error(code)),
378            }
379        }
380    }
381}
382
383impl GenericObject for TransientObject {
384    unsafe fn as_raw_ref(&self) -> &optee_utee_sys::TEE_ObjectHandle {
385        unsafe { self.0.as_raw_ref() }
386    }
387}
388
389#[cfg(test)]
390mod tests {
391    use optee_utee_sys::{
392        mock_api,
393        mock_utils::{SERIAL_TEST_LOCK, object::MockHandle},
394    };
395
396    use super::*;
397
398    #[test]
399    // If a transient object is successfully allocated, TEE_CloseObject will be
400    // called when it is dropped.
401    //
402    // According to `GPD_TEE_Internal_Core_API_Specification_v1.3.1`:
403    // At 5.5.5 TEE_CloseObject:
404    // The `TEE_CloseObject` function closes an opened object handle. The object
405    // can be persistent or transient.
406    // For transient objects, `TEE_CloseObject` is equivalent to
407    // `TEE_FreeTransientObject`.
408    fn test_allocate_and_drop() {
409        let _lock = SERIAL_TEST_LOCK.lock().expect("should get the lock");
410
411        let mut raw_handle = MockHandle::new();
412        let handle = raw_handle.as_handle();
413        let fn1 = mock_api::TEE_AllocateTransientObject_context();
414        let fn2 = mock_api::TEE_CloseObject_context();
415
416        fn1.expect().return_once_st(move |_, _, obj| {
417            unsafe { *obj = handle.clone() };
418            raw::TEE_SUCCESS
419        });
420        fn2.expect().return_once_st(move |obj| {
421            debug_assert_eq!(obj, handle.clone());
422        });
423
424        let _obj =
425            TransientObject::allocate(TransientObjectType::Aes, 128).expect("it should be ok");
426    }
427
428    #[test]
429    fn test_allocate_fail() {
430        let _lock = SERIAL_TEST_LOCK.lock().expect("should get the lock");
431
432        static RETURN_CODE: raw::TEE_Result = raw::TEE_ERROR_BAD_STATE;
433        let fn1 = mock_api::TEE_AllocateTransientObject_context();
434
435        fn1.expect().return_const(RETURN_CODE);
436
437        let err =
438            TransientObject::allocate(TransientObjectType::Aes, 128).expect_err("it should be err");
439
440        assert_eq!(err.raw_code(), RETURN_CODE);
441    }
442}