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