mod aes_gcm_gmac;
mod builtin_key;
mod crypto_key_exchange;
mod crypto_key_factory;
mod crypto_transform;
mod encode;
mod key_material;
pub(crate) mod types;
mod validate_receiver_specific_macs;
use std::collections::{HashMap, HashSet};
use crate::{
create_security_error_and_log,
security::{
access_control::types::*,
authentication::types::*,
cryptographic::{cryptographic_builtin::types::*, cryptographic_plugin::*, types::*},
types::*,
},
};
use self::{builtin_key::*, key_material::*};
pub struct CryptographicBuiltin {
common_encode_key_materials: HashMap<CryptoHandle, CommonEncodeKeyMaterials>,
receiver_specific_encode_key_materials: HashMap<CryptoHandle, KeyMaterial_AES_GCM_GMAC_seq>,
decode_key_materials: HashMap<CryptoHandle, KeyMaterial_AES_GCM_GMAC_seq>,
participant_encrypt_options: HashMap<ParticipantCryptoHandle, ParticipantSecurityAttributes>,
endpoint_encrypt_options: HashMap<EndpointCryptoHandle, EndpointSecurityAttributes>,
participant_to_endpoint_info: HashMap<ParticipantCryptoHandle, HashSet<EndpointInfo>>,
endpoint_to_participant: HashMap<EndpointCryptoHandle, ParticipantCryptoHandle>,
used_local_key_ids: HashSet<CryptoTransformKeyId>,
matched_remote_endpoint:
HashMap<EndpointCryptoHandle, HashMap<ParticipantCryptoHandle, EndpointCryptoHandle>>,
matched_local_endpoint: HashMap<EndpointCryptoHandle, EndpointCryptoHandle>,
crypto_handle_counter: u32,
}
impl super::Cryptographic for CryptographicBuiltin {}
impl CryptographicBuiltin {
pub fn new() -> Self {
CryptographicBuiltin {
common_encode_key_materials: HashMap::new(),
receiver_specific_encode_key_materials: HashMap::new(),
decode_key_materials: HashMap::new(),
participant_encrypt_options: HashMap::new(),
endpoint_encrypt_options: HashMap::new(),
participant_to_endpoint_info: HashMap::new(),
endpoint_to_participant: HashMap::new(),
used_local_key_ids: HashSet::from([CryptoTransformKeyId::ZERO]),
matched_remote_endpoint: HashMap::new(),
matched_local_endpoint: HashMap::new(),
crypto_handle_counter: 0,
}
}
fn insert_common_encode_key_materials(
&mut self,
local_entity_crypto_handle: CryptoHandle,
key_materials: CommonEncodeKeyMaterials,
) -> SecurityResult<()> {
match self
.common_encode_key_materials
.insert(local_entity_crypto_handle, key_materials)
{
None => SecurityResult::Ok(()),
Some(old_key_materials) => {
self
.common_encode_key_materials
.insert(local_entity_crypto_handle, old_key_materials);
SecurityResult::Err(create_security_error_and_log!(
"The CryptoHandle {} was already associated with common encode key materials",
local_entity_crypto_handle
))
}
}
}
fn get_common_encode_key_materials(
&self,
local_entity_crypto_handle: &CryptoHandle,
) -> SecurityResult<&CommonEncodeKeyMaterials> {
self
.common_encode_key_materials
.get(local_entity_crypto_handle)
.ok_or_else(|| {
create_security_error_and_log!(
"Could not find common encode key materials for the CryptoHandle {}",
local_entity_crypto_handle
)
})
}
fn insert_receiver_specific_encode_key_materials(
&mut self,
remote_entity_crypto_handle: CryptoHandle,
key_materials: KeyMaterial_AES_GCM_GMAC_seq,
) -> SecurityResult<()> {
match self
.receiver_specific_encode_key_materials
.insert(remote_entity_crypto_handle, key_materials)
{
None => SecurityResult::Ok(()),
Some(old_key_materials) => {
self
.receiver_specific_encode_key_materials
.insert(remote_entity_crypto_handle, old_key_materials);
SecurityResult::Err(create_security_error_and_log!(
"The CryptoHandle {} was already associated with receiver-specific encode key materials",
remote_entity_crypto_handle
))
}
}
}
fn get_receiver_specific_encode_key_materials(
&self,
remote_entity_crypto_handle: &CryptoHandle,
) -> SecurityResult<&KeyMaterial_AES_GCM_GMAC_seq> {
self
.receiver_specific_encode_key_materials
.get(remote_entity_crypto_handle)
.ok_or_else(|| {
create_security_error_and_log!(
"Could not find receiver-specific encode key materials for the CryptoHandle {}",
remote_entity_crypto_handle
)
})
}
fn insert_decode_key_materials(
&mut self,
remote_entity_crypto_handle: CryptoHandle,
key_materials: KeyMaterial_AES_GCM_GMAC_seq,
) -> SecurityResult<()> {
match self
.decode_key_materials
.insert(remote_entity_crypto_handle, key_materials)
{
None => SecurityResult::Ok(()),
Some(old_key_materials) => {
self
.decode_key_materials
.insert(remote_entity_crypto_handle, old_key_materials);
SecurityResult::Err(create_security_error_and_log!(
"The CryptoHandle {} was already associated with decode key material",
remote_entity_crypto_handle
))
}
}
}
fn get_decode_key_material(
&self,
remote_entity_crypto_handle: CryptoHandle,
key_id: CryptoTransformKeyId,
key_material_scope: KeyMaterialScope,
) -> Option<&KeyMaterial_AES_GCM_GMAC> {
self
.decode_key_materials
.get(&remote_entity_crypto_handle)
.map(|key_materials| key_materials.select(key_material_scope))
.filter(|KeyMaterial_AES_GCM_GMAC { sender_key_id, .. }| sender_key_id.eq(&key_id))
}
fn insert_endpoint_info(
&mut self,
participant_crypto_handle: ParticipantCryptoHandle,
endpoint_info: EndpointInfo,
) {
match self
.participant_to_endpoint_info
.get_mut(&participant_crypto_handle)
{
Some(endpoint_set) => {
endpoint_set.insert(endpoint_info);
}
None => {
self
.participant_to_endpoint_info
.insert(participant_crypto_handle, HashSet::from([endpoint_info]));
}
};
}
fn insert_participant_attributes(
&mut self,
participant_crypto_handle: ParticipantCryptoHandle,
attributes: ParticipantSecurityAttributes,
) -> SecurityResult<()> {
match self
.participant_encrypt_options
.insert(participant_crypto_handle, attributes)
{
None => SecurityResult::Ok(()),
Some(old_attributes) => {
self
.participant_encrypt_options
.insert(participant_crypto_handle, old_attributes);
SecurityResult::Err(create_security_error_and_log!(
"The ParticipantCryptoHandle {} was already associated with security attributes",
participant_crypto_handle
))
}
}
}
fn insert_endpoint_attributes(
&mut self,
endpoint_crypto_handle: EndpointCryptoHandle,
attributes: EndpointSecurityAttributes,
) -> SecurityResult<()> {
match self
.endpoint_encrypt_options
.insert(endpoint_crypto_handle, attributes)
{
None => SecurityResult::Ok(()),
Some(old_attributes) => {
self
.endpoint_encrypt_options
.insert(endpoint_crypto_handle, old_attributes);
SecurityResult::Err(create_security_error_and_log!(
"The EndpointCryptoHandle {} was already associated with security attributes",
endpoint_crypto_handle
))
}
}
}
fn session_id(&self) -> SessionId {
SessionId::new([1, 3, 3, 7])
}
fn random_initialization_vector(&self) -> BuiltinInitializationVector {
BuiltinInitializationVector::new(self.session_id(), rand::random())
}
fn compute_session_key(
rec_spec: ReceiverSpecific,
master_key: &BuiltinKey,
master_salt: &BuiltinKey,
iv: BuiltinInitializationVector,
) -> BuiltinKey {
if let BuiltinKey::None = master_key {
return BuiltinKey::None;
}
use ring::hmac;
let magic_prefix = match rec_spec {
ReceiverSpecific::No => b"SessionKey".as_ref(),
ReceiverSpecific::Yes => b"SessionReceiverKey".as_ref(),
};
let ring_master_key = hmac::Key::new(hmac::HMAC_SHA256, master_key.as_bytes());
let digest = hmac::sign(
&ring_master_key,
&[
magic_prefix,
master_salt.as_bytes(),
iv.session_id().as_bytes(),
]
.concat(),
);
BuiltinKey::from_bytes(master_key.key_length(), digest.as_ref()).unwrap()
}
fn session_encoding_materials(
&self,
sending_local_entity_crypto_handle: CryptoHandle,
key_material_scope: KeyMaterialScope,
receiving_remote_entity_crypto_handles: &[CryptoHandle],
) -> SecurityResult<EncodeSessionMaterials> {
let common_encode_key_materials =
self.get_common_encode_key_materials(&sending_local_entity_crypto_handle)?;
let common_encode_key_material = match common_encode_key_materials {
CommonEncodeKeyMaterials::Some(common_encode_key_materials) => common_encode_key_materials,
CommonEncodeKeyMaterials::Volatile(_) => {
if let [receiving_remote_volatile_endpoint_crypto_handle] =
receiving_remote_entity_crypto_handles
{
self.get_receiver_specific_encode_key_materials(
receiving_remote_volatile_endpoint_crypto_handle,
)
} else {
Err(create_security_error_and_log!(
"For volatile local endpoint, expected exactly one remote endpoint handle."
))
}?
}
}
.select(key_material_scope);
let KeyMaterial_AES_GCM_GMAC {
transformation_kind,
master_salt,
sender_key_id,
master_sender_key,
..
} = common_encode_key_material;
let transformation_kind = *transformation_kind;
let initialization_vector = self.random_initialization_vector();
let session_key = Self::compute_session_key(
ReceiverSpecific::No,
master_sender_key,
master_salt,
initialization_vector,
);
let receiver_specific_keys = SecurityResult::<Vec<ReceiverSpecificKeyMaterial>>::from_iter(
receiving_remote_entity_crypto_handles
.iter()
.filter_map(|receiver_crypto_handle| {
self
.get_receiver_specific_encode_key_materials(receiver_crypto_handle)
.map(|m| m.select(key_material_scope))
.and_then(|receiver_key_material| {
receiver_key_material.receiver_key_material_for(common_encode_key_material)
})
.map(|ReceiverSpecificKeyMaterial { key_id, key }| {
if key_id.is_zero() {
None
} else {
let session_key = Self::compute_session_key(
ReceiverSpecific::Yes,
&key,
master_salt,
initialization_vector,
);
Some(ReceiverSpecificKeyMaterial {
key_id,
key: session_key,
})
}
})
.transpose()
}),
)?;
Ok(EncodeSessionMaterials {
key_id: *sender_key_id,
transformation_kind,
session_key,
initialization_vector,
receiver_specific_keys,
})
}
fn session_decode_crypto_materials(
&self,
remote_sender_handle: CryptoHandle,
header_key_id: CryptoTransformKeyId, key_material_scope: KeyMaterialScope,
initialization_vector: BuiltinInitializationVector, ) -> SecurityResult<DecodeSessionMaterials> {
self
.get_session_decode_crypto_materials(
remote_sender_handle,
header_key_id,
key_material_scope,
initialization_vector,
)
.ok_or_else(|| {
create_security_error_and_log!(
"Could not find decode key materials for the CryptoHandle {}",
remote_sender_handle
)
})
}
fn get_session_decode_crypto_materials(
&self,
remote_sender_handle: CryptoHandle,
header_key_id: CryptoTransformKeyId, key_material_scope: KeyMaterialScope,
initialization_vector: BuiltinInitializationVector, ) -> Option<DecodeSessionMaterials> {
let KeyMaterial_AES_GCM_GMAC {
transformation_kind,
master_salt,
sender_key_id,
master_sender_key,
receiver_specific_key_id,
master_receiver_specific_key,
} = self.get_decode_key_material(remote_sender_handle, header_key_id, key_material_scope)?;
let transformation_kind = *transformation_kind;
let session_key = Self::compute_session_key(
ReceiverSpecific::No,
master_sender_key,
master_salt,
initialization_vector,
);
let receiver_specific_key = if receiver_specific_key_id.is_zero() {
None } else {
let session_key = Self::compute_session_key(
ReceiverSpecific::Yes,
master_receiver_specific_key,
master_salt,
initialization_vector,
);
Some(ReceiverSpecificKeyMaterial {
key_id: *receiver_specific_key_id,
key: session_key,
})
};
Some(DecodeSessionMaterials {
key_id: *sender_key_id,
transformation_kind,
session_key,
receiver_specific_key,
})
}
}
struct EncodeSessionMaterials {
key_id: CryptoTransformKeyId, transformation_kind: BuiltinCryptoTransformationKind, session_key: BuiltinKey, initialization_vector: BuiltinInitializationVector,
receiver_specific_keys: Vec<ReceiverSpecificKeyMaterial>,
}
struct DecodeSessionMaterials {
key_id: CryptoTransformKeyId, transformation_kind: BuiltinCryptoTransformationKind, session_key: BuiltinKey, receiver_specific_key: Option<ReceiverSpecificKeyMaterial>,
}