1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //! COSE/CBOR helper functions and macros 18 19 /// Macro helper to wrap an AIDL enum and provide conversion implementations for it. It could 20 /// potentially be re-written using a procedural derive macro, but using a macro_rules for now for 21 /// simplicity. 22 /// It provides conversion helpers from u64 and from Ciborium::Integer types and should have the 23 /// following form: 24 /// 25 /// aidl_enum_wrapper! { 26 /// aidl_name: AidlEnumName, 27 /// wrapper_name: NewRustEnumName, 28 /// fields: [AIDL_FIELD_1, AIDL_FIELD_2,...] 29 /// } 30 /// 31 #[macro_export] 32 macro_rules! aidl_enum_wrapper { 33 (aidl_name: $aidl_name:ident, wrapper_name: $wrapper_name:ident, fields: [$($field:ident),+ $(,)*]$(,)?) => { 34 #[derive(Debug, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] 35 pub struct $wrapper_name(pub $aidl_name); 36 37 impl From<$wrapper_name> for $aidl_name { 38 fn from(value: $wrapper_name) -> Self { 39 value.0 40 } 41 } 42 43 impl TryFrom<$aidl_name> for $wrapper_name { 44 type Error = $crate::err::HwCryptoError; 45 46 fn try_from(value: $aidl_name) -> Result<Self, Self::Error> { 47 let val = $wrapper_name(value); 48 val.check_value()?; 49 Ok(val) 50 } 51 } 52 53 impl TryFrom<u64> for $wrapper_name { 54 type Error = $crate::err::HwCryptoError; 55 56 fn try_from(value: u64) -> Result<Self, Self::Error> { 57 let val = match value { 58 $(x if x == $aidl_name::$field.0 as u64 =>Ok($aidl_name::$field)),+, 59 _ => Err($crate::hwcrypto_err!(SERIALIZATION_ERROR, "unsupported enum val {}", value)), 60 }?; 61 Ok($wrapper_name(val)) 62 } 63 } 64 65 impl TryFrom<ciborium::value::Integer> for $wrapper_name { 66 type Error = coset::CoseError; 67 68 fn try_from(value: ciborium::value::Integer) -> Result<Self, Self::Error> { 69 let value: u64 = value.try_into()?; 70 Ok(value.try_into().map_err(|_| coset::CoseError::EncodeFailed)?) 71 } 72 } 73 74 impl From<$wrapper_name> for ciborium::value::Integer { 75 fn from(value: $wrapper_name) -> Self { 76 (value.0.0 as u64).into() 77 } 78 } 79 80 impl $wrapper_name { 81 fn check_value(&self) -> Result<(), $crate::err::HwCryptoError> { 82 // `TryInto` from a u64 will return an error if the enum value 83 // is not one of the declared ones in `fields` 84 let _: $wrapper_name = (self.0.0 as u64).try_into()?; 85 Ok(()) 86 } 87 } 88 } 89 } 90 91 /// Macro to create enums that can easily be used as cose labels for serialization 92 /// It expects the macro definition to have the following form: 93 /// 94 /// cose_enum_gen! { 95 /// enum CoseEnumName { 96 /// CoseEnumField1 = value1, 97 /// CoseEnumField2 = value2, 98 /// } 99 /// } 100 #[macro_export] 101 macro_rules! cose_enum_gen { 102 (enum $name:ident {$($field:ident = $field_val:literal),+ $(,)*}) => { 103 enum $name { 104 $($field = $field_val),+ 105 } 106 107 impl TryFrom<i64> for $name { 108 type Error = $crate::err::HwCryptoError; 109 110 fn try_from(value: i64) -> Result<Self, Self::Error> { 111 match value { 112 $(x if x == $name::$field as i64 => Ok($name::$field)),+, 113 _ => Err($crate::hwcrypto_err!(SERIALIZATION_ERROR, "unsupported COSE enum label val {}", value)), 114 } 115 } 116 } 117 118 impl TryFrom<ciborium::value::Integer> for $name { 119 type Error = coset::CoseError; 120 121 fn try_from(value: ciborium::value::Integer) -> Result<Self, Self::Error> { 122 let value: i64 = value.try_into()?; 123 Ok(value.try_into().map_err(|_| coset::CoseError::EncodeFailed)?) 124 } 125 } 126 } 127 } 128