positive_report.rs 11 KB

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