1 // Copyright 2023 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 use crypto_provider::CryptoProvider; 16 use np_adv::{ 17 legacy::{ 18 data_elements::{actions::*, tx_power::TxPowerDataElement, *}, 19 serialize::*, 20 *, 21 }, 22 shared_data::*, 23 }; 24 use std::fmt::{Display, Formatter}; 25 26 /// Wrapper around a V0 advertisement builder which 27 /// is agnostic to the kind of identity used in the advertisement. 28 /// Instead of compile-time errors for non-matching packet flavors, 29 /// this builder instead defers any generated errors to run-time. 30 /// Generic over the Aes algorithm used for any encrypted identities, 31 /// since that is generally specified at compile-time. 32 pub enum BoxedAdvBuilder<C: CryptoProvider> { 33 /// Builder for unencrypted advertisements. 34 Unencrypted(AdvBuilder<UnencryptedEncoder>), 35 /// Builder for LDT-encrypted advertisements. 36 Ldt(AdvBuilder<LdtEncoder<C>>), 37 } 38 39 /// Wrapper around possible errors which occur only during 40 /// advertisement construction from a builder. 41 #[derive(Debug)] 42 pub enum BoxedAdvConstructionError { 43 /// An error originating from a problem with LDT 44 /// encryption of the advertisement contents. 45 Ldt(LdtEncodeError), 46 /// An error from encoding an unencrypted adv 47 Unencrypted(UnencryptedEncodeError), 48 } 49 50 impl<C: CryptoProvider> BoxedAdvBuilder<C> { 51 /// Returns true if this wraps an adv builder which 52 /// leverages some encrypted identity. is_encrypted(&self) -> bool53 pub fn is_encrypted(&self) -> bool { 54 match self { 55 BoxedAdvBuilder::Unencrypted(_) => false, 56 BoxedAdvBuilder::Ldt(_) => true, 57 } 58 } 59 /// Constructs a new BoxedAdvBuilder from the given BoxedIdentity new(identity: BoxedEncoder<C>) -> Self60 pub fn new(identity: BoxedEncoder<C>) -> Self { 61 match identity { 62 BoxedEncoder::Unencrypted(encoder) => { 63 BoxedAdvBuilder::Unencrypted(AdvBuilder::new(encoder)) 64 } 65 BoxedEncoder::LdtEncrypted(encoder) => BoxedAdvBuilder::Ldt(AdvBuilder::new(encoder)), 66 } 67 } 68 /// Attempts to add a data element to the advertisement 69 /// being built by this BoxedAdvBuilder. Returns 70 /// nothing if successful, and a BoxedAddDataElementError 71 /// if something went wrong in the attempt to add the DE. add_data_element( &mut self, data_element: ToBoxedSerializeDataElement, ) -> Result<(), BoxedAddDataElementError>72 pub fn add_data_element( 73 &mut self, 74 data_element: ToBoxedSerializeDataElement, 75 ) -> Result<(), BoxedAddDataElementError> { 76 match self { 77 BoxedAdvBuilder::Unencrypted(public_builder) => { 78 //Verify that we can get the data element as plaintext 79 let maybe_plaintext_data_element = data_element.to_plaintext(); 80 match maybe_plaintext_data_element { 81 Some(plaintext_data_element) => public_builder 82 .add_data_element(plaintext_data_element) 83 .map_err(|e| e.into()), 84 None => Err(BoxedAddDataElementError::FlavorMismatchError), 85 } 86 } 87 BoxedAdvBuilder::Ldt(private_builder) => { 88 //Verify that we can get the data element as ciphertext 89 let maybe_ciphertext_data_element = data_element.to_ciphertext(); 90 match maybe_ciphertext_data_element { 91 Some(ciphertext_data_element) => private_builder 92 .add_data_element(ciphertext_data_element) 93 .map_err(|e| e.into()), 94 None => Err(BoxedAddDataElementError::FlavorMismatchError), 95 } 96 } 97 } 98 } 99 /// Consume this BoxedAdvBuilder and attempt to create 100 /// a serialized advertisement including the added DEs. into_advertisement(self) -> Result<SerializedAdv, BoxedAdvConstructionError>101 pub fn into_advertisement(self) -> Result<SerializedAdv, BoxedAdvConstructionError> { 102 match self { 103 BoxedAdvBuilder::Unencrypted(x) => { 104 x.into_advertisement().map_err(BoxedAdvConstructionError::Unencrypted) 105 } 106 BoxedAdvBuilder::Ldt(x) => { 107 x.into_advertisement().map_err(BoxedAdvConstructionError::Ldt) 108 } 109 } 110 } 111 } 112 113 /// Possible errors generated when trying to add a DE to a 114 /// BoxedAdvBuilder. 115 #[derive(Debug)] 116 pub enum BoxedAddDataElementError { 117 /// Some kind of error in adding the data element which 118 /// is not an issue with trying to add a DE of the incorrect 119 /// packet flavoring. 120 UnderlyingError(AddDataElementError), 121 /// Error when attempting to add a DE which requires one 122 /// of an (encrypted/plaintext) advertisement, but the 123 /// advertisement builder doesn't match this requirement. 124 FlavorMismatchError, 125 } 126 127 impl Display for BoxedAddDataElementError { fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result128 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 129 match self { 130 BoxedAddDataElementError::UnderlyingError(u) => { 131 write!(f, "{0:?}", u) 132 } 133 BoxedAddDataElementError::FlavorMismatchError => { 134 write!(f, "Expected packet flavoring for added DEs does not match the actual packet flavor of the DE") 135 } 136 } 137 } 138 } 139 140 impl std::error::Error for BoxedAddDataElementError {} 141 142 impl From<AddDataElementError> for BoxedAddDataElementError { from(add_data_element_error: AddDataElementError) -> Self143 fn from(add_data_element_error: AddDataElementError) -> Self { 144 BoxedAddDataElementError::UnderlyingError(add_data_element_error) 145 } 146 } 147 148 /// Trait for types which can provide trait object 149 /// references to either plaintext or ciphertext [SerializeDataElement] 150 pub trait ToMultiFlavorSerializeDataElement { 151 /// Gets the associated trait object reference to a `SerializeDataElement<Plaintext>` 152 /// with the same lifetime as a reference to the implementor. to_plaintext(&self) -> DynamicSerializeDataElement<Plaintext>153 fn to_plaintext(&self) -> DynamicSerializeDataElement<Plaintext>; 154 155 /// Gets the associated trait object reference to a `SerializeDataElement<Ciphertext>` 156 /// with the same lifetime as a reference to the implementor. to_ciphertext(&self) -> DynamicSerializeDataElement<Ciphertext>157 fn to_ciphertext(&self) -> DynamicSerializeDataElement<Ciphertext>; 158 } 159 160 /// Blanket impl of [ToMultiFlavorSerializeDataElement] for implementors of [SerializeDataElement] 161 /// for both [Plaintext] and [Ciphertext] packet flavors. 162 impl<T: SerializeDataElement<Plaintext> + SerializeDataElement<Ciphertext>> 163 ToMultiFlavorSerializeDataElement for T 164 { to_plaintext(&self) -> DynamicSerializeDataElement<Plaintext>165 fn to_plaintext(&self) -> DynamicSerializeDataElement<Plaintext> { 166 let reference: &dyn SerializeDataElement<Plaintext> = self; 167 reference.into() 168 } to_ciphertext(&self) -> DynamicSerializeDataElement<Ciphertext>169 fn to_ciphertext(&self) -> DynamicSerializeDataElement<Ciphertext> { 170 let reference: &dyn SerializeDataElement<Ciphertext> = self; 171 reference.into() 172 } 173 } 174 175 /// Boxed trait object version of [SerializeDataElement] which incorporates 176 /// all possible variants on generatable packet flavoring 177 /// (`Plaintext`, `Ciphertext`, or both, as a [ToMultiFlavorSerializeDataElement]) 178 pub enum ToBoxedSerializeDataElement { 179 /// The underlying DE is plaintext-only. 180 Plaintext(Box<dyn SerializeDataElement<Plaintext>>), 181 /// The underlying DE is ciphertext-only. 182 Ciphertext(Box<dyn SerializeDataElement<Ciphertext>>), 183 /// The underlying DE may exist in plaintext or 184 /// in ciphertext advertisements. 185 Both(Box<dyn ToMultiFlavorSerializeDataElement>), 186 } 187 188 impl ToBoxedSerializeDataElement { 189 /// If this [ToBoxedSerializeDataElement] can generate plaintext, returns 190 /// a trait object reference to a `SerializeDataElement<Plaintext>` to_plaintext(&self) -> Option<DynamicSerializeDataElement<Plaintext>>191 pub fn to_plaintext(&self) -> Option<DynamicSerializeDataElement<Plaintext>> { 192 match &self { 193 ToBoxedSerializeDataElement::Plaintext(x) => Some(x.as_ref().into()), 194 ToBoxedSerializeDataElement::Ciphertext(_) => None, 195 ToBoxedSerializeDataElement::Both(x) => Some(x.as_ref().to_plaintext()), 196 } 197 } 198 /// If this [ToBoxedSerializeDataElement] can generate ciphertext, returns 199 /// a trait object reference to a `SerializeDataElement<Ciphertext>` to_ciphertext(&self) -> Option<DynamicSerializeDataElement<Ciphertext>>200 pub fn to_ciphertext(&self) -> Option<DynamicSerializeDataElement<Ciphertext>> { 201 match &self { 202 ToBoxedSerializeDataElement::Plaintext(_) => None, 203 ToBoxedSerializeDataElement::Ciphertext(x) => Some(x.as_ref().into()), 204 ToBoxedSerializeDataElement::Both(x) => Some(x.as_ref().to_ciphertext()), 205 } 206 } 207 } 208 209 /// Boxed version of implementors of the [AdvEncoder] trait. 210 pub enum BoxedEncoder<C: CryptoProvider> { 211 /// Unencrypted encoding. 212 Unencrypted(UnencryptedEncoder), 213 /// An encrypted encoding, using LDT encryption. 214 LdtEncrypted(LdtEncoder<C>), 215 } 216 217 impl<C: CryptoProvider> From<UnencryptedEncoder> for BoxedEncoder<C> { from(encoder: UnencryptedEncoder) -> BoxedEncoder<C>218 fn from(encoder: UnencryptedEncoder) -> BoxedEncoder<C> { 219 BoxedEncoder::Unencrypted(encoder) 220 } 221 } 222 223 impl<C: CryptoProvider> From<LdtEncoder<C>> for BoxedEncoder<C> { from(encoder: LdtEncoder<C>) -> BoxedEncoder<C>224 fn from(encoder: LdtEncoder<C>) -> BoxedEncoder<C> { 225 BoxedEncoder::LdtEncrypted(encoder) 226 } 227 } 228 229 impl From<TxPower> for ToBoxedSerializeDataElement { from(data: TxPower) -> Self230 fn from(data: TxPower) -> Self { 231 ToBoxedSerializeDataElement::Both(Box::new(TxPowerDataElement::from(data))) 232 } 233 } 234 235 impl From<BoxedActionBits> for ToBoxedSerializeDataElement { from(action_bits: BoxedActionBits) -> Self236 fn from(action_bits: BoxedActionBits) -> Self { 237 match action_bits { 238 BoxedActionBits::Plaintext(action_bits) => ToBoxedSerializeDataElement::Plaintext( 239 Box::new(ActionsDataElement::from(action_bits)), 240 ), 241 BoxedActionBits::Ciphertext(action_bits) => ToBoxedSerializeDataElement::Ciphertext( 242 Box::new(ActionsDataElement::from(action_bits)), 243 ), 244 } 245 } 246 } 247 248 /// Boxed version of `ToActionElement` which allows abstracting over 249 /// what packet flavors are supported by a given action. 250 pub enum ToBoxedActionElement { 251 /// Action bit for cross device SDK. 252 CrossDevSdk(bool), 253 /// Action bit for call transfer. 254 CallTransfer(bool), 255 /// Action bit for active unlock. 256 ActiveUnlock(bool), 257 /// Action bit for nearby share. 258 NearbyShare(bool), 259 /// Action bit for instant tethering. 260 InstantTethering(bool), 261 /// Action bit for PhoneHub. 262 PhoneHub(bool), 263 } 264 265 /// [`ActionBits`] with runtime-determined packet flavoring 266 pub enum BoxedActionBits { 267 /// Action-bits for a plaintext advertisement. 268 Plaintext(ActionBits<Plaintext>), 269 /// Action-bits for a ciphertext advertisement. 270 Ciphertext(ActionBits<Ciphertext>), 271 } 272 273 impl From<ActionBits<Plaintext>> for BoxedActionBits { from(bits: ActionBits<Plaintext>) -> Self274 fn from(bits: ActionBits<Plaintext>) -> Self { 275 Self::Plaintext(bits) 276 } 277 } 278 279 impl From<ActionBits<Ciphertext>> for BoxedActionBits { from(bits: ActionBits<Ciphertext>) -> Self280 fn from(bits: ActionBits<Ciphertext>) -> Self { 281 Self::Ciphertext(bits) 282 } 283 } 284 285 /// Error which is raised when the flavor of a [`BoxedActionBits`] 286 /// does not match the supported flavors of a [`ToBoxedActionElement`] 287 /// upon attempting to add the action to the bit-field. 288 #[derive(Debug)] 289 pub struct BoxedSetActionFlavorError; 290 291 impl BoxedActionBits { 292 /// Constructs the [`BoxedActionBits`] variant with the specified packet 293 /// flavor variant, and no bits set. new(packet_flavor: PacketFlavorEnum) -> Self294 pub fn new(packet_flavor: PacketFlavorEnum) -> Self { 295 match packet_flavor { 296 PacketFlavorEnum::Plaintext => BoxedActionBits::Plaintext(ActionBits::default()), 297 PacketFlavorEnum::Ciphertext => BoxedActionBits::Ciphertext(ActionBits::default()), 298 } 299 } 300 301 /// Returns whether a boolean action type is set in these action bits, or `None` 302 /// if the given action type does not represent a boolean (e.g: a context-sync 303 /// sequence number). has_action(&self, action_type: ActionType) -> bool304 pub fn has_action(&self, action_type: ActionType) -> bool { 305 match self { 306 BoxedActionBits::Plaintext(x) => x.has_action(action_type), 307 BoxedActionBits::Ciphertext(x) => x.has_action(action_type), 308 } 309 } 310 set<F: PacketFlavor, E: ActionElementFlavor<F>>( action_bits: &mut ActionBits<F>, to_element: E, ) -> Result<(), BoxedSetActionFlavorError>311 fn set<F: PacketFlavor, E: ActionElementFlavor<F>>( 312 action_bits: &mut ActionBits<F>, 313 to_element: E, 314 ) -> Result<(), BoxedSetActionFlavorError> { 315 action_bits.set_action(to_element); 316 Ok(()) 317 } 318 319 /// Attempts to set the specified [`ToBoxedActionElement`], yielding 320 /// a [`BoxedSetActionFlavorError`] if the flavor of this 321 /// [`BoxedActionBits`] isn't supported by the passed [`ToBoxedActionElement`]. set_action( &mut self, to_element: ToBoxedActionElement, ) -> Result<(), BoxedSetActionFlavorError>322 pub fn set_action( 323 &mut self, 324 to_element: ToBoxedActionElement, 325 ) -> Result<(), BoxedSetActionFlavorError> { 326 match self { 327 BoxedActionBits::Plaintext(action_bits) => match to_element { 328 ToBoxedActionElement::CrossDevSdk(b) => { 329 Self::set(action_bits, CrossDevSdk::from(b)) 330 } 331 ToBoxedActionElement::NearbyShare(b) => { 332 Self::set(action_bits, NearbyShare::from(b)) 333 } 334 ToBoxedActionElement::CallTransfer(_) 335 | ToBoxedActionElement::ActiveUnlock(_) 336 | ToBoxedActionElement::InstantTethering(_) 337 | ToBoxedActionElement::PhoneHub(_) => Err(BoxedSetActionFlavorError), 338 }, 339 BoxedActionBits::Ciphertext(action_bits) => match to_element { 340 ToBoxedActionElement::CrossDevSdk(b) => { 341 Self::set(action_bits, CrossDevSdk::from(b)) 342 } 343 ToBoxedActionElement::CallTransfer(b) => { 344 Self::set(action_bits, CallTransfer::from(b)) 345 } 346 ToBoxedActionElement::ActiveUnlock(b) => { 347 Self::set(action_bits, ActiveUnlock::from(b)) 348 } 349 ToBoxedActionElement::NearbyShare(b) => { 350 Self::set(action_bits, NearbyShare::from(b)) 351 } 352 ToBoxedActionElement::InstantTethering(b) => { 353 Self::set(action_bits, InstantTethering::from(b)) 354 } 355 ToBoxedActionElement::PhoneHub(b) => Self::set(action_bits, PhoneHub::from(b)), 356 }, 357 } 358 } 359 } 360