|
|
@@ -0,0 +1,142 @@
|
|
|
+/*! A module for the protocol for a user to request the issuing of an updated credential after a key rotation has occurred
|
|
|
+
|
|
|
+
|
|
|
+They are allowed to do this as long as their current Lox credential is valid
|
|
|
+
|
|
|
+The user presents their current Lox credential:
|
|
|
+- id: revealed
|
|
|
+- bucket: blinded
|
|
|
+- trust_level: blinded
|
|
|
+- level_since: blinded
|
|
|
+- invites_remaining: blinded
|
|
|
+- blockages: blinded
|
|
|
+
|
|
|
+and a new Lox credential to be issued:
|
|
|
+- id: jointly chosen by the user and BA
|
|
|
+- bucket: blinded, but proved in ZK that it's the same as in the Lox
|
|
|
+ credential above
|
|
|
+- trust_level: blinded, but proved in ZK that it's the same as in the
|
|
|
+ Lox credential above
|
|
|
+- level_since: blinded, but proved in ZK that it's the same as in the
|
|
|
+ Lox credential above
|
|
|
+- invites_remaining: blinded, but proved in ZK that it's the same as in the Lox credential above
|
|
|
+- blockages: blinded, but proved in ZK that it's the same as in the
|
|
|
+ Lox credential above
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+#[cfg(feature = "bridgeauth")]
|
|
|
+use super::super::dup_filter::SeenType;
|
|
|
+#[cfg(feature = "bridgeauth")]
|
|
|
+use super::super::BridgeAuth;
|
|
|
+use super::errors::CredentialError;
|
|
|
+use crate::lox_creds::Lox;
|
|
|
+use cmz::*;
|
|
|
+use curve25519_dalek::ristretto::RistrettoPoint as G;
|
|
|
+use group::Group;
|
|
|
+use rand_core::RngCore;
|
|
|
+use sha2::Sha512;
|
|
|
+
|
|
|
+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(
|
|
|
+ L: Lox,
|
|
|
+ pubkeys: CMZPubkey<G>,
|
|
|
+) -> Result<(update_cred::Request, update_cred::ClientState), CredentialError> {
|
|
|
+ let mut rng = rand::thread_rng();
|
|
|
+ cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
|
|
|
+
|
|
|
+ let N = Lox::using_pubkey(&pubkeys);
|
|
|
+ match update_cred::prepare(&mut rng, &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,
|
|
|
+ req: update_cred::Request,
|
|
|
+ ) -> Result<update_cred::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.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,
|
|
|
+ recvreq,
|
|
|
+ |L: &mut Lox, N: &mut Lox| {
|
|
|
+ // 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
|
|
|
+ .lox_keys
|
|
|
+ .iter()
|
|
|
+ .find(|x| x.pub_key == *L.get_pubkey())
|
|
|
+ {
|
|
|
+ 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 == *L.get_pubkey())
|
|
|
+ {
|
|
|
+ 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),
|
|
|
+ }
|
|
|
+}
|