1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! V0 data element deserialization. 16 //! 17 //! This module only deals with the _contents_ of an advertisement, not the advertisement header. 18 19 use core::fmt; 20 use core::marker::PhantomData; 21 22 use crate::legacy::data_elements::tx_power::TxPowerDataElement; 23 use crate::{ 24 credential::v0::V0, 25 legacy::{ 26 data_elements::{ 27 actions, 28 de_type::{DeEncodedLength, DeTypeCode}, 29 DataElementDeserializeError, DeserializeDataElement, LengthMapper, 30 }, 31 Ciphertext, PacketFlavor, 32 }, 33 DeLengthOutOfRange, 34 }; 35 use array_view::ArrayView; 36 use ldt_np_adv::{V0IdentityToken, V0Salt, NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN}; 37 use nom::{bytes, combinator, number, Finish}; 38 39 #[cfg(test)] 40 mod tests; 41 42 pub(crate) mod intermediate; 43 44 use crate::credential::matched::HasIdentityMatch; 45 use crate::legacy::data_elements::actions::ActionsDataElement; 46 use crate::legacy::data_elements::de_type::{DataElementType, DeActualLength}; 47 use crate::legacy::Plaintext; 48 /// exposed because the unencrypted case isn't just for intermediate: no further processing is needed 49 pub use intermediate::UnencryptedAdvContents; 50 51 /// Legacy advertisement parsing errors 52 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 53 pub(crate) enum AdvDeserializeError { 54 /// Header or other structure was invalid 55 InvalidStructure, 56 /// DE contents must not be empty 57 NoDataElements, 58 } 59 60 /// A data element with content length determined and validated per its type's length rules, but 61 /// no further decoding performed. 62 #[derive(Debug, PartialEq, Eq)] 63 pub(in crate::legacy) struct RawDataElement<'d, D: DataElementDeserializer> { 64 pub(in crate::legacy) de_type: D::DeTypeDisambiguator, 65 /// Byte array payload of the data element, without the DE header. 66 pub(in crate::legacy) contents: &'d [u8], 67 } 68 69 impl<'d, D: DataElementDeserializer> RawDataElement<'d, D> { 70 /// Parse an individual DE into its header and contents. parse(input: &'d [u8]) -> nom::IResult<&[u8], Self, DataElementDeserializeError>71 fn parse(input: &'d [u8]) -> nom::IResult<&[u8], Self, DataElementDeserializeError> { 72 let (input, (de_type, actual_len)) = combinator::map_res( 73 combinator::map_opt(number::complete::u8, |de_header| { 74 // header: LLLLTTTT 75 let len = de_header >> 4; 76 let de_type_num = de_header & 0x0F; 77 78 // these can't fail since both inputs are 4 bits and will fit 79 DeTypeCode::try_from(de_type_num).ok().and_then(|de_type| { 80 DeEncodedLength::try_from(len).ok().map(|encoded_len| (de_type, encoded_len)) 81 }) 82 }), 83 |(de_type, encoded_len)| { 84 D::map_encoded_len_to_actual_len(de_type, encoded_len).map_err(|e| match e { 85 LengthError::InvalidLength => { 86 DataElementDeserializeError::InvalidDeLength { de_type, len: encoded_len } 87 } 88 LengthError::InvalidType => { 89 DataElementDeserializeError::InvalidDeType { de_type } 90 } 91 }) 92 }, 93 )(input)?; 94 95 combinator::map(bytes::complete::take(actual_len.as_usize()), move |contents| { 96 RawDataElement { de_type, contents } 97 })(input) 98 } 99 } 100 101 /// An iterator that parses the given data elements iteratively. In environments 102 /// where memory is not severely constrained, it is usually safer to collect 103 /// this into `Result<Vec<DeserializedDataElement>>` so the validity of the whole 104 /// advertisement can be checked before proceeding with further processing. 105 #[derive(Clone, Debug, PartialEq, Eq)] 106 pub struct DeIterator<'d, F> { 107 delegate: GenericDeIterator<'d, F, StandardDeserializer>, 108 } 109 110 impl<'d, F> DeIterator<'d, F> { new(data: &'d [u8]) -> Self111 pub(in crate::legacy) fn new(data: &'d [u8]) -> Self { 112 Self { delegate: GenericDeIterator::new(data) } 113 } 114 } 115 116 impl<'d, F: PacketFlavor> Iterator for DeIterator<'d, F> { 117 type Item = Result<DeserializedDataElement<F>, DataElementDeserializeError>; 118 next(&mut self) -> Option<Self::Item>119 fn next(&mut self) -> Option<Self::Item> { 120 self.delegate.next() 121 } 122 } 123 124 /// The generified innards of [DeIterator] so that it's possible to also use test-only 125 /// deserializers. 126 #[derive(Clone, Debug, PartialEq, Eq)] 127 pub(in crate::legacy) struct GenericDeIterator<'d, F, D> { 128 /// Data to be parsed, containing a sequence of data elements in serialized 129 /// form. 130 data: &'d [u8], 131 _flavor_marker: PhantomData<F>, 132 _deser_marker: PhantomData<D>, 133 } 134 135 impl<'d, F, D> GenericDeIterator<'d, F, D> { new(data: &'d [u8]) -> Self136 fn new(data: &'d [u8]) -> Self { 137 Self { data, _flavor_marker: Default::default(), _deser_marker: Default::default() } 138 } 139 } 140 141 impl<'d, F: PacketFlavor, D: DataElementDeserializer> Iterator for GenericDeIterator<'d, F, D> { 142 type Item = Result<D::Deserialized<F>, DataElementDeserializeError>; 143 next(&mut self) -> Option<Self::Item>144 fn next(&mut self) -> Option<Self::Item> { 145 if self.data.is_empty() { 146 return None; 147 } 148 let parse_result = combinator::cut(combinator::map_res( 149 RawDataElement::parse, 150 D::deserialize_de, 151 ))(self.data); 152 153 match parse_result.finish() { 154 Ok((rem, de)) => { 155 self.data = rem; 156 Some(Ok(de)) 157 } 158 Err(e) => Some(Err(e)), 159 } 160 } 161 } 162 163 /// Errors that can occur decrypting encrypted advertisements. 164 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 165 pub(crate) enum DecryptError { 166 /// Decrypting or verifying the advertisement ciphertext failed 167 DecryptOrVerifyError, 168 } 169 170 /// All v0 DE types with deserialized contents. 171 #[derive(Debug, PartialEq, Eq, Clone)] 172 #[allow(missing_docs)] 173 pub enum DeserializedDataElement<F: PacketFlavor> { 174 Actions(actions::ActionsDataElement<F>), 175 TxPower(TxPowerDataElement), 176 } 177 178 impl<F: PacketFlavor> DeserializedDataElement<F> { 179 /// Returns the DE type as a u8 180 #[cfg(feature = "devtools")] de_type_code(&self) -> u8181 pub fn de_type_code(&self) -> u8 { 182 match self { 183 DeserializedDataElement::Actions(_) => ActionsDataElement::<F>::DE_TYPE_CODE.as_u8(), 184 DeserializedDataElement::TxPower(_) => TxPowerDataElement::DE_TYPE_CODE.as_u8(), 185 } 186 } 187 188 /// Returns the serialized contents of the DE 189 #[cfg(feature = "devtools")] 190 #[allow(clippy::unwrap_used)] de_contents(&self) -> alloc::vec::Vec<u8> where actions::ActionsDataElement<F>: crate::legacy::data_elements::SerializeDataElement<F>,191 pub fn de_contents(&self) -> alloc::vec::Vec<u8> 192 where 193 actions::ActionsDataElement<F>: crate::legacy::data_elements::SerializeDataElement<F>, 194 { 195 use crate::legacy::data_elements::{DataElementSerializationBuffer, SerializeDataElement}; 196 197 let mut sink = DataElementSerializationBuffer::new(super::NP_MAX_ADV_CONTENT_LEN).unwrap(); 198 match self { 199 DeserializedDataElement::Actions(a) => a.serialize_contents(&mut sink), 200 DeserializedDataElement::TxPower(t) => { 201 SerializeDataElement::<F>::serialize_contents(t, &mut sink) 202 } 203 } 204 .unwrap(); 205 sink.into_inner().into_inner().as_slice().to_vec() 206 } 207 } 208 209 /// Contents of an LDT advertisement after decryption. 210 #[derive(Debug, PartialEq, Eq)] 211 pub struct DecryptedAdvContents { 212 identity_token: V0IdentityToken, 213 salt: V0Salt, 214 /// The decrypted data in this advertisement after the identity token. 215 /// This is hopefully a sequence of serialized data elements, but that hasn't been validated 216 /// yet at construction time. 217 data: ArrayView<u8, { NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN }>, 218 } 219 220 impl DecryptedAdvContents { 221 /// Returns a new DecryptedAdvContents with the provided contents. 222 fn new( 223 metadata_key: V0IdentityToken, 224 salt: V0Salt, 225 data: ArrayView<u8, { NP_LDT_MAX_EFFECTIVE_PAYLOAD_LEN }>, 226 ) -> Self { 227 Self { identity_token: metadata_key, salt, data } 228 } 229 230 /// Iterator over the data elements in an advertisement, except for any DEs related to resolving 231 /// the identity or otherwise validating the payload (e.g. any identity DEs like Private 232 /// Identity). data_elements(&self) -> DeIterator<Ciphertext>233 pub fn data_elements(&self) -> DeIterator<Ciphertext> { 234 DeIterator::new(self.data.as_slice()) 235 } 236 237 /// The salt used for decryption of this advertisement. salt(&self) -> V0Salt238 pub fn salt(&self) -> V0Salt { 239 self.salt 240 } 241 242 #[cfg(test)] generic_data_elements<D: DataElementDeserializer>( &self, ) -> GenericDeIterator<Ciphertext, D>243 pub(in crate::legacy) fn generic_data_elements<D: DataElementDeserializer>( 244 &self, 245 ) -> GenericDeIterator<Ciphertext, D> { 246 GenericDeIterator::new(self.data.as_slice()) 247 } 248 } 249 250 impl HasIdentityMatch for DecryptedAdvContents { 251 type Version = V0; identity_token(&self) -> V0IdentityToken252 fn identity_token(&self) -> V0IdentityToken { 253 self.identity_token 254 } 255 } 256 257 /// Overall strategy for deserializing adv contents (once decrypted, if applicable) into data 258 /// elements 259 pub(in crate::legacy) trait DataElementDeserializer: Sized { 260 /// Disambiguates the intermediate form of a DE 261 type DeTypeDisambiguator: Copy; 262 /// The fully deserialized form of a DE 263 type Deserialized<F: PacketFlavor>: fmt::Debug + PartialEq + Eq + Clone; 264 265 /// Map the encoded len found in a DE header to the actual len that should be consumed from the 266 /// advertisement payload map_encoded_len_to_actual_len( de_type: DeTypeCode, encoded_len: DeEncodedLength, ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError>267 fn map_encoded_len_to_actual_len( 268 de_type: DeTypeCode, 269 encoded_len: DeEncodedLength, 270 ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError>; 271 272 /// Deserialize into a [Self::Deserialized] to expose DE-type-specific data representations. 273 /// 274 /// Returns `Err` if the contents of the raw DE can't be deserialized into the corresponding 275 /// DE's representation. deserialize_de<F: PacketFlavor>( raw_de: RawDataElement<Self>, ) -> Result<Self::Deserialized<F>, DataElementDeserializeError>276 fn deserialize_de<F: PacketFlavor>( 277 raw_de: RawDataElement<Self>, 278 ) -> Result<Self::Deserialized<F>, DataElementDeserializeError>; 279 } 280 281 /// Possible errors when mapping DE encoded lengths to actual lengths 282 pub(in crate::legacy) enum LengthError { 283 /// The DE type was known, but the encoded length was invalid 284 InvalidLength, 285 /// The DE type was not unrecognized 286 InvalidType, 287 } 288 289 impl From<DeLengthOutOfRange> for LengthError { from(_value: DeLengthOutOfRange) -> Self290 fn from(_value: DeLengthOutOfRange) -> Self { 291 Self::InvalidLength 292 } 293 } 294 295 /// The default deserialization strategy that maps type codes to [DataElementType], and deserializes 296 /// to [DeserializedDataElement]. 297 #[derive(Debug, PartialEq, Eq, Clone)] 298 struct StandardDeserializer; 299 300 impl DataElementDeserializer for StandardDeserializer { 301 type DeTypeDisambiguator = DataElementType; 302 type Deserialized<F: PacketFlavor> = DeserializedDataElement<F>; 303 map_encoded_len_to_actual_len( de_type: DeTypeCode, encoded_len: DeEncodedLength, ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError>304 fn map_encoded_len_to_actual_len( 305 de_type: DeTypeCode, 306 encoded_len: DeEncodedLength, 307 ) -> Result<(Self::DeTypeDisambiguator, DeActualLength), LengthError> { 308 match de_type { 309 TxPowerDataElement::DE_TYPE_CODE => { 310 <TxPowerDataElement as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(encoded_len) 311 .map_err(|e| e.into()) 312 .map(|l| (DataElementType::TxPower, l)) 313 } 314 ActionsDataElement::<Plaintext>::DE_TYPE_CODE => { 315 <ActionsDataElement<Plaintext> as DeserializeDataElement>::LengthMapper::map_encoded_len_to_actual_len(encoded_len) 316 .map_err(|e| e.into()) 317 .map(|l| (DataElementType::Actions, l)) 318 } 319 _ => Err(LengthError::InvalidType), 320 } 321 } 322 deserialize_de<F: PacketFlavor>( raw_de: RawDataElement<Self>, ) -> Result<Self::Deserialized<F>, DataElementDeserializeError>323 fn deserialize_de<F: PacketFlavor>( 324 raw_de: RawDataElement<Self>, 325 ) -> Result<Self::Deserialized<F>, DataElementDeserializeError> { 326 match raw_de.de_type { 327 DataElementType::Actions => { 328 actions::ActionsDataElement::deserialize::<F>(raw_de.contents) 329 .map(DeserializedDataElement::Actions) 330 } 331 DataElementType::TxPower => TxPowerDataElement::deserialize::<F>(raw_de.contents) 332 .map(DeserializedDataElement::TxPower), 333 } 334 } 335 } 336