blob: 297fdb58748fbd58dad81c309201ac0c62d8910d [file] [log] [blame]
// 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.
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))
}