update_invite.rs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*! A module for the protocol for a user to request the issuing of an updated
  2. * invitation credential after a key rotation has occurred
  3. The user presents their current Invitation credential:
  4. - id: revealed
  5. - date: blinded
  6. - bucket: blinded
  7. - blockages: blinded
  8. and a new Invitation credential to be issued:
  9. - id: jointly chosen by the user and BA
  10. - date: blinded, but proved in ZK that it's the same as in the invitation
  11. date above
  12. - bucket: blinded, but proved in ZK that it's the same as in the Invitation
  13. credential above
  14. - blockages: blinded, but proved in ZK that it's the same as in the
  15. Invitation credential above
  16. */
  17. #[cfg(feature = "bridgeauth")]
  18. use super::super::dup_filter::SeenType;
  19. #[cfg(feature = "bridgeauth")]
  20. use super::super::BridgeAuth;
  21. use super::super::G;
  22. use super::errors::CredentialError;
  23. use crate::lox_creds::Invitation;
  24. use cmz::*;
  25. use group::Group;
  26. use rand::{CryptoRng, RngCore};
  27. use sha2::Sha512;
  28. const SESSION_ID: &[u8] = b"update_invite";
  29. muCMZProtocol! { update_invite,
  30. I: Invitation { inv_id: R, date: H, bucket: H, blockages: H },
  31. N: Invitation { inv_id: J, date: H, bucket: H, blockages: H },
  32. I.date = N.date,
  33. I.bucket = N.bucket,
  34. I.blockages = N.blockages,
  35. }
  36. pub fn request(
  37. rng: &mut (impl CryptoRng + RngCore),
  38. I: Invitation,
  39. new_pubkeys: CMZPubkey<G>,
  40. ) -> Result<(update_invite::Request, update_invite::ClientState), CredentialError> {
  41. cmz_group_init(G::hash_from_bytes::<Sha512>(b"CMZ Generator A"));
  42. let mut N = Invitation::using_pubkey(&new_pubkeys);
  43. N.date = I.date;
  44. N.bucket = I.bucket;
  45. N.blockages = I.blockages;
  46. match update_invite::prepare(&mut *rng, SESSION_ID, &I, N) {
  47. Ok(req_state) => Ok(req_state),
  48. Err(e) => Err(CredentialError::CMZError(e)),
  49. }
  50. }
  51. #[cfg(feature = "bridgeauth")]
  52. impl BridgeAuth {
  53. pub fn handle_update_invite(
  54. &mut self,
  55. old_pub_key: CMZPubkey<G>,
  56. req: update_invite::Request,
  57. ) -> Result<update_invite::Reply, CredentialError> {
  58. let mut rng = rand::thread_rng();
  59. // Both of these must be true and should be true after rotate_lox_keys is called
  60. if self.old_keys.invitation_keys.is_empty() || self.old_filters.invitation_filter.is_empty()
  61. {
  62. return Err(CredentialError::CredentialMismatch);
  63. }
  64. let reqbytes = req.as_bytes();
  65. let recvreq = update_invite::Request::try_from(&reqbytes[..]).unwrap();
  66. match update_invite::handle(
  67. &mut rng,
  68. SESSION_ID,
  69. recvreq,
  70. |I: &mut Invitation, N: &mut Invitation| {
  71. // calling this function will automatically use the most recent old private key for
  72. // verification and the new private key for issuing.
  73. // Recompute the "error factors" using knowledge of our own
  74. // (the issuer's) outdated private key instead of knowledge of the
  75. // hidden attributes
  76. let old_keys = match self
  77. .old_keys
  78. .invitation_keys
  79. .iter()
  80. .find(|x| x.pub_key == old_pub_key)
  81. {
  82. Some(old_keys) => old_keys,
  83. None => return Err(CMZError::RevealAttrMissing("Key", "Mismatch")),
  84. };
  85. let old_priv_key = old_keys.priv_key.clone();
  86. I.set_privkey(&old_priv_key);
  87. N.set_privkey(&self.invitation_priv);
  88. Ok(())
  89. },
  90. |I: &Invitation, _N: &Invitation| {
  91. let index = match self
  92. .old_keys
  93. .invitation_keys
  94. .iter()
  95. .position(|x| x.pub_key == old_pub_key)
  96. {
  97. Some(index) => index,
  98. None => return Err(CMZError::RevealAttrMissing("Key", "Mismatch")),
  99. };
  100. if self
  101. .old_filters
  102. .invitation_filter
  103. .get_mut(index)
  104. .unwrap()
  105. .filter(&I.inv_id.unwrap())
  106. == SeenType::Seen
  107. {
  108. return Err(CMZError::RevealAttrMissing("id", "Credential Expired"));
  109. }
  110. Ok(())
  111. },
  112. ) {
  113. Ok((response, (_I_issuer, _N_issuer))) => Ok(response),
  114. Err(e) => Err(CredentialError::CMZError(e)),
  115. }
  116. }
  117. }
  118. pub fn handle_response(
  119. state: update_invite::ClientState,
  120. rep: update_invite::Reply,
  121. ) -> Result<Invitation, CMZError> {
  122. let replybytes = rep.as_bytes();
  123. let recvreply = update_invite::Reply::try_from(&replybytes[..]).unwrap();
  124. match state.finalize(recvreply) {
  125. Ok(cred) => Ok(cred),
  126. Err(_e) => Err(CMZError::Unknown),
  127. }
  128. }
  129. #[cfg(all(test, feature = "bridgeauth"))]
  130. mod tests {
  131. use crate::mock_auth::TestHarness;
  132. use crate::proto::update_invite;
  133. #[test]
  134. fn test_update_invite() {
  135. let mut th = TestHarness::new();
  136. let rng = &mut rand::thread_rng();
  137. let invite = th.bdb.invite().unwrap();
  138. let mut lox_cred = th.open_invite(rng, &invite);
  139. let mig_cred = th.trust_promotion(rng, lox_cred.clone());
  140. lox_cred = th.migration(rng, lox_cred.clone(), mig_cred.clone());
  141. lox_cred = th.level_up(rng, lox_cred.clone());
  142. let issue_invite_cred = th.issue_invite(rng, lox_cred.clone());
  143. let old_pub = th.ba.invitation_pub.clone();
  144. th.ba.rotate_invitation_keys(rng);
  145. let update_invite_request = update_invite::request(
  146. rng,
  147. issue_invite_cred.clone().0,
  148. th.ba.invitation_pub.clone(),
  149. );
  150. assert!(
  151. update_invite_request.is_ok(),
  152. "Update invitation request should succeed"
  153. );
  154. let (request, client_state) = update_invite_request.unwrap();
  155. let update_invite_response = th.ba.handle_update_invite(old_pub, request);
  156. assert!(
  157. update_invite_response.is_ok(),
  158. "Update invite response from server should succeed"
  159. );
  160. let response = update_invite_response.unwrap();
  161. let creds = update_invite::handle_response(client_state, response);
  162. assert!(creds.is_ok(), "Handle response should succeed");
  163. th.verify_invitation(&creds.unwrap());
  164. }
  165. }