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::extended::salt::MultiSalt;
17 use np_adv::{extended::data_elements::*, extended::serialize::*, shared_data::*};
18 use sink::Sink;
19 use std::fmt::{Display, Formatter};
20 
21 /// An advertisement builder for V1 advertisements where the
22 /// presence/absence of salt is determined at run-time instead of compile-time.
23 pub struct BoxedAdvBuilder {
24     adv_builder: Box<AdvBuilder>,
25 }
26 
27 impl From<AdvBuilder> for BoxedAdvBuilder {
from(adv_builder: AdvBuilder) -> Self28     fn from(adv_builder: AdvBuilder) -> Self {
29         let adv_builder = Box::new(adv_builder);
30         BoxedAdvBuilder { adv_builder }
31     }
32 }
33 
34 /// Error possibly generated when attempting to add a section to
35 /// a BoxedAdvBuilder.
36 #[derive(Debug)]
37 pub enum BoxedAddSectionError {
38     /// An error which was generated by the underlying AdvBuilder wrapped by the BoxedAdvBuilder
39     Underlying(AddSectionError),
40     /// An error generated when the boxed advertisement builder is unsalted, but the section
41     /// identity requires salt.
42     IdentityRequiresSaltError,
43 }
44 
45 impl Display for BoxedAddSectionError {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result46     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
47         match self {
48             BoxedAddSectionError::Underlying(u) => {
49                 write!(f, "{0}", u)
50             }
51             BoxedAddSectionError::IdentityRequiresSaltError => {
52                 write!(f, "Error generated when the BoxedAdvBuilder is unsalted, but the section identity requires salt.")
53             }
54         }
55     }
56 }
57 
58 impl std::error::Error for BoxedAddSectionError {}
59 
60 impl From<AddSectionError> for BoxedAddSectionError {
from(wrapped: AddSectionError) -> Self61     fn from(wrapped: AddSectionError) -> Self {
62         BoxedAddSectionError::Underlying(wrapped)
63     }
64 }
65 
wrap_owning_section_builder<S: Into<BoxedSectionBuilder<AdvBuilder>>>( maybe_section_builder: Result<S, (AdvBuilder, AddSectionError)>, ) -> Result<BoxedSectionBuilder<AdvBuilder>, (BoxedAdvBuilder, BoxedAddSectionError)>66 fn wrap_owning_section_builder<S: Into<BoxedSectionBuilder<AdvBuilder>>>(
67     maybe_section_builder: Result<S, (AdvBuilder, AddSectionError)>,
68 ) -> Result<BoxedSectionBuilder<AdvBuilder>, (BoxedAdvBuilder, BoxedAddSectionError)> {
69     match maybe_section_builder {
70         Ok(section_builder) => Ok(section_builder.into()),
71         Err((adv_builder, err)) => Err((adv_builder.into(), err.into())),
72     }
73 }
74 
wrap_mut_ref_section_builder<'a, S: Into<BoxedSectionBuilder<&'a mut AdvBuilder>>>( maybe_section_builder: Result<S, AddSectionError>, ) -> Result<BoxedSectionBuilder<&'a mut AdvBuilder>, BoxedAddSectionError>75 fn wrap_mut_ref_section_builder<'a, S: Into<BoxedSectionBuilder<&'a mut AdvBuilder>>>(
76     maybe_section_builder: Result<S, AddSectionError>,
77 ) -> Result<BoxedSectionBuilder<&'a mut AdvBuilder>, BoxedAddSectionError> {
78     let section_builder = maybe_section_builder?;
79     Ok(section_builder.into())
80 }
81 
82 impl BoxedAdvBuilder {
83     /// Gets the current count of sections which have been added
84     /// to this advertisement builder. Does not count currently-
85     /// outstanding section builders.
section_count(&self) -> usize86     pub fn section_count(&self) -> usize {
87         self.adv_builder.section_count()
88     }
89 
90     /// Create a section builder using the given identity,
91     /// taking ownership of this advertisement builder.
92     ///
93     /// Unlike `BoxedAdvBuilder#section_builder`, the returned
94     /// section builder will take ownership of this advertisement
95     /// builder, if the operation was successful. Otherwise,
96     /// this advertisement builder will be returned back to the
97     /// caller unaltered as part of the `Err` arm.
into_section_builder( self, identity: BoxedEncoder, ) -> Result<BoxedSectionBuilder<AdvBuilder>, (Self, BoxedAddSectionError)>98     pub fn into_section_builder(
99         self,
100         identity: BoxedEncoder,
101     ) -> Result<BoxedSectionBuilder<AdvBuilder>, (Self, BoxedAddSectionError)> {
102         match identity {
103             BoxedEncoder::Unencrypted => wrap_owning_section_builder(
104                 self.adv_builder.into_section_builder(UnencryptedSectionEncoder),
105             ),
106             BoxedEncoder::MicEncrypted(ident) => {
107                 wrap_owning_section_builder(self.adv_builder.into_section_builder(ident))
108             }
109             BoxedEncoder::SignedEncrypted(ident) => {
110                 wrap_owning_section_builder(self.adv_builder.into_section_builder(ident))
111             }
112         }
113     }
114 
115     /// Create a section builder using the given encoder.
116     ///
117     /// Returns `Err` if the underlying advertisement builder
118     /// yields an error when attempting to add a new section
119     /// (typically because there's no more available adv space),
120     /// or if the requested identity requires salt, and the
121     /// advertisement builder is salt-less.
section_builder( &mut self, encoder: BoxedEncoder, ) -> Result<BoxedSectionBuilder<&mut AdvBuilder>, BoxedAddSectionError>122     pub fn section_builder(
123         &mut self,
124         encoder: BoxedEncoder,
125     ) -> Result<BoxedSectionBuilder<&mut AdvBuilder>, BoxedAddSectionError> {
126         match encoder {
127             BoxedEncoder::Unencrypted => wrap_mut_ref_section_builder(
128                 self.adv_builder.section_builder(UnencryptedSectionEncoder),
129             ),
130             BoxedEncoder::MicEncrypted(ident) => {
131                 wrap_mut_ref_section_builder(self.adv_builder.section_builder(ident))
132             }
133             BoxedEncoder::SignedEncrypted(ident) => {
134                 wrap_mut_ref_section_builder(self.adv_builder.section_builder(ident))
135             }
136         }
137     }
138 
139     /// Convert the builder into an encoded advertisement.
into_advertisement(self) -> EncodedAdvertisement140     pub fn into_advertisement(self) -> EncodedAdvertisement {
141         self.adv_builder.into_advertisement()
142     }
143 }
144 
145 /// A wrapped v1 encoder whose type is given at run-time.
146 pub enum BoxedEncoder {
147     /// Unencrypted encoder.
148     Unencrypted,
149     /// An encrypted encoder leveraging MIC for verification.
150     MicEncrypted(MicEncryptedSectionEncoder<MultiSalt>),
151     /// An encrypted encoder leveraging signatures for verification.
152     SignedEncrypted(SignedEncryptedSectionEncoder),
153 }
154 
155 /// A `SectionBuilder` whose corresponding Identity
156 /// and salted-ness is given at run-time instead of
157 /// at compile-time.
158 pub enum BoxedSectionBuilder<R: AsMut<AdvBuilder>> {
159     /// A builder for a public section.
160     Public(Box<SectionBuilder<R, UnencryptedSectionEncoder>>),
161     /// A builder for a MIC-verified section.
162     MicEncrypted(Box<SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>>),
163     /// A builder for a signature-verified section.
164     SignedEncrypted(Box<SectionBuilder<R, SignedEncryptedSectionEncoder>>),
165 }
166 
167 impl BoxedSectionBuilder<AdvBuilder> {
168     /// Gets the 0-based index of the section currently under construction
169     /// in the context of the containing advertisement.
section_index(&self) -> usize170     pub fn section_index(&self) -> usize {
171         match self {
172             BoxedSectionBuilder::Public(x) => x.section_index(),
173             BoxedSectionBuilder::MicEncrypted(x) => x.section_index(),
174             BoxedSectionBuilder::SignedEncrypted(x) => x.section_index(),
175         }
176     }
177     /// Add this builder to the advertisement that created it,
178     /// returning the containing advertisement builder.
add_to_advertisement<C: CryptoProvider>(self) -> BoxedAdvBuilder179     pub fn add_to_advertisement<C: CryptoProvider>(self) -> BoxedAdvBuilder {
180         let adv_builder = match self {
181             BoxedSectionBuilder::Public(x) => x.add_to_advertisement::<C>(),
182             BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement::<C>(),
183             BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement::<C>(),
184         };
185         BoxedAdvBuilder::from(adv_builder)
186     }
187 }
188 
189 impl<'a> BoxedSectionBuilder<&'a mut AdvBuilder> {
190     /// Add this builder to the advertisement that created it.
add_to_advertisement<C: CryptoProvider>(self)191     pub fn add_to_advertisement<C: CryptoProvider>(self) {
192         match self {
193             BoxedSectionBuilder::Public(x) => x.add_to_advertisement::<C>(),
194             BoxedSectionBuilder::MicEncrypted(x) => x.add_to_advertisement::<C>(),
195             BoxedSectionBuilder::SignedEncrypted(x) => x.add_to_advertisement::<C>(),
196         }
197     }
198 }
199 
200 impl<R: AsMut<AdvBuilder>> BoxedSectionBuilder<R> {
201     /// Returns true if this wraps a section builder which
202     /// leverages some encrypted identity.
is_encrypted(&self) -> bool203     pub fn is_encrypted(&self) -> bool {
204         match self {
205             BoxedSectionBuilder::Public(_) => false,
206             BoxedSectionBuilder::MicEncrypted(_) => true,
207             BoxedSectionBuilder::SignedEncrypted(_) => true,
208         }
209     }
210     /// Gets the derived salt of the next DE to be added to the section,
211     /// if this section-builder corresponds to an encrypted section that can
212     /// provide per-DE salts.
213     /// Otherwise, returns nothing.
214     ///
215     /// Suitable for scenarios (like FFI) where a closure would be inappropriate
216     /// for DE construction, and interaction with the client is preferred.
next_de_salt(&self) -> Option<DeSalt>217     pub fn next_de_salt(&self) -> Option<DeSalt> {
218         match self {
219             BoxedSectionBuilder::Public(_) => None,
220             BoxedSectionBuilder::MicEncrypted(x) => x.next_de_salt(),
221             BoxedSectionBuilder::SignedEncrypted(x) => Some(x.next_de_salt()),
222         }
223     }
224 
225     /// Add a data element to the section with a closure that returns a `Result`.
226     ///
227     /// The provided `build_de` closure will be invoked with the derived salt for this DE,
228     /// if any salt has been specified for the surrounding advertisement.
add_de_res<E>( &mut self, build_de: impl FnOnce(Option<DeSalt>) -> Result<BoxedWriteDataElement, E>, ) -> Result<(), AddDataElementError<E>>229     pub fn add_de_res<E>(
230         &mut self,
231         build_de: impl FnOnce(Option<DeSalt>) -> Result<BoxedWriteDataElement, E>,
232     ) -> Result<(), AddDataElementError<E>> {
233         match self {
234             BoxedSectionBuilder::Public(x) => {
235                 let build_de_modified = |()| build_de(None);
236                 x.add_de_res(build_de_modified)
237             }
238             BoxedSectionBuilder::MicEncrypted(x) => x.add_de_res(build_de),
239             BoxedSectionBuilder::SignedEncrypted(x) => {
240                 let build_de_modified = |de_salt: DeSalt| build_de(Some(de_salt));
241                 x.add_de_res(build_de_modified)
242             }
243         }
244     }
245     /// Like add_de_res, but for infalliable closures
add_de( &mut self, build_de: impl FnOnce(Option<DeSalt>) -> BoxedWriteDataElement, ) -> Result<(), AddDataElementError<()>>246     pub fn add_de(
247         &mut self,
248         build_de: impl FnOnce(Option<DeSalt>) -> BoxedWriteDataElement,
249     ) -> Result<(), AddDataElementError<()>> {
250         self.add_de_res(|derived_salt| Ok::<_, ()>(build_de(derived_salt)))
251     }
252 }
253 
254 impl<R: AsMut<AdvBuilder>> From<SectionBuilder<R, UnencryptedSectionEncoder>>
255     for BoxedSectionBuilder<R>
256 {
from(section_builder: SectionBuilder<R, UnencryptedSectionEncoder>) -> Self257     fn from(section_builder: SectionBuilder<R, UnencryptedSectionEncoder>) -> Self {
258         BoxedSectionBuilder::Public(Box::new(section_builder))
259     }
260 }
261 
262 impl<R: AsMut<AdvBuilder>> From<SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>>
263     for BoxedSectionBuilder<R>
264 {
from(section_builder: SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>) -> Self265     fn from(section_builder: SectionBuilder<R, MicEncryptedSectionEncoder<MultiSalt>>) -> Self {
266         BoxedSectionBuilder::MicEncrypted(Box::new(section_builder))
267     }
268 }
269 
270 impl<R: AsMut<AdvBuilder>> From<SectionBuilder<R, SignedEncryptedSectionEncoder>>
271     for BoxedSectionBuilder<R>
272 {
from(section_builder: SectionBuilder<R, SignedEncryptedSectionEncoder>) -> Self273     fn from(section_builder: SectionBuilder<R, SignedEncryptedSectionEncoder>) -> Self {
274         BoxedSectionBuilder::SignedEncrypted(Box::new(section_builder))
275     }
276 }
277 
278 /// Mutable trait object reference to a `Sink<u8>`
279 pub struct DynSink<'a> {
280     wrapped: &'a mut dyn Sink<u8>,
281 }
282 
283 impl<'a> Sink<u8> for DynSink<'a> {
try_extend_from_slice(&mut self, items: &[u8]) -> Option<()>284     fn try_extend_from_slice(&mut self, items: &[u8]) -> Option<()> {
285         self.wrapped.try_extend_from_slice(items)
286     }
try_push(&mut self, item: u8) -> Option<()>287     fn try_push(&mut self, item: u8) -> Option<()> {
288         self.wrapped.try_push(item)
289     }
290 }
291 
292 impl<'a> From<&'a mut dyn Sink<u8>> for DynSink<'a> {
from(wrapped: &'a mut dyn Sink<u8>) -> Self293     fn from(wrapped: &'a mut dyn Sink<u8>) -> Self {
294         DynSink { wrapped }
295     }
296 }
297 
298 /// A version of the WriteDataElement trait which is object-safe
299 pub trait DynWriteDataElement {
300     /// Gets the data-element header for the data element
de_header(&self) -> DeHeader301     fn de_header(&self) -> DeHeader;
302     /// Writes the contents of the DE payload to the given DynSink.
303     /// Returns Some(()) if the write operation was successful,
304     /// and None if it was unsuccessful
write_de_contents(&self, sink: DynSink) -> Option<()>305     fn write_de_contents(&self, sink: DynSink) -> Option<()>;
306 }
307 
308 impl<T: WriteDataElement> DynWriteDataElement for T {
de_header(&self) -> DeHeader309     fn de_header(&self) -> DeHeader {
310         WriteDataElement::de_header(self)
311     }
write_de_contents(&self, mut sink: DynSink) -> Option<()>312     fn write_de_contents(&self, mut sink: DynSink) -> Option<()> {
313         WriteDataElement::write_de_contents(self, &mut sink)
314     }
315 }
316 
317 /// Trait object wrapper for DynWriteDataElement instances
318 pub struct BoxedWriteDataElement {
319     wrapped: Box<dyn DynWriteDataElement>,
320 }
321 
322 impl BoxedWriteDataElement {
323     /// Constructs a new `BoxedWriteDataElement` from a `WriteDataElement`
324     /// whose trait impl is valid for a `'static` lifetime.
new<D: WriteDataElement + 'static>(wrapped: D) -> Self325     pub fn new<D: WriteDataElement + 'static>(wrapped: D) -> Self {
326         let wrapped = Box::new(wrapped);
327         Self { wrapped }
328     }
329 }
330 
331 impl WriteDataElement for BoxedWriteDataElement {
de_header(&self) -> DeHeader332     fn de_header(&self) -> DeHeader {
333         self.wrapped.de_header()
334     }
write_de_contents<S: Sink<u8>>(&self, sink: &mut S) -> Option<()>335     fn write_de_contents<S: Sink<u8>>(&self, sink: &mut S) -> Option<()> {
336         let sink: &mut dyn Sink<u8> = sink;
337         let dyn_sink = DynSink::from(sink);
338         self.wrapped.write_de_contents(dyn_sink)
339     }
340 }
341 
342 impl From<TxPower> for BoxedWriteDataElement {
from(tx_power: TxPower) -> Self343     fn from(tx_power: TxPower) -> Self {
344         BoxedWriteDataElement::new::<TxPowerDataElement>(tx_power.into())
345     }
346 }
347 
348 impl From<ContextSyncSeqNum> for BoxedWriteDataElement {
from(context_sync_sequence_num: ContextSyncSeqNum) -> Self349     fn from(context_sync_sequence_num: ContextSyncSeqNum) -> Self {
350         BoxedWriteDataElement::new::<ContextSyncSeqNumDataElement>(context_sync_sequence_num.into())
351     }
352 }
353 
354 impl From<ActionsDataElement> for BoxedWriteDataElement {
from(data: ActionsDataElement) -> Self355     fn from(data: ActionsDataElement) -> Self {
356         BoxedWriteDataElement::new(data)
357     }
358 }
359