From 59e6c3b0667f82ee2768ee17e60fd94adbd8e5c3 Mon Sep 17 00:00:00 2001 From: Vecna Date: Thu, 7 Sep 2023 13:51:55 -0400 Subject: [PATCH] Get today from lox-distributor; add days function (for testing) --- Cargo.toml | 3 +- src/client_lib.rs | 178 ++++++++++++++++++++++++---------------------- src/main.rs | 70 ++++++++++++------ 3 files changed, 143 insertions(+), 108 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1f4c3e1..59aa718 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" [dependencies] #lox = { git = "https://git-crysp.uwaterloo.ca/iang/lox.git", branch = "vvecna/lox_test" } -lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git" } +lox-library = { git = "https://gitlab.torproject.org/tpo/anti-censorship/lox-rs.git", version = "0.1.0" } +lox_utils = { git = "https://gitlab.torproject.org/tpo/anti-censorship/lox-rs.git", version = "0.1.0" } curve25519-dalek = { package = "curve25519-dalek-ng", version = "3", default-features = false, features = ["serde", "std"] } ed25519-dalek = { version = "1", features = ["serde"] } getopts = "0.2" diff --git a/src/client_lib.rs b/src/client_lib.rs index 93424b3..4439407 100644 --- a/src/client_lib.rs +++ b/src/client_lib.rs @@ -1,12 +1,15 @@ use async_trait::async_trait; use curve25519_dalek::scalar::Scalar; -use lox::bridge_table::BridgeLine; -use lox::bridge_table::ENC_BUCKET_BYTES; -use lox::proto::*; -use lox::IssuerPubKey; -use lox::OPENINV_LENGTH; +use lox_library::bridge_table::BridgeLine; +use lox_library::bridge_table::EncryptedBucket; +use lox_library::proto::*; +use lox_library::scalar_u32; +use lox_library::IssuerPubKey; +use lox_library::OPENINV_LENGTH; +use lox_utils::EncBridgeTable; use serde::{Deserialize, Serialize}; use serde_with::serde_as; +use std::collections::HashMap; use std::time::Duration; // used for testing function @@ -26,42 +29,6 @@ pub struct Invite { #[serde_as(as = "[_; OPENINV_LENGTH]")] invite: [u8; OPENINV_LENGTH], } -#[serde_as] -#[derive(Serialize, Deserialize)] -pub struct EncBridgeTable { - #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] - etable: Vec<[u8; ENC_BUCKET_BYTES]>, -} - -// These two functions should only be used for testing. -// This file should probably belong to the client, not the library. -const TIME_OFFSET_FILENAME: &str = "time_offset.json"; -fn get_time_offset() -> u32 { - if std::path::Path::new(&TIME_OFFSET_FILENAME).exists() { - let infile = std::fs::File::open(&TIME_OFFSET_FILENAME).unwrap(); - serde_json::from_reader(infile).unwrap() - } else { - 0 - } -} -fn save_time_offset(secs: &u32) { - let mut outfile = - std::fs::File::create(&TIME_OFFSET_FILENAME).expect("Failed to create time_offset"); - write!(outfile, "{}", serde_json::to_string(&secs).unwrap()) - .expect("Failed to write to time_offset"); -} - -/// Get today's (real or simulated) date -/// -/// This function is modified from the lox lib.rs -fn today(time_offset: Duration) -> u32 { - // We will not encounter negative Julian dates (~6700 years ago) - // or ones larger than 32 bits - (time::OffsetDateTime::now_utc().date() + time_offset) - .julian_day() - .try_into() - .unwrap() -} // Helper functions to get public keys from vector pub fn get_lox_pub(lox_auth_pubkeys: &Vec) -> &IssuerPubKey { @@ -86,7 +53,7 @@ pub fn get_invitation_pub(lox_auth_pubkeys: &Vec) -> &IssuerPubKey // Helper function to get credential trust level as i8 // (Note that this value should only be 0-4) -pub fn get_cred_trust_level(cred: &lox::cred::Lox) -> i8 { +pub fn get_cred_trust_level(cred: &lox_library::cred::Lox) -> i8 { let trust_levels: [Scalar; 5] = [ Scalar::zero(), Scalar::one(), @@ -102,6 +69,41 @@ pub fn get_cred_trust_level(cred: &lox::cred::Lox) -> i8 { -1 } +// Helper function to check if credential is eligible for +// promotion from level 0 to 1 +pub async fn eligible_for_trust_promotion( + net: &dyn Networking, + cred: &lox_library::cred::Lox, +) -> bool { + let level_since: u32 = match scalar_u32(&cred.level_since) { + Some(v) => v, + None => return false, + }; + get_cred_trust_level(cred) == 0 + && level_since + lox_library::proto::trust_promotion::UNTRUSTED_INTERVAL + <= get_today(net).await +} + +// Helper function to check if credential is eligible for +// level up from level 1+ +pub async fn eligible_for_level_up(net: &dyn Networking, cred: &lox_library::cred::Lox) -> bool { + let level_since: u32 = match scalar_u32(&cred.level_since) { + Some(v) => v, + None => return false, + }; + let trust_level: usize = get_cred_trust_level(cred).try_into().unwrap(); + trust_level > 0 + && level_since + lox_library::proto::level_up::LEVEL_INTERVAL[trust_level] + <= get_today(net).await +} + +// Get current date from Lox Auth +pub async fn get_today(net: &dyn Networking) -> u32 { + let resp = net.request("/today".to_string(), [].to_vec()).await; + let today: u32 = serde_json::from_slice(&resp).unwrap(); + today +} + // Download Lox Auth pubkeys pub async fn get_lox_auth_keys(net: &dyn Networking) -> Vec { let resp = net.request("/pubkeys".to_string(), [].to_vec()).await; @@ -110,7 +112,7 @@ pub async fn get_lox_auth_keys(net: &dyn Networking) -> Vec { } // Get encrypted bridge table -pub async fn get_reachability_credential(net: &dyn Networking) -> Vec<[u8; ENC_BUCKET_BYTES]> { +pub async fn get_reachability_credential(net: &dyn Networking) -> HashMap { let resp = net.request("/reachability".to_string(), [].to_vec()).await; let reachability_cred: EncBridgeTable = serde_json::from_slice(&resp).unwrap(); reachability_cred.etable @@ -128,7 +130,7 @@ pub async fn get_lox_credential( net: &dyn Networking, open_invite: &[u8; OPENINV_LENGTH], lox_pub: &IssuerPubKey, -) -> (lox::cred::Lox, BridgeLine) { +) -> (lox_library::cred::Lox, BridgeLine) { let (req, state) = open_invite::request(&open_invite); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); let encoded_resp = net.request("/openreq".to_string(), encoded_req).await; @@ -140,16 +142,10 @@ pub async fn get_lox_credential( // Get a migration credential to migrate to higher trust pub async fn trust_promotion( net: &dyn Networking, - lox_cred: &lox::cred::Lox, + lox_cred: &lox_library::cred::Lox, lox_pub: &IssuerPubKey, -) -> lox::cred::Migration { - // FOR TESTING ONLY - let time_offset = get_time_offset() + 60 * 60 * 24 * 31; - save_time_offset(&time_offset); - - let (req, state) = -// trust_promotion::request(&lox_cred, &lox_pub, today(Duration::ZERO)).unwrap(); - trust_promotion::request(&lox_cred, &lox_pub, today(Duration::from_secs(time_offset.into()))).unwrap(); // FOR TESTING ONLY +) -> lox_library::cred::Migration { + let (req, state) = trust_promotion::request(&lox_cred, &lox_pub, get_today(net).await).unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); let encoded_resp = net.request("/trustpromo".to_string(), encoded_req).await; let decoded_resp: trust_promotion::Response = serde_json::from_slice(&encoded_resp).unwrap(); @@ -160,11 +156,11 @@ pub async fn trust_promotion( // Promote from untrusted (trust level 0) to trusted (trust level 1) pub async fn trust_migration( net: &dyn Networking, - lox_cred: &lox::cred::Lox, - migration_cred: &lox::cred::Migration, + lox_cred: &lox_library::cred::Lox, + migration_cred: &lox_library::cred::Migration, lox_pub: &IssuerPubKey, migration_pub: &IssuerPubKey, -) -> lox::cred::Lox { +) -> lox_library::cred::Lox { let (req, state) = migration::request(lox_cred, migration_cred, lox_pub, migration_pub).unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); @@ -177,23 +173,22 @@ pub async fn trust_migration( // Increase trust from at least level 1 to higher levels pub async fn level_up( net: &dyn Networking, - lox_cred: &lox::cred::Lox, - encbuckets: &Vec<[u8; ENC_BUCKET_BYTES]>, + lox_cred: &lox_library::cred::Lox, + encbuckets: &HashMap, lox_pub: &IssuerPubKey, reachability_pub: &IssuerPubKey, -) -> lox::cred::Lox { +) -> lox_library::cred::Lox { // Read the bucket in the credential to get today's Bucket // Reachability credential - - let (id, key) = lox::bridge_table::from_scalar(lox_cred.bucket).unwrap(); - let bucket = - lox::bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); + let (id, key) = lox_library::bridge_table::from_scalar(lox_cred.bucket).unwrap(); + let bucket = lox_library::bridge_table::BridgeTable::decrypt_bucket( + id, + &key, + &encbuckets.get(&id).unwrap(), + ) + .unwrap(); let reachcred = bucket.1.unwrap(); - // FOR TESTING ONLY - let time_offset = get_time_offset() + 60 * 60 * 24 * 85; - save_time_offset(&time_offset); - // Use the Bucket Reachability credential to advance to the next // level let (req, state) = level_up::request( @@ -201,8 +196,7 @@ pub async fn level_up( &reachcred, lox_pub, reachability_pub, - //today(Duration::ZERO), - today(Duration::from_secs(time_offset.into())), // FOR TESTING ONLY + get_today(net).await, ) .unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); @@ -215,18 +209,22 @@ pub async fn level_up( // Request an Invitation credential to give to a friend pub async fn issue_invite( net: &dyn Networking, - lox_cred: &lox::cred::Lox, - encbuckets: &Vec<[u8; ENC_BUCKET_BYTES]>, + lox_cred: &lox_library::cred::Lox, + encbuckets: &HashMap, lox_pub: &IssuerPubKey, reachability_pub: &IssuerPubKey, invitation_pub: &IssuerPubKey, -) -> (lox::cred::Lox, lox::cred::Invitation) { +) -> (lox_library::cred::Lox, lox_library::cred::Invitation) { // Read the bucket in the credential to get today's Bucket // Reachability credential - let (id, key) = lox::bridge_table::from_scalar(lox_cred.bucket).unwrap(); - let bucket = - lox::bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap(); + let (id, key) = lox_library::bridge_table::from_scalar(lox_cred.bucket).unwrap(); + let bucket = lox_library::bridge_table::BridgeTable::decrypt_bucket( + id, + &key, + &encbuckets.get(&id).unwrap(), + ) + .unwrap(); let reachcred = bucket.1.unwrap(); let (req, state) = issue_invite::request( @@ -234,7 +232,7 @@ pub async fn issue_invite( &reachcred, lox_pub, reachability_pub, - today(Duration::ZERO), + get_today(net).await, ) .unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); @@ -248,12 +246,12 @@ pub async fn issue_invite( // Redeem an Invitation credential to start at trust level 1 pub async fn redeem_invite( net: &dyn Networking, - invite: &lox::cred::Invitation, + invite: &lox_library::cred::Invitation, lox_pub: &IssuerPubKey, invitation_pub: &IssuerPubKey, -) -> lox::cred::Lox { +) -> lox_library::cred::Lox { let (req, state) = - redeem_invite::request(invite, invitation_pub, today(Duration::ZERO)).unwrap(); + redeem_invite::request(invite, invitation_pub, get_today(net).await).unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); let encoded_resp = net.request("/redeem".to_string(), encoded_req).await; let decoded_resp: redeem_invite::Response = serde_json::from_slice(&encoded_resp).unwrap(); @@ -264,9 +262,9 @@ pub async fn redeem_invite( // Check for a migration credential to move to a new bucket pub async fn check_blockage( net: &dyn Networking, - lox_cred: &lox::cred::Lox, + lox_cred: &lox_library::cred::Lox, lox_pub: &IssuerPubKey, -) -> lox::cred::Migration { +) -> lox_library::cred::Migration { let (req, state) = check_blockage::request(lox_cred, lox_pub).unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); let encoded_resp = net.request("/checkblockage".to_string(), encoded_req).await; @@ -278,11 +276,11 @@ pub async fn check_blockage( // Migrate to a new bucket (must be level >= 3) pub async fn blockage_migration( net: &dyn Networking, - lox_cred: &lox::cred::Lox, - migcred: &lox::cred::Migration, + lox_cred: &lox_library::cred::Lox, + migcred: &lox_library::cred::Migration, lox_pub: &IssuerPubKey, migration_pub: &IssuerPubKey, -) -> lox::cred::Lox { +) -> lox_library::cred::Lox { let (req, state) = blockage_migration::request(lox_cred, migcred, lox_pub, migration_pub).unwrap(); let encoded_req: Vec = serde_json::to_vec(&req).unwrap(); @@ -293,3 +291,15 @@ pub async fn blockage_migration( let cred = blockage_migration::handle_response(state, decoded_resp, lox_pub).unwrap(); cred } + +// Advance days on server (ONLY FOR TESTING) +pub async fn advance_days(net: &dyn Networking, days: u16) -> u32 { + let resp = net + .request( + "/advancedays".to_string(), + serde_json::to_vec(&days).unwrap(), + ) + .await; + let today: u32 = serde_json::from_slice(&resp).unwrap(); + today +} diff --git a/src/main.rs b/src/main.rs index 6f7cb79..aa6590d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,13 +6,14 @@ use client_net::HyperNet; use curve25519_dalek::scalar::Scalar; use getopts::Options; -use lox::bridge_table::BridgeLine; -use lox::IssuerPubKey; +use lox_library::bridge_table::BridgeLine; +use lox_library::IssuerPubKey; use serde::Serialize; use std::env::args; use std::fs::File; use std::io::Write; use std::path::Path; +use std::str::FromStr; // Prints the argument details for this program fn print_usage(program: &str, opts: Options) { @@ -33,6 +34,13 @@ async fn main() { let mut opts = Options::new(); opts.optflag("h", "help", "print this help menu"); + //#[cfg(test)] + opts.optopt( + "A", + "advance-days", + "increase server days by NUM_DAYS", + "NUM_DAYS", + ); opts.optflag("L", "level-up", "increase trust level"); opts.optflag("N", "new-lox-cred", "get a new Lox Credential"); opts.optopt( @@ -64,6 +72,14 @@ async fn main() { } }; + // Advance days on server (TESTING ONLY) + //#[cfg(test)] + if matches.opt_present("A") { + let days: u16 = u16::from_str(matches.opt_str("A").unwrap().as_str()).unwrap(); + let today: u32 = advance_days(&net, days).await; + println!("Today's date according to the server: {}", today); + } + // Get Lox Authority public keys // TODO: Make this filename configurable let lox_auth_pubkeys_filename = "lox_auth_pubkeys.json"; @@ -108,28 +124,36 @@ async fn main() { // If trust level is 0, do trust promotion, otherwise level up. let cred = if old_level == 0 { - let migration_cred = - trust_promotion(&net, &lox_cred, get_lox_pub(&lox_auth_pubkeys)).await; - let cred = trust_migration( - &net, - &lox_cred, - &migration_cred, - get_lox_pub(&lox_auth_pubkeys), - get_migration_pub(&lox_auth_pubkeys), - ) - .await; - cred + if eligible_for_trust_promotion(&net, &lox_cred).await { + let migration_cred = + trust_promotion(&net, &lox_cred, get_lox_pub(&lox_auth_pubkeys)).await; + let cred = trust_migration( + &net, + &lox_cred, + &migration_cred, + get_lox_pub(&lox_auth_pubkeys), + get_migration_pub(&lox_auth_pubkeys), + ) + .await; + cred + } else { + lox_cred + } } else { - let encbuckets = get_reachability_credential(&net).await; - let cred = level_up( - &net, - &lox_cred, - &encbuckets, - get_lox_pub(&lox_auth_pubkeys), - get_reachability_pub(&lox_auth_pubkeys), - ) - .await; - cred + if eligible_for_level_up(&net, &lox_cred).await { + let encbuckets = get_reachability_credential(&net).await; + let cred = level_up( + &net, + &lox_cred, + &encbuckets, + get_lox_pub(&lox_auth_pubkeys), + get_reachability_pub(&lox_auth_pubkeys), + ) + .await; + cred + } else { + lox_cred + } }; save_object(&cred, &lox_cred_filename); let new_level = get_cred_trust_level(&cred);