-
Notifications
You must be signed in to change notification settings - Fork 9
[Innovation-Sprint/PM-19065] Add opaque authentication / unlock #185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
582854f
d6ba83b
c17a752
116ab8b
24fff58
a82287a
29eb7ed
bc17bf0
697f9aa
8cfef9b
c89c0eb
2b1cb0e
435d6bf
33ddf6a
27aadef
27f94e1
8796b4f
06c759e
cc36109
7da2f7b
f1bd00c
d9964a9
b9fa0e9
83b1218
7cdfcae
a2e7e4f
7c74150
6155e1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
use bitwarden_crypto::CryptoError; | ||
use bitwarden_crypto::{opaque_ke::opaque::OpaqueImpl, CryptoError, SymmetricCryptoKey}; | ||
#[cfg(feature = "internal")] | ||
use bitwarden_crypto::{AsymmetricEncString, EncString}; | ||
|
||
|
@@ -81,6 +81,72 @@ | |
) -> Result<VerifyAsymmetricKeysResponse, CryptoError> { | ||
verify_asymmetric_keys(request) | ||
} | ||
|
||
pub fn opaque_register_start( | ||
&self, | ||
password: &str, | ||
config: &bitwarden_crypto::opaque_ke::types::CipherConfiguration, | ||
) -> Result< | ||
bitwarden_crypto::opaque_ke::types::ClientRegistrationStartResult, | ||
bitwarden_crypto::OpaqueError, | ||
> { | ||
config.start_client_registration(password) | ||
} | ||
|
||
pub fn opaque_register_finish( | ||
&self, | ||
password: &str, | ||
config: &bitwarden_crypto::opaque_ke::types::CipherConfiguration, | ||
registration_response: &[u8], | ||
state: &[u8], | ||
) -> Result< | ||
bitwarden_crypto::opaque_ke::types::ClientRegistrationFinishResult, | ||
bitwarden_crypto::OpaqueError, | ||
> { | ||
config.finish_client_registration(state, registration_response, password) | ||
} | ||
|
||
pub fn opaque_login_start( | ||
&self, | ||
password: &str, | ||
config: &bitwarden_crypto::opaque_ke::types::CipherConfiguration, | ||
) -> Result< | ||
bitwarden_crypto::opaque_ke::types::ClientLoginStartResult, | ||
bitwarden_crypto::OpaqueError, | ||
> { | ||
config.start_client_login(password) | ||
} | ||
|
||
pub fn opaque_login_finish( | ||
&self, | ||
password: &str, | ||
config: &bitwarden_crypto::opaque_ke::types::CipherConfiguration, | ||
login_response: &[u8], | ||
state: &[u8], | ||
) -> Result< | ||
bitwarden_crypto::opaque_ke::types::ClientLoginFinishResult, | ||
bitwarden_crypto::OpaqueError, | ||
> { | ||
config.finish_client_login(state, login_response, password) | ||
} | ||
|
||
/// Create a new rotateable keyset from an export key and an encapsulated key | ||
/// Note: The export key must be 32 bytes | ||
pub fn create_rotateablekeyset_from_exportkey( | ||
&self, | ||
export_key: &mut [u8], | ||
encapsulated_key: &SymmetricCryptoKey, | ||
) -> Result<bitwarden_crypto::rotateable_keyset::RotateableKeyset, CryptoError> { | ||
bitwarden_crypto::rotateable_keyset::RotateableKeyset::new(export_key, encapsulated_key) | ||
} | ||
|
||
pub fn decapsulate_key_from_rotateablekeyset( | ||
&self, | ||
rotateable_keyset: bitwarden_crypto::rotateable_keyset::RotateableKeyset, | ||
encapsulating_key: &[u8], | ||
) -> Result<SymmetricCryptoKey, CryptoError> { | ||
rotateable_keyset.decapsulate_key(encapsulating_key) | ||
} | ||
Comment on lines
+132
to
+149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @dani-garcia will these APIs work in the more limited mobile environment? I don't believe mobile can create a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The exact API won't, but we can adapt them slightly in The For |
||
} | ||
|
||
impl<'a> Client { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: These does not follow https://contributing.bitwarden.com/architecture/sdk/dependencies/#explicit-ranges |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use serde::{Deserialize, Serialize}; | ||
use thiserror::Error; | ||
#[cfg(feature = "wasm")] | ||
use tsify_next::Tsify; | ||
|
||
#[derive(Debug, Error, Deserialize, Serialize)] | ||
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] | ||
pub enum OpaqueError { | ||
#[error("Error creating message {0}")] | ||
Message(String), | ||
#[error("Error deserializing message")] | ||
Deserialize, | ||
Comment on lines
+9
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Unused? |
||
#[error("Invalid input: {0}")] | ||
InvalidInput(String), | ||
#[error("Opaque protocol error {0}")] | ||
Protocol(String), | ||
} | ||
|
||
impl From<opaque_ke::errors::ProtocolError> for OpaqueError { | ||
fn from(error: opaque_ke::errors::ProtocolError) -> Self { | ||
Self::Protocol(error.to_string()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use std::collections::HashMap; | ||
|
||
use opaque_ke::ServerSetup; | ||
|
||
use super::{ | ||
opaque::OpaqueImpl, | ||
types::{CipherConfiguration, RistrettoTripleDhArgonSuite}, | ||
}; | ||
use crate::OpaqueError; | ||
|
||
/// Mock opaque server implementation for testing purposes. | ||
/// Stores server state and registrations in-memory | ||
pub(crate) struct MockServer { | ||
server_setups: HashMap<u8, Vec<u8>>, | ||
password_files: HashMap<u8, Vec<u8>>, | ||
server_login_state: HashMap<u8, Vec<u8>>, | ||
id_counter: u8, | ||
} | ||
|
||
impl MockServer { | ||
pub(crate) fn new() -> Self { | ||
MockServer { | ||
server_setups: HashMap::new(), | ||
password_files: HashMap::new(), | ||
server_login_state: HashMap::new(), | ||
id_counter: 0, | ||
} | ||
} | ||
|
||
pub(crate) fn register_start( | ||
&mut self, | ||
register_start_message: &[u8], | ||
config: CipherConfiguration, | ||
) -> Result<(Vec<u8>, u8), OpaqueError> { | ||
let id = self.id_counter; | ||
self.id_counter += 1; | ||
|
||
let server_setup = ServerSetup::<RistrettoTripleDhArgonSuite>::new(&mut rand::thread_rng()) | ||
.serialize() | ||
.to_vec(); | ||
let result = config | ||
.start_server_registration(Some(&server_setup), register_start_message, "username") | ||
.unwrap(); | ||
self.server_setups.insert(id, server_setup); | ||
Ok((result.registration_response, id)) | ||
} | ||
|
||
pub(crate) fn register_finish( | ||
&mut self, | ||
register_finish_message: &[u8], | ||
id: u8, | ||
config: CipherConfiguration, | ||
) { | ||
let result = config | ||
.finish_server_registration(register_finish_message) | ||
.unwrap(); | ||
self.password_files.insert(id, result.server_registration); | ||
} | ||
|
||
pub(crate) fn login_start( | ||
&mut self, | ||
login_start_message: &[u8], | ||
id: u8, | ||
config: CipherConfiguration, | ||
) -> Vec<u8> { | ||
let login_state = config | ||
.start_server_login( | ||
self.server_setups.get(&id).unwrap(), | ||
self.password_files.get(&id).unwrap(), | ||
login_start_message, | ||
"username", | ||
) | ||
.unwrap(); | ||
self.server_login_state.insert(id, login_state.state); | ||
login_state.credential_response | ||
} | ||
|
||
pub(crate) fn login_finish( | ||
&self, | ||
login_finish_message: &[u8], | ||
id: u8, | ||
config: CipherConfiguration, | ||
) -> Vec<u8> { | ||
config | ||
.finish_server_login( | ||
self.server_login_state.get(&id).unwrap(), | ||
login_finish_message, | ||
) | ||
.unwrap() | ||
.session_key | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Lacks documentation about what this is.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pub mod error; | ||
#[cfg(test)] | ||
mod mock_server; | ||
pub mod opaque; | ||
pub mod types; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: There seems to be little reason to use the client at all here since it's just obfuscating direct calls to types?
This is related to my comment about
CipherConfiguration
leaking sensitive values.