Browse Source

Apply PR 7747 review changes to emergency access

pull/7746/head
tom27052006 1 week ago
parent
commit
6525041dc7
  1. 32
      src/api/core/accounts.rs
  2. 43
      src/api/core/emergency_access.rs
  3. 4
      src/db/models/user.rs

32
src/api/core/accounts.rs

@ -708,18 +708,32 @@ fn set_kdf_data(user: &mut User, data: &KDFData) -> EmptyResult {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct AuthenticationData { pub(super) struct AuthenticationData {
salt: String, salt: String,
kdf: KDFData, pub(super) kdf: KDFData,
master_password_authentication_hash: String, pub(super) master_password_authentication_hash: String,
}
impl AuthenticationData {
pub(super) fn check(&self, user: &User, unlock: &UnlockData) -> EmptyResult {
if self.kdf != unlock.kdf {
err!("KDF settings must be equal for authentication and unlock")
}
if self.salt != user.master_password_salt() || self.salt != unlock.salt {
err!("Invalid master password salt")
}
Ok(())
}
} }
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct UnlockData { pub(super) struct UnlockData {
salt: String, salt: String,
kdf: KDFData, kdf: KDFData,
master_key_wrapped_user_key: String, pub(super) master_key_wrapped_user_key: String,
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -738,13 +752,7 @@ async fn post_kdf(data: Json<ChangeKdfData>, headers: Headers, conn: DbConn, nt:
err!("Invalid password") err!("Invalid password")
} }
if data.authentication_data.kdf != data.unlock_data.kdf { data.authentication_data.check(&headers.user, &data.unlock_data)?;
err!("KDF settings must be equal for authentication and unlock")
}
if headers.user.email != data.authentication_data.salt || headers.user.email != data.unlock_data.salt {
err!("Invalid master password salt")
}
let mut user = headers.user; let mut user = headers.user;

43
src/api/core/emergency_access.rs

@ -6,7 +6,10 @@ use crate::{
CONFIG, CONFIG,
api::{ api::{
EmptyResult, JsonResult, EmptyResult, JsonResult,
core::{CipherSyncData, CipherSyncType, accounts::KDFData}, core::{
CipherSyncData, CipherSyncType,
accounts::{AuthenticationData, UnlockData},
},
}, },
auth::{Headers, decode_emergency_access_invite}, auth::{Headers, decode_emergency_access_invite},
db::{ db::{
@ -615,29 +618,13 @@ async fn takeover_emergency_access(emer_id: EmergencyAccessId, headers: Headers,
"kdfMemory": grantor_user.client_kdf_memory, "kdfMemory": grantor_user.client_kdf_memory,
"kdfParallelism": grantor_user.client_kdf_parallelism, "kdfParallelism": grantor_user.client_kdf_parallelism,
"keyEncrypted": &emergency_access.key_encrypted, "keyEncrypted": &emergency_access.key_encrypted,
"salt": master_password_salt(&grantor_user), "salt": grantor_user.master_password_salt(),
"object": "emergencyAccessTakeover", "object": "emergencyAccessTakeover",
}); });
Ok(Json(result)) Ok(Json(result))
} }
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct EmergencyAccessAuthenticationData {
salt: String,
kdf: KDFData,
master_password_authentication_hash: String,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct EmergencyAccessUnlockData {
salt: String,
kdf: KDFData,
master_key_wrapped_user_key: String,
}
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct EmergencyAccessPasswordData { struct EmergencyAccessPasswordData {
@ -646,8 +633,8 @@ struct EmergencyAccessPasswordData {
key: Option<String>, key: Option<String>,
// Current payload // Current payload
authentication_data: Option<EmergencyAccessAuthenticationData>, authentication_data: Option<AuthenticationData>,
unlock_data: Option<EmergencyAccessUnlockData>, unlock_data: Option<UnlockData>,
} }
#[post("/emergency-access/<emer_id>/password", data = "<data>")] #[post("/emergency-access/<emer_id>/password", data = "<data>")]
@ -678,22 +665,12 @@ async fn password_emergency_access(
let (new_master_password_hash, new_key) = let (new_master_password_hash, new_key) =
if let (Some(authentication_data), Some(unlock_data)) = (data.authentication_data, data.unlock_data) { if let (Some(authentication_data), Some(unlock_data)) = (data.authentication_data, data.unlock_data) {
if authentication_data.kdf != unlock_data.kdf { authentication_data.check(&grantor_user, &unlock_data)?;
err!("KDF settings must be equal for authentication and unlock")
}
if authentication_data.salt != unlock_data.salt {
err!("Invalid master password salt")
}
if !authentication_data.kdf.matches_user(&grantor_user) { if !authentication_data.kdf.matches_user(&grantor_user) {
err!("KDF settings do not match the grantor account") err!("KDF settings do not match the grantor account")
} }
if authentication_data.salt != master_password_salt(&grantor_user) {
err!("Invalid master password salt")
}
(authentication_data.master_password_authentication_hash, unlock_data.master_key_wrapped_user_key) (authentication_data.master_password_authentication_hash, unlock_data.master_key_wrapped_user_key)
} else if let (Some(new_master_password_hash), Some(new_key)) = (data.new_master_password_hash, data.key) { } else if let (Some(new_master_password_hash), Some(new_key)) = (data.new_master_password_hash, data.key) {
(new_master_password_hash, new_key) (new_master_password_hash, new_key)
@ -746,10 +723,6 @@ async fn policies_emergency_access(emer_id: EmergencyAccessId, headers: Headers,
}))) })))
} }
fn master_password_salt(user: &User) -> String {
user.email.trim().to_lowercase()
}
fn is_valid_request( fn is_valid_request(
emergency_access: &EmergencyAccess, emergency_access: &EmergencyAccess,
requesting_user_id: &UserId, requesting_user_id: &UserId,

4
src/db/models/user.rs

@ -166,6 +166,10 @@ impl User {
) )
} }
pub fn master_password_salt(&self) -> String {
self.email.trim().to_lowercase()
}
pub fn check_valid_recovery_code(&self, recovery_code: &str) -> bool { pub fn check_valid_recovery_code(&self, recovery_code: &str) -> bool {
if let Some(ref totp_recover) = self.totp_recover { if let Some(ref totp_recover) = self.totp_recover {
crypto::ct_eq(recovery_code, totp_recover.to_lowercase()) crypto::ct_eq(recovery_code, totp_recover.to_lowercase())

Loading…
Cancel
Save