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 //! Traits defining credential books. These are used in the deserialization path to provide
16 //! the credentials to try for either advertisement version.
17 //! See [`CredentialBookBuilder`] for batteries-included implementations.
18
19 use crate::credential::{
20 source::{CredentialSource, SliceCredentialSource},
21 v0::{V0DiscoveryCryptoMaterial, V0},
22 v1::{
23 MicExtendedSaltSectionIdentityResolutionMaterial,
24 MicExtendedSaltSectionVerificationMaterial, MicShortSaltSectionIdentityResolutionMaterial,
25 MicShortSaltSectionVerificationMaterial, SignedSectionIdentityResolutionMaterial,
26 SignedSectionVerificationMaterial, V1DiscoveryCryptoMaterial, V1,
27 },
28 DiscoveryMetadataCryptoMaterial, MatchableCredential, MatchedCredential, ProtocolVersion,
29 };
30 use core::{borrow::Borrow, marker::PhantomData};
31 use crypto_provider::CryptoProvider;
32
33 #[cfg(any(feature = "alloc", test))]
34 extern crate alloc;
35 #[cfg(any(feature = "alloc", test))]
36 use crate::credential::ReferencedMatchedCredential;
37 #[cfg(any(feature = "alloc", test))]
38 use alloc::vec::Vec;
39
40 /// A collection of credentials to try when attempting to deserialize
41 /// advertisements of either advertisement version which is
42 /// valid for the given lifetime.
43 pub trait CredentialBook<'a>
44 where
45 Self: 'a,
46 {
47 /// The type of the matched credentials for the credentials
48 /// held within this credential-book. May lend from the credential-book.
49 type Matched: MatchedCredential;
50
51 /// The type of V0 crypto-materials yielded by this credential-book.
52 type V0Crypto: V0DiscoveryCryptoMaterial;
53
54 /// The type of V1 crypto-materials yielded by this credential-book.
55 type V1Crypto: V1DiscoveryCryptoMaterial;
56
57 /// The iterator type returned from [`CredentialBook#v0_iter()`],
58 /// which yields `(crypto-material, match_data)` pairs.
59 /// This is a lending iterator which may borrow things from `self`.
60 type V0Iterator: Iterator<Item = (Self::V0Crypto, Self::Matched)>;
61
62 /// The iterator type returned from [`CredentialBook#v1_iter()`],
63 /// which yields `(crypto-material, match_data)` pairs.
64 /// This is a lending iterator which may borrow things from `self`.
65 type V1Iterator: Iterator<Item = (Self::V1Crypto, Self::Matched)>;
66
67 /// Returns an iterator over V0 credentials in this credential book.
v0_iter(&'a self) -> Self::V0Iterator68 fn v0_iter(&'a self) -> Self::V0Iterator;
69
70 /// Returns an iterator over V1 credentials in this credential book.
v1_iter(&'a self) -> Self::V1Iterator71 fn v1_iter(&'a self) -> Self::V1Iterator;
72 }
73
74 /// Convenient marker struct for building credential-books with
75 /// some given match-data type.
76 pub struct CredentialBookBuilder<M: MatchedCredential> {
77 _marker: PhantomData<M>,
78 }
79
80 impl<M: MatchedCredential> CredentialBookBuilder<M> {
81 /// Constructs a [`CachedSliceCredentialBook`] from the given slices of discovery credentials,
82 /// populating its internal buffers of cached credential crypto-materials for up to the
83 /// given number of credentials in each version (up to `N0` credentials cached in V0,
84 /// and up to `N1` credentials cached in `V1`.)
build_cached_slice_book<'a, const N0: usize, const N1: usize, P: CryptoProvider>( v0_creds: &'a [MatchableCredential<V0, M>], v1_creds: &'a [MatchableCredential<V1, M>], ) -> CachedSliceCredentialBook<'a, M, N0, N1>85 pub fn build_cached_slice_book<'a, const N0: usize, const N1: usize, P: CryptoProvider>(
86 v0_creds: &'a [MatchableCredential<V0, M>],
87 v1_creds: &'a [MatchableCredential<V1, M>],
88 ) -> CachedSliceCredentialBook<'a, M, N0, N1> {
89 let v0_source = SliceCredentialSource::new(v0_creds);
90 let v0_cache = init_cache_from_source::<V0, _, N0, P>(&v0_source);
91 let v0_source = CachedCredentialSource::<_, _, N0>::new(v0_source, v0_cache);
92
93 let v1_source = SliceCredentialSource::new(v1_creds);
94 let v1_cache = init_cache_from_source::<V1, _, N1, P>(&v1_source);
95 let v1_source = CachedCredentialSource::<_, _, N1>::new(v1_source, v1_cache);
96
97 CredentialBookFromSources::new(v0_source, v1_source)
98 }
99
100 #[cfg(feature = "alloc")]
101 /// Constructs a new credential-book which owns all of the given credentials,
102 /// and maintains pre-calculated cryptographic information about them
103 /// for speedy advertisement deserialization.
build_precalculated_owned_book<P: CryptoProvider>( v0_iter: impl IntoIterator<Item = MatchableCredential<V0, M>>, v1_iter: impl IntoIterator<Item = MatchableCredential<V1, M>>, ) -> PrecalculatedOwnedCredentialBook<M>104 pub fn build_precalculated_owned_book<P: CryptoProvider>(
105 v0_iter: impl IntoIterator<Item = MatchableCredential<V0, M>>,
106 v1_iter: impl IntoIterator<Item = MatchableCredential<V1, M>>,
107 ) -> PrecalculatedOwnedCredentialBook<M> {
108 let v0_source = PrecalculatedOwnedCredentialSource::<V0, M>::new::<P>(v0_iter);
109 let v1_source = PrecalculatedOwnedCredentialSource::<V1, M>::new::<P>(v1_iter);
110 CredentialBookFromSources::new(v0_source, v1_source)
111 }
112 }
113
114 // Now, for the implementation details. External implementors still need
115 // to be able to reference these types (since the returned types from
116 // [`CredentialBookBuilder`]'s convenience methods are just type-aliases),
117 // and if they want, they can use them as building-blocks to construct
118 // their own [`CredentialBook`]s, but they're largely just scaffolding.
119
120 /// A structure bundling both V0 and V1 credential-sources to define
121 /// a credential-book which owns both of these independent sources.
122 pub struct CredentialBookFromSources<S0, S1> {
123 /// The source for V0 credentials.
124 v0_source: S0,
125 /// The source for V1 credentials.
126 v1_source: S1,
127 }
128
129 impl<'a, S0, S1> CredentialBookFromSources<S0, S1>
130 where
131 Self: 'a,
132 S0: CredentialSource<'a, V0>,
133 S1: CredentialSource<'a, V1, Matched = <S0 as CredentialSource<'a, V0>>::Matched>,
134 <S0 as CredentialSource<'a, V0>>::Crypto: V0DiscoveryCryptoMaterial,
135 <S1 as CredentialSource<'a, V1>>::Crypto: V1DiscoveryCryptoMaterial,
136 {
137 /// Constructs a new [`CredentialBook`] out of the two given
138 /// credential-sources, one for v0 and one for v1. The match-data
139 /// of both credential sources must be the same.
new(v0_source: S0, v1_source: S1) -> Self140 pub fn new(v0_source: S0, v1_source: S1) -> Self {
141 Self { v0_source, v1_source }
142 }
143 }
144
145 impl<'a, S0, S1> CredentialBook<'a> for CredentialBookFromSources<S0, S1>
146 where
147 Self: 'a,
148 S0: CredentialSource<'a, V0>,
149 S1: CredentialSource<'a, V1, Matched = <S0 as CredentialSource<'a, V0>>::Matched>,
150 <S0 as CredentialSource<'a, V0>>::Crypto: V0DiscoveryCryptoMaterial,
151 <S1 as CredentialSource<'a, V1>>::Crypto: V1DiscoveryCryptoMaterial,
152 {
153 type Matched = <S0 as CredentialSource<'a, V0>>::Matched;
154 type V0Crypto = <S0 as CredentialSource<'a, V0>>::Crypto;
155 type V1Crypto = <S1 as CredentialSource<'a, V1>>::Crypto;
156 type V0Iterator = <S0 as CredentialSource<'a, V0>>::Iterator;
157 type V1Iterator = <S1 as CredentialSource<'a, V1>>::Iterator;
158
v0_iter(&'a self) -> Self::V0Iterator159 fn v0_iter(&'a self) -> Self::V0Iterator {
160 self.v0_source.iter()
161 }
v1_iter(&'a self) -> Self::V1Iterator162 fn v1_iter(&'a self) -> Self::V1Iterator {
163 self.v1_source.iter()
164 }
165 }
166
167 /// Type-level function used internally
168 /// by [`CachedCredentialSource`] in order to uniformly
169 /// refer to the "precalculated" crypto-material variants
170 /// for each protocol version.
171 pub(crate) mod precalculated_for_version {
172 use crate::credential::{
173 v0::{PrecalculatedV0DiscoveryCryptoMaterial, V0DiscoveryCredential, V0},
174 v1::{PrecalculatedV1DiscoveryCryptoMaterial, V1DiscoveryCredential, V1},
175 DiscoveryMetadataCryptoMaterial, ProtocolVersion,
176 };
177 use crypto_provider::CryptoProvider;
178
179 pub trait MappingTrait<V: ProtocolVersion> {
180 type Output: DiscoveryMetadataCryptoMaterial<V>;
181 /// Provides pre-calculated crypto-material for the given
182 /// discovery credential.
precalculate<C: CryptoProvider>( discovery_credential: &V::DiscoveryCredential, ) -> Self::Output183 fn precalculate<C: CryptoProvider>(
184 discovery_credential: &V::DiscoveryCredential,
185 ) -> Self::Output;
186 }
187 pub enum Marker {}
188 impl MappingTrait<V0> for Marker {
189 type Output = PrecalculatedV0DiscoveryCryptoMaterial;
precalculate<C: CryptoProvider>( discovery_credential: &V0DiscoveryCredential, ) -> PrecalculatedV0DiscoveryCryptoMaterial190 fn precalculate<C: CryptoProvider>(
191 discovery_credential: &V0DiscoveryCredential,
192 ) -> PrecalculatedV0DiscoveryCryptoMaterial {
193 PrecalculatedV0DiscoveryCryptoMaterial::new::<C>(discovery_credential)
194 }
195 }
196 impl MappingTrait<V1> for Marker {
197 type Output = PrecalculatedV1DiscoveryCryptoMaterial;
precalculate<C: CryptoProvider>( discovery_credential: &V1DiscoveryCredential, ) -> PrecalculatedV1DiscoveryCryptoMaterial198 fn precalculate<C: CryptoProvider>(
199 discovery_credential: &V1DiscoveryCredential,
200 ) -> PrecalculatedV1DiscoveryCryptoMaterial {
201 discovery_credential.to_precalculated::<C>()
202 }
203 }
204 }
205
206 type PrecalculatedCryptoForProtocolVersion<V> =
207 <precalculated_for_version::Marker as precalculated_for_version::MappingTrait<V>>::Output;
208
precalculate_crypto_material<V: ProtocolVersion, C: CryptoProvider>( discovery_credential: &V::DiscoveryCredential, ) -> PrecalculatedCryptoForProtocolVersion<V> where precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,209 fn precalculate_crypto_material<V: ProtocolVersion, C: CryptoProvider>(
210 discovery_credential: &V::DiscoveryCredential,
211 ) -> PrecalculatedCryptoForProtocolVersion<V>
212 where
213 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
214 {
215 <precalculated_for_version::Marker as precalculated_for_version::MappingTrait<V>>::precalculate::<
216 C,
217 >(discovery_credential)
218 }
219
220 /// Iterator type for [`CachedCredentialSource`].
221 pub struct CachedCredentialSourceIterator<'a, V, S, const N: usize>
222 where
223 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
224 V: ProtocolVersion + 'a,
225 S: CredentialSource<'a, V> + 'a,
226 S::Crypto: Borrow<V::DiscoveryCredential>,
227 {
228 /// The current index of the (enumerated) elements that we're iterating over.
229 /// Always counts up at every iteration, and may lie outside of the range
230 /// of the `cache` slice for uncached elements.
231 current_index: usize,
232 /// The cache of pre-calculated crypto-materials from the original source.
233 ///
234 /// The [`self.source_iterator`]'s (up-to) first `N` elements
235 /// must match (up-to) the first `N` elements in the cache,
236 /// and they must both appear in the same order.
237 cache: &'a [Option<PrecalculatedCryptoForProtocolVersion<V>>; N],
238 /// The iterator over the credentials in the original source
239 source_iterator: S::Iterator,
240 }
241
242 impl<'a, V, S, const N: usize> Iterator for CachedCredentialSourceIterator<'a, V, S, N>
243 where
244 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
245 V: ProtocolVersion + 'a,
246 S: CredentialSource<'a, V> + 'a,
247 S::Crypto: Borrow<V::DiscoveryCredential>,
248 {
249 type Item = (PossiblyCachedDiscoveryCryptoMaterial<'a, V>, S::Matched);
next(&mut self) -> Option<Self::Item>250 fn next(&mut self) -> Option<Self::Item> {
251 // Regardless of what we're going to do with the crypto-materials, we still need
252 // to advance the underlying iterator, and bail if it runs out.
253 let (discovery_credential, match_data) = self.source_iterator.next()?;
254 // Check whether/not we have cached crypto-material for the current index
255 let crypto = match self.cache.get(self.current_index) {
256 Some(precalculated_crypto_entry) => {
257 let precalculated_crypto = precalculated_crypto_entry
258 .as_ref()
259 .expect("iterator still going, but cache is not full?");
260 PossiblyCachedDiscoveryCryptoMaterial::from_precalculated(precalculated_crypto)
261 }
262 None => PossiblyCachedDiscoveryCryptoMaterial::from_discovery_credential(
263 discovery_credential.borrow().clone(),
264 ),
265 };
266 // Advance the index forward to point to the next item in the cache.
267 self.current_index += 1;
268 Some((crypto, match_data))
269 }
270 }
271
272 /// A [`CredentialSource`] which augments the externally-provided [`CredentialSource`] with
273 /// a cache containing up to the specified number of pre-calculated credentials.
274 pub struct CachedCredentialSource<V: ProtocolVersion, S, const N: usize>
275 where
276 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
277 {
278 wrapped: S,
279 cache: [Option<PrecalculatedCryptoForProtocolVersion<V>>; N],
280 }
281
282 /// Helper function to construct a cache for a [`CachedCredentialSource`] from
283 /// a reference to some source of discovery-credentials.
284 ///
285 /// This function needs to be kept separate from [`CachedCredentialSource#new`]
286 /// to get around otherwise-tricky lifetime issues around ephemerally-borrowing
287 /// from a moved object within the body of a function.
init_cache_from_source<'a, V: ProtocolVersion, S, const N: usize, P: CryptoProvider>( original: &'a S, ) -> [Option<PrecalculatedCryptoForProtocolVersion<V>>; N] where S: CredentialSource<'a, V> + 'a, S::Crypto: Borrow<V::DiscoveryCredential>, precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,288 pub(crate) fn init_cache_from_source<'a, V: ProtocolVersion, S, const N: usize, P: CryptoProvider>(
289 original: &'a S,
290 ) -> [Option<PrecalculatedCryptoForProtocolVersion<V>>; N]
291 where
292 S: CredentialSource<'a, V> + 'a,
293 S::Crypto: Borrow<V::DiscoveryCredential>,
294 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
295 {
296 let mut cache = [0u8; N].map(|_| None);
297 for (cache_entry, source_credential) in cache.iter_mut().zip(original.iter()) {
298 let (discovery_credential, _) = source_credential;
299 let precalculated_crypto_material =
300 precalculate_crypto_material::<V, P>(discovery_credential.borrow());
301 let _ = cache_entry.insert(precalculated_crypto_material);
302 }
303 cache
304 }
305
306 impl<'a, V: ProtocolVersion, S, const N: usize> CachedCredentialSource<V, S, N>
307 where
308 S: CredentialSource<'a, V> + 'a,
309 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
310 {
311 /// Constructs a [`CachedCredentialSource`] from the given [`CredentialSource`]
312 /// and the given (initial) cache contents, as constructed via the
313 /// [`init_cache_from_source`] helper function.
new( wrapped: S, cache: [Option<PrecalculatedCryptoForProtocolVersion<V>>; N], ) -> Self314 pub(crate) fn new(
315 wrapped: S,
316 cache: [Option<PrecalculatedCryptoForProtocolVersion<V>>; N],
317 ) -> Self {
318 Self { wrapped, cache }
319 }
320 }
321
322 /// Internal implementation of [`PossiblyCachedDiscoveryCryptoMaterial`] to hide
323 /// what crypto-material variants we're actually storing in cached
324 /// credential-books.
325 pub(crate) enum PossiblyCachedDiscoveryCryptoMaterialKind<'a, V: ProtocolVersion>
326 where
327 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
328 {
329 Discovery(V::DiscoveryCredential),
330 Precalculated(&'a PrecalculatedCryptoForProtocolVersion<V>),
331 }
332
333 /// Crypto-materials that are potentially references to
334 /// already-cached precomputed variants, or raw discovery
335 /// credentials.
336 pub struct PossiblyCachedDiscoveryCryptoMaterial<'a, V: ProtocolVersion>
337 where
338 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
339 {
340 pub(crate) wrapped: PossiblyCachedDiscoveryCryptoMaterialKind<'a, V>,
341 }
342
343 impl<'a, V: ProtocolVersion> PossiblyCachedDiscoveryCryptoMaterial<'a, V>
344 where
345 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
346 {
from_discovery_credential(discovery_credential: V::DiscoveryCredential) -> Self347 fn from_discovery_credential(discovery_credential: V::DiscoveryCredential) -> Self {
348 Self { wrapped: PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(discovery_credential) }
349 }
from_precalculated(precalculated: &'a PrecalculatedCryptoForProtocolVersion<V>) -> Self350 fn from_precalculated(precalculated: &'a PrecalculatedCryptoForProtocolVersion<V>) -> Self {
351 Self { wrapped: PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(precalculated) }
352 }
353 }
354
355 impl<'a, V: ProtocolVersion> DiscoveryMetadataCryptoMaterial<V>
356 for PossiblyCachedDiscoveryCryptoMaterial<'a, V>
357 where
358 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
359 {
metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12]360 fn metadata_nonce<C: CryptoProvider>(&self) -> [u8; 12] {
361 match &self.wrapped {
362 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => x.metadata_nonce::<C>(),
363 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => x.metadata_nonce::<C>(),
364 }
365 }
366 }
367
368 impl<'a> V0DiscoveryCryptoMaterial for PossiblyCachedDiscoveryCryptoMaterial<'a, V0> {
ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C>369 fn ldt_adv_cipher<C: CryptoProvider>(&self) -> ldt_np_adv::AuthenticatedNpLdtDecryptCipher<C> {
370 match &self.wrapped {
371 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => x.ldt_adv_cipher::<C>(),
372 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => x.ldt_adv_cipher::<C>(),
373 }
374 }
375 }
376
377 impl<'a> V1DiscoveryCryptoMaterial for PossiblyCachedDiscoveryCryptoMaterial<'a, V1> {
signed_identity_resolution_material<C: CryptoProvider>( &self, ) -> SignedSectionIdentityResolutionMaterial378 fn signed_identity_resolution_material<C: CryptoProvider>(
379 &self,
380 ) -> SignedSectionIdentityResolutionMaterial {
381 match &self.wrapped {
382 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
383 x.signed_identity_resolution_material::<C>()
384 }
385 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
386 x.signed_identity_resolution_material::<C>()
387 }
388 }
389 }
390
mic_short_salt_identity_resolution_material<C: CryptoProvider>( &self, ) -> MicShortSaltSectionIdentityResolutionMaterial391 fn mic_short_salt_identity_resolution_material<C: CryptoProvider>(
392 &self,
393 ) -> MicShortSaltSectionIdentityResolutionMaterial {
394 match &self.wrapped {
395 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
396 x.mic_short_salt_identity_resolution_material::<C>()
397 }
398 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
399 x.mic_short_salt_identity_resolution_material::<C>()
400 }
401 }
402 }
403
mic_extended_salt_identity_resolution_material<C: CryptoProvider>( &self, ) -> MicExtendedSaltSectionIdentityResolutionMaterial404 fn mic_extended_salt_identity_resolution_material<C: CryptoProvider>(
405 &self,
406 ) -> MicExtendedSaltSectionIdentityResolutionMaterial {
407 match &self.wrapped {
408 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
409 x.mic_extended_salt_identity_resolution_material::<C>()
410 }
411 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
412 x.mic_extended_salt_identity_resolution_material::<C>()
413 }
414 }
415 }
416
signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial417 fn signed_verification_material<C: CryptoProvider>(&self) -> SignedSectionVerificationMaterial {
418 match &self.wrapped {
419 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
420 x.signed_verification_material::<C>()
421 }
422 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
423 x.signed_verification_material::<C>()
424 }
425 }
426 }
427
mic_short_salt_verification_material<C: CryptoProvider>( &self, ) -> MicShortSaltSectionVerificationMaterial428 fn mic_short_salt_verification_material<C: CryptoProvider>(
429 &self,
430 ) -> MicShortSaltSectionVerificationMaterial {
431 match &self.wrapped {
432 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
433 x.mic_short_salt_verification_material::<C>()
434 }
435 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
436 x.mic_short_salt_verification_material::<C>()
437 }
438 }
439 }
440
mic_extended_salt_verification_material<C: CryptoProvider>( &self, ) -> MicExtendedSaltSectionVerificationMaterial441 fn mic_extended_salt_verification_material<C: CryptoProvider>(
442 &self,
443 ) -> MicExtendedSaltSectionVerificationMaterial {
444 match &self.wrapped {
445 PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(x) => {
446 x.mic_extended_salt_verification_material::<C>()
447 }
448 PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(x) => {
449 x.mic_extended_salt_verification_material::<C>()
450 }
451 }
452 }
453 }
454
455 impl<'a, V: ProtocolVersion, S, const N: usize> CredentialSource<'a, V>
456 for CachedCredentialSource<V, S, N>
457 where
458 Self: 'a,
459 S: CredentialSource<'a, V> + 'a,
460 S::Crypto: Borrow<V::DiscoveryCredential>,
461 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
462 PossiblyCachedDiscoveryCryptoMaterial<'a, V>: DiscoveryMetadataCryptoMaterial<V>,
463 {
464 type Matched = <S as CredentialSource<'a, V>>::Matched;
465 type Crypto = PossiblyCachedDiscoveryCryptoMaterial<'a, V>;
466 type Iterator = CachedCredentialSourceIterator<'a, V, S, N>;
467
iter(&'a self) -> Self::Iterator468 fn iter(&'a self) -> Self::Iterator {
469 CachedCredentialSourceIterator {
470 current_index: 0,
471 cache: &self.cache,
472 source_iterator: self.wrapped.iter(),
473 }
474 }
475 }
476
477 /// A simple credentials source for environments which are,
478 /// for all practical purposes, not space-constrained, and hence
479 /// can store an arbitrary amount of pre-calculated crypto-materials.
480 ///
481 /// Requires `alloc` as a result of internally leveraging a `Vec`.
482 #[cfg(any(feature = "alloc", test))]
483 pub struct PrecalculatedOwnedCredentialSource<V: ProtocolVersion, M: MatchedCredential>
484 where
485 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
486 {
487 credentials: Vec<(PrecalculatedCryptoForProtocolVersion<V>, M)>,
488 }
489
490 #[cfg(any(feature = "alloc", test))]
491 impl<'a, V: ProtocolVersion + 'a, M: MatchedCredential + 'a>
492 PrecalculatedOwnedCredentialSource<V, M>
493 where
494 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
495 {
496 /// Pre-calculates crypto material for the given credentials, and constructs a
497 /// credentials source which holds owned copies of this crypto-material.
new<P: CryptoProvider>( credential_iter: impl IntoIterator<Item = MatchableCredential<V, M>>, ) -> Self498 pub fn new<P: CryptoProvider>(
499 credential_iter: impl IntoIterator<Item = MatchableCredential<V, M>>,
500 ) -> Self {
501 let credentials = credential_iter
502 .into_iter()
503 .map(|credential| {
504 (
505 precalculate_crypto_material::<V, P>(&credential.discovery_credential),
506 credential.match_data,
507 )
508 })
509 .collect();
510 Self { credentials }
511 }
512 }
513
514 #[cfg(any(feature = "alloc", test))]
reference_crypto_and_match_data<C, M: MatchedCredential>( pair_ref: &(C, M), ) -> (&C, ReferencedMatchedCredential<M>)515 fn reference_crypto_and_match_data<C, M: MatchedCredential>(
516 pair_ref: &(C, M),
517 ) -> (&C, ReferencedMatchedCredential<M>) {
518 let (c, m) = pair_ref;
519 (c, m.into())
520 }
521
522 #[cfg(any(feature = "alloc", test))]
523 impl<'a, V: ProtocolVersion, M: MatchedCredential> CredentialSource<'a, V>
524 for PrecalculatedOwnedCredentialSource<V, M>
525 where
526 Self: 'a,
527 precalculated_for_version::Marker: precalculated_for_version::MappingTrait<V>,
528 &'a PrecalculatedCryptoForProtocolVersion<V>: DiscoveryMetadataCryptoMaterial<V>,
529 {
530 type Matched = ReferencedMatchedCredential<'a, M>;
531 type Crypto = &'a PrecalculatedCryptoForProtocolVersion<V>;
532 type Iterator = core::iter::Map<
533 core::slice::Iter<'a, (PrecalculatedCryptoForProtocolVersion<V>, M)>,
534 fn(
535 &'a (PrecalculatedCryptoForProtocolVersion<V>, M),
536 )
537 -> (&'a PrecalculatedCryptoForProtocolVersion<V>, ReferencedMatchedCredential<'a, M>),
538 >;
539
iter(&'a self) -> Self::Iterator540 fn iter(&'a self) -> Self::Iterator {
541 self.credentials.iter().map(reference_crypto_and_match_data)
542 }
543 }
544
545 /// Type-alias for credential sources which are provided via slice credential-sources
546 /// with a pre-calculated credential cache layered on top.
547 pub type CachedSliceCredentialSource<'a, V, M, const N: usize> =
548 CachedCredentialSource<V, SliceCredentialSource<'a, V, M>, N>;
549
550 /// A [`CredentialBook`] whose sources for V0 and V1 credentials come from the given slices
551 /// of discovery credentials, with crypto-materials for up to the given number of credentials
552 /// from the beginning of each slice kept in an in-memory cache.
553 pub type CachedSliceCredentialBook<'a, M, const N0: usize, const N1: usize> =
554 CredentialBookFromSources<
555 CachedSliceCredentialSource<'a, V0, M, N0>,
556 CachedSliceCredentialSource<'a, V1, M, N1>,
557 >;
558
559 #[cfg(any(feature = "alloc", test))]
560 /// A credential-book which owns all of its (non-matched) credential data,
561 /// and maintains pre-calculated cryptographic information about all
562 /// stored credentials for speedy advertisement deserialization.
563 ///
564 /// Use this credential book if memory usage is not terribly tight,
565 /// and you're operating in an environment with an allocator.
566 pub type PrecalculatedOwnedCredentialBook<M> = CredentialBookFromSources<
567 PrecalculatedOwnedCredentialSource<V0, M>,
568 PrecalculatedOwnedCredentialSource<V1, M>,
569 >;
570