From 9c2b7703a8a56d32bdf46846634fde57d26b4189 Mon Sep 17 00:00:00 2001 From: onyinyang Date: Thu, 13 Jul 2023 17:36:40 -0400 Subject: [PATCH] Added open inv cleanup test --- crates/lox-distributor/src/lox_context.rs | 3 +- crates/lox-distributor/src/request_handler.rs | 2 +- crates/lox-library/src/bridge_table.rs | 3 +- crates/lox-library/src/lib.rs | 42 +++++--- crates/lox-library/src/proto/open_invite.rs | 11 +- crates/lox-library/src/tests.rs | 101 ++++++++++++++++-- 6 files changed, 130 insertions(+), 32 deletions(-) diff --git a/crates/lox-distributor/src/lox_context.rs b/crates/lox-distributor/src/lox_context.rs index 0e27e44..9f62f51 100644 --- a/crates/lox-distributor/src/lox_context.rs +++ b/crates/lox-distributor/src/lox_context.rs @@ -65,7 +65,8 @@ impl LoxServerContext { pub fn add_spare_bucket(&self, bucket: [BridgeLine; 3]) { let mut ba_obj = self.ba.lock().unwrap(); - ba_obj.add_spare_bucket(bucket); + let mut db_obj = self.db.lock().unwrap(); + ba_obj.add_spare_bucket(bucket, &mut db_obj); } pub fn replace_with_new(&self, bridgeline: BridgeLine) -> lox_library::ReplaceSuccess { diff --git a/crates/lox-distributor/src/request_handler.rs b/crates/lox-distributor/src/request_handler.rs index 55265f2..39c234d 100644 --- a/crates/lox-distributor/src/request_handler.rs +++ b/crates/lox-distributor/src/request_handler.rs @@ -235,7 +235,7 @@ mod tests { // Add hot_spare more hot spare buckets for _ in 0..5 { let bucket = [random(), random(), random()]; - lox_auth.add_spare_bucket(bucket); + lox_auth.add_spare_bucket(bucket, &mut bridgedb); } // Create the encrypted bridge table lox_auth.enc_bridge_table(); diff --git a/crates/lox-library/src/bridge_table.rs b/crates/lox-library/src/bridge_table.rs index add3f8c..1078618 100644 --- a/crates/lox-library/src/bridge_table.rs +++ b/crates/lox-library/src/bridge_table.rs @@ -290,7 +290,7 @@ impl BridgeTable { // } /// Append a new bucket to the bridge table, returning its index - pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET], index: u32) -> u32 { + pub fn new_bucket(&mut self, bucket: &[BridgeLine; MAX_BRIDGES_PER_BUCKET], index: u32) { // Pick a random key to encrypt this bucket let mut rng = rand::thread_rng(); let mut key: [u8; 16] = [0; 16]; @@ -311,7 +311,6 @@ impl BridgeTable { } } } - self.counter } /// Create the vector of encrypted buckets from the keys and buckets diff --git a/crates/lox-library/src/lib.rs b/crates/lox-library/src/lib.rs index 761431b..3324d32 100644 --- a/crates/lox-library/src/lib.rs +++ b/crates/lox-library/src/lib.rs @@ -300,24 +300,28 @@ impl BridgeAuth { bridges: [BridgeLine; MAX_BRIDGES_PER_BUCKET], bdb: &mut BridgeDb, ) { - let index = self.find_next_available_key(); - let bnum = self.bridge_table.new_bucket(&bridges, index); + let bindex = self.find_next_available_key(bdb); + self.bridge_table.new_bucket(&bridges, bindex); let mut single = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET]; for b in bridges.iter() { - let index = self.find_next_available_key(); + let sindex = self.find_next_available_key(bdb); single[0] = *b; - let snum = self.bridge_table.new_bucket(&single, index); - self.bridge_table.open_inv_keys.push((snum, self.today())); - bdb.insert_openinv(snum); - self.trustup_migration_table.table.insert(snum, bnum); + self.bridge_table.new_bucket(&single, sindex); + self.bridge_table.open_inv_keys.push((sindex, self.today())); + bdb.insert_openinv(sindex); + self.trustup_migration_table.table.insert(sindex, bindex); } } /// Insert a hot spare bucket of bridges - pub fn add_spare_bucket(&mut self, bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET]) { - let index = self.find_next_available_key(); - let bnum = self.bridge_table.new_bucket(&bucket, index); - self.bridge_table.spares.insert(bnum); + pub fn add_spare_bucket( + &mut self, + bucket: [BridgeLine; MAX_BRIDGES_PER_BUCKET], + bdb: &mut BridgeDb, + ) { + let index = self.find_next_available_key(bdb); + self.bridge_table.new_bucket(&bucket, index); + self.bridge_table.spares.insert(index); } pub fn sync_table(&mut self) { @@ -607,8 +611,8 @@ impl BridgeAuth { // does not overwrite existing bridges could become an issue. We keep a list // of recycleable lookup keys from buckets that have been removed and prioritize // this list before increasing the counter - fn find_next_available_key(&mut self) -> u32 { - self.clean_up_expired_buckets(); //This function probably should be moved to lib.rs to handle trustup and migration tables too + fn find_next_available_key(&mut self, bdb: &mut BridgeDb) -> u32 { + self.clean_up_expired_buckets(bdb); if self.bridge_table.recycleable_keys.is_empty() { let mut test_index = 1; let mut test_counter = self.bridge_table.counter.wrapping_add(test_index); @@ -630,7 +634,7 @@ impl BridgeAuth { // that we no longer want to allow migration to, or else, open-entry buckets that // have been unblocked long enough to become trusted and who's users' credentials // would have expired (after 511 days) - pub fn clean_up_expired_buckets(&mut self) { + pub fn clean_up_expired_buckets(&mut self, bdb: &mut BridgeDb) { // Consider including migration tables and check age of from buckets // If an open-invitation bucket is more than 511 days old, it should be recycled // If a blocked bridge is more than 511 (the maximum validity of a credential in days) days old, it should also be recycled @@ -638,7 +642,7 @@ impl BridgeAuth { // First check if there are any blocked indexes that are old enough to be replaced self.clean_up_blocked(); // Next do the same for open_invitations buckets - // self.clean_up_open_entry(); + self.clean_up_open_entry(bdb); } fn clean_up_blocked(&mut self) { @@ -687,7 +691,7 @@ impl BridgeAuth { } } - fn clean_up_open_entry(&mut self) { + fn clean_up_open_entry(&mut self, bdb: &mut BridgeDb) { // First check if there are any open invitation indexes that are old enough to be replaced if !self.bridge_table.open_inv_keys.is_empty() && self @@ -704,6 +708,12 @@ impl BridgeAuth { .partition(|&x| x.1 + 511 < self.today()); for item in expired { let new_item = item.0; + bdb.remove_openinv(&new_item); + // Remove any trust upgrade migrations from this + // bucket + self.trustup_migration_table + .table + .retain(|&k, _| k != new_item); self.bridge_table.buckets.remove(&new_item); self.bridge_table.keys.remove(&new_item); //and add them to the recyclable keys diff --git a/crates/lox-library/src/proto/open_invite.rs b/crates/lox-library/src/proto/open_invite.rs index 5b66333..69960dd 100644 --- a/crates/lox-library/src/proto/open_invite.rs +++ b/crates/lox-library/src/proto/open_invite.rs @@ -154,11 +154,10 @@ impl BridgeAuth { // Check the signature on the open_invite. We manually match // here because we're changing the Err type from SignatureError // to ProofError - let (invite_id, bucket_id_u32) = match BridgeDb::verify(req.invite, self.bridgedb_pub) { + let (invite_id, bucket_id) = match BridgeDb::verify(req.invite, self.bridgedb_pub) { Ok(res) => res, Err(_) => return Err(ProofError::VerificationFailure), }; - let bucket_id: usize = bucket_id_u32 as usize; // Only proceed if the invite_id is fresh if self.openinv_filter.filter(&invite_id) == SeenType::Seen { @@ -166,7 +165,7 @@ impl BridgeAuth { } // And also check that the bucket id is valid - if bucket_id >= self.bridge_table.num_buckets() { + if !self.bridge_table.buckets.contains_key(&bucket_id) { return Err(ProofError::VerificationFailure); } @@ -196,9 +195,9 @@ impl BridgeAuth { // Create the bucket attribute (Scalar), which is a combination // of the bucket id (u32) and the bucket's decryption key ([u8; 16]) - let bucket_key = self.bridge_table.keys.get(&bucket_id_u32).unwrap(); - let bucket: Scalar = bridge_table::to_scalar(bucket_id_u32, bucket_key); - let bridge_lines = self.bridge_table.buckets.get(&bucket_id_u32).unwrap(); + let bucket_key = self.bridge_table.keys.get(&bucket_id).unwrap(); + let bucket: Scalar = bridge_table::to_scalar(bucket_id, bucket_key); + let bridge_lines = self.bridge_table.buckets.get(&bucket_id).unwrap(); let bridge_line = bridge_lines[0]; // Create the level_since attribute (Scalar), which is today's diff --git a/crates/lox-library/src/tests.rs b/crates/lox-library/src/tests.rs index 4be2ef8..19a42e8 100644 --- a/crates/lox-library/src/tests.rs +++ b/crates/lox-library/src/tests.rs @@ -50,7 +50,7 @@ impl TestHarness { BridgeLine::random(), BridgeLine::random(), ]; - ba.add_spare_bucket(bucket); + ba.add_spare_bucket(bucket, &mut bdb); } // Create the encrypted bridge table ba.enc_bridge_table(); @@ -651,13 +651,16 @@ fn test_clean_up_blocked() { BridgeLine::random(), BridgeLine::random(), ]; - // Add new bridges to trigger bucket cleanup + // Add new bridges to trigger bucket cleanup, but also open invitation cleanup so 150 buckets - blocked th.ba.add_openinv_bridges(bucket, &mut th.bdb); } + // 150 is the number of open invitation buckets that will be cleared, + the number of blocked bridges + // 40 is the number of keys that will have had to be used after creating 10 new open invitation buckets println!( - "Size of recyclable keys: {:?}", - th.ba.bridge_table.recycleable_keys.len() + "Size of recyclable keys: {:?}. Which should be the same as 150+blocked-40 = {:?}", + th.ba.bridge_table.recycleable_keys.len(), + 150 + blocked - 40 ); println!("Counter: {:?}", th.ba.bridge_table.counter); println!("\n**AFTER NEW BUCKETS ADDED**\n"); @@ -666,7 +669,7 @@ fn test_clean_up_blocked() { "After adding new buckets, blocked keys should be empty" ); assert!( - th.ba.bridge_table.recycleable_keys.is_empty(), + th.ba.bridge_table.recycleable_keys.len() == 150 + blocked - 40, "After adding new buckets, recycleable keys should be empty" ); // Because of open-entry buckets added and open-entry cleanup, the counter increases to 278 @@ -674,7 +677,93 @@ fn test_clean_up_blocked() { } #[test] -fn test_clean_up_open_entry() {} +fn test_clean_up_open_entry() { + let mut th = TestHarness::new_buckets(50, 50); + let mut credentials: Vec = Vec::new(); + let mut level_1_credentials: Vec = Vec::new(); + // Users + for _ in 0..100 { + let cred = th.open_invite().1 .0; + credentials.push(cred); + } + assert!( + th.ba.trustup_migration_table.table.len() == 150, + "There should be 50*3 eligible trust up migrations" + ); + th.advance_days(30); + for cred in credentials { + let (_, migcred) = th.trust_promotion(&cred); + let (_, cred1) = th.level0_migration(&cred, &migcred); + level_1_credentials.push(cred1); + } + th.advance_days(512); + assert!( + th.ba.bridge_table.open_inv_keys.len() == 150, + "Open Inv keys does not equal 50*3 = 150" + ); + assert!(th.ba.bridge_table.recycleable_keys.is_empty(), ""); + th.ba.clean_up_open_entry(&mut th.bdb); + assert!( + th.ba.bridge_table.open_inv_keys.is_empty(), + "Open entry keys should be 0" + ); + assert!( + th.ba.trustup_migration_table.table.len() == 0, + "There should be no remaining eligible trust up migrations" + ); + assert!( + th.ba.bridge_table.recycleable_keys.len() == 150, + "Recycleable keys is 150" + ); + // Each open invitation bucket creates 4 buckets -> 50*4 = 200 + 50 hotspare buckets = 250 total + assert!( + th.ba.bridge_table.counter == 250, + "Total number of buckets should be 250" + ); + for cred in level_1_credentials { + let (_, _cred2) = th.level_up(&cred); + } + println!("Succeeded upgrading all creds to level 2"); + + // Open Invite will fail since there are no open invitation buckets + // Lets add more + + for _ in 0..10 { + let bucket = [ + BridgeLine::random(), + BridgeLine::random(), + BridgeLine::random(), + ]; + // Add new bridges to trigger bucket cleanup + th.ba.add_openinv_bridges(bucket, &mut th.bdb); + } + println!( + "The number of trustup migrations after adding 10 new buckets is: {:?}", + th.ba.trustup_migration_table.table.len() + ); + assert!( + th.ba.trustup_migration_table.table.len() == 30, + "There should be 10*3 eligible trust up migrations" + ); + + // Let's also make sure that open invitation works again + let cred = th.open_invite().1 .0; + println!("Yep, worked!"); + th.advance_days(30); + + assert!( + th.ba.bridge_table.recycleable_keys.len() == 110, + "Size of recycleable keys should be 150 - (10*4) = 110" + ); + assert!( + th.ba.bridge_table.counter == 250, + "Counter should be unchanged" + ); + assert!( + th.ba.bridge_table.open_inv_keys.len() == 30, + "Open inv keys should be 10*3 = 30" + ); +} #[test] fn find_next_available_key() {}