#[cfg(feature = "bridgeauth")]
use super::super::dup_filter::SeenType;
#[cfg(feature = "bridgeauth")]
use super::super::BridgeAuth;
use super::super::G;
use super::errors::CredentialError;
use crate::lox_creds::Lox;
use cmz::*;
use group::Group;
use rand::{CryptoRng, RngCore};
use sha2::Sha512;
const SESSION_ID: &[u8] = b"update_cred";
muCMZProtocol! { update_cred,
L: Lox { id: R, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H },
N: Lox {id: J, bucket: H, trust_level: H, level_since: H, invites_remaining: H, blockages: H },
N.bucket = L.bucket,
N.trust_level = L.trust_level,
N.level_since = L.level_since,
N.invites_remaining = L.invites_remaining,
N.blockages = L.blockages,
}
pub fn request(
rng: &mut (impl CryptoRng + RngCore),
L: Lox,
pubkeys: CMZPubkey<G>,
) -> Result<(update_cred::Request, update_cred::ClientState), CredentialError> {
cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
let mut N: Lox = Lox::using_pubkey(&pubkeys);
N.bucket = L.bucket;
N.trust_level = L.trust_level;
N.level_since = L.level_since;
N.invites_remaining = L.invites_remaining;
N.blockages = L.blockages;
match update_cred::prepare(&mut *rng, SESSION_ID, &L, N) {
Ok(req_state) => Ok(req_state),
Err(e) => Err(CredentialError::CMZError(e)),
}
}
#[cfg(feature = "bridgeauth")]
impl BridgeAuth {
pub fn handle_update_cred(
&mut self,
old_pub_key: CMZPubkey<G>,
req: update_cred::Request,
) -> Result<update_cred::Reply, CredentialError> {
let mut rng = rand::thread_rng();
if self.old_keys.lox_keys.is_empty() || self.old_filters.lox_filter.is_empty() {
return Err(CredentialError::CredentialMismatch);
}
let reqbytes = req.as_bytes();
let recvreq = update_cred::Request::try_from(&reqbytes[..]).unwrap();
match update_cred::handle(
&mut rng,
SESSION_ID,
recvreq,
|L: &mut Lox, N: &mut Lox| {
let old_keys = match self
.old_keys
.lox_keys
.iter()
.find(|x| x.pub_key == old_pub_key)
{
Some(old_keys) => old_keys,
None => {
return Err(CMZError::RevealAttrMissing("Key", "Mismatch"));
}
};
let old_priv_key = old_keys.priv_key.clone();
L.set_privkey(&old_priv_key);
N.set_privkey(&self.lox_priv);
Ok(())
},
|L: &Lox, _N: &Lox| {
let index = match self
.old_keys
.lox_keys
.iter()
.position(|x| x.pub_key == old_pub_key)
{
Some(index) => index,
None => return Err(CMZError::RevealAttrMissing("Key", "Mismatch")),
};
if self
.old_filters
.lox_filter
.get_mut(index)
.unwrap()
.filter(&L.id.unwrap())
== SeenType::Seen
{
return Err(CMZError::RevealAttrMissing("id", "Credential Expired"));
}
Ok(())
},
) {
Ok((response, (_L_issuer, _N_issuer))) => Ok(response),
Err(e) => Err(CredentialError::CMZError(e)),
}
}
}
pub fn handle_response(
state: update_cred::ClientState,
rep: update_cred::Reply,
) -> Result<Lox, CMZError> {
let replybytes = rep.as_bytes();
let recvreply = update_cred::Reply::try_from(&replybytes[..]).unwrap();
match state.finalize(recvreply) {
Ok(cred) => Ok(cred),
Err(_e) => Err(CMZError::Unknown),
}
}
#[cfg(all(test, feature = "bridgeauth"))]
mod tests {
use crate::mock_auth::TestHarness;
use crate::proto::update_cred;
#[test]
fn test_update_cred() {
let mut th = TestHarness::new();
let rng = &mut rand::thread_rng();
let invite = th.bdb.invite().unwrap();
let lox_cred = th.open_invite(rng, &invite);
let old_pub = th.ba.lox_pub.clone();
th.ba.rotate_lox_keys(rng);
let update_cred_request =
update_cred::request(rng, lox_cred.clone(), th.ba.lox_pub.clone());
assert!(
update_cred_request.is_ok(),
"Update credential request should succeed"
);
let (request, client_state) = update_cred_request.unwrap();
let update_cred_response = th.ba.handle_update_cred(old_pub, request);
assert!(
update_cred_response.is_ok(),
"Update cred response from server should succeed"
);
let response = update_cred_response.unwrap();
let creds = update_cred::handle_response(client_state, response);
assert!(creds.is_ok(), "Handle response should succeed");
th.verify_lox(&creds.unwrap());
}
}