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 #![allow(clippy::unwrap_used)]
16
17 extern crate std;
18
19 use super::super::*;
20 use crate::{
21 deserialization_arena,
22 extended::{
23 data_elements::TxPowerDataElement,
24 deserialize::{
25 encrypted_section::tests::first_section_identity_token,
26 section::intermediate::{
27 parse_sections, tests::IntermediateSectionExt, CiphertextSection,
28 },
29 DataElement, DataElementParseError, Section,
30 },
31 salt::{ShortV1Salt, SHORT_SALT_LEN},
32 serialize::{
33 AdvBuilder, AdvertisementType, CapacityLimitedVec, MicEncryptedSectionEncoder,
34 WriteDataElement,
35 },
36 V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN,
37 V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN,
38 },
39 shared_data::TxPower,
40 NpVersionHeader,
41 };
42 use crypto_provider::ed25519;
43 use crypto_provider_default::CryptoProviderImpl;
44 use np_hkdf::{v1_salt::EXTENDED_SALT_LEN, DerivedSectionKeys};
45 use sink::Sink;
46
47 type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519;
48
49 #[test]
deserialize_mic_encrypted_correct_keys_extended_salt()50 fn deserialize_mic_encrypted_correct_keys_extended_salt() {
51 deserialize_mic_encrypted_correct_keys(ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into())
52 }
53
54 #[test]
deserialize_mic_encrypted_correct_keys_short_salt()55 fn deserialize_mic_encrypted_correct_keys_short_salt() {
56 deserialize_mic_encrypted_correct_keys(ShortV1Salt::from([3; SHORT_SALT_LEN]).into())
57 }
58
deserialize_mic_encrypted_correct_keys(salt: MultiSalt)59 fn deserialize_mic_encrypted_correct_keys(salt: MultiSalt) {
60 let identity_token = V1IdentityToken::from([1; 16]);
61 let key_seed = [2; 32];
62 let broadcast_cm = V1BroadcastCredential::new(
63 key_seed,
64 identity_token,
65 ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(),
66 );
67
68 let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
69 let mut section_builder = adv_builder
70 .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>(
71 salt,
72 &broadcast_cm,
73 ))
74 .unwrap();
75
76 let txpower_de = TxPowerDataElement::from(TxPower::try_from(5).unwrap());
77 section_builder.add_de(|_| txpower_de.clone()).unwrap();
78 section_builder.add_to_advertisement::<CryptoProviderImpl>();
79 let adv = adv_builder.into_advertisement();
80
81 let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
82
83 let adv_header = if let NpVersionHeader::V1(h) = header {
84 h
85 } else {
86 panic!("incorrect header");
87 };
88
89 let sections = parse_sections(adv_header, remaining).unwrap();
90 assert_eq!(1, sections.len());
91
92 let section = sections.into_iter().next().unwrap();
93 let enc_section = section.as_ciphertext().unwrap();
94
95 let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section {
96 contents
97 } else {
98 panic!("incorrect flavor");
99 };
100
101 let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>();
102 // deserializing to Section works
103 let discovery_credential = V1BroadcastCredential::new(key_seed, identity_token, private_key)
104 .derive_discovery_credential::<CryptoProviderImpl>();
105
106 let arena = deserialization_arena!();
107 let mut allocator = arena.into_allocator();
108 let section = contents
109 .try_resolve_identity_and_deserialize::<CryptoProviderImpl>(
110 &mut allocator,
111 &discovery_credential,
112 )
113 .unwrap();
114
115 assert_eq!(
116 DecryptedSection::new(
117 VerificationMode::Mic,
118 salt,
119 identity_token,
120 &[txpower_de.de_header().serialize().as_slice(), &[5],].concat(),
121 ),
122 section
123 );
124 let data_elements = section.collect_data_elements().unwrap();
125 assert_eq!(data_elements, &[DataElement::new(0.into(), 0x05_u8.into(), &[5])]);
126
127 let (_header, contents_bytes) =
128 remaining.split_at(1 + 1 + salt.as_slice().len() + V1_IDENTITY_TOKEN_LEN);
129 assert_eq!(
130 &MicEncryptedSection {
131 contents: EncryptedSectionContents {
132 adv_header,
133 format_bytes: &[match salt {
134 MultiSalt::Short(_) => {
135 V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN
136 }
137 MultiSalt::Extended(_) => {
138 V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN
139 }
140 }],
141 salt,
142 identity_token: first_section_identity_token(salt, remaining),
143 section_contents: &contents_bytes
144 [..contents_bytes.len() - SectionMic::CONTENTS_LEN],
145 total_section_contents_len: contents_bytes.len().try_into().unwrap(),
146 },
147 mic: SectionMic {
148 mic: contents_bytes[contents_bytes.len() - SectionMic::CONTENTS_LEN..]
149 .try_into()
150 .unwrap()
151 },
152 },
153 contents
154 );
155
156 // plaintext is correct
157 {
158 let identity_resolution_contents =
159 contents.contents.compute_identity_resolution_contents::<CryptoProviderImpl>();
160 let identity_match = identity_resolution_contents
161 .try_match::<CryptoProviderImpl>(&match salt {
162 MultiSalt::Short(_) => discovery_credential
163 .mic_short_salt_identity_resolution_material::<CryptoProviderImpl>()
164 .into_raw_resolution_material(),
165 MultiSalt::Extended(_) => discovery_credential
166 .mic_extended_salt_identity_resolution_material::<CryptoProviderImpl>()
167 .into_raw_resolution_material(),
168 })
169 .unwrap();
170 let arena = deserialization_arena!();
171 let mut allocator = arena.into_allocator();
172 let decrypted = contents
173 .contents
174 .decrypt_ciphertext::<CryptoProviderImpl>(&mut allocator, identity_match)
175 .unwrap();
176
177 let mut expected = Vec::new();
178 // battery de
179 expected.extend_from_slice(txpower_de.clone().de_header().serialize().as_slice());
180 let _ = txpower_de.write_de_contents(&mut expected);
181
182 assert_eq!(identity_token, decrypted.identity_token);
183 assert_eq!(&expected, decrypted.plaintext_contents);
184 }
185 }
186
187 #[test]
deserialize_mic_encrypted_short_salt_incorrect_aes_key_error()188 fn deserialize_mic_encrypted_short_salt_incorrect_aes_key_error() {
189 // bad aes key -> bad metadata key plaintext
190 do_bad_deserialize_params::<CryptoProviderImpl>(
191 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
192 IdentityResolutionOrDeserializationError::IdentityMatchingError,
193 |cm| {
194 cm.mic_short_salt_identity_resolution_material
195 .as_mut_raw_resolution_material()
196 .aes_key = [0xFF; 16].into();
197 },
198 );
199 }
200
201 #[test]
deserialize_mic_encrypted_short_salt_incorrect_identity_token_hmac_key_error()202 fn deserialize_mic_encrypted_short_salt_incorrect_identity_token_hmac_key_error() {
203 // bad metadata key hmac key -> bad calculated metadata key mac
204 do_bad_deserialize_params::<CryptoProviderImpl>(
205 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
206 IdentityResolutionOrDeserializationError::IdentityMatchingError,
207 |cm| {
208 cm.mic_short_salt_identity_resolution_material
209 .as_mut_raw_resolution_material()
210 .identity_token_hmac_key = [0xFF; 32];
211 },
212 );
213 }
214
215 #[test]
deserialize_mic_encrypted_short_salt_incorrect_mic_hmac_key_error()216 fn deserialize_mic_encrypted_short_salt_incorrect_mic_hmac_key_error() {
217 // bad mic hmac key -> bad calculated mic
218 do_bad_deserialize_params::<CryptoProviderImpl>(
219 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
220 MicVerificationError::MicMismatch.into(),
221 |cm| {
222 cm.mic_short_salt_verification_material.mic_hmac_key = [0xFF; 32];
223 },
224 );
225 }
226
227 #[test]
deserialize_mic_encrypted_short_salt_incorrect_expected_identity_token_hmac_error()228 fn deserialize_mic_encrypted_short_salt_incorrect_expected_identity_token_hmac_error() {
229 // bad expected metadata key mac
230 do_bad_deserialize_params::<CryptoProviderImpl>(
231 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
232 IdentityResolutionOrDeserializationError::IdentityMatchingError,
233 |cm| {
234 cm.mic_short_salt_identity_resolution_material
235 .as_mut_raw_resolution_material()
236 .expected_identity_token_hmac = [0xFF; 32];
237 },
238 );
239 }
240
241 #[test]
deserialize_mic_encrypted_extended_salt_incorrect_aes_key_error()242 fn deserialize_mic_encrypted_extended_salt_incorrect_aes_key_error() {
243 // bad aes key -> bad metadata key plaintext
244 do_bad_deserialize_params::<CryptoProviderImpl>(
245 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
246 IdentityResolutionOrDeserializationError::IdentityMatchingError,
247 |cm| {
248 cm.mic_extended_salt_identity_resolution_material
249 .as_mut_raw_resolution_material()
250 .aes_key = [0xFF; 16].into();
251 },
252 );
253 }
254
255 #[test]
deserialize_mic_encrypted_extended_salt_incorrect_identity_token_hmac_key_error()256 fn deserialize_mic_encrypted_extended_salt_incorrect_identity_token_hmac_key_error() {
257 // bad metadata key hmac key -> bad calculated metadata key mac
258 do_bad_deserialize_params::<CryptoProviderImpl>(
259 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
260 IdentityResolutionOrDeserializationError::IdentityMatchingError,
261 |cm| {
262 cm.mic_extended_salt_identity_resolution_material
263 .as_mut_raw_resolution_material()
264 .identity_token_hmac_key = [0xFF; 32];
265 },
266 );
267 }
268
269 #[test]
deserialize_mic_encrypted_extended_salt_incorrect_mic_hmac_key_error()270 fn deserialize_mic_encrypted_extended_salt_incorrect_mic_hmac_key_error() {
271 // bad mic hmac key -> bad calculated mic
272 do_bad_deserialize_params::<CryptoProviderImpl>(
273 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
274 MicVerificationError::MicMismatch.into(),
275 |cm| {
276 cm.mic_extended_salt_verification_material.mic_hmac_key = [0xFF; 32];
277 },
278 );
279 }
280
281 #[test]
deserialize_mic_encrypted_extended_salt_incorrect_expected_identity_token_hmac_error()282 fn deserialize_mic_encrypted_extended_salt_incorrect_expected_identity_token_hmac_error() {
283 // bad expected metadata key mac
284 do_bad_deserialize_params::<CryptoProviderImpl>(
285 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
286 IdentityResolutionOrDeserializationError::IdentityMatchingError,
287 |cm| {
288 cm.mic_extended_salt_identity_resolution_material
289 .as_mut_raw_resolution_material()
290 .expected_identity_token_hmac = [0xFF; 32];
291 },
292 );
293 }
294
295 #[test]
deserialize_mic_encrypted_extended_salt_incorrect_salt_error()296 fn deserialize_mic_encrypted_extended_salt_incorrect_salt_error() {
297 // bad salt -> bad iv -> bad metadata key plaintext
298 do_bad_deserialize_tampered(
299 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
300 DeserializeError::IdentityResolutionOrDeserializationError(
301 IdentityResolutionOrDeserializationError::IdentityMatchingError,
302 ),
303 |_| {},
304 // replace the extended salt bytes
305 |adv| adv[2..18].fill(0xFF),
306 );
307 }
308
309 #[test]
deserialize_mic_encrypted_extended_salt_de_that_wont_parse()310 fn deserialize_mic_encrypted_extended_salt_de_that_wont_parse() {
311 // add an extra byte to the section, leading it to try to parse a DE that doesn't exist
312 do_bad_deserialize_tampered(
313 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
314 DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd),
315 |sec| sec.try_push(0xFF).unwrap(),
316 |_| {},
317 );
318 }
319
320 #[test]
deserialize_mic_encrypted_extended_salt_tampered_mic_error()321 fn deserialize_mic_encrypted_extended_salt_tampered_mic_error() {
322 // flip a bit in the first MIC byte
323 do_bad_deserialize_tampered(
324 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
325 DeserializeError::IdentityResolutionOrDeserializationError(
326 MicVerificationError::MicMismatch.into(),
327 ),
328 |_| {},
329 |adv| {
330 let mic_start = adv.len() - 16;
331 adv[mic_start] ^= 0x01
332 },
333 );
334 }
335
336 #[test]
deserialize_mic_encrypted_extended_salt_tampered_payload_error()337 fn deserialize_mic_encrypted_extended_salt_tampered_payload_error() {
338 // flip the last payload bit
339 do_bad_deserialize_tampered(
340 ExtendedV1Salt::from([3; EXTENDED_SALT_LEN]).into(),
341 DeserializeError::IdentityResolutionOrDeserializationError(
342 MicVerificationError::MicMismatch.into(),
343 ),
344 |_| {},
345 |adv| {
346 let before_mic = adv.len() - 17;
347 adv[before_mic] ^= 0x01
348 },
349 );
350 }
351 #[test]
deserialize_mic_encrypted_short_salt_incorrect_salt_error()352 fn deserialize_mic_encrypted_short_salt_incorrect_salt_error() {
353 // bad salt -> bad iv -> bad metadata key plaintext
354 do_bad_deserialize_tampered(
355 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
356 DeserializeError::IdentityResolutionOrDeserializationError(
357 IdentityResolutionOrDeserializationError::IdentityMatchingError,
358 ),
359 |_| {},
360 // replace the extended salt bytes
361 |adv| adv[2..4].fill(0xFF),
362 );
363 }
364
365 #[test]
deserialize_mic_encrypted_short_salt_de_that_wont_parse()366 fn deserialize_mic_encrypted_short_salt_de_that_wont_parse() {
367 // add an extra byte to the section, leading it to try to parse a DE that doesn't exist
368 do_bad_deserialize_tampered(
369 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
370 DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd),
371 |sec| sec.try_push(0xFF).unwrap(),
372 |_| {},
373 );
374 }
375
376 #[test]
deserialize_mic_encrypted_short_salt_tampered_mic_error()377 fn deserialize_mic_encrypted_short_salt_tampered_mic_error() {
378 // flip a bit in the first MIC byte
379 do_bad_deserialize_tampered(
380 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
381 DeserializeError::IdentityResolutionOrDeserializationError(
382 MicVerificationError::MicMismatch.into(),
383 ),
384 |_| {},
385 |adv| {
386 let mic_start = adv.len() - 16;
387 adv[mic_start] ^= 0x01
388 },
389 );
390 }
391
392 #[test]
deserialize_mic_encrypted_short_salt_tampered_payload_error()393 fn deserialize_mic_encrypted_short_salt_tampered_payload_error() {
394 // flip the last payload bit
395 do_bad_deserialize_tampered(
396 ShortV1Salt::from([3; SHORT_SALT_LEN]).into(),
397 DeserializeError::IdentityResolutionOrDeserializationError(
398 MicVerificationError::MicMismatch.into(),
399 ),
400 |_| {},
401 |adv| {
402 let before_mic = adv.len() - 17;
403 adv[before_mic] ^= 0x01
404 },
405 );
406 }
407
408 #[test]
arena_out_of_space_on_mic_verify()409 fn arena_out_of_space_on_mic_verify() {
410 let identity_token = V1IdentityToken::from([1; 16]);
411 let key_seed = [2; 32];
412 let section_salt = ExtendedV1Salt::from([3; 16]);
413 let broadcast_cm = V1BroadcastCredential::new(
414 key_seed,
415 identity_token,
416 ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(),
417 );
418
419 let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
420 let mut section_builder = adv_builder
421 .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>(
422 section_salt,
423 &broadcast_cm,
424 ))
425 .unwrap();
426
427 let txpower_de = TxPowerDataElement::from(TxPower::try_from(5).unwrap());
428 section_builder.add_de(|_| txpower_de.clone()).unwrap();
429 section_builder.add_to_advertisement::<CryptoProviderImpl>();
430 let adv = adv_builder.into_advertisement();
431
432 let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
433
434 let adv_header = if let NpVersionHeader::V1(h) = header {
435 h
436 } else {
437 panic!("incorrect header");
438 };
439
440 let sections = parse_sections(adv_header, remaining).unwrap();
441 assert_eq!(1, sections.len());
442
443 let section = sections.into_iter().next().unwrap();
444 let enc_section = section.as_ciphertext().unwrap();
445
446 let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section {
447 contents
448 } else {
449 panic!("incorrect flavor");
450 };
451
452 let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>();
453 // deserializing to Section works
454 let discovery_credential = V1BroadcastCredential::new(key_seed, identity_token, private_key)
455 .derive_discovery_credential::<CryptoProviderImpl>();
456
457 let arena = deserialization_arena!();
458 let mut allocator = arena.into_allocator();
459 let _ = allocator.allocate(250).unwrap();
460 let res = contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>(
461 &mut allocator,
462 &discovery_credential,
463 );
464 assert_eq!(
465 Err(IdentityResolutionOrDeserializationError::DeserializationError(
466 DeserializationError::ArenaOutOfSpace
467 )),
468 res
469 );
470 }
471
472 /// Attempt a decryption that will fail when using the provided parameters for decryption only.
473 /// `None` means use the correct value for that parameter.
do_bad_deserialize_params<C: CryptoProvider>( salt: MultiSalt, error: IdentityResolutionOrDeserializationError<MicVerificationError>, mut mangle_crypto_material: impl FnMut(&mut PrecalculatedV1DiscoveryCryptoMaterial), )474 fn do_bad_deserialize_params<C: CryptoProvider>(
475 salt: MultiSalt,
476 error: IdentityResolutionOrDeserializationError<MicVerificationError>,
477 mut mangle_crypto_material: impl FnMut(&mut PrecalculatedV1DiscoveryCryptoMaterial),
478 ) {
479 let identity_token = V1IdentityToken([1; 16]);
480 let key_seed = [2; 32];
481 let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed);
482
483 let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
484
485 let broadcast_cm = V1BroadcastCredential::new(
486 key_seed,
487 identity_token,
488 ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(),
489 );
490
491 let mut section_builder = adv_builder
492 .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>(
493 salt,
494 &broadcast_cm,
495 ))
496 .unwrap();
497
498 section_builder.add_de(|_| TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap();
499
500 section_builder.add_to_advertisement::<CryptoProviderImpl>();
501
502 let adv = adv_builder.into_advertisement();
503
504 let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
505
506 let v1_header = if let NpVersionHeader::V1(h) = header {
507 h
508 } else {
509 panic!("incorrect header");
510 };
511
512 let sections = parse_sections(v1_header, remaining).unwrap();
513 assert_eq!(1, sections.len());
514
515 let section = sections.into_iter().next().unwrap();
516 let enc_section = section.as_ciphertext().unwrap();
517 let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section {
518 contents
519 } else {
520 panic!("incorrect flavor");
521 };
522
523 // start with correct crypto material
524 let mut crypto_material = V1DiscoveryCredential::new(
525 key_seed,
526 key_seed_hkdf
527 .v1_mic_short_salt_keys()
528 .identity_token_hmac_key()
529 .calculate_hmac::<C>(&identity_token.0),
530 key_seed_hkdf
531 .v1_mic_extended_salt_keys()
532 .identity_token_hmac_key()
533 .calculate_hmac::<C>(&identity_token.0),
534 key_seed_hkdf
535 .v1_signature_keys()
536 .identity_token_hmac_key()
537 .calculate_hmac::<C>(&identity_token.0),
538 crypto_provider::ed25519::PrivateKey::generate::<C::Ed25519>()
539 .derive_public_key::<C::Ed25519>(),
540 )
541 .to_precalculated::<C>();
542
543 // then break it per the test case
544 mangle_crypto_material(&mut crypto_material);
545
546 assert_eq!(
547 error,
548 contents
549 .try_resolve_identity_and_deserialize::<C>(
550 &mut deserialization_arena!().into_allocator(),
551 &crypto_material
552 )
553 .unwrap_err()
554 );
555 }
556
557 #[derive(Debug, PartialEq)]
558 enum DeserializeError {
559 IdentityResolutionOrDeserializationError(
560 IdentityResolutionOrDeserializationError<MicVerificationError>,
561 ),
562 DataElementParseError(DataElementParseError),
563 }
564
do_bad_deserialize_tampered( salt: MultiSalt, expected_error: DeserializeError, mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), mangle_adv: impl Fn(&mut Vec<u8>), )565 fn do_bad_deserialize_tampered(
566 salt: MultiSalt,
567 expected_error: DeserializeError,
568 mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>),
569 mangle_adv: impl Fn(&mut Vec<u8>),
570 ) {
571 let metadata_key = V1IdentityToken([1; 16]);
572 let key_seed = [2; 32];
573
574 let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
575
576 let broadcast_cm = V1BroadcastCredential::new(
577 key_seed,
578 metadata_key,
579 ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(),
580 );
581
582 let mut section_builder = adv_builder
583 .section_builder(MicEncryptedSectionEncoder::<_>::new::<CryptoProviderImpl>(
584 salt,
585 &broadcast_cm,
586 ))
587 .unwrap();
588
589 section_builder.add_de(|_| TxPowerDataElement::from(TxPower::try_from(7).unwrap())).unwrap();
590
591 mangle_section(&mut section_builder.section);
592
593 section_builder.add_to_advertisement::<CryptoProviderImpl>();
594
595 let adv = adv_builder.into_advertisement();
596 let mut adv_mut = adv.as_slice().to_vec();
597 mangle_adv(&mut adv_mut);
598
599 let (remaining, header) = NpVersionHeader::parse(&adv_mut).unwrap();
600
601 let v1_header = if let NpVersionHeader::V1(h) = header {
602 h
603 } else {
604 panic!("incorrect header");
605 };
606
607 let sections = parse_sections(v1_header, remaining).unwrap();
608 assert_eq!(1, sections.len());
609
610 let section = sections.into_iter().next().unwrap();
611 let enc_section = section.as_ciphertext().unwrap();
612 let contents = if let CiphertextSection::MicEncrypted(contents) = &enc_section {
613 contents
614 } else {
615 panic!("incorrect flavor");
616 };
617
618 // generate a random key pair since we need _some_ public key in our discovery
619 // credential, even if it winds up going unused
620 let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>();
621
622 let discovery_credential = V1BroadcastCredential::new(key_seed, metadata_key, private_key)
623 .derive_discovery_credential::<CryptoProviderImpl>();
624
625 match contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>(
626 &mut deserialization_arena!().into_allocator(),
627 &discovery_credential,
628 ) {
629 Ok(section) => {
630 assert_eq!(
631 expected_error,
632 DeserializeError::DataElementParseError(
633 section.collect_data_elements().unwrap_err()
634 )
635 );
636 }
637 Err(e) => assert_eq!(
638 expected_error,
639 DeserializeError::IdentityResolutionOrDeserializationError(e),
640 ),
641 };
642 }
643