| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*! A module for the protocol for a user to request the issuing of an updated
- * invitation credential after a key rotation has occurred
- The user presents their current Invitation credential:
- - id: revealed
- - date: blinded
- - bucket: blinded
- - blockages: blinded
- and a new Invitation credential to be issued:
- - id: jointly chosen by the user and BA
- - date: blinded, but proved in ZK that it's the same as in the invitation
- date above
- - bucket: blinded, but proved in ZK that it's the same as in the Invitation
- credential above
- - blockages: blinded, but proved in ZK that it's the same as in the
- Invitation credential above
- */
- #[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::Invitation;
- use cmz::*;
- use group::Group;
- use rand::{CryptoRng, RngCore};
- use sha2::Sha512;
- const SESSION_ID: &[u8] = b"update_invite";
- muCMZProtocol! { update_invite,
- I: Invitation { inv_id: R, date: H, bucket: H, blockages: H },
- N: Invitation { inv_id: J, date: H, bucket: H, blockages: H },
- I.date = N.date,
- I.bucket = N.bucket,
- I.blockages = N.blockages,
- }
- pub fn request(
- rng: &mut (impl CryptoRng + RngCore),
- I: Invitation,
- new_pubkeys: CMZPubkey<G>,
- ) -> Result<(update_invite::Request, update_invite::ClientState), CredentialError> {
- cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
- let mut N = Invitation::using_pubkey(&new_pubkeys);
- N.date = I.date;
- N.bucket = I.bucket;
- N.blockages = I.blockages;
- match update_invite::prepare(&mut *rng, SESSION_ID, &I, N) {
- Ok(req_state) => Ok(req_state),
- Err(e) => Err(CredentialError::CMZError(e)),
- }
- }
- #[cfg(feature = "bridgeauth")]
- impl BridgeAuth {
- pub fn handle_update_invite(
- &mut self,
- old_pub_key: CMZPubkey<G>,
- req: update_invite::Request,
- ) -> Result<update_invite::Reply, CredentialError> {
- let mut rng = rand::thread_rng();
- // Both of these must be true and should be true after rotate_lox_keys is called
- if self.old_keys.invitation_keys.is_empty() || self.old_filters.invitation_filter.is_empty()
- {
- return Err(CredentialError::CredentialMismatch);
- }
- let reqbytes = req.as_bytes();
- let recvreq = update_invite::Request::try_from(&reqbytes[..]).unwrap();
- match update_invite::handle(
- &mut rng,
- SESSION_ID,
- recvreq,
- |I: &mut Invitation, N: &mut Invitation| {
- // calling this function will automatically use the most recent old private key for
- // verification and the new private key for issuing.
- // Recompute the "error factors" using knowledge of our own
- // (the issuer's) outdated private key instead of knowledge of the
- // hidden attributes
- let old_keys = match self
- .old_keys
- .invitation_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();
- I.set_privkey(&old_priv_key);
- N.set_privkey(&self.invitation_priv);
- Ok(())
- },
- |I: &Invitation, _N: &Invitation| {
- let index = match self
- .old_keys
- .invitation_keys
- .iter()
- .position(|x| x.pub_key == old_pub_key)
- {
- Some(index) => index,
- None => return Err(CMZError::RevealAttrMissing("Key", "Mismatch")),
- };
- if self
- .old_filters
- .invitation_filter
- .get_mut(index)
- .unwrap()
- .filter(&I.inv_id.unwrap())
- == SeenType::Seen
- {
- return Err(CMZError::RevealAttrMissing("id", "Credential Expired"));
- }
- Ok(())
- },
- ) {
- Ok((response, (_I_issuer, _N_issuer))) => Ok(response),
- Err(e) => Err(CredentialError::CMZError(e)),
- }
- }
- }
- pub fn handle_response(
- state: update_invite::ClientState,
- rep: update_invite::Reply,
- ) -> Result<Invitation, CMZError> {
- let replybytes = rep.as_bytes();
- let recvreply = update_invite::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_invite;
- #[test]
- fn test_update_invite() {
- 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 mig_cred = th.trust_promotion(rng, lox_cred.clone());
- lox_cred = th.migration(rng, lox_cred.clone(), mig_cred.clone());
- lox_cred = th.level_up(rng, lox_cred.clone());
- let issue_invite_cred = th.issue_invite(rng, lox_cred.clone());
- let old_pub = th.ba.invitation_pub.clone();
- th.ba.rotate_invitation_keys(rng);
- let update_invite_request = update_invite::request(
- rng,
- issue_invite_cred.clone().0,
- th.ba.invitation_pub.clone(),
- );
- assert!(
- update_invite_request.is_ok(),
- "Update invitation request should succeed"
- );
- let (request, client_state) = update_invite_request.unwrap();
- let update_invite_response = th.ba.handle_update_invite(old_pub, request);
- assert!(
- update_invite_response.is_ok(),
- "Update invite response from server should succeed"
- );
- let response = update_invite_response.unwrap();
- let creds = update_invite::handle_response(client_state, response);
- assert!(creds.is_ok(), "Handle response should succeed");
- th.verify_invitation(&creds.unwrap());
- }
- }
|