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