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::*;
20 use crate::{
21     deserialization_arena,
22     extended::{
23         data_elements::TxPowerDataElement,
24         deserialize::{
25             encrypted_section,
26             section::intermediate::{
27                 parse_sections, tests::IntermediateSectionExt, CiphertextSection,
28             },
29             DataElement, DataElementParseError, Section,
30         },
31         serialize::{
32             AdvBuilder, AdvertisementType, CapacityLimitedVec, SignedEncryptedSectionEncoder,
33             SingleTypeDataElement, WriteDataElement,
34         },
35         V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN,
36     },
37     shared_data::TxPower,
38     NpVersionHeader,
39 };
40 use crypto_provider::ed25519;
41 use crypto_provider_default::CryptoProviderImpl;
42 use np_hkdf::{v1_salt, DerivedSectionKeys};
43 use sink::Sink;
44 use std::{prelude::rust_2021::*, vec};
45 
46 type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519;
47 
48 #[test]
deserialize_signature_encrypted_correct_keys_extended_salt()49 fn deserialize_signature_encrypted_correct_keys_extended_salt() {
50     let identity_token = V1IdentityToken::from([1; 16]);
51     let key_seed = [2; 32];
52     let section_salt = ExtendedV1Salt::from([3; 16]);
53     let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed);
54     let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>();
55 
56     let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
57 
58     let broadcast_cm = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone());
59 
60     let mut section_builder = adv_builder
61         .section_builder(SignedEncryptedSectionEncoder::new::<CryptoProviderImpl>(
62             section_salt,
63             &broadcast_cm,
64         ))
65         .unwrap();
66 
67     let txpower_de = TxPowerDataElement::from(TxPower::try_from(7).unwrap());
68     section_builder.add_de(|_| txpower_de.clone()).unwrap();
69 
70     section_builder.add_to_advertisement::<CryptoProviderImpl>();
71 
72     let adv = adv_builder.into_advertisement();
73 
74     let (after_version_header, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
75 
76     let adv_header = if let NpVersionHeader::V1(h) = header {
77         h
78     } else {
79         panic!("incorrect header");
80     };
81 
82     let sections = parse_sections(adv_header, after_version_header).unwrap();
83     assert_eq!(1, sections.len());
84 
85     let section = sections.into_iter().next().unwrap();
86     let enc_section = section.as_ciphertext().unwrap();
87     let contents = if let CiphertextSection::SignatureEncrypted(contents) = &enc_section {
88         contents
89     } else {
90         panic!("incorrect flavor");
91     };
92 
93     assert_eq!(
94         &SignatureEncryptedSection {
95             contents: EncryptedSectionContents {
96                 adv_header,
97                 format_bytes: &[V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN],
98                 salt: section_salt,
99                 identity_token: first_section_identity_token(
100                     section_salt.into(),
101                     after_version_header
102                 ),
103                 // adv header + section len + format + salt + identity token
104                 section_contents: first_section_contents(after_version_header),
105                 total_section_contents_len: contents.contents.total_section_contents_len
106             },
107         },
108         contents
109     );
110 
111     let mut de_bytes = Vec::new();
112     de_bytes.extend_from_slice(txpower_de.de_header().serialize().as_slice());
113     let _ = txpower_de.write_de_contents(&mut de_bytes);
114     let de_bytes = de_bytes;
115 
116     // plaintext is correct
117     {
118         let credential = V1DiscoveryCredential::new(
119             key_seed,
120             key_seed_hkdf
121                 .v1_mic_short_salt_keys()
122                 .identity_token_hmac_key()
123                 .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
124             key_seed_hkdf
125                 .v1_mic_extended_salt_keys()
126                 .identity_token_hmac_key()
127                 .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
128             key_seed_hkdf
129                 .v1_signature_keys()
130                 .identity_token_hmac_key()
131                 .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
132             private_key.derive_public_key::<Ed25519ProviderImpl>(),
133         );
134         let signed_identity_resolution_material =
135             credential.signed_identity_resolution_material::<CryptoProviderImpl>();
136         let identity_resolution_contents =
137             contents.contents.compute_identity_resolution_contents::<CryptoProviderImpl>();
138         let identity_match = identity_resolution_contents
139             .try_match::<CryptoProviderImpl>(
140                 &signed_identity_resolution_material.into_raw_resolution_material(),
141             )
142             .unwrap();
143 
144         let arena = deserialization_arena!();
145         let mut allocator = arena.into_allocator();
146         let decrypted =
147             contents.contents.decrypt_ciphertext(&mut allocator, identity_match).unwrap();
148 
149         let nonce: AesCtrNonce = section_salt.compute_nonce::<CryptoProviderImpl>();
150 
151         let sig_payload = SectionSignaturePayload::new(
152             &[V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN],
153             section_salt.as_slice(),
154             &nonce,
155             identity_token.as_slice(),
156             (de_bytes.len() + crypto_provider::ed25519::SIGNATURE_LENGTH).try_into().unwrap(),
157             &de_bytes,
158         );
159 
160         let mut de_and_sig = de_bytes.clone();
161         de_and_sig
162             .extend_from_slice(&sig_payload.sign::<Ed25519ProviderImpl>(&private_key).to_bytes());
163         assert_eq!(identity_token, decrypted.identity_token);
164         assert_eq!(nonce, decrypted.nonce);
165         assert_eq!(&de_and_sig, decrypted.plaintext_contents);
166     }
167 
168     // deserialization to Section works
169     {
170         let credential = V1DiscoveryCredential::new(
171             key_seed,
172             key_seed_hkdf
173                 .v1_mic_short_salt_keys()
174                 .identity_token_hmac_key()
175                 .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
176             key_seed_hkdf
177                 .v1_mic_extended_salt_keys()
178                 .identity_token_hmac_key()
179                 .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
180             key_seed_hkdf
181                 .v1_signature_keys()
182                 .identity_token_hmac_key()
183                 .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
184             private_key.derive_public_key::<Ed25519ProviderImpl>(),
185         );
186         let signed_identity_resolution_material =
187             credential.signed_identity_resolution_material::<CryptoProviderImpl>();
188         let signed_verification_material =
189             credential.signed_verification_material::<CryptoProviderImpl>();
190 
191         let arena = deserialization_arena!();
192         let mut allocator = arena.into_allocator();
193         let section = contents
194             .try_resolve_identity_and_deserialize::<CryptoProviderImpl>(
195                 &mut allocator,
196                 &signed_identity_resolution_material,
197                 &signed_verification_material,
198             )
199             .unwrap();
200 
201         assert_eq!(
202             DecryptedSection::new(
203                 VerificationMode::Signature,
204                 section_salt.into(),
205                 identity_token,
206                 &de_bytes,
207             ),
208             section
209         );
210         let data_elements = section.collect_data_elements().unwrap();
211         assert_eq!(data_elements, &[DataElement::new(0.into(), 0x05_u8.into(), &[7])]);
212 
213         assert_eq!(
214             vec![(v1_salt::DataElementOffset::from(0_u8), TxPowerDataElement::DE_TYPE, vec![7u8])],
215             data_elements
216                 .into_iter()
217                 .map(|de| (de.offset(), de.de_type(), de.contents().to_vec()))
218                 .collect::<Vec<_>>()
219         );
220     }
221 }
222 
223 #[test]
deserialize_signature_encrypted_incorrect_aes_key_error()224 fn deserialize_signature_encrypted_incorrect_aes_key_error() {
225     // bad aes key -> bad metadata key plaintext
226     do_bad_deserialize_params::<CryptoProviderImpl>(
227         IdentityResolutionOrDeserializationError::IdentityMatchingError,
228         Some([0xFF; 16].into()),
229         None,
230         None,
231         None,
232     );
233 }
234 
235 #[test]
deserialize_signature_encrypted_incorrect_metadata_key_hmac_key_error()236 fn deserialize_signature_encrypted_incorrect_metadata_key_hmac_key_error() {
237     // bad metadata key hmac key -> bad calculated metadata key mac
238     do_bad_deserialize_params::<CryptoProviderImpl>(
239         IdentityResolutionOrDeserializationError::IdentityMatchingError,
240         None,
241         Some([0xFF; 32].into()),
242         None,
243         None,
244     );
245 }
246 
247 #[test]
deserialize_signature_encrypted_incorrect_expected_metadata_key_hmac_error()248 fn deserialize_signature_encrypted_incorrect_expected_metadata_key_hmac_error() {
249     // bad expected metadata key mac
250     do_bad_deserialize_params::<CryptoProviderImpl>(
251         IdentityResolutionOrDeserializationError::IdentityMatchingError,
252         None,
253         None,
254         Some([0xFF; 32]),
255         None,
256     );
257 }
258 
259 #[test]
deserialize_signature_encrypted_incorrect_pub_key_error()260 fn deserialize_signature_encrypted_incorrect_pub_key_error() {
261     // a random pub key will lead to signature mismatch
262     do_bad_deserialize_params::<CryptoProviderImpl>(
263         SignatureVerificationError::SignatureMismatch.into(),
264         None,
265         None,
266         None,
267         Some(
268             ed25519::PrivateKey::generate::<Ed25519ProviderImpl>()
269                 .derive_public_key::<Ed25519ProviderImpl>(),
270         ),
271     );
272 }
273 
274 #[test]
deserialize_signature_encrypted_incorrect_salt_error()275 fn deserialize_signature_encrypted_incorrect_salt_error() {
276     // bad salt -> bad iv -> bad metadata key plaintext
277     do_bad_deserialize_tampered(
278         DeserializeError::IdentityResolutionOrDeserializationError(
279             IdentityResolutionOrDeserializationError::IdentityMatchingError,
280         ),
281         None,
282         |_| {},
283         |adv_mut| {
284             adv_mut[1 + 1 + 1..][..EXTENDED_SALT_LEN].copy_from_slice(&[0xFF; EXTENDED_SALT_LEN])
285         },
286     )
287 }
288 
289 #[test]
deserialize_signature_encrypted_tampered_signature_error()290 fn deserialize_signature_encrypted_tampered_signature_error() {
291     do_bad_deserialize_tampered(
292         DeserializeError::IdentityResolutionOrDeserializationError(
293             SignatureVerificationError::SignatureMismatch.into(),
294         ),
295         None,
296         |_| {},
297         // flip a bit in the middle of the signature
298         |adv_mut| {
299             let len = adv_mut.len();
300             adv_mut[len - 30] ^= 0x1
301         },
302     )
303 }
304 
305 #[test]
deserialize_signature_encrypted_tampered_ciphertext_error()306 fn deserialize_signature_encrypted_tampered_ciphertext_error() {
307     do_bad_deserialize_tampered(
308         DeserializeError::IdentityResolutionOrDeserializationError(
309             SignatureVerificationError::SignatureMismatch.into(),
310         ),
311         None,
312         |_| {},
313         // flip a bit outside of the signature
314         |adv_mut| {
315             let len = adv_mut.len();
316             adv_mut[len - 1 - 64] ^= 0x1
317         },
318     )
319 }
320 
321 #[test]
deserialize_signature_encrypted_missing_signature_error()322 fn deserialize_signature_encrypted_missing_signature_error() {
323     let de_len = 2;
324     do_bad_deserialize_tampered(
325         DeserializeError::IdentityResolutionOrDeserializationError(
326             SignatureVerificationError::SignatureMissing.into(),
327         ),
328         Some(de_len as u8),
329         |_| {},
330         |adv_mut| {
331             // chop off signature
332             adv_mut.truncate(adv_mut.len() - 64);
333             // fix section length
334             adv_mut[1 + 1 + EXTENDED_SALT_LEN + V1_IDENTITY_TOKEN_LEN..][0] = de_len as u8;
335         },
336     )
337 }
338 
339 #[test]
deserialize_signature_encrypted_des_wont_parse()340 fn deserialize_signature_encrypted_des_wont_parse() {
341     do_bad_deserialize_tampered(
342         DeserializeError::DataElementParseError(DataElementParseError::UnexpectedDataAfterEnd),
343         Some(2 + 1 + crypto_provider::ed25519::SIGNATURE_LENGTH as u8),
344         // add an impossible DE
345         |section| {
346             section.try_push(0xFF).unwrap();
347         },
348         |_| {},
349     )
350 }
351 
352 #[test]
arena_out_of_space_on_signature_verify()353 fn arena_out_of_space_on_signature_verify() {
354     let salt: ExtendedV1Salt = [0; 16].into();
355     let nonce = salt.compute_nonce::<CryptoProviderImpl>();
356     let sig_enc_section = SignatureEncryptedSection {
357         contents: EncryptedSectionContents::new(
358             V1AdvHeader::new(0),
359             &[0],
360             [0; 16].into(),
361             [0x00; V1_IDENTITY_TOKEN_LEN].into(),
362             1,
363             &[0x00; 1],
364         ),
365     };
366 
367     let arena = deserialization_arena!();
368     let mut allocator = arena.into_allocator();
369     let _ = allocator.allocate(250).unwrap();
370 
371     let cipher = <CryptoProviderImpl as CryptoProvider>::AesCtr128::new(
372         &[0u8; 16].into(),
373         NonceAndCounter::from_nonce(nonce),
374     );
375     let im: encrypted_section::IdentityMatch<CryptoProviderImpl> =
376         IdentityMatch { cipher, identity_token: V1IdentityToken([0; 16]), nonce };
377 
378     let signed_verification_material = SignedSectionVerificationMaterial {
379         public_key: ed25519::PublicKey::from_bytes::<Ed25519ProviderImpl>([0u8; 32])
380             .expect("public key should be valid bytes"),
381     };
382 
383     let _ = sig_enc_section.try_deserialize(&mut allocator, im, &signed_verification_material);
384 }
385 
386 /// Attempt a deserialization that will fail when using the provided parameters for decryption only.
387 /// `None` means use the correct value for that parameter.
do_bad_deserialize_params<C: CryptoProvider>( error: IdentityResolutionOrDeserializationError<SignatureVerificationError>, aes_key: Option<crypto_provider::aes::Aes128Key>, metadata_key_hmac_key: Option<np_hkdf::NpHmacSha256Key>, expected_metadata_key_hmac: Option<[u8; 32]>, pub_key: Option<ed25519::PublicKey>, )388 fn do_bad_deserialize_params<C: CryptoProvider>(
389     error: IdentityResolutionOrDeserializationError<SignatureVerificationError>,
390     aes_key: Option<crypto_provider::aes::Aes128Key>,
391     metadata_key_hmac_key: Option<np_hkdf::NpHmacSha256Key>,
392     expected_metadata_key_hmac: Option<[u8; 32]>,
393     pub_key: Option<ed25519::PublicKey>,
394 ) {
395     let metadata_key = V1IdentityToken([1; 16]);
396     let key_seed = [2; 32];
397     let section_salt: v1_salt::ExtendedV1Salt = [3; 16].into();
398     let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<C>::new(&key_seed);
399     let private_key = ed25519::PrivateKey::generate::<C::Ed25519>();
400 
401     let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
402 
403     let broadcast_cm = V1BroadcastCredential::new(key_seed, metadata_key, private_key.clone());
404 
405     let mut section_builder = adv_builder
406         .section_builder(SignedEncryptedSectionEncoder::new::<C>(section_salt, &broadcast_cm))
407         .unwrap();
408 
409     section_builder.add_de_res(|_| TxPower::try_from(2).map(TxPowerDataElement::from)).unwrap();
410 
411     section_builder.add_to_advertisement::<CryptoProviderImpl>();
412 
413     let adv = adv_builder.into_advertisement();
414 
415     let (remaining, header) = NpVersionHeader::parse(adv.as_slice()).unwrap();
416 
417     let v1_header = if let NpVersionHeader::V1(h) = header {
418         h
419     } else {
420         panic!("incorrect header");
421     };
422 
423     let sections = parse_sections(v1_header, remaining).unwrap();
424     assert_eq!(1, sections.len());
425 
426     let section = sections.into_iter().next().unwrap();
427     let enc_section = section.as_ciphertext().unwrap();
428     let contents = if let CiphertextSection::SignatureEncrypted(contents) = &enc_section {
429         contents
430     } else {
431         panic!("incorrect flavor");
432     };
433 
434     let signed_identity_resolution_material =
435         SignedSectionIdentityResolutionMaterial::from_raw(SectionIdentityResolutionMaterial {
436             aes_key: aes_key.unwrap_or_else(|| key_seed_hkdf.v1_signature_keys().aes_key()),
437 
438             identity_token_hmac_key: *metadata_key_hmac_key
439                 .unwrap_or_else(|| key_seed_hkdf.v1_signature_keys().identity_token_hmac_key())
440                 .as_bytes(),
441             expected_identity_token_hmac: expected_metadata_key_hmac.unwrap_or_else(|| {
442                 key_seed_hkdf
443                     .v1_signature_keys()
444                     .identity_token_hmac_key()
445                     .calculate_hmac::<CryptoProviderImpl>(&metadata_key.0)
446             }),
447         });
448 
449     let signed_verification_material = SignedSectionVerificationMaterial {
450         public_key: pub_key
451             .unwrap_or_else(|| private_key.derive_public_key::<Ed25519ProviderImpl>()),
452     };
453 
454     assert_eq!(
455         error,
456         contents
457             .try_resolve_identity_and_deserialize::<C>(
458                 &mut deserialization_arena!().into_allocator(),
459                 &signed_identity_resolution_material,
460                 &signed_verification_material,
461             )
462             .unwrap_err()
463     );
464 }
465 
466 #[derive(Debug, PartialEq)]
467 enum DeserializeError {
468     IdentityResolutionOrDeserializationError(
469         IdentityResolutionOrDeserializationError<SignatureVerificationError>,
470     ),
471     DataElementParseError(DataElementParseError),
472 }
473 
474 /// Run a test that mangles the advertisement contents before attempting to deserialize.
475 ///
476 /// The section will have a TxPower DE added.
do_bad_deserialize_tampered( expected_error: DeserializeError, expected_section_de_len: Option<u8>, mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>), mangle_adv_contents: impl Fn(&mut Vec<u8>), )477 fn do_bad_deserialize_tampered(
478     expected_error: DeserializeError,
479     expected_section_de_len: Option<u8>,
480     mangle_section: impl Fn(&mut CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>),
481     mangle_adv_contents: impl Fn(&mut Vec<u8>),
482 ) {
483     let identity_token = V1IdentityToken::from([1; V1_IDENTITY_TOKEN_LEN]);
484     let key_seed = [2; 32];
485     let section_salt: v1_salt::ExtendedV1Salt = [3; EXTENDED_SALT_LEN].into();
486     let key_seed_hkdf = np_hkdf::NpKeySeedHkdf::<CryptoProviderImpl>::new(&key_seed);
487     let private_key = ed25519::PrivateKey::generate::<Ed25519ProviderImpl>();
488 
489     let mut adv_builder = AdvBuilder::new(AdvertisementType::Encrypted);
490 
491     let broadcast_cm = V1BroadcastCredential::new(key_seed, identity_token, private_key.clone());
492 
493     let mut section_builder = adv_builder
494         .section_builder(SignedEncryptedSectionEncoder::new::<CryptoProviderImpl>(
495             section_salt,
496             &broadcast_cm,
497         ))
498         .unwrap();
499 
500     section_builder.add_de_res(|_| TxPower::try_from(2).map(TxPowerDataElement::from)).unwrap();
501 
502     mangle_section(&mut section_builder.section);
503 
504     section_builder.add_to_advertisement::<CryptoProviderImpl>();
505 
506     let adv = adv_builder.into_advertisement();
507     let mut adv_mut = adv.as_slice().to_vec();
508     mangle_adv_contents(&mut adv_mut);
509 
510     let (after_version_header, header) = NpVersionHeader::parse(&adv_mut).unwrap();
511 
512     let adv_header = if let NpVersionHeader::V1(h) = header {
513         h
514     } else {
515         panic!("incorrect header");
516     };
517 
518     let sections = parse_sections(adv_header, after_version_header).unwrap();
519     assert_eq!(1, sections.len());
520 
521     let section = sections.into_iter().next().unwrap();
522     let enc_section = section.as_ciphertext().unwrap();
523     let contents = if let CiphertextSection::SignatureEncrypted(contents) = &enc_section {
524         contents
525     } else {
526         panic!("incorrect flavor");
527     };
528     if let Some(len) = expected_section_de_len {
529         assert_eq!(usize::from(len), contents.contents.section_contents.len());
530     }
531 
532     let extracted_salt = first_section_salt(after_version_header);
533     assert_eq!(
534         &SignatureEncryptedSection {
535             contents: EncryptedSectionContents {
536                 adv_header,
537                 // extract data from adv buffer in case the caller tampered with things
538                 salt: extracted_salt,
539                 identity_token: first_section_identity_token(
540                     extracted_salt.into(),
541                     after_version_header
542                 ),
543                 section_contents: first_section_contents(after_version_header),
544                 format_bytes: first_section_format(after_version_header),
545                 total_section_contents_len: first_section_contents_len(after_version_header),
546             },
547         },
548         contents
549     );
550 
551     let credential = V1DiscoveryCredential::new(
552         key_seed,
553         key_seed_hkdf
554             .v1_mic_short_salt_keys()
555             .identity_token_hmac_key()
556             .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
557         key_seed_hkdf
558             .v1_mic_extended_salt_keys()
559             .identity_token_hmac_key()
560             .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
561         key_seed_hkdf
562             .v1_signature_keys()
563             .identity_token_hmac_key()
564             .calculate_hmac::<CryptoProviderImpl>(&identity_token.0),
565         private_key.derive_public_key::<Ed25519ProviderImpl>(),
566     );
567     let identity_resolution_material =
568         credential.signed_identity_resolution_material::<CryptoProviderImpl>();
569     let verification_material = credential.signed_verification_material::<CryptoProviderImpl>();
570 
571     match contents.try_resolve_identity_and_deserialize::<CryptoProviderImpl>(
572         &mut deserialization_arena!().into_allocator(),
573         &identity_resolution_material,
574         &verification_material,
575     ) {
576         Ok(section) => {
577             assert_eq!(
578                 expected_error,
579                 DeserializeError::DataElementParseError(
580                     section.collect_data_elements().unwrap_err()
581                 ),
582             );
583         }
584         Err(e) => assert_eq!(
585             expected_error,
586             DeserializeError::IdentityResolutionOrDeserializationError(e),
587         ),
588     };
589 }
590