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 §ion1[..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 §ion2[..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 §ion1[..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 §ion2[..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 §ion3[..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 §ion1[..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 §ion2[..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 §ion3[..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 §ion1[..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