mock_auth.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #[cfg(all(test, feature = "bridgeauth"))]
  2. use super::*;
  3. #[cfg(all(test, feature = "bridgeauth"))]
  4. use crate::bridge_table::BridgeLine;
  5. #[cfg(all(test, feature = "bridgeauth"))]
  6. use rand::RngCore;
  7. #[cfg(all(test, feature = "bridgeauth"))]
  8. #[allow(unused_imports)]
  9. use base64::{engine::general_purpose, Engine as _};
  10. #[derive(Default)]
  11. #[cfg(all(test, feature = "bridgeauth"))]
  12. pub struct TestHarness {
  13. pub bdb: BridgeDb,
  14. pub ba: BridgeAuth,
  15. }
  16. #[cfg(all(test, feature = "bridgeauth"))]
  17. impl TestHarness {
  18. pub fn new() -> Self {
  19. TestHarness::new_buckets(5, 5)
  20. }
  21. pub fn new_buckets(num_buckets: u16, hot_spare: u16) -> Self {
  22. // Create a BridegDb
  23. let mut bdb = BridgeDb::new();
  24. let mut rng = rand::thread_rng();
  25. // Create a BridgeAuth
  26. let mut ba = BridgeAuth::new(bdb.pubkey.clone(), &mut rng);
  27. // Make 3 x num_buckets open invitation bridges, in sets of 3
  28. for _ in 0..num_buckets {
  29. let bucket = [random(), random(), random()];
  30. let _ = ba.add_openinv_bridges(bucket, &mut bdb);
  31. }
  32. // Add hot_spare more hot spare buckets
  33. for _ in 0..hot_spare {
  34. let bucket = [random(), random(), random()];
  35. let _ = ba.add_spare_bucket(bucket, &mut bdb);
  36. }
  37. // Create the encrypted bridge table
  38. ba.enc_bridge_table();
  39. Self { bdb, ba }
  40. }
  41. // pub fn advance_days(&mut self, days: u16) {
  42. // self.ba.advance_days(days);
  43. // }
  44. /// Verify the two MACs on a Lox credential
  45. pub fn verify_lox(&self, cred: &lox_creds::Lox) {
  46. assert!(
  47. !bool::from(cred.MAC.P.is_identity()),
  48. "Lox cred MAC P should not be identity"
  49. );
  50. let Q = (self.ba.lox_priv.x0
  51. + self.ba.lox_priv.xr
  52. + cred.id.unwrap() * self.ba.lox_priv.x[0]
  53. + cred.bucket.unwrap() * self.ba.lox_priv.x[1]
  54. + cred.trust_level.unwrap() * self.ba.lox_priv.x[2]
  55. + cred.level_since.unwrap() * self.ba.lox_priv.x[3]
  56. + cred.invites_remaining.unwrap() * self.ba.lox_priv.x[4]
  57. + cred.blockages.unwrap() * self.ba.lox_priv.x[5])
  58. * cred.MAC.P;
  59. assert_eq!(Q, cred.MAC.Q, "Lox MAC Q should match computation");
  60. }
  61. /// Verify the MAC on a Migration credential
  62. pub fn verify_migration(&self, cred: &lox_creds::Migration) {
  63. assert!(
  64. !bool::from(cred.MAC.P.is_identity()),
  65. "Migration cred MAC P should not be identity"
  66. );
  67. let Q = (self.ba.migration_priv.x0
  68. + self.ba.migration_priv.xr
  69. + cred.lox_id.unwrap() * self.ba.migration_priv.x[0]
  70. + cred.from_bucket.unwrap() * self.ba.migration_priv.x[1]
  71. + cred.to_bucket.unwrap() * self.ba.migration_priv.x[2])
  72. * cred.MAC.P;
  73. assert_eq!(Q, cred.MAC.Q, "Migration MAC Q should match computation");
  74. }
  75. /// Verify the MAC on a Bucket Reachability credential
  76. pub fn verify_reachability(&self, cred: &lox_creds::BucketReachability) {
  77. assert!(
  78. !bool::from(cred.MAC.P.is_identity()),
  79. "Reachability cred MAC P should not be identity"
  80. );
  81. let Q = (self.ba.reachability_priv.x0
  82. + self.ba.reachability_priv.xr
  83. + cred.date.unwrap() * self.ba.reachability_priv.x[0]
  84. + cred.bucket.unwrap() * self.ba.reachability_priv.x[1])
  85. * cred.MAC.P;
  86. assert_eq!(Q, cred.MAC.Q, "Reachability MAC Q should match computation");
  87. }
  88. /// Verify the MAC on a Invitation credential
  89. pub fn verify_invitation(&mut self, cred: &lox_creds::Invitation) {
  90. assert!(
  91. !bool::from(cred.MAC.P.is_identity()),
  92. "Invitation MAC P should not be identity"
  93. );
  94. let Q = (self.ba.invitation_priv.x0
  95. + self.ba.invitation_priv.xr
  96. + cred.inv_id.unwrap() * self.ba.invitation_priv.x[0]
  97. + cred.date.unwrap() * self.ba.invitation_priv.x[1]
  98. + cred.bucket.unwrap() * self.ba.invitation_priv.x[2]
  99. + cred.blockages.unwrap() * self.ba.invitation_priv.x[3])
  100. * cred.MAC.P;
  101. assert_eq!(Q, cred.MAC.Q, "Invitation MAC Q should match");
  102. }
  103. }
  104. /// Create a random BridgeLine for testing
  105. #[cfg(all(test, feature = "bridgeauth"))]
  106. pub fn random() -> BridgeLine {
  107. let mut rng = rand::rngs::OsRng;
  108. let mut res: BridgeLine = Default::default();
  109. // Pick a random 4-byte address
  110. let mut addr: [u8; 4] = [0; 4];
  111. rng.fill_bytes(&mut addr);
  112. // If the leading byte is 224 or more, that's not a valid IPv4
  113. // address. Choose an IPv6 address instead (but don't worry too
  114. // much about it being well formed).
  115. if addr[0] >= 224 {
  116. rng.fill_bytes(&mut res.addr);
  117. } else {
  118. // Store an IPv4 address as a v4-mapped IPv6 address
  119. res.addr[10] = 255;
  120. res.addr[11] = 255;
  121. res.addr[12..16].copy_from_slice(&addr);
  122. };
  123. let ports: [u16; 4] = [443, 4433, 8080, 43079];
  124. let portidx = (rng.next_u32() % 4) as usize;
  125. res.port = ports[portidx];
  126. res.uid_fingerprint = rng.next_u64();
  127. let mut cert: [u8; 52] = [0; 52];
  128. rng.fill_bytes(&mut cert);
  129. let infostr: String = format!(
  130. "obfs4 cert={}, iat-mode=0",
  131. general_purpose::STANDARD_NO_PAD.encode(cert)
  132. );
  133. res.info[..infostr.len()].copy_from_slice(infostr.as_bytes());
  134. res
  135. }