/*! A module for the protocol for the user to check for the availability of a migration credential they can use in order to move to a new bucket if theirs has been blocked. The user presents their current Lox credential: - id: revealed - bucket: blinded - trust_level: revealed to be 3 or above - level_since: blinded - invites_remaining: blinded - blockages: blinded They are allowed to to this as long as they are level 3 or above. If they have too many blockages (but are level 3 or above), they will be allowed to perform this migration, but will not be able to advance to level 3 in their new bucket, so this will be their last allowed migration without rejoining the system either with a new invitation or an open invitation. They will receive in return the encrypted MAC (Pk, EncQk) for their implicit Migration Key credential with attributes id and bucket, along with a HashMap of encrypted Migration credentials. For each (from_i, to_i) in the BA's migration list, there will be an entry in the HashMap with key H1(id, from_attr_i, Qk_i) and value Enc_{H2(id, from_attr_i, Qk_i)}(to_attr_i, P_i, Q_i). Here H1 and H2 are the first 16 bytes and the second 16 bytes respectively of the SHA256 hash of the input, P_i and Q_i are a MAC on the Migration credential with attributes id, from_attr_i, and to_attr_i. Qk_i is the value EncQk would decrypt to if bucket were equal to from_attr_i. */ #[cfg(feature = "bridgeauth")] use super::super::dup_filter::SeenType; #[cfg(feature = "bridgeauth")] use super::super::BridgeAuth; use super::super::{scalar_u32, G}; use super::errors::CredentialError; use super::level_up::MAX_LEVEL; use crate::lox_creds::{Lox, Migration, MigrationKey}; use crate::migration_table; use crate::migration_table::ENC_MIGRATION_BYTES; #[cfg(feature = "bridgeauth")] use crate::migration_table::WNAF_SIZE; use cmz::*; use group::Group; #[cfg(feature = "bridgeauth")] use group::WnafBase; use rand::{CryptoRng, RngCore}; use sha2::Sha512; use std::collections::HashMap; /// The minimum trust level a Lox credential must have to be allowed to /// perform this protocol. pub const MIN_TRUST_LEVEL: u32 = 3; muCMZProtocol! { check_blockage, L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: R, blockages: R }, M: MigrationKey { lox_id: J, from_bucket: H} , L.bucket = M.from_bucket, [min_trust_level..max_trust_leve].contains(L.trust_level), } pub fn request( L: Lox, mig_pubkeys: CMZPubkey, ) -> Result<(check_blockage::Request, check_blockage::ClientState), CredentialError> { let mut rng = rand::thread_rng(); cmz_group_init(G::hash_from_bytes::(b"CMZ Generator A")); // Ensure that the credenials can be correctly shown; that is, the // ids match and the Lox credential bucket matches the Migration // credential from_bucket if L.id.is_none() { return Err(CredentialError::CredentialMismatch); } // Ensure the credential can be correctly shown: it must be the case // that trust_level >= MIN_TRUST_LEVEL if let Some(tl) = L.trust_level { let level: u32 = match scalar_u32(&tl) { Some(v) => v, None => { return Err(CredentialError::InvalidField( String::from("trust_level"), String::from("could not be converted to u32"), )) } }; if level < MIN_TRUST_LEVEL { return Err(CredentialError::InvalidField( String::from("trust_level"), format!("level {:?} not in range", level), )); } } let params = check_blockage::Params { min_trust_level: MIN_TRUST_LEVEL.into(), max_trust_level: (MAX_LEVEL as u32).into(), }; match check_blockage::prepare( &mut rng, &L, MigrationKey::using_pubkey(&mig_pubkeys), ¶ms, ) { Ok(req_state) => Ok(req_state), Err(e) => Err(CredentialError::CMZError(e)), } } #[cfg(feature = "bridgeauth")] impl BridgeAuth { pub fn handle_check_blockage( &mut self, req: check_blockage::Request, ) -> Result< ( check_blockage::Reply, HashMap<[u8; 16], [u8; ENC_MIGRATION_BYTES]>, ), CredentialError, > { let mut rng = rand::thread_rng(); let reqbytes = req.as_bytes(); let recvreq = check_blockage::Request::try_from(&reqbytes[..]).unwrap(); match check_blockage::handle( &mut rng, recvreq, |L: &mut Lox, M: &mut MigrationKey| { L.set_privkey(&self.lox_priv); M.set_privkey(&self.migrationkey_priv); M.lox_id = L.id; M.from_bucket = L.bucket; Ok(check_blockage::Params { min_trust_level: MIN_TRUST_LEVEL.into(), max_trust_level: (MAX_LEVEL as u32).into(), }) }, |L: &Lox, _M: &MigrationKey| { if self.id_filter.filter(&L.id.unwrap()) == SeenType::Seen { return Err(CMZError::RevealAttrMissing("id", "Credential Expired")); } Ok(()) }, ) { Ok((response, (L_issuer, M_issuer))) => { let Pktable: WnafBase = WnafBase::new(M_issuer.MAC.P); let enc_migration_table = self.blockage_migration_table.encrypt_table( L_issuer.id.unwrap(), &self.bridge_table, &Pktable, &self.migration_priv, &self.migrationkey_priv, ); Ok((response, enc_migration_table)) } Err(e) => Err(CredentialError::CMZError(e)), } } } pub fn handle_response( migration_pubkey: CMZPubkey, state: check_blockage::ClientState, rep: check_blockage::Reply, enc_migration_table: HashMap<[u8; 16], [u8; ENC_MIGRATION_BYTES]>, ) -> Result { let replybytes = rep.as_bytes(); let recvreply = check_blockage::Reply::try_from(&replybytes[..]).unwrap(); let migkey = match state.finalize(recvreply) { Ok(cred) => cred, Err(_e) => return Err(CMZError::Unknown), }; match migration_table::decrypt_cred( migkey, migration_table::MigrationType::Blockage, migration_pubkey, &enc_migration_table, ) { Some(cred) => Ok(cred), None => Err(CMZError::Unknown), } }