1 // Copyright 2023 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 //! Tests of functionality related to credentials, credential-views, and credential suppliers.
15
16 extern crate alloc;
17
18 use crate::credential::matched::{
19 EmptyMatchedCredential, KeySeedMatchedCredential, ReferencedMatchedCredential,
20 };
21 use crate::credential::v1::MicSectionVerificationMaterial;
22 use crate::credential::{
23 book::{
24 init_cache_from_source, CachedCredentialSource, PossiblyCachedDiscoveryCryptoMaterialKind,
25 },
26 source::{CredentialSource, SliceCredentialSource},
27 v0::{V0DiscoveryCredential, V0},
28 v1::{V1BroadcastCredential, V1DiscoveryCredential, V1DiscoveryCryptoMaterial, V1},
29 MatchableCredential,
30 };
31 use crate::extended::{V1IdentityToken, V1_IDENTITY_TOKEN_LEN};
32 use alloc::vec::Vec;
33 use crypto_provider::{ed25519, CryptoProvider};
34 use crypto_provider_default::CryptoProviderImpl;
35
36 type Ed25519ProviderImpl = <CryptoProviderImpl as CryptoProvider>::Ed25519;
37
get_zeroed_v0_discovery_credential() -> V0DiscoveryCredential38 fn get_zeroed_v0_discovery_credential() -> V0DiscoveryCredential {
39 V0DiscoveryCredential::new([0u8; 32], [0u8; 32])
40 }
41
get_constant_packed_v1_discovery_credential(value: u8) -> V1DiscoveryCredential42 fn get_constant_packed_v1_discovery_credential(value: u8) -> V1DiscoveryCredential {
43 V1BroadcastCredential::new(
44 [value; 32],
45 V1IdentityToken::from([value; V1_IDENTITY_TOKEN_LEN]),
46 // NOTE: This winds up being unused in these test cases
47 ed25519::PrivateKey::generate::<Ed25519ProviderImpl>(),
48 )
49 .derive_discovery_credential::<CryptoProviderImpl>()
50 }
51
52 #[test]
cached_credential_source_keeps_same_entries_as_original()53 fn cached_credential_source_keeps_same_entries_as_original() {
54 let creds: [MatchableCredential<V1, KeySeedMatchedCredential>; 5] =
55 [0u8, 1, 2, 3, 4].map(|x| {
56 let match_data = KeySeedMatchedCredential::from([x; 32]);
57 MatchableCredential {
58 discovery_credential: get_constant_packed_v1_discovery_credential(x),
59 match_data,
60 }
61 });
62 let supplier = SliceCredentialSource::new(&creds);
63 let cache = init_cache_from_source::<_, _, 3, CryptoProviderImpl>(&supplier);
64 let cached = CachedCredentialSource::new(supplier, cache);
65 let cached_view = &cached;
66 assert_eq!(cached_view.iter().count(), 5);
67 // Now we're going to check that the pairings between the match-data
68 // and the MIC hmac key wind up being the same between the original
69 // creds list and what's provided by the cached source.
70 let expected: Vec<_> = creds
71 .iter()
72 .map(|cred| {
73 (
74 *cred
75 .discovery_credential
76 .mic_extended_salt_verification_material::<CryptoProviderImpl>()
77 .mic_hmac_key()
78 .as_bytes(),
79 ReferencedMatchedCredential::from(&cred.match_data),
80 )
81 })
82 .collect();
83 let actual: Vec<_> = cached_view
84 .iter()
85 .map(|(crypto_material, match_data)| {
86 (
87 *crypto_material
88 .mic_extended_salt_verification_material::<CryptoProviderImpl>()
89 .mic_hmac_key()
90 .as_bytes(),
91 match_data,
92 )
93 })
94 .collect();
95 assert_eq!(actual, expected);
96 }
97
98 #[test]
cached_credential_source_has_requested_cache_size()99 fn cached_credential_source_has_requested_cache_size() {
100 let creds: [MatchableCredential<V0, EmptyMatchedCredential>; 10] =
101 [0u8; 10].map(|_| MatchableCredential {
102 discovery_credential: get_zeroed_v0_discovery_credential(),
103 match_data: EmptyMatchedCredential,
104 });
105 let supplier = SliceCredentialSource::new(&creds);
106 let cache = init_cache_from_source::<_, _, 5, CryptoProviderImpl>(&supplier);
107 let cached = CachedCredentialSource::new(supplier, cache);
108 let cached_view = &cached;
109 assert_eq!(cached_view.iter().count(), 10);
110 for (i, (cred, _)) in cached_view.iter().enumerate() {
111 if i < 5 {
112 // Should be cached
113 if let PossiblyCachedDiscoveryCryptoMaterialKind::Precalculated(_) = cred.wrapped {
114 } else {
115 panic!("Credential #{} was not cached", i);
116 }
117 } else {
118 // Should be discovery credentials
119 if let PossiblyCachedDiscoveryCryptoMaterialKind::Discovery(_) = cred.wrapped {
120 } else {
121 panic!("Credential #{} was not supposed to be cached", i);
122 }
123 }
124 }
125 }
126
127 mod coverage_gaming {
128 use crate::credential::MetadataDecryptionError;
129 use alloc::format;
130
131 #[test]
metadata_decryption_error_debug()132 fn metadata_decryption_error_debug() {
133 let err = MetadataDecryptionError;
134 let _ = format!("{:?}", err);
135 }
136 }
137