Skip to content

Commit

Permalink
fix: make RwLock in RustCrypto async [WPB-10044]
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonThormeyer committed Jul 8, 2024
1 parent 6d2f5a2 commit 651d930
Show file tree
Hide file tree
Showing 45 changed files with 317 additions and 205 deletions.
1 change: 1 addition & 0 deletions openmls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ async-lock = { version = "3.3", optional = true }
rstest = { version = "0.18.2", optional = true }
rstest_reuse = { version = "0.6.0", optional = true }
tokio = { version = "1.24", optional = true, features = ["macros", "rt", "rt-multi-thread"] }
futures = "0.3.30"

[features]
default = []
Expand Down
18 changes: 10 additions & 8 deletions openmls/src/ciphersuite/hpke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl From<(&str, &[u8])> for EncryptContext {
}

/// Encrypt to an HPKE key with a label.
pub(crate) fn encrypt_with_label(
pub(crate) async fn encrypt_with_label(
public_key: &[u8],
label: &str,
context: &[u8],
Expand All @@ -109,13 +109,15 @@ pub(crate) fn encrypt_with_label(
log_crypto!(debug, "* public key: {public_key:x?}");
log_crypto!(debug, "* plaintext: {plaintext:x?}");

let cipher = crypto.hpke_seal(
ciphersuite.hpke_config(),
public_key,
&context,
&[],
plaintext,
)?;
let cipher = crypto
.hpke_seal(
ciphersuite.hpke_config(),
public_key,
&context,
&[],
plaintext,
)
.await?;

log_crypto!(debug, "* ciphertext: {:x?}", cipher);

Expand Down
3 changes: 2 additions & 1 deletion openmls/src/ciphersuite/reuse_guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ pub struct ReuseGuard {

impl ReuseGuard {
/// Samples a fresh reuse guard uniformly at random.
pub(crate) fn try_from_random(
pub(crate) async fn try_from_random(
crypto: &impl OpenMlsCryptoProvider,
) -> Result<Self, CryptoError> {
Ok(Self {
value: crypto
.rand()
.random_array()
.await
.map_err(|_| CryptoError::InsufficientRandomness)?,
})
}
Expand Down
3 changes: 2 additions & 1 deletion openmls/src/ciphersuite/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl Secret {
/// Randomly sample a fresh `Secret`.
/// This default random initialiser uses the default Secret length of `hash_length`.
/// The function can return a [`CryptoError`] if there is insufficient randomness.
pub(crate) fn random(
pub(crate) async fn random(
ciphersuite: Ciphersuite,
crypto: &impl OpenMlsCryptoProvider,
version: impl Into<Option<ProtocolVersion>>,
Expand All @@ -88,6 +88,7 @@ impl Secret {
value: crypto
.rand()
.random_vec(ciphersuite.hash_length())
.await
.map_err(|_| CryptoError::InsufficientRandomness)?
.into(),
mls_version,
Expand Down
19 changes: 11 additions & 8 deletions openmls/src/ciphersuite/tests/kat_crypto_basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,14 +341,17 @@ pub fn run_test_vector(
assert_eq!(plaintext, decrypted_plaintext);

// Check that encryption works.
let my_ciphertext = hpke::encrypt_with_label(
&public,
&label,
&context,
&plaintext,
ciphersuite,
backend.crypto(),
)
let my_ciphertext = async_std::task::block_on(async {
hpke::encrypt_with_label(
&public,
&label,
&context,
&plaintext,
ciphersuite,
backend.crypto(),
)
.await
})
.unwrap();
let decrypted_plaintext = hpke::decrypt_with_label(
&private,
Expand Down
16 changes: 10 additions & 6 deletions openmls/src/framing/private_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl PrivateMessage {
///
/// TODO #1148: Refactor theses constructors to avoid test code in main and
/// to avoid validation using a special feature flag.
pub(crate) fn try_from_authenticated_content(
pub(crate) async fn try_from_authenticated_content(
public_message: &AuthenticatedContent,
ciphersuite: Ciphersuite,
backend: &impl OpenMlsCryptoProvider,
Expand All @@ -90,10 +90,11 @@ impl PrivateMessage {
message_secrets,
padding_size,
)
.await
}

#[cfg(any(feature = "test-utils", test))]
pub(crate) fn encrypt_without_check(
pub(crate) async fn encrypt_without_check(
public_message: &AuthenticatedContent,
ciphersuite: Ciphersuite,
backend: &impl OpenMlsCryptoProvider,
Expand All @@ -108,10 +109,11 @@ impl PrivateMessage {
message_secrets,
padding_size,
)
.await
}

#[cfg(test)]
pub(crate) fn encrypt_with_different_header(
pub(crate) async fn encrypt_with_different_header(
public_message: &AuthenticatedContent,
ciphersuite: Ciphersuite,
backend: &impl OpenMlsCryptoProvider,
Expand All @@ -127,11 +129,12 @@ impl PrivateMessage {
message_secrets,
padding_size,
)
.await
}

/// Internal function to encrypt content. The extra message header is only used
/// for tests. Otherwise, the data from the given `AuthenticatedContent` is used.
fn encrypt_content(
async fn encrypt_content(
test_header: Option<MlsMessageHeader>,
public_message: &AuthenticatedContent,
ciphersuite: Ciphersuite,
Expand Down Expand Up @@ -170,8 +173,9 @@ impl PrivateMessage {
// Even in tests we want to use the real sender index, so we have a key to encrypt.
.secret_for_encryption(ciphersuite, backend, sender_index, secret_type)?;
// Sample reuse guard uniformly at random.
let reuse_guard: ReuseGuard =
ReuseGuard::try_from_random(backend).map_err(LibraryError::unexpected_crypto_error)?;
let reuse_guard: ReuseGuard = ReuseGuard::try_from_random(backend)
.await
.map_err(LibraryError::unexpected_crypto_error)?;
// Prepare the nonce by xoring with the reuse guard.
let prepared_nonce = ratchet_nonce.xor_with_reuse_guard(&reuse_guard);
// Encrypt the payload
Expand Down
3 changes: 3 additions & 0 deletions openmls/src/framing/test_framing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ async fn codec_ciphertext(ciphersuite: Ciphersuite, backend: &impl OpenMlsCrypto
&mut message_secrets,
0,
)
.await
.expect("Could not encrypt PublicMessage.");

let enc = orig
Expand Down Expand Up @@ -200,6 +201,7 @@ async fn wire_format_checks(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryp
&mut message_secrets,
0,
)
.await
.expect("Could not encrypt PublicMessage.")
.into();

Expand Down Expand Up @@ -575,6 +577,7 @@ async fn unknown_sender(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr
group_alice.message_secrets_test_mut(),
0,
)
.await
.expect("Encryption error");

let received_message = group_charlie.decrypt(&enc_message.into(), backend, configuration);
Expand Down
36 changes: 21 additions & 15 deletions openmls/src/group/core_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,10 @@ impl CoreGroupBuilder {
backend: &impl OpenMlsCryptoProvider<KeyStoreProvider = KeyStore>,
signer: &impl Signer,
) -> Result<CoreGroup, CoreGroupBuildError<KeyStore::Error>> {
let (public_group_builder, commit_secret, leaf_keypair) =
self.public_group_builder.get_secrets(backend, signer)?;
let (public_group_builder, commit_secret, leaf_keypair) = self
.public_group_builder
.get_secrets(backend, signer)
.await?;

let ciphersuite = public_group_builder.crypto_config().ciphersuite;
let config = self.config.unwrap_or_default();
Expand All @@ -267,6 +269,7 @@ impl CoreGroupBuilder {
backend,
commit_secret,
&InitSecret::random(ciphersuite, backend, version)
.await
.map_err(LibraryError::unexpected_crypto_error)?,
&serialized_group_context,
)
Expand Down Expand Up @@ -515,7 +518,7 @@ impl CoreGroup {
.map_err(|e| e.into())
}
// Create application message
pub(crate) fn create_application_message(
pub(crate) async fn create_application_message(
&mut self,
aad: &[u8],
msg: &[u8],
Expand All @@ -530,11 +533,11 @@ impl CoreGroup {
self.context(),
signer,
)?;
self.encrypt(public_message, padding_size, backend)
self.encrypt(public_message, padding_size, backend).await
}

// Encrypt an PublicMessage into an PrivateMessage
pub(crate) fn encrypt(
pub(crate) async fn encrypt(
&mut self,
public_message: AuthenticatedContent,
padding_size: usize,
Expand All @@ -547,6 +550,7 @@ impl CoreGroup {
self.message_secrets_store.message_secrets_mut(),
padding_size,
)
.await
}

/// Decrypt an PrivateMessage into an PublicMessage
Expand Down Expand Up @@ -986,7 +990,7 @@ impl CoreGroup {
signer,
params.take_credential_with_key(),
apply_proposals_values.extensions,
)?
).await?
} else {
// If path is not needed, update the group context and return
// empty path processing results
Expand Down Expand Up @@ -1127,15 +1131,17 @@ impl CoreGroup {

// Create group secrets for later use, so we can afterwards consume the
// `joiner_secret`.
let encrypted_secrets = diff.encrypt_group_secrets(
&joiner_secret,
apply_proposals_values.invitation_list,
path_computation_result.plain_path.as_deref(),
&apply_proposals_values.presharedkeys,
&encrypted_group_info,
backend,
self.own_leaf_index(),
)?;
let encrypted_secrets = diff
.encrypt_group_secrets(
&joiner_secret,
apply_proposals_values.invitation_list,
path_computation_result.plain_path.as_deref(),
&apply_proposals_values.presharedkeys,
&encrypted_group_info,
backend,
self.own_leaf_index(),
)
.await?;

// Create welcome message
let welcome = Welcome::new(self.ciphersuite(), encrypted_secrets, encrypted_group_info);
Expand Down
1 change: 1 addition & 0 deletions openmls/src/group/core_group/new_from_external_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ impl CoreGroup {

let (init_secret, kem_output) =
InitSecret::from_group_context(backend, group_context, external_pub.as_slice())
.await
.map_err(|_| ExternalCommitError::UnsupportedCiphersuite)?;

// The `EpochSecrets` we create here are essentially zero, with the
Expand Down
3 changes: 2 additions & 1 deletion openmls/src/group/mls_group/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl MlsGroup {
/// Returns `CreateMessageError::MlsGroupStateError::PendingProposal` if pending proposals
/// exist. In that case `.process_pending_proposals()` must be called first
/// and incoming messages from the DS must be processed afterwards.
pub fn create_message(
pub async fn create_message(
&mut self,
backend: &impl OpenMlsCryptoProvider,
signer: &impl Signer,
Expand All @@ -37,6 +37,7 @@ impl MlsGroup {
backend,
signer,
)
.await
// We know the application message is wellformed and we have the key material of the current epoch
.map_err(|_| LibraryError::custom("Malformed plaintext"))?;

Expand Down
2 changes: 1 addition & 1 deletion openmls/src/group/mls_group/creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl MlsGroup {
backend,
signer,
mls_group_config,
GroupId::random(backend),
GroupId::random(backend).await,
credential_with_key,
)
.await
Expand Down
8 changes: 5 additions & 3 deletions openmls/src/group/mls_group/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl MlsGroup {
/// of the group but does not merge them yet.
///
/// Returns an error if there is a pending commit.
pub fn propose_extensions(
pub async fn propose_extensions(
&mut self,
backend: &impl OpenMlsCryptoProvider,
signer: &impl Signer,
Expand All @@ -43,7 +43,7 @@ impl MlsGroup {

self.proposal_store.add(proposal);

let mls_message = self.content_to_mls_message(gce_proposal, backend)?;
let mls_message = self.content_to_mls_message(gce_proposal, backend).await?;

// Since the state of the group might be changed, arm the state flag
self.flag_state_change();
Expand Down Expand Up @@ -84,7 +84,9 @@ impl MlsGroup {

// Convert PublicMessage messages to MLSMessage and encrypt them if required by
// the configuration
let mls_messages = self.content_to_mls_message(create_commit_result.commit, backend)?;
let mls_messages = self
.content_to_mls_message(create_commit_result.commit, backend)
.await?;

// Set the current group state to [`MlsGroupState::PendingCommit`],
// storing the current [`StagedCommit`] from the commit results
Expand Down
14 changes: 10 additions & 4 deletions openmls/src/group/mls_group/membership.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ impl MlsGroup {

// Convert PublicMessage messages to MLSMessage and encrypt them if required by
// the configuration
let mls_messages = self.content_to_mls_message(create_commit_result.commit, backend)?;
let mls_messages = self
.content_to_mls_message(create_commit_result.commit, backend)
.await?;

// Set the current group state to [`MlsGroupState::PendingCommit`],
// storing the current [`StagedCommit`] from the commit results
Expand Down Expand Up @@ -149,7 +151,9 @@ impl MlsGroup {

// Convert PublicMessage messages to MLSMessage and encrypt them if required by
// the configuration
let mls_message = self.content_to_mls_message(create_commit_result.commit, backend)?;
let mls_message = self
.content_to_mls_message(create_commit_result.commit, backend)
.await?;

// Set the current group state to [`MlsGroupState::PendingCommit`],
// storing the current [`StagedCommit`] from the commit results
Expand All @@ -175,7 +179,7 @@ impl MlsGroup {
/// The Remove Proposal is returned as a [`MlsMessageOut`].
///
/// Returns an error if there is a pending commit.
pub fn leave_group(
pub async fn leave_group(
&mut self,
backend: &impl OpenMlsCryptoProvider,
signer: &impl Signer,
Expand All @@ -195,7 +199,9 @@ impl MlsGroup {
remove_proposal.clone(),
)?);

Ok(self.content_to_mls_message(remove_proposal, backend)?)
Ok(self
.content_to_mls_message(remove_proposal, backend)
.await?)
}

/// Returns a list of [`Member`]s in the group.
Expand Down
3 changes: 2 additions & 1 deletion openmls/src/group/mls_group/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ impl MlsGroup {
/// Converts PublicMessage to MlsMessage. Depending on whether handshake
/// message should be encrypted, PublicMessage messages are encrypted to
/// PrivateMessage first.
fn content_to_mls_message(
async fn content_to_mls_message(
&mut self,
mls_auth_content: AuthenticatedContent,
backend: &impl OpenMlsCryptoProvider,
Expand All @@ -383,6 +383,7 @@ impl MlsGroup {
self.configuration().padding_size(),
backend,
)
.await
// We can be sure the encryption will work because the plaintext was created by us
.map_err(|_| LibraryError::custom("Malformed plaintext"))?;
MlsMessageOut::from_private_message(ciphertext, self.group.version())
Expand Down
Loading

0 comments on commit 651d930

Please sign in to comment.