| // Copyright 2023 Google LLC | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | //! Tests of functionality related to credentials, credential-views, and credential suppliers. | 
 |  | 
 | extern crate alloc; | 
 |  | 
 | use crate::credential::{ | 
 |     book::{ | 
 |         init_cache_from_source, CachedCredentialSource, PossiblyCachedDiscoveryCryptoMaterialKind, | 
 |     }, | 
 |     source::{CredentialSource, SliceCredentialSource}, | 
 |     v0::{V0DiscoveryCredential, V0}, | 
 |     v1::{ | 
 |         SignedBroadcastCryptoMaterial, SimpleSignedBroadcastCryptoMaterial, V1DiscoveryCredential, | 
 |         V1DiscoveryCryptoMaterial, V1, | 
 |     }, | 
 |     BroadcastCryptoMaterial, EmptyMatchedCredential, KeySeedMatchedCredential, MatchableCredential, | 
 |     MetadataDecryptionError, ProtocolVersion, ReferencedMatchedCredential, | 
 |     SimpleBroadcastCryptoMaterial, | 
 | }; | 
 | use crate::legacy::ShortMetadataKey; | 
 | use crate::MetadataKey; | 
 | use alloc::{vec, vec::Vec}; | 
 | use crypto_provider_default::CryptoProviderImpl; | 
 |  | 
 | fn get_zeroed_v0_discovery_credential() -> V0DiscoveryCredential { | 
 |     V0DiscoveryCredential::new([0u8; 32], [0u8; 32]) | 
 | } | 
 |  | 
 | fn get_constant_packed_v1_discovery_credential(value: u8) -> V1DiscoveryCredential { | 
 |     let key_pair = np_ed25519::KeyPair::<CryptoProviderImpl>::generate(); | 
 |     SimpleSignedBroadcastCryptoMaterial::new( | 
 |         [value; 32], | 
 |         MetadataKey([value; 16]), | 
 |         // NOTE: This winds up being unused in these test cases | 
 |         key_pair.private_key(), | 
 |     ) | 
 |     .derive_v1_discovery_credential::<CryptoProviderImpl>() | 
 | } | 
 |  | 
 | #[test] | 
 | fn cached_credential_source_keeps_same_entries_as_original() { | 
 |     let creds: [MatchableCredential<V1, KeySeedMatchedCredential>; 5] = | 
 |         [0u8, 1, 2, 3, 4].map(|x| { | 
 |             let match_data = KeySeedMatchedCredential::from([x; 32]); | 
 |             MatchableCredential { | 
 |                 discovery_credential: get_constant_packed_v1_discovery_credential(x), | 
 |                 match_data, | 
 |             } | 
 |         }); | 
 |     let supplier = SliceCredentialSource::new(&creds); | 
 |     let cache = init_cache_from_source::<_, _, 3, CryptoProviderImpl>(&supplier); | 
 |     let cached = CachedCredentialSource::new(supplier, cache); | 
 |     let cached_view = &cached; | 
 |     assert_eq!(cached_view.iter().count(), 5); | 
 |     // Now we're going to check that the pairings between the match-data | 
 |     // and the MIC hmac key wind up being the same between the original | 
 |     // creds list and what's provided by the cached source. | 
 |     let expected: Vec<_> = creds | 
 |         .iter() | 
 |         .map(|cred| { | 
 |             ( | 
 |                 cred.discovery_credential | 
 |                     .unsigned_verification_material::<CryptoProviderImpl>() | 
 |                     .mic_hmac_key, | 
 |                 ReferencedMatchedCredential::from(&cred.match_data), | 
 |             ) | 
 |         }) | 
 |         .collect(); | 
 |     let actual: Vec<_> = cached_view | 
 |         .iter() | 
 |         .map(|(crypto_material, match_data)| { | 
 |             ( | 
 |                 crypto_material.unsigned_verification_material::<CryptoProviderImpl>().mic_hmac_key, | 
 |                 match_data, | 
 |             ) | 
 |         }) | 
 |         .collect(); | 
 |     assert_eq!(actual, expected); | 
 | } | 
 |  | 
 | #[test] | 
 | fn cached_credential_source_has_requested_cache_size() { | 
 |     let creds: [MatchableCredential<V0, EmptyMatchedCredential>; 10] = | 
 |         [0u8; 10].map(|_| MatchableCredential { | 
 |             discovery_credential: get_zeroed_v0_discovery_credential(), | 
 |             match_data: EmptyMatchedCredential, | 
 |         }); | 
 |     let supplier = SliceCredentialSource::new(&creds); | 
 |     let cache = init_cache_from_source::<_, _, 5, CryptoProviderImpl>(&supplier); | 
 |     let cached = CachedCredentialSource::new(supplier, cache); | 
 |     let cached_view = &cached; | 
 |     assert_eq!(cached_view.iter().count(), 10); | 
 |     for (i, (cred, _)) in cached_view.iter().enumerate() { | 
 |         if i < 5 { | 
 |             // Should be cached | 
 |             if let PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(_) = cred.wrapped { | 
 |             } else { | 
 |                 panic!("Credential #{} was not cached", i); | 
 |             } | 
 |         } else { | 
 |             // Should be discovery credentials | 
 |             if let PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(_) = cred.wrapped { | 
 |             } else { | 
 |                 panic!("Credential #{} was not supposed to be cached", i); | 
 |             } | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | #[test] | 
 | fn v0_metadata_decryption_works_same_metadata_key() { | 
 |     let key_seed = [3u8; 32]; | 
 |     let metadata_key = ShortMetadataKey([5u8; 14]); | 
 |  | 
 |     let metadata = vec![7u8; 42]; | 
 |  | 
 |     let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, metadata_key); | 
 |  | 
 |     let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); | 
 |  | 
 |     let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); | 
 |  | 
 |     let decryption_result = V0::decrypt_metadata::<CryptoProviderImpl>( | 
 |         metadata_nonce, | 
 |         metadata_key, | 
 |         &encrypted_metadata, | 
 |     ); | 
 |     assert_eq!(decryption_result, Ok(metadata)) | 
 | } | 
 |  | 
 | #[test] | 
 | fn v1_metadata_decryption_works_same_metadata_key() { | 
 |     let key_seed = [9u8; 32]; | 
 |     let metadata_key = MetadataKey([2u8; 16]); | 
 |  | 
 |     let metadata = vec![6u8; 51]; | 
 |  | 
 |     let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, metadata_key); | 
 |  | 
 |     let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); | 
 |  | 
 |     let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); | 
 |  | 
 |     let decryption_result = V1::decrypt_metadata::<CryptoProviderImpl>( | 
 |         metadata_nonce, | 
 |         metadata_key, | 
 |         &encrypted_metadata, | 
 |     ); | 
 |     assert_eq!(decryption_result, Ok(metadata)) | 
 | } | 
 |  | 
 | #[test] | 
 | fn v0_metadata_decryption_fails_different_metadata_key() { | 
 |     let key_seed = [3u8; 32]; | 
 |     let encrypting_metadata_key = ShortMetadataKey([5u8; 14]); | 
 |  | 
 |     let metadata = vec![7u8; 42]; | 
 |  | 
 |     let broadcast_cm = SimpleBroadcastCryptoMaterial::<V0>::new(key_seed, encrypting_metadata_key); | 
 |  | 
 |     let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); | 
 |  | 
 |     let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); | 
 |  | 
 |     let decrypting_metadata_key = ShortMetadataKey([6u8; 14]); | 
 |  | 
 |     let decryption_result = V0::decrypt_metadata::<CryptoProviderImpl>( | 
 |         metadata_nonce, | 
 |         decrypting_metadata_key, | 
 |         &encrypted_metadata, | 
 |     ); | 
 |     assert_eq!(decryption_result, Err(MetadataDecryptionError)) | 
 | } | 
 |  | 
 | #[test] | 
 | fn v1_metadata_decryption_fails_different_metadata_key() { | 
 |     let key_seed = [251u8; 32]; | 
 |     let encrypting_metadata_key = MetadataKey([127u8; 16]); | 
 |  | 
 |     let metadata = vec![255u8; 42]; | 
 |  | 
 |     let broadcast_cm = SimpleBroadcastCryptoMaterial::<V1>::new(key_seed, encrypting_metadata_key); | 
 |  | 
 |     let encrypted_metadata = broadcast_cm.encrypt_metadata::<CryptoProviderImpl>(&metadata); | 
 |  | 
 |     let metadata_nonce = broadcast_cm.metadata_nonce::<CryptoProviderImpl>(); | 
 |  | 
 |     let decrypting_metadata_key = MetadataKey([249u8; 16]); | 
 |  | 
 |     let decryption_result = V1::decrypt_metadata::<CryptoProviderImpl>( | 
 |         metadata_nonce, | 
 |         decrypting_metadata_key, | 
 |         &encrypted_metadata, | 
 |     ); | 
 |     assert_eq!(decryption_result, Err(MetadataDecryptionError)) | 
 | } |