1 // Copyright 2024 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 //! Tests for intermediate sections representation and logic - this is the initial stage of parsing
18 //! before any ciphertext is actually decrypted.
19 
20 extern crate std;
21 use std::{prelude::rust_2021::*, vec};
22 
23 use super::*;
24 use crate::{
25     extended::{
26         deserialize::{
27             data_element::DataElement,
28             encrypted_section::{
29                 EncryptedSectionContents, MicEncryptedSection, SignatureEncryptedSection,
30             },
31             SectionMic,
32         },
33         salt::{ShortV1Salt, SHORT_SALT_LEN},
34         serialize::{AdvBuilder, AdvertisementType},
35         NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN,
36         V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN,
37         V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN, V1_ENCODING_UNENCRYPTED,
38         V1_IDENTITY_TOKEN_LEN,
39     },
40     header::V1AdvHeader,
41     NpVersionHeader,
42 };
43 use crypto_provider_default::CryptoProviderImpl;
44 use nom::error;
45 use np_hkdf::v1_salt::EXTENDED_SALT_LEN;
46 use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng as _};
47 
48 /// Section header length after the length byte for ext salt + token
49 const EXT_SALT_SECTION_HEADER_LEN: usize = 1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1;
50 
51 /// Section header length after the length byte for ext salt + token
52 const SHORT_SALT_SECTION_HEADER_LEN: usize = 1 + SHORT_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1;
53 
54 mod happy_path {
55     use super::*;
56     use crate::{
57         extended::{data_elements::TxPowerDataElement, serialize::UnencryptedSectionEncoder},
58         shared_data::TxPower,
59     };
60     use np_hkdf::v1_salt::ExtendedV1Salt;
61 
62     #[test]
parse_adv_ext_public_identity()63     fn parse_adv_ext_public_identity() {
64         let mut adv_body = vec![];
65         // public identity
66         adv_body.push(V1_ENCODING_UNENCRYPTED);
67         // section len
68         adv_body.push(6 + 3);
69         // de 1 byte header, type 5, len 5
70         adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]);
71         // de 2 byte header, type 22, len 1
72         adv_body.extend_from_slice(&[0x81, 0x16, 0x01]);
73 
74         let parsed_sections = parse_sections(V1AdvHeader::new(0x20), &adv_body).unwrap().into_vec();
75         assert_eq!(
76             vec![IntermediateSection::from(PlaintextSection::new(&adv_body[2..]))],
77             parsed_sections,
78         );
79         let expected_des = [
80             // 1 byte header, len 5
81             DataElement::new(0_u8.into(), 5_u8.into(), &[0x01, 0x02, 0x03, 0x04, 0x05]),
82             // 2 byte header, len 1
83             DataElement::new(1_u8.into(), 22_u8.into(), &[0x01]),
84         ];
85 
86         assert_eq!(
87             &expected_des[..],
88             &parsed_sections[0].as_plaintext().unwrap().collect_data_elements().unwrap()
89         );
90     }
91 
92     #[test]
do_deserialize_max_number_of_public_sections()93     fn do_deserialize_max_number_of_public_sections() {
94         let mut adv_builder = AdvBuilder::new(AdvertisementType::Plaintext);
95         for _ in 0..NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT {
96             let mut section_builder =
97                 adv_builder.section_builder(UnencryptedSectionEncoder).unwrap();
98             section_builder
99                 .add_de(|_salt| TxPowerDataElement::from(TxPower::try_from(7).unwrap()))
100                 .unwrap();
101             section_builder.add_to_advertisement::<CryptoProviderImpl>();
102         }
103 
104         let adv = adv_builder.into_advertisement();
105         let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
106 
107         let v1_header = if let NpVersionHeader::V1(h) = header {
108             h
109         } else {
110             panic!("incorrect header");
111         };
112         let sections = parse_sections(v1_header, remaining).unwrap();
113         assert_eq!(NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT, sections.len());
114     }
115 
116     #[test]
max_number_encrypted_sections_mic()117     fn max_number_encrypted_sections_mic() {
118         let mut adv_body = vec![];
119         for _ in 0..NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT {
120             let _ = add_mic_short_salt_section_to_adv(&mut adv_body);
121         }
122         let adv_header = V1AdvHeader::new(0x20);
123         assert!(parse_sections(adv_header, &adv_body).is_ok());
124     }
125 
126     #[test]
max_number_encrypted_sections_sig()127     fn max_number_encrypted_sections_sig() {
128         let mut adv_body = vec![];
129         for _ in 0..NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT {
130             let _ = add_sig_encrpyted_section(&mut adv_body, 5, &[0x55; EXTENDED_SALT_LEN]);
131         }
132         let adv_header = V1AdvHeader::new(0x20);
133         assert!(parse_sections(adv_header, &adv_body).is_ok());
134     }
135 
136     #[test]
both_mic_and_sig_sections()137     fn both_mic_and_sig_sections() {
138         let mut adv_body = vec![];
139         let short_salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]);
140         let token_bytes = [0x55; V1_IDENTITY_TOKEN_LEN];
141         let extended_salt = ExtendedV1Salt::from([0x55; EXTENDED_SALT_LEN]);
142         let total_section_1_len = add_mic_short_salt_section_to_adv(&mut adv_body);
143         let _ = add_sig_encrpyted_section(&mut adv_body, 5, extended_salt.bytes());
144 
145         let adv_header = V1AdvHeader::new(0x20);
146         let section1 = &adv_body[0..total_section_1_len];
147         let section2 = &adv_body[total_section_1_len..];
148         let expected_sections = [
149             IntermediateSection::from(MicEncryptedSection {
150                 contents: EncryptedSectionContents::new(
151                     adv_header,
152                     &section1[..1],
153                     short_salt.into(),
154                     token_bytes.into(),
155                     (10 + SectionMic::CONTENTS_LEN).try_into().unwrap(),
156                     &[0xFF; 10],
157                 ),
158                 mic: SectionMic::from([0x33; SectionMic::CONTENTS_LEN]),
159             }),
160             IntermediateSection::from(SignatureEncryptedSection {
161                 contents: EncryptedSectionContents::new(
162                     adv_header,
163                     &section2[..1],
164                     extended_salt,
165                     [0x33; V1_IDENTITY_TOKEN_LEN].into(),
166                     5,
167                     &[0xFF; 5],
168                 ),
169             }),
170         ];
171         let parsed_sections = parse_sections(adv_header, &adv_body).unwrap();
172         assert_eq!(parsed_sections.into_vec(), expected_sections);
173     }
174 
175     #[test]
parse_adv_sig_encrypted_sections()176     fn parse_adv_sig_encrypted_sections() {
177         // 3 sections
178         let mut adv_body = vec![];
179         let salt_bytes = [0x11; EXTENDED_SALT_LEN];
180 
181         let section_1_len = add_sig_encrpyted_section(&mut adv_body, 10, &salt_bytes);
182         let section_2_len = add_sig_encrpyted_section(&mut adv_body, 11, &salt_bytes);
183         let _ = add_sig_encrpyted_section(&mut adv_body, 12, &salt_bytes);
184 
185         let adv_header = V1AdvHeader::new(0x20);
186         let section1 = &adv_body[..section_1_len];
187         let section2 = &adv_body[section_1_len..][..section_2_len];
188         let section3 = &adv_body[(section_1_len + section_2_len)..];
189         let expected_sections = [
190             SignatureEncryptedSection {
191                 contents: EncryptedSectionContents::new(
192                     adv_header,
193                     &section1[..1],
194                     salt_bytes.into(),
195                     [0x33; V1_IDENTITY_TOKEN_LEN].into(),
196                     10,
197                     &[0xFF; 10],
198                 ),
199             },
200             SignatureEncryptedSection {
201                 contents: EncryptedSectionContents::new(
202                     adv_header,
203                     &section2[..1],
204                     salt_bytes.into(),
205                     [0x33; V1_IDENTITY_TOKEN_LEN].into(),
206                     11,
207                     &[0xFF; 11],
208                 ),
209             },
210             SignatureEncryptedSection {
211                 contents: EncryptedSectionContents::new(
212                     adv_header,
213                     &section3[..1],
214                     salt_bytes.into(),
215                     [0x33; V1_IDENTITY_TOKEN_LEN].into(),
216                     12,
217                     &[0xFF; 12],
218                 ),
219             },
220         ];
221         let parsed_sections = parse_sections(adv_header, &adv_body).unwrap();
222         assert_eq!(parsed_sections.into_vec(), expected_sections.map(IntermediateSection::from));
223     }
224 
225     #[test]
parse_adv_ext_salt_mic_sections()226     fn parse_adv_ext_salt_mic_sections() {
227         // 3 sections
228         let mut adv_body = vec![];
229         // section
230         adv_body.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN);
231         let salt = ExtendedV1Salt::from([0x11; EXTENDED_SALT_LEN]);
232         adv_body.extend_from_slice(salt.bytes().as_slice());
233         let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN];
234         adv_body.extend_from_slice(&token_bytes_1);
235         let section_1_len = EXT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8;
236         adv_body.push(10 + SectionMic::CONTENTS_LEN as u8);
237         // 10 bytes of 0xFF ciphertext
238         adv_body.extend_from_slice(&[0xFF; 10]);
239         // mic - 16x 0x33
240         adv_body.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]);
241 
242         // section
243         adv_body.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN);
244         adv_body.extend_from_slice(salt.bytes().as_slice());
245         let token_bytes_2 = [0x77; V1_IDENTITY_TOKEN_LEN];
246         adv_body.extend_from_slice(&token_bytes_2);
247         let section_2_len = EXT_SALT_SECTION_HEADER_LEN as u8 + 11 + SectionMic::CONTENTS_LEN as u8;
248         adv_body.push(11 + SectionMic::CONTENTS_LEN as u8);
249         // 11 bytes of 0xFF ciphertext
250         adv_body.extend_from_slice(&[0xFF; 11]);
251         // mic - 16x 0x66
252         adv_body.extend_from_slice(&[0x66; SectionMic::CONTENTS_LEN]);
253 
254         // section
255         adv_body.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN);
256         adv_body.extend_from_slice(salt.bytes().as_slice());
257         let token_bytes_3 = [0xAA; V1_IDENTITY_TOKEN_LEN];
258         adv_body.extend_from_slice(&token_bytes_3);
259         let _ = EXT_SALT_SECTION_HEADER_LEN as u8 + 12 + SectionMic::CONTENTS_LEN as u8;
260         adv_body.push(12 + SectionMic::CONTENTS_LEN as u8);
261         // 12 bytes of 0xFF ciphertext
262         adv_body.extend_from_slice(&[0xFF; 12]);
263         // mic - 16x 0x99
264         adv_body.extend_from_slice(&[0x99; SectionMic::CONTENTS_LEN]);
265 
266         let adv_header = V1AdvHeader::new(0x20);
267         let section1 = &adv_body[..section_1_len as usize];
268         let section2 = &adv_body[section_1_len as usize..][..section_2_len as usize];
269         let section3 = &adv_body[section_1_len as usize + section_2_len as usize..];
270         let expected_sections = [
271             MicEncryptedSection {
272                 contents: EncryptedSectionContents::new(
273                     adv_header,
274                     &section1[..1],
275                     salt.into(),
276                     token_bytes_1.into(),
277                     (10 + SectionMic::CONTENTS_LEN).try_into().unwrap(),
278                     &[0xFF; 10],
279                 ),
280                 mic: SectionMic::from([0x33; SectionMic::CONTENTS_LEN]),
281             },
282             MicEncryptedSection {
283                 contents: EncryptedSectionContents::new(
284                     adv_header,
285                     &section2[..1],
286                     salt.into(),
287                     token_bytes_2.into(),
288                     (11 + SectionMic::CONTENTS_LEN).try_into().unwrap(),
289                     &[0xFF; 11],
290                 ),
291                 mic: SectionMic::from([0x66; SectionMic::CONTENTS_LEN]),
292             },
293             MicEncryptedSection {
294                 contents: EncryptedSectionContents::new(
295                     adv_header,
296                     &section3[..1],
297                     salt.into(),
298                     token_bytes_3.into(),
299                     (12 + SectionMic::CONTENTS_LEN).try_into().unwrap(),
300                     &[0xFF; 12],
301                 ),
302                 mic: SectionMic::from([0x99; SectionMic::CONTENTS_LEN]),
303             },
304         ];
305         let parsed_sections = parse_sections(adv_header, &adv_body).unwrap();
306         assert_eq!(parsed_sections.into_vec(), &expected_sections.map(IntermediateSection::from));
307     }
308 
309     #[test]
parse_adv_short_salt_mic()310     fn parse_adv_short_salt_mic() {
311         // 3 sections
312         let short_salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]);
313         let token_bytes = [0x55; V1_IDENTITY_TOKEN_LEN];
314         let mut adv_body = vec![];
315         let section_1_len = add_mic_short_salt_section_to_adv(&mut adv_body);
316         let _ = add_mic_short_salt_section_to_adv(&mut adv_body);
317         let _ = add_mic_short_salt_section_to_adv(&mut adv_body);
318 
319         let adv_header = V1AdvHeader::new(0x20);
320         let section1 = &adv_body[..(1 + section_1_len)];
321         let mut expected_sections = [None, None, None];
322         for section in &mut expected_sections {
323             *section = Some(MicEncryptedSection {
324                 contents: EncryptedSectionContents::new(
325                     adv_header,
326                     &section1[..1],
327                     short_salt.into(),
328                     token_bytes.into(),
329                     (10 + SectionMic::CONTENTS_LEN).try_into().unwrap(),
330                     &[0xFF; 10],
331                 ),
332                 mic: SectionMic::from([0x33; SectionMic::CONTENTS_LEN]),
333             })
334         }
335         let expected: Vec<IntermediateSection> =
336             expected_sections.into_iter().map(|x| IntermediateSection::from(x.unwrap())).collect();
337         let parsed_sections = parse_sections(adv_header, &adv_body).unwrap();
338         assert_eq!(parsed_sections.into_vec(), expected);
339     }
340 }
341 
342 mod error_condition {
343     use super::*;
344     #[test]
parse_adv_too_many_unencrypted()345     fn parse_adv_too_many_unencrypted() {
346         // 2 sections
347         let mut adv_body = vec![];
348 
349         // section 1 - plaintext - 9 bytes
350         adv_body.push(V1_ENCODING_UNENCRYPTED);
351         adv_body.push(6 + 3); // section len
352                               // de 1 byte header, type 5, len 5
353         adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]);
354         // de 2 byte header, type 6, len 1
355         adv_body.extend_from_slice(&[0x81, 0x06, 0x01]);
356 
357         // section 2 - plaintext - 10 bytes
358         adv_body.push(V1_ENCODING_UNENCRYPTED);
359         adv_body.push(6 + 3); // section len
360                               // de 1 byte header, type 5, len 5
361         adv_body.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]);
362         // de 2 byte header, type 6, len 1
363         adv_body.extend_from_slice(&[0x81, 0x06, 0x01]);
364 
365         let adv_header = V1AdvHeader::new(0x20);
366 
367         assert_eq!(
368             nom::Err::Error(error::Error { input: &adv_body[11..], code: error::ErrorKind::Eof }),
369             parse_sections(adv_header, &adv_body).unwrap_err()
370         );
371     }
372 
373     #[test]
parse_adv_too_many_encrypted()374     fn parse_adv_too_many_encrypted() {
375         // 3 sections
376         let mut adv_body = vec![];
377         for _ in 0..NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT + 1 {
378             let _ = add_mic_short_salt_section_to_adv(&mut adv_body);
379         }
380         let adv_header = V1AdvHeader::new(0x20);
381         let _ = parse_sections(adv_header, &adv_body).expect_err("Expected an error");
382     }
383 
384     #[test]
do_deserialize_zero_section_header()385     fn do_deserialize_zero_section_header() {
386         let mut adv: tinyvec::ArrayVec<[u8; 254]> = tinyvec::ArrayVec::new();
387         adv.push(0x20); // V1 Advertisement
388         adv.push(0x00); // Section header of 0
389         let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
390         let v1_header = if let NpVersionHeader::V1(h) = header {
391             h
392         } else {
393             panic!("incorrect header");
394         };
395         let _ = parse_sections(v1_header, remaining).expect_err("Expected an error");
396     }
397 
398     #[test]
invalid_public_section()399     fn invalid_public_section() {
400         let mut rng = StdRng::from_entropy();
401         for _ in 0..100 {
402             let mut adv_body = vec![];
403             // Add section length
404             let remove_section_len = rng.gen_bool(0.5);
405             // Add public identity
406             let add_public_identity = rng.gen_bool(0.5);
407             // Add DEs
408             let add_des = rng.gen_bool(0.5);
409             // Shuffle adv
410             let shuffle = rng.gen_bool(0.5);
411 
412             adv_body.push(0);
413             if add_public_identity {
414                 adv_body[0] += 1;
415                 adv_body.push(0x03);
416             }
417             if add_des {
418                 adv_body[0] += 1;
419                 adv_body.extend_from_slice(&[0x81]);
420             }
421             if remove_section_len {
422                 let _ = adv_body.remove(0);
423             }
424 
425             let ordered_adv = adv_body.clone();
426 
427             if shuffle {
428                 adv_body.shuffle(&mut rng);
429             }
430             // A V1 public section is invalid if
431             // * section length is missing
432             // * the section is empty
433             // * the section identity is missing
434             // * the identity does not follow the section length
435             // * the section length is 0
436             if remove_section_len || !add_public_identity || (ordered_adv != adv_body) {
437                 let _ = parse_sections(V1AdvHeader::new(0x20), &adv_body)
438                     .expect_err("Expected to fail because of missing section length or identity");
439             }
440         }
441     }
442 
443     #[test]
parse_empty_section_as_encrypted()444     fn parse_empty_section_as_encrypted() {
445         // empty section - should return an EOF error
446         let input = [];
447         assert_eq!(
448             nom::Err::Error(error::Error {
449                 // attempted to read section contents
450                 input: input.as_slice(),
451                 code: error::ErrorKind::Eof,
452             }),
453             IntermediateSection::parser_encrypted_with_header(V1AdvHeader::new(0x20))(&input)
454                 .unwrap_err()
455         );
456     }
457 
458     #[test]
parse_unencrypted_as_encrypted()459     fn parse_unencrypted_as_encrypted() {
460         let mut input = vec![];
461         // public identity
462         input.push(V1_ENCODING_UNENCRYPTED);
463         // section len
464         input.push(6 + 3);
465         // de 1 byte header, type 5, len 5
466         input.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]);
467         // de 2 byte header, type 22, len 1
468         input.extend_from_slice(&[0x81, 0x16, 0x01]);
469         assert_eq!(
470             nom::Err::Error(error::Error {
471                 // attempted to read section contents
472                 input: input.as_slice(),
473                 code: error::ErrorKind::MapOpt,
474             }),
475             IntermediateSection::parser_encrypted_with_header(V1AdvHeader::new(0x20))(&input)
476                 .unwrap_err()
477         );
478     }
479 
480     #[test]
parse_section_length_overrun()481     fn parse_section_length_overrun() {
482         // section of length 0xF0 - legal but way longer than 2
483         let input = [V1_ENCODING_UNENCRYPTED, 0xF0, 0x10, 0x11];
484         assert_eq!(
485             nom::Err::Error(error::Error {
486                 // attempted to read section contents after parsing header
487                 input: &input.as_slice()[2..],
488                 code: error::ErrorKind::Eof,
489             }),
490             SectionContents::parse(&input).unwrap_err()
491         );
492     }
493 
494     #[test]
do_deserialize_empty_section()495     fn do_deserialize_empty_section() {
496         let adv_builder = AdvBuilder::new(AdvertisementType::Plaintext);
497         let adv = adv_builder.into_advertisement();
498         let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
499         let v1_header = if let NpVersionHeader::V1(h) = header {
500             h
501         } else {
502             panic!("incorrect header");
503         };
504         let _ = parse_sections(v1_header, remaining).expect_err("Expected an error");
505     }
506 
507     #[test]
parse_adv_sig_encrypted_section_with_short_salt()508     fn parse_adv_sig_encrypted_section_with_short_salt() {
509         // 3 sections
510         let mut adv_body = vec![];
511         let salt_bytes = [0x11; SHORT_SALT_LEN];
512         let section_len = EXT_SALT_SECTION_HEADER_LEN as u8 + 10;
513         adv_body.push(section_len);
514         adv_body.push(V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN);
515         adv_body.extend_from_slice(&salt_bytes);
516         adv_body.extend_from_slice(&[0x33; V1_IDENTITY_TOKEN_LEN]);
517         adv_body.extend_from_slice(&[0x22; 10]);
518         let adv_header = V1AdvHeader::new(0x20);
519         let parsed_sections = parse_sections(adv_header, &adv_body);
520         assert!(parsed_sections.is_err());
521     }
522 
523     // specify extended salt in the header but adv actual contains short salt
524     #[test]
parse_adv_mic_encrypted_wrong_salt_for_extended_header()525     fn parse_adv_mic_encrypted_wrong_salt_for_extended_header() {
526         // 3 sections
527         let mut adv = vec![];
528         let section_len = SHORT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8;
529         adv.push(section_len);
530         adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN);
531         let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]);
532         adv.extend_from_slice(salt.bytes().as_slice());
533         let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN];
534         adv.extend_from_slice(&token_bytes_1);
535         // 10 bytes of 0xFF ciphertext
536         adv.extend_from_slice(&[0xFF; 10]);
537         // mic - 16x 0x33
538         adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]);
539 
540         let adv_header = V1AdvHeader::new(0x20);
541         let parsed_sections = parse_sections(adv_header, &adv);
542         assert!(parsed_sections.is_err());
543     }
544 
545     // specify extended salt in the header but adv actual contains short salt
546     #[test]
encrypted_then_unencrpyted_fails_to_parse()547     fn encrypted_then_unencrpyted_fails_to_parse() {
548         // 3 sections
549         let mut adv = vec![];
550         let section_len = SHORT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8;
551         adv.push(section_len);
552         adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN);
553         let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]);
554         adv.extend_from_slice(salt.bytes().as_slice());
555         let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN];
556         adv.extend_from_slice(&token_bytes_1);
557         // 10 bytes of 0xFF ciphertext
558         adv.extend_from_slice(&[0xFF; 10]);
559         // mic - 16x 0x33
560         adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]);
561 
562         // Now add public section
563         // section len
564         adv.push(1 + 6 + 3);
565         // public identity
566         adv.push(V1_ENCODING_UNENCRYPTED);
567         // de 1 byte header, type 5, len 5
568         adv.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]);
569         // de 2 byte header, type 6, len 1
570         adv.extend_from_slice(&[0x81, 0x06, 0x01]);
571 
572         let adv_header = V1AdvHeader::new(0x20);
573         let parsed_sections = parse_sections(adv_header, &adv);
574         assert!(parsed_sections.is_err());
575     }
576 
577     // specify extended salt in the header but adv actual contains short salt
578     #[test]
unencrypted_then_encrpyted_fails_to_parse()579     fn unencrypted_then_encrpyted_fails_to_parse() {
580         let mut adv = vec![];
581 
582         // Public section
583         // section len
584         adv.push(1 + 6 + 3);
585         // public identity
586         adv.push(V1_ENCODING_UNENCRYPTED);
587         // de 1 byte header, type 5, len 5
588         adv.extend_from_slice(&[0x55, 0x01, 0x02, 0x03, 0x04, 0x05]);
589         // de 2 byte header, type 6, len 1
590         adv.extend_from_slice(&[0x81, 0x06, 0x01]);
591 
592         // mic encrypted section
593         let section_len = SHORT_SALT_SECTION_HEADER_LEN as u8 + 10 + SectionMic::CONTENTS_LEN as u8;
594         adv.push(section_len);
595         adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN);
596         let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]);
597         adv.extend_from_slice(salt.bytes().as_slice());
598         let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN];
599         adv.extend_from_slice(&token_bytes_1);
600         // 10 bytes of 0xFF ciphertext
601         adv.extend_from_slice(&[0xFF; 10]);
602         // mic - 16x 0x33
603         adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]);
604 
605         let adv_header = V1AdvHeader::new(0x20);
606         let parsed_sections = parse_sections(adv_header, &adv);
607         assert!(parsed_sections.is_err());
608     }
609 }
610 
611 mod coverage_gaming {
612     use super::*;
613     use alloc::format;
614 
615     #[test]
section_contents()616     fn section_contents() {
617         let sc = SectionContents {
618             format_bytes: &[],
619             header: SectionHeader::Unencrypted,
620             contents: &[],
621             contents_len: 0,
622         };
623         let _ = format!("{:?}", sc);
624         assert_eq!(sc, sc);
625     }
626 
627     #[test]
intermediate_section()628     fn intermediate_section() {
629         let is = IntermediateSection::Plaintext(PlaintextSection::new(&[]));
630         let _ = format!("{:?}", is);
631     }
632     #[test]
ciphertext_section()633     fn ciphertext_section() {
634         let ms = MicEncryptedSection {
635             contents: EncryptedSectionContents::new(
636                 V1AdvHeader::new(1),
637                 &[],
638                 ShortV1Salt::from([0x00; 2]).into(),
639                 CiphertextExtendedIdentityToken([0x00; 16]),
640                 0,
641                 &[],
642             ),
643             mic: [0x00; 16].into(),
644         };
645         let cs = CiphertextSection::MicEncrypted(ms);
646         let _ = format!("{:?}", cs);
647     }
648 }
649 
650 pub(crate) trait IntermediateSectionExt<'adv> {
651     /// Returns `Some` if `self` is `Plaintext`
as_plaintext(&self) -> Option<&PlaintextSection<'adv>>652     fn as_plaintext(&self) -> Option<&PlaintextSection<'adv>>;
653     /// Returns `Some` if `self` is `Ciphertext`
as_ciphertext(&self) -> Option<&CiphertextSection<'adv>>654     fn as_ciphertext(&self) -> Option<&CiphertextSection<'adv>>;
655 }
656 
657 impl<'adv> IntermediateSectionExt<'adv> for IntermediateSection<'adv> {
as_plaintext(&self) -> Option<&PlaintextSection<'adv>>658     fn as_plaintext(&self) -> Option<&PlaintextSection<'adv>> {
659         match self {
660             IntermediateSection::Plaintext(s) => Some(s),
661             IntermediateSection::Ciphertext(_) => None,
662         }
663     }
664 
as_ciphertext(&self) -> Option<&CiphertextSection<'adv>>665     fn as_ciphertext(&self) -> Option<&CiphertextSection<'adv>> {
666         match self {
667             IntermediateSection::Plaintext(_) => None,
668             IntermediateSection::Ciphertext(s) => Some(s),
669         }
670     }
671 }
672 
673 // returns the number of bytes appended to adv
add_mic_short_salt_section_to_adv(adv: &mut Vec<u8>) -> usize674 fn add_mic_short_salt_section_to_adv(adv: &mut Vec<u8>) -> usize {
675     // section
676     adv.push(V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN);
677     let salt = ShortV1Salt::from([0x11; SHORT_SALT_LEN]);
678     adv.extend_from_slice(salt.bytes().as_slice());
679     let token_bytes_1 = [0x55; V1_IDENTITY_TOKEN_LEN];
680     adv.extend_from_slice(&token_bytes_1);
681     let section_len = 10 + SectionMic::CONTENTS_LEN as u8;
682     adv.push(section_len);
683     // 10 bytes of 0xFF ciphertext
684     adv.extend_from_slice(&[0xFF; 10]);
685     // mic - 16x 0x33
686     adv.extend_from_slice(&[0x33; SectionMic::CONTENTS_LEN]);
687     1 + SHORT_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1 + 10 + SectionMic::CONTENTS_LEN
688 }
689 
690 // returns the total number of bytes appended to adv
add_sig_encrpyted_section( adv_body: &mut Vec<u8>, len: u8, salt_bytes: &[u8; EXTENDED_SALT_LEN], ) -> usize691 fn add_sig_encrpyted_section(
692     adv_body: &mut Vec<u8>,
693     len: u8,
694     salt_bytes: &[u8; EXTENDED_SALT_LEN],
695 ) -> usize {
696     adv_body.push(V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN);
697     adv_body.extend_from_slice(salt_bytes);
698     adv_body.extend_from_slice(&[0x33; V1_IDENTITY_TOKEN_LEN]);
699     adv_body.push(len);
700     // len bytes of 0xFF ciphertext -- in a real adv this would include the
701     // signature, but for the purposes of this parser, it's all just ciphertext
702     for _ in 0..len {
703         adv_body.push(0xFF);
704     }
705     1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN + 1 + len as usize
706 }
707 
708 // for convenient .into() in expected test data
709 impl<'a> From<SignatureEncryptedSection<'a>> for IntermediateSection<'a> {
from(s: SignatureEncryptedSection<'a>) -> Self710     fn from(s: SignatureEncryptedSection<'a>) -> Self {
711         IntermediateSection::Ciphertext(CiphertextSection::SignatureEncrypted(s))
712     }
713 }
714 
715 impl<'a> From<MicEncryptedSection<'a>> for IntermediateSection<'a> {
from(s: MicEncryptedSection<'a>) -> Self716     fn from(s: MicEncryptedSection<'a>) -> Self {
717         IntermediateSection::Ciphertext(CiphertextSection::MicEncrypted(s))
718     }
719 }
720 
721 impl<'a> From<PlaintextSection<'a>> for IntermediateSection<'a> {
from(s: PlaintextSection<'a>) -> Self722     fn from(s: PlaintextSection<'a>) -> Self {
723         IntermediateSection::Plaintext(s)
724     }
725 }
726