positive_report.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // For Lox-related code where points are uppercase and scalars are lowercase
  2. #![allow(non_snake_case)]
  3. use crate::{
  4. bridge_verification_info::BridgeVerificationInfo, get_date, COUNTRY_CODES, MAX_BACKDATE,
  5. };
  6. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  7. use ed25519_dalek::{Signature, Signer, SigningKey, Verifier};
  8. use lox_library::{cred::Lox, proto::positive_report as lox_pr, BridgeAuth, IssuerPubKey};
  9. use serde::{Deserialize, Serialize};
  10. use sha1::{Digest, Sha1};
  11. use std::option::Option;
  12. pub const REQUIRE_BRIDGE_TOKEN: bool = false;
  13. #[derive(Debug, Serialize)]
  14. pub enum PositiveReportError {
  15. DateInFuture,
  16. DateInPast, // report is more than MAX_BACKDATE days old
  17. FailedToDeserialize, // couldn't deserialize to PositiveReport
  18. InvalidBridgeToken,
  19. InvalidCountryCode,
  20. InvalidLoxProof,
  21. MissingBridgeToken,
  22. MissingCountryCode,
  23. }
  24. /// A report that the user was able to connect to the bridge
  25. pub struct PositiveReport {
  26. /// hashed fingerprint (SHA-1 hash of 20-byte bridge ID)
  27. pub fingerprint: [u8; 20],
  28. /// token from the bridge indicating it was reached
  29. bridge_token: Option<BridgeToken>,
  30. // proof of Lox cred with level >= 3 and this bridge
  31. lox_proof: lox_pr::Request,
  32. /// user's country code, may be an empty string
  33. pub country: String,
  34. /// today's Julian date
  35. pub date: u32,
  36. }
  37. impl PositiveReport {
  38. pub fn new(
  39. bridge_id: [u8; 20],
  40. bridge_token: Option<BridgeToken>,
  41. lox_proof: lox_pr::Request,
  42. country: String,
  43. ) -> Self {
  44. //if CONFIG.require_bridge_token && bridge_token.is_none() {
  45. if REQUIRE_BRIDGE_TOKEN && bridge_token.is_none() {
  46. panic!("Bridge tokens are required for positive reports.");
  47. }
  48. let mut hasher = Sha1::new();
  49. hasher.update(bridge_id);
  50. let fingerprint: [u8; 20] = hasher.finalize().into();
  51. let date = get_date();
  52. Self {
  53. fingerprint,
  54. bridge_token,
  55. lox_proof,
  56. country,
  57. date,
  58. }
  59. }
  60. pub fn from_lox_credential(
  61. bridge_id: [u8; 20],
  62. bridge_token: Option<BridgeToken>,
  63. lox_cred: &Lox,
  64. lox_pub: &IssuerPubKey,
  65. country: String,
  66. ) -> Result<Self, lox_library::proto::positive_report::requestproof::ProofError> {
  67. let lox_proof = lox_pr::request(lox_cred, lox_pub)?;
  68. Ok(PositiveReport::new(
  69. bridge_id,
  70. bridge_token,
  71. lox_proof,
  72. country,
  73. ))
  74. }
  75. /// Convert report to a serializable version
  76. pub fn to_serializable_report(self) -> SerializablePositiveReport {
  77. let bridge_token = if self.bridge_token.is_none() {
  78. None
  79. } else {
  80. Some(self.bridge_token.unwrap().to_serializable_bridge_token())
  81. };
  82. SerializablePositiveReport {
  83. fingerprint: self.fingerprint,
  84. bridge_token: bridge_token,
  85. lox_proof: self.lox_proof,
  86. country: self.country,
  87. date: self.date,
  88. }
  89. }
  90. /// Serializes the report, eliding the underlying process
  91. pub fn to_json(self) -> String {
  92. serde_json::to_string(&self.to_serializable_report()).unwrap()
  93. }
  94. /// Deserializes the report, eliding the underlying process
  95. pub fn from_json(str: String) -> Result<Self, PositiveReportError> {
  96. match serde_json::from_str::<SerializablePositiveReport>(&str) {
  97. Ok(v) => v.to_report(),
  98. Err(_) => Err(PositiveReportError::FailedToDeserialize),
  99. }
  100. }
  101. /// Deserializes the report from slice, eliding the underlying process
  102. pub fn from_slice(slice: &[u8]) -> Result<Self, PositiveReportError> {
  103. match serde_json::from_slice::<SerializablePositiveReport>(&slice) {
  104. Ok(v) => v.to_report(),
  105. Err(_) => Err(PositiveReportError::FailedToDeserialize),
  106. }
  107. }
  108. /// Verify report
  109. pub fn verify(
  110. self,
  111. la: &mut BridgeAuth,
  112. bridge_info: &BridgeVerificationInfo,
  113. Htable: &RistrettoBasepointTable,
  114. ) -> bool {
  115. // Verify bridge token
  116. //if CONFIG.require_bridge_token {
  117. if REQUIRE_BRIDGE_TOKEN {
  118. let bridge_token = self.bridge_token.unwrap();
  119. let bridge_key = bridge_info.pubkey;
  120. if bridge_key.is_none() {
  121. return false;
  122. }
  123. if bridge_key
  124. .unwrap()
  125. .verify(
  126. &bridge_token.unsigned_bridge_token.to_bincode(),
  127. &bridge_token.sig,
  128. )
  129. .is_err()
  130. {
  131. return false;
  132. }
  133. }
  134. // Verify knowledge of bucket ID
  135. let buckets = &bridge_info.buckets;
  136. let BP = self.lox_proof.BP;
  137. for bucket in buckets {
  138. if bucket * Htable == BP {
  139. return la.handle_positive_report(self.lox_proof, &Htable).is_ok();
  140. }
  141. }
  142. false
  143. }
  144. }
  145. /// (De)serializable positive report object which must be consumed by the
  146. /// checking function before it can be used
  147. #[derive(Deserialize, Serialize)]
  148. pub struct SerializablePositiveReport {
  149. pub fingerprint: [u8; 20],
  150. bridge_token: Option<SerializableBridgeToken>,
  151. lox_proof: lox_pr::Request,
  152. pub country: String,
  153. pub date: u32,
  154. }
  155. impl SerializablePositiveReport {
  156. pub fn to_report(self) -> Result<PositiveReport, PositiveReportError> {
  157. // Check that fields are valid
  158. //if CONFIG.require_bridge_token && self.bridge_token.is_none() {
  159. if REQUIRE_BRIDGE_TOKEN && self.bridge_token.is_none() {
  160. return Err(PositiveReportError::MissingBridgeToken);
  161. }
  162. if self.country == "" {
  163. return Err(PositiveReportError::MissingCountryCode);
  164. }
  165. if !COUNTRY_CODES.contains(self.country.as_str()) {
  166. return Err(PositiveReportError::InvalidCountryCode);
  167. }
  168. let date: u32 = get_date();
  169. if self.date > date {
  170. return Err(PositiveReportError::DateInFuture);
  171. }
  172. if self.date < date - MAX_BACKDATE {
  173. return Err(PositiveReportError::DateInPast);
  174. }
  175. if self.lox_proof.date != date {
  176. return Err(PositiveReportError::InvalidLoxProof);
  177. }
  178. let bridge_token = if self.bridge_token.is_none() {
  179. None
  180. } else {
  181. let bridge_token_unchecked = self.bridge_token.unwrap().to_bridge_token()?;
  182. // Check that bridge token fields match report fields...
  183. // The user may override the bridge's autodetected country code,
  184. // so allow the country code to be different.
  185. if self.fingerprint != bridge_token_unchecked.unsigned_bridge_token.fingerprint
  186. || self.date != bridge_token_unchecked.unsigned_bridge_token.date
  187. {
  188. return Err(PositiveReportError::InvalidBridgeToken);
  189. }
  190. Some(bridge_token_unchecked)
  191. };
  192. Ok(PositiveReport {
  193. fingerprint: self.fingerprint,
  194. bridge_token: bridge_token,
  195. lox_proof: self.lox_proof,
  196. country: self.country,
  197. date: self.date,
  198. })
  199. }
  200. }
  201. /// An unsigned token which indicates that the bridge was reached
  202. pub struct UnsignedBridgeToken {
  203. /// hashed fingerprint (SHA-1 hash of 20-byte bridge ID)
  204. pub fingerprint: [u8; 20],
  205. /// client's country code
  206. pub country: String,
  207. /// today's Julian date
  208. pub date: u32,
  209. }
  210. impl UnsignedBridgeToken {
  211. pub fn new(bridge_id: [u8; 20], country: String) -> Self {
  212. let mut hasher = Sha1::new();
  213. hasher.update(bridge_id);
  214. let fingerprint: [u8; 20] = hasher.finalize().into();
  215. let date = get_date();
  216. Self {
  217. fingerprint,
  218. country,
  219. date,
  220. }
  221. }
  222. pub fn to_serializable_unsigned_bridge_token(self) -> SerializableUnsignedBridgeToken {
  223. SerializableUnsignedBridgeToken {
  224. fingerprint: self.fingerprint,
  225. country: self.country,
  226. date: self.date,
  227. }
  228. }
  229. /// Serializes the token, eliding the underlying process
  230. pub fn to_bincode(self) -> Vec<u8> {
  231. bincode::serialize(&self.to_serializable_unsigned_bridge_token()).unwrap()
  232. }
  233. /// Deserializes the token, eliding the underlying process
  234. pub fn from_bincode(vec: Vec<u8>) -> Result<Self, PositiveReportError> {
  235. match bincode::deserialize::<SerializableUnsignedBridgeToken>(&vec[..]) {
  236. Ok(v) => v.to_unsigned_bridge_token(),
  237. Err(_) => Err(PositiveReportError::FailedToDeserialize),
  238. }
  239. }
  240. }
  241. /// (De)serializable unsigned bridge token object which must be consumed by the
  242. /// checking function before it can be used
  243. #[derive(Serialize, Deserialize)]
  244. pub struct SerializableUnsignedBridgeToken {
  245. pub fingerprint: [u8; 20],
  246. pub country: String,
  247. pub date: u32,
  248. }
  249. impl SerializableUnsignedBridgeToken {
  250. pub fn to_unsigned_bridge_token(self) -> Result<UnsignedBridgeToken, PositiveReportError> {
  251. if self.country == ""
  252. || !COUNTRY_CODES.contains(self.country.as_str())
  253. || self.date > get_date().into()
  254. {
  255. return Err(PositiveReportError::InvalidBridgeToken);
  256. }
  257. Ok(UnsignedBridgeToken {
  258. fingerprint: self.fingerprint,
  259. country: self.country,
  260. date: self.date,
  261. })
  262. }
  263. }
  264. /// A signed token which indicates that the bridge was reached
  265. pub struct BridgeToken {
  266. /// the unsigned version of this token
  267. pub unsigned_bridge_token: UnsignedBridgeToken,
  268. /// signature from bridge's ed25519 key
  269. sig: Signature,
  270. }
  271. impl BridgeToken {
  272. pub fn new(unsigned_bridge_token: UnsignedBridgeToken, keypair: SigningKey) -> Self {
  273. let bin = unsigned_bridge_token.to_bincode();
  274. let sig = keypair.sign(&bin);
  275. let unsigned_bridge_token = UnsignedBridgeToken::from_bincode(bin).unwrap();
  276. Self {
  277. unsigned_bridge_token,
  278. sig,
  279. }
  280. }
  281. /// Convert bridge token to a serializable version
  282. pub fn to_serializable_bridge_token(self) -> SerializableBridgeToken {
  283. SerializableBridgeToken {
  284. unsigned_bridge_token: self
  285. .unsigned_bridge_token
  286. .to_serializable_unsigned_bridge_token(),
  287. sig: self.sig,
  288. }
  289. }
  290. /// Serializes the bridge token, eliding the underlying process
  291. pub fn to_json(self) -> String {
  292. serde_json::to_string(&self.to_serializable_bridge_token()).unwrap()
  293. }
  294. /// Deserializes the bridge token, eliding the underlying process
  295. pub fn from_json(str: String) -> Result<Self, PositiveReportError> {
  296. match serde_json::from_str::<SerializableBridgeToken>(&str) {
  297. Ok(v) => v.to_bridge_token(),
  298. Err(_) => Err(PositiveReportError::InvalidBridgeToken),
  299. }
  300. }
  301. }
  302. /// (De)serializable bridge token object which must be consumed by the
  303. /// checking function before it can be used
  304. #[derive(Serialize, Deserialize)]
  305. pub struct SerializableBridgeToken {
  306. pub unsigned_bridge_token: SerializableUnsignedBridgeToken,
  307. sig: Signature,
  308. }
  309. impl SerializableBridgeToken {
  310. pub fn to_bridge_token(self) -> Result<BridgeToken, PositiveReportError> {
  311. let unsigned_bridge_token = self.unsigned_bridge_token.to_unsigned_bridge_token()?;
  312. Ok(BridgeToken {
  313. unsigned_bridge_token: unsigned_bridge_token,
  314. sig: self.sig,
  315. })
  316. }
  317. }