#[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};
#[cfg(feature = "bridgeauth")]
use crate::migration_table::WNAF_SIZE;
use crate::migration_table::{self, EncMigrationTable};
use cmz::*;
use group::Group;
#[cfg(feature = "bridgeauth")]
use group::WnafBase;
use rand::{CryptoRng, RngCore};
use serde_with::serde_as;
use sha2::Sha512;
pub const MIN_TRUST_LEVEL: u32 = 3;
const SESSION_ID: &[u8] = b"check_blockage";
muCMZProtocol! { check_blockage,
L: Lox { id: R, bucket: H, trust_level: R, level_since: H, invites_remaining: H, blockages: H },
M: MigrationKey { lox_id: R, from_bucket: H},
M.lox_id = L.id,
M.from_bucket = L.bucket,
}
pub fn request(
rng: &mut (impl CryptoRng + RngCore),
L: Lox,
migkey_pubkeys: CMZPubkey<G>,
) -> Result<(check_blockage::Request, check_blockage::ClientState), CredentialError> {
cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
if L.id.is_none() {
return Err(CredentialError::CredentialMismatch);
}
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 !(MIN_TRUST_LEVEL..=MAX_LEVEL as u32).contains(&level) {
return Err(CredentialError::InvalidField(
String::from("trust_level"),
format!("level {:?} not in range", level),
));
}
}
let mut M = MigrationKey::using_pubkey(&migkey_pubkeys);
M.lox_id = L.id;
M.from_bucket = L.bucket;
match check_blockage::prepare(rng, SESSION_ID, &L, M) {
Ok(req_state) => Ok(req_state),
Err(e) => Err(CredentialError::CMZError(e)),
}
}
#[allow(clippy::type_complexity)]
#[cfg(feature = "bridgeauth")]
impl BridgeAuth {
pub fn handle_check_blockage(
&mut self,
req: check_blockage::Request,
) -> Result<(check_blockage::Reply, EncMigrationTable), 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,
SESSION_ID,
recvreq,
|L: &mut Lox, M: &mut MigrationKey| {
if let Some(tl) = L.trust_level {
let level: u32 = match scalar_u32(&tl) {
Some(v) => v,
None => {
return Err(CMZError::RevealAttrMissing(
"trust_level",
"could not be converted to u32",
))
}
};
if !(MIN_TRUST_LEVEL..=MAX_LEVEL as u32).contains(&level) {
return Err(CMZError::RevealAttrMissing(
"trust_level",
"level not in range",
));
}
};
L.set_privkey(&self.lox_priv);
M.set_privkey(&self.migrationkey_priv);
Ok(())
},
|L: &Lox, _M: &MigrationKey| {
if self.id_filter.check(&L.id.unwrap()) == SeenType::Seen {
return Err(CMZError::RevealAttrMissing("id", "Credential Expired"));
}
Ok(())
},
) {
Ok((response, (L_issuer, M_issuer))) => {
let Pktable: WnafBase<G, WNAF_SIZE> = WnafBase::new(M_issuer.MAC.P);
let enc_migration_table = EncMigrationTable {
mig_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<G>,
state: check_blockage::ClientState,
rep: check_blockage::Reply,
enc_migration_table: EncMigrationTable,
) -> Result<Migration, CMZError> {
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.mig_table,
) {
Some(cred) => Ok(cred),
None => Err(CMZError::Unknown),
}
}
#[cfg(all(test, feature = "bridgeauth"))]
mod tests {
use crate::mock_auth::TestHarness;
#[test]
fn test_check_blockage() {
let mut th = TestHarness::new();
let rng = &mut rand::thread_rng();
let invite = th.bdb.invite().unwrap();
let mut lox_cred = th.open_invite(rng, &invite);
let mut mig_cred = th.trust_promotion(rng, lox_cred.clone());
lox_cred = th.migration(rng, lox_cred.clone(), mig_cred.clone());
let lox_cred_1 = th.level_up(rng, lox_cred.clone());
let lox_cred_2 = th.level_up(rng, lox_cred_1.clone());
let lox_cred_3 = th.level_up(rng, lox_cred_2.clone());
th.block_bridges(lox_cred_3.clone());
mig_cred = th.check_blockage(rng, lox_cred_3.clone());
th.verify_migration(&mig_cred);
}
}