crypto_auth.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. //! CryptoAuth
  2. use std::sync::Arc;
  3. use std::sync::Mutex;
  4. use std::sync::RwLock;
  5. use log::*;
  6. use sodiumoxide::crypto;
  7. use thiserror::Error;
  8. use crate::crypto::crypto_header::AuthType;
  9. use crate::crypto::crypto_header::Challenge;
  10. use crate::crypto::keys::{IpV6, PrivateKey, PublicKey};
  11. use crate::crypto::random::Random;
  12. use crate::crypto::replay_protector::ReplayProtector;
  13. use crate::interface::wire::message::Message;
  14. use crate::rtypes::RTypes_CryptoAuth_State_t as State;
  15. use crate::rtypes::*;
  16. use crate::util::events::EventBase;
  17. pub struct CryptoAuth {
  18. pub public_key: PublicKey,
  19. private_key: PrivateKey,
  20. users: RwLock<Vec<User>>,
  21. event_base: EventBase,
  22. rand: Random,
  23. }
  24. #[derive(Default)]
  25. struct User {
  26. /// Double-hash of password for AuthType 1
  27. password_hash: [u8; Challenge::KEYSIZE],
  28. /// Hash of username for AuthType 2
  29. user_name_hash: [u8; Challenge::KEYSIZE],
  30. secret: [u8; 32],
  31. login: Vec<u8>,
  32. restricted_to_ip6: Option<IpV6>,
  33. }
  34. pub struct SessionMut {
  35. pub her_public_key: PublicKey,
  36. pub display_name: Option<String>,
  37. /// Bind this CryptoAuth session to the other node's ip6 address,
  38. /// any packet advertising a key which doesn't hash to this will be dropped.
  39. pub her_ip6: IpV6,
  40. /// After this number of seconds of inactivity,
  41. /// a connection will be reset to prevent them hanging in a bad state.
  42. pub reset_after_inactivity_seconds: u32,
  43. /// If a session is not completely setup, reset it after this many seconds of inactivity.
  44. pub setup_reset_after_inactivity_seconds: u32,
  45. /// The shared secret.
  46. shared_secret: [u8; 32],
  47. her_temp_pub_key: [u8; 32],
  48. our_temp_priv_key: [u8; 32],
  49. our_temp_pub_key: [u8; 32],
  50. /// A password to use for authing with the other party.
  51. password: Option<Vec<u8>>,
  52. /// The login name to auth with the other party.
  53. login: Option<Vec<u8>>,
  54. /// The next nonce to use.
  55. next_nonce: u32,
  56. /// Used to reset the connection if it's in a bad state (no traffic coming in).
  57. time_of_last_packet: u32,
  58. /// The method to use for trying to auth with the server.
  59. auth_type: AuthType,
  60. /// True if this node began the conversation.
  61. is_initiator: bool,
  62. /// If true and the other end is connecting, do not respond until a valid password is sent.
  63. require_auth: bool,
  64. established: bool,
  65. }
  66. pub struct Session {
  67. pub m: RwLock<SessionMut>,
  68. // This has to be briefly locked every packet, it should not contaminate the write lock
  69. // of the SessionMut so that multiple threads can decrypt at the same time...
  70. pub replay_protector: Mutex<ReplayProtector>,
  71. /// A pointer back to the main CryptoAuth context.
  72. context: Arc<CryptoAuth>,
  73. }
  74. #[derive(Error, Debug, Clone, PartialEq, Eq)]
  75. pub enum AddUserError {
  76. #[error("Duplicate user")]
  77. Duplicate,
  78. }
  79. // Keep these numbers same as cffi::CryptoAuth_DecryptErr because we return numbers directly
  80. #[derive(Error, Debug, Clone, PartialEq, Eq)]
  81. pub enum DecryptErr {
  82. #[error("NONE")]
  83. None = 0,
  84. #[error("RUNT")]
  85. Runt = 1,
  86. #[error("NO_SESSION")]
  87. NoSession = 2,
  88. #[error("FINAL_HANDSHAKE_FAIL")]
  89. FinalShakeFail = 3,
  90. #[error("FAILED_DECRYPT_RUN_MSG")]
  91. FailedDecryptionRunMsg = 4,
  92. #[error("KEY_PKT_ESTABLISHED_SESSION")]
  93. KeyPktEstablishedSession = 5,
  94. #[error("WRONG_PERM_PUBKEY")]
  95. WrongPermPubkey = 6,
  96. #[error("IP_RESTRICTED")]
  97. IpRestricted = 7,
  98. #[error("AUTH_REQUIRED")]
  99. AuthRequired = 8,
  100. #[error("UNRECOGNIZED_AUTH")]
  101. UnrecognizedAuth = 9,
  102. #[error("STRAY_KEY")]
  103. StrayKey = 10,
  104. #[error("HANDSHAKE_DECRYPT_FAILED")]
  105. HandshakeDecryptFailed = 11,
  106. #[error("WISEGUY")]
  107. Wiseguy = 12,
  108. #[error("INVALID_PACKET")]
  109. InvalidPacket = 13,
  110. #[error("REPLAY")]
  111. Replay = 14,
  112. #[error("DECRYPT")]
  113. Decrypt = 15,
  114. }
  115. fn crypto_scalarmult_curve25519_base(pvt: &[u8; 32]) -> [u8; 32] {
  116. let mut s = crypto::scalarmult::curve25519::Scalar(*pvt);
  117. let o = crypto::scalarmult::curve25519::scalarmult_base(&s).0;
  118. // zero dat stack
  119. s.0 = [0; 32];
  120. o
  121. }
  122. // Don't use this for comparisons because anything with a non-utf8 char will be equal
  123. // to the same hex value, just for debugging...
  124. fn str_u8(b: Vec<u8>) -> String {
  125. match String::from_utf8(b) {
  126. Ok(x) => x,
  127. Err(e) => hex::encode(e.into_bytes()),
  128. }
  129. }
  130. impl CryptoAuth {
  131. const LOG_KEYS: bool = false;
  132. pub fn new(private_key: Option<PrivateKey>, event_base: EventBase, rand: Random) -> Self {
  133. let private_key = private_key.unwrap_or_else(|| {
  134. let mut pk: [u8; 32] = [0; 32];
  135. rand.random_bytes(&mut pk);
  136. PrivateKey(pk)
  137. });
  138. let public_key = PublicKey(crypto_scalarmult_curve25519_base(&private_key.0));
  139. if Self::LOG_KEYS {
  140. debug!(
  141. "Initialized CryptoAuth:\n myPrivateKey={}\n myPublicKey={}\n",
  142. hex::encode(&private_key.0),
  143. hex::encode(&public_key.0),
  144. );
  145. }
  146. CryptoAuth {
  147. public_key,
  148. private_key,
  149. users: RwLock::new(vec![]),
  150. event_base,
  151. rand,
  152. }
  153. }
  154. pub fn add_user_ipv6(
  155. &self,
  156. password: &[u8],
  157. login: Option<Vec<u8>>,
  158. ipv6: Option<IpV6>,
  159. ) -> Result<(), AddUserError> {
  160. let mut users = self.users.write().unwrap();
  161. let mut user = User::default();
  162. if let Some(login) = login.clone() {
  163. user.login = Vec::from(login);
  164. } else {
  165. user.login = format!("Anon #{}", users.len()).into_bytes();
  166. }
  167. let mut ac = Challenge::default();
  168. // Users specified with a login field might want to use authType 1 still.
  169. hash_password(
  170. &mut user.secret,
  171. &mut ac,
  172. &user.login,
  173. &password,
  174. AuthType::Two,
  175. );
  176. user.user_name_hash.copy_from_slice(ac.as_key_bytes());
  177. hash_password(
  178. &mut user.secret,
  179. &mut ac,
  180. &[0; 0][..],
  181. &password,
  182. AuthType::One,
  183. );
  184. user.password_hash.copy_from_slice(ac.as_key_bytes());
  185. //TODO user.secret being overwritten twice - what is the use of it?
  186. for u in &*users {
  187. if user.secret == u.secret {
  188. // Do nothing
  189. } else if let Some(login) = login.as_ref() {
  190. if *login == u.login {
  191. return Err(AddUserError::Duplicate);
  192. }
  193. }
  194. }
  195. user.restricted_to_ip6 = ipv6;
  196. users.push(user);
  197. Ok(())
  198. }
  199. pub fn remove_users(&self, login: Option<Vec<u8>>) -> usize {
  200. let mut users = self.users.write().unwrap();
  201. let mut count = 0;
  202. users.retain(|u| {
  203. let remove = login.is_none() || login.as_deref() == Some(&u.login);
  204. if remove {
  205. count += 1;
  206. }
  207. !remove
  208. });
  209. if let Some(login) = login {
  210. debug!(
  211. "Removing [{}] user(s) identified by [{}]",
  212. count,
  213. str_u8(Vec::from(login))
  214. );
  215. } else {
  216. debug!("Flushing [{}] users", count);
  217. }
  218. return count;
  219. }
  220. pub fn get_users(&self) -> Vec<Vec<u8>> {
  221. self.users
  222. .read()
  223. .unwrap()
  224. .iter()
  225. .map(|user| user.login.clone())
  226. .collect()
  227. }
  228. }
  229. impl SessionMut {
  230. pub fn set_auth(&mut self, password: Option<Vec<u8>>, login: Option<Vec<u8>>) {
  231. if password.is_none() && (self.password.is_some() || self.auth_type != AuthType::Zero) {
  232. self.password = None;
  233. self.auth_type = AuthType::Zero;
  234. } else if self.password.is_none() || self.password != password {
  235. self.password = password;
  236. self.auth_type = AuthType::One;
  237. if login.is_some() {
  238. self.auth_type = AuthType::Two;
  239. self.login = login;
  240. }
  241. } else {
  242. return;
  243. }
  244. self.reset();
  245. }
  246. pub fn get_state(&self) -> State {
  247. if self.next_nonce <= State::ReceivedKey as u32 {
  248. let ret = match self.next_nonce {
  249. 0 => State::Init,
  250. 1 => State::SentHello,
  251. 2 => State::ReceivedHello,
  252. 3 => State::SentKey,
  253. 4 => State::ReceivedKey,
  254. _ => unreachable!(),
  255. };
  256. debug_assert_eq!(self.next_nonce, ret as u32);
  257. ret
  258. } else if self.established {
  259. State::Established
  260. } else {
  261. State::ReceivedKey
  262. }
  263. }
  264. pub fn get_her_pubkey(&self) -> [u8; 32] {
  265. self.her_public_key.0.clone()
  266. }
  267. pub fn get_her_ip6(&self) -> [u8; 16] {
  268. self.her_ip6.0.clone()
  269. }
  270. pub fn get_name(&self) -> Option<String> {
  271. self.display_name.clone()
  272. }
  273. pub fn reset_if_timeout(&mut self, event_base: &EventBase) {
  274. if self.next_nonce == State::SentHello as u32 {
  275. // Lets not reset the session, we just sent one or more hello packets and
  276. // have not received a response, if they respond after we reset then we'll
  277. // be in a tough state.
  278. return;
  279. }
  280. let now_secs = event_base.current_time_seconds() as i64;
  281. let time_of_last_packet = self.time_of_last_packet as i64;
  282. let delta = now_secs - time_of_last_packet;
  283. if delta < self.setup_reset_after_inactivity_seconds as i64 {
  284. return;
  285. } else if delta < self.reset_after_inactivity_seconds as i64 {
  286. if self.established {
  287. return;
  288. }
  289. }
  290. debug::log(self, || {
  291. format!("No traffic in [{}] seconds, resetting connection.", delta)
  292. });
  293. self.time_of_last_packet = now_secs as u32;
  294. self.reset();
  295. }
  296. // Does not reset the replay_protector
  297. fn reset(&mut self) {
  298. self.next_nonce = State::Init as u32;
  299. self.is_initiator = false;
  300. self.our_temp_priv_key = [0; 32];
  301. self.our_temp_pub_key = [0; 32];
  302. self.her_temp_pub_key = [0; 32];
  303. self.shared_secret = [0; 32];
  304. self.established = false;
  305. }
  306. pub fn her_key_known(&self) -> bool {
  307. self.her_public_key.is_non_zero()
  308. }
  309. }
  310. impl Session {
  311. const DEFAULT_RESET_AFTER_INACTIVITY_SECONDS: u32 = 60;
  312. const DEFAULT_SETUP_RESET_AFTER_INACTIVITY_SECONDS: u32 = 10;
  313. pub fn new(
  314. context: Arc<CryptoAuth>,
  315. her_pub_key: PublicKey,
  316. require_auth: bool,
  317. display_name: Option<String>,
  318. use_noise: bool,
  319. ) -> Self {
  320. let now = context.event_base.current_time_seconds();
  321. if use_noise {
  322. panic!("noise protocol not yet implemented");
  323. }
  324. assert!(her_pub_key.is_non_zero());
  325. let her_ip6 = her_pub_key.address_for_public_key();
  326. Session {
  327. m: RwLock::new(SessionMut {
  328. her_public_key: her_pub_key,
  329. display_name,
  330. her_ip6,
  331. reset_after_inactivity_seconds: Self::DEFAULT_RESET_AFTER_INACTIVITY_SECONDS,
  332. setup_reset_after_inactivity_seconds:
  333. Self::DEFAULT_SETUP_RESET_AFTER_INACTIVITY_SECONDS,
  334. shared_secret: [0; 32],
  335. her_temp_pub_key: [0; 32],
  336. our_temp_priv_key: [0; 32],
  337. our_temp_pub_key: [0; 32],
  338. password: None,
  339. login: None,
  340. next_nonce: State::Init as u32,
  341. time_of_last_packet: now,
  342. auth_type: AuthType::Zero,
  343. is_initiator: false,
  344. require_auth,
  345. established: false,
  346. }),
  347. replay_protector: Mutex::new(ReplayProtector::default()),
  348. context,
  349. }
  350. }
  351. pub fn encrypt(&self, msg: &mut Message) -> anyhow::Result<()> {
  352. todo!();
  353. }
  354. pub fn decrypt(&self, msg: &mut Message) -> Result<(), DecryptErr> {
  355. todo!();
  356. }
  357. pub fn set_auth(&self, password: Option<Vec<u8>>, login: Option<Vec<u8>>) {
  358. self.m.write().unwrap().set_auth(password, login)
  359. }
  360. pub fn get_state(&self) -> State {
  361. self.m.read().unwrap().get_state()
  362. }
  363. pub fn get_her_pubkey(&self) -> [u8; 32] {
  364. self.m.read().unwrap().get_her_pubkey()
  365. }
  366. pub fn get_her_ip6(&self) -> [u8; 16] {
  367. self.m.read().unwrap().get_her_ip6()
  368. }
  369. pub fn get_name(&self) -> Option<String> {
  370. self.m.read().unwrap().get_name()
  371. }
  372. pub fn stats(&self) -> RTypes_CryptoStats_t {
  373. // Stats come from the replay protector
  374. let rp = self.replay_protector.lock().unwrap();
  375. // RTypes_CryptoStats_t{
  376. // received_packets: rp.
  377. // }
  378. todo!()
  379. }
  380. pub fn reset_if_timeout(&self) {
  381. self.m
  382. .write()
  383. .unwrap()
  384. .reset_if_timeout(&self.context.event_base)
  385. }
  386. pub fn reset(&self) {
  387. // Make sure we're write() m when we do the replay because
  388. // decrypt threads will read() m
  389. let mut m = self.m.write().unwrap();
  390. self.replay_protector.lock().unwrap().reset();
  391. m.reset();
  392. }
  393. pub fn her_key_known(&self) -> bool {
  394. self.m.read().unwrap().her_key_known()
  395. }
  396. }
  397. fn crypto_hash_sha256(b: &[u8]) -> [u8; 32] {
  398. crypto::hash::sha256::hash(b).0
  399. }
  400. #[inline]
  401. fn hash_password(
  402. secret_out: &mut [u8; 32],
  403. challenge_out: &mut Challenge,
  404. login: &[u8],
  405. password: &[u8],
  406. auth_type: AuthType,
  407. ) {
  408. *secret_out = crypto_hash_sha256(password);
  409. let tmp_buf = match auth_type {
  410. AuthType::One => crypto_hash_sha256(secret_out),
  411. AuthType::Two => crypto_hash_sha256(login),
  412. _ => panic!("Unsupported auth type [{}]", auth_type as u8),
  413. };
  414. // TODO In theory this would cause UB in Rust because enum `Challenge::auth_type` being overwritten with random data.
  415. unsafe {
  416. let src = &tmp_buf[0..Challenge::SIZE];
  417. let dest = std::slice::from_raw_parts_mut(
  418. challenge_out as *mut Challenge as *mut u8,
  419. Challenge::SIZE,
  420. );
  421. dest.copy_from_slice(src);
  422. }
  423. challenge_out.require_packet_auth_and_derivation_count = 0;
  424. challenge_out.auth_type = auth_type;
  425. challenge_out.additional = 0;
  426. }
  427. mod debug {
  428. use super::SessionMut;
  429. pub(super) fn log<F: FnOnce() -> String>(session: &SessionMut, msg: F) {
  430. if log::log_enabled!(log::Level::Debug) {
  431. let sess_ptr = session as *const SessionMut;
  432. let dn = session.display_name.as_deref().unwrap_or("");
  433. let addr = get_ip6(session);
  434. let msg = msg();
  435. log::debug!(
  436. "{:?} {} [{}] state[{}]: {}",
  437. sess_ptr,
  438. dn,
  439. addr,
  440. session.next_nonce,
  441. msg
  442. );
  443. }
  444. }
  445. fn get_ip6(session: &SessionMut) -> String {
  446. assert!(session.her_key_known());
  447. let ipv6 = session.her_public_key.address_for_public_key();
  448. hex::encode(&ipv6.0) //TODO Use proper formatting
  449. }
  450. }