Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
beltram committed Dec 21, 2023
1 parent 20917e8 commit 3b98d53
Show file tree
Hide file tree
Showing 36 changed files with 427 additions and 241 deletions.
5 changes: 4 additions & 1 deletion openmls/src/credentials/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::error::LibraryError;
use thiserror::Error;

/// An error that occurs in methods of a [`super::Credential`].
#[derive(Error, Debug, PartialEq, Clone)]
#[derive(Error, Debug, Eq, PartialEq, Clone)]
pub enum CredentialError {
/// A library error occurred.
#[error(transparent)]
Expand All @@ -26,4 +26,7 @@ pub enum CredentialError {
/// x509 certificate chain is either unordered or a child is missigned by its issuer
#[error("Invalid x509 certificate chain.")]
InvalidCertificateChain,
/// one of x509 certificate chain member is expired
#[error("Expired x509 certificate chain.")]
ExpiredCertificate,
}
20 changes: 20 additions & 0 deletions openmls/src/credentials/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mod codec;
#[cfg(test)]
mod tests;
use errors::*;
use openmls_traits::types::CryptoError;
use openmls_x509_credential::X509Ext;
use x509_cert::{der::Decode, PkiPath};

Expand Down Expand Up @@ -273,6 +274,25 @@ impl Credential {
MlsCredentialType::X509(cert) => cert.identity.as_slice(),
}
}

pub fn verify(&self) -> Result<(), CredentialError> {
match &self.credential {
MlsCredentialType::X509(cert) => {
// TODO: implement this on the whole chain with certval
let ee_cert = cert
.certificates
.first()
.ok_or(CredentialError::InvalidCertificateChain)?;
let ee_cert = x509_cert::Certificate::from_der(ee_cert.as_slice())?;
ee_cert.is_valid().map_err(|e| match e {
CryptoError::ExpiredCertificate => CredentialError::ExpiredCertificate,
_ => CredentialError::InvalidCertificateChain,
})?;
}
MlsCredentialType::Basic(_) => {}
}
Ok(())
}
}

impl From<MlsCredentialType> for Credential {
Expand Down
4 changes: 2 additions & 2 deletions openmls/src/extensions/test_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async fn ratchet_tree_extension(ciphersuite: Ciphersuite, backend: &impl OpenMls

let bob_group = match CoreGroup::new_from_welcome(
create_commit_result
.welcome_option
.welcome
.expect("An unexpected error occurred."),
None,
bob_kpb.key_package(),
Expand Down Expand Up @@ -186,7 +186,7 @@ async fn ratchet_tree_extension(ciphersuite: Ciphersuite, backend: &impl OpenMls

let error = CoreGroup::new_from_welcome(
create_commit_result
.welcome_option
.welcome
.expect("An unexpected error occurred."),
None,
bob_kpb.key_package(),
Expand Down
8 changes: 4 additions & 4 deletions openmls/src/framing/test_framing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ async fn unknown_sender(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr

let _group_bob = CoreGroup::new_from_welcome(
create_commit_result
.welcome_option
.welcome
.expect("An unexpected error occurred."),
Some(group_alice.public_group().export_ratchet_tree().into()),
bob_kpb.key_package(),
Expand Down Expand Up @@ -495,7 +495,7 @@ async fn unknown_sender(ciphersuite: Ciphersuite, backend: &impl OpenMlsCryptoPr

let mut group_charlie = CoreGroup::new_from_welcome(
create_commit_result
.welcome_option
.welcome
.expect("An unexpected error occurred."),
Some(group_alice.public_group().export_ratchet_tree().into()),
charlie_kpb.key_package(),
Expand Down Expand Up @@ -684,7 +684,7 @@ pub(crate) async fn setup_alice_bob_group(
};
assert!(!commit.has_path());
// Check that the function returned a Welcome message
assert!(create_commit_result.welcome_option.is_some());
assert!(create_commit_result.welcome.is_some());

group_alice
.merge_commit(backend, create_commit_result.staged_commit)
Expand All @@ -695,7 +695,7 @@ pub(crate) async fn setup_alice_bob_group(
// broken confirmation tag, because Alice can't process her own commit.
let group_bob = CoreGroup::new_from_welcome(
create_commit_result
.welcome_option
.welcome
.expect("commit didn't return a welcome as expected"),
Some(group_alice.public_group().export_ratchet_tree().into()),
bob_kpb.key_package(),
Expand Down
69 changes: 39 additions & 30 deletions openmls/src/framing/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
//! │ │
//! ▼ -'
//! ProcessedMessage
//!
//! ```
// TODO #106/#151: Update the above diagram

Expand Down Expand Up @@ -53,9 +52,10 @@ use super::{
*,
};

/// Intermediate message that can be constructed either from a public message or from private message.
/// If it it constructed from a ciphertext message, the ciphertext message is decrypted first.
/// This function implements the following checks:
/// Intermediate message that can be constructed either from a public message or
/// from private message. If it it constructed from a ciphertext message, the
/// ciphertext message is decrypted first. This function implements the
/// following checks:
/// - ValSem005
/// - ValSem007
/// - ValSem009
Expand All @@ -78,9 +78,9 @@ impl DecryptedMessage {
}

if let Some(message_secrets) = message_secrets_option.into() {
// Verify the membership tag. This needs to be done explicitly for PublicMessage messages,
// it is implicit for PrivateMessage messages (because the encryption can only be known by members).
// ValSem008
// Verify the membership tag. This needs to be done explicitly for PublicMessage
// messages, it is implicit for PrivateMessage messages (because
// the encryption can only be known by members). ValSem008
public_message.verify_membership(
backend,
message_secrets.membership_key(),
Expand All @@ -94,8 +94,8 @@ impl DecryptedMessage {
Self::from_verifiable_content(verifiable_content)
}

/// Constructs a [DecryptedMessage] from a [PrivateMessage] by attempting to decrypt it
/// to a [VerifiableAuthenticatedContent] first.
/// Constructs a [DecryptedMessage] from a [PrivateMessage] by attempting to
/// decrypt it to a [VerifiableAuthenticatedContent] first.
pub(crate) fn from_inbound_ciphertext(
ciphertext: PrivateMessageIn,
backend: &impl OpenMlsCryptoProvider,
Expand Down Expand Up @@ -126,7 +126,8 @@ impl DecryptedMessage {

// Internal constructor function. Does the following checks:
// - Confirmation tag must be present for Commit messages
// - Membership tag must be present for member messages, if the original incoming message was not an PrivateMessage
// - Membership tag must be present for member messages, if the original
// incoming message was not an PrivateMessage
// - Ensures application messages were originally PrivateMessage messages
fn from_verifiable_content(
verifiable_content: VerifiableAuthenticatedContentIn,
Expand All @@ -142,19 +143,20 @@ impl DecryptedMessage {
if verifiable_content.wire_format() != WireFormat::PrivateMessage {
return Err(ValidationError::UnencryptedApplicationMessage);
} else if !verifiable_content.sender().is_member() {
// This should not happen because the sender of an PrivateMessage should always be a member
// This should not happen because the sender of an PrivateMessage should always
// be a member
return Err(LibraryError::custom("Expected sender to be member.").into());
}
}
Ok(DecryptedMessage { verifiable_content })
}

/// Gets the correct credential from the message depending on the sender type.
/// Checks the following semantic validation:
/// Gets the correct credential from the message depending on the sender
/// type. Checks the following semantic validation:
/// - ValSem112
/// - ValSem245
/// - Prepares ValSem246 by setting the right credential. The remainder
/// of ValSem246 is validated as part of ValSem010.
/// - Prepares ValSem246 by setting the right credential. The remainder of
/// ValSem246 is validated as part of ValSem010.
///
/// Returns the [`Credential`] and the leaf's [`SignaturePublicKey`].
pub fn credential(
Expand Down Expand Up @@ -242,8 +244,8 @@ pub enum SenderContext {
ExternalCommit((GroupId, LeafNodeIndex)),
}

/// Partially checked and potentially decrypted message (if it was originally encrypted).
/// Use this to inspect the [`Credential`] of the message sender
/// Partially checked and potentially decrypted message (if it was originally
/// encrypted). Use this to inspect the [`Credential`] of the message sender
/// and the optional `aad` if the original message was encrypted.
/// The [`OpenMlsSignaturePublicKey`] is used to verify the signature of the
/// message.
Expand All @@ -256,7 +258,8 @@ pub(crate) struct UnverifiedMessage {
}

impl UnverifiedMessage {
/// Construct an [UnverifiedMessage] from a [DecryptedMessage] and an optional [Credential].
/// Construct an [UnverifiedMessage] from a [DecryptedMessage] and an
/// optional [Credential].
pub(crate) fn from_decrypted_message(
decrypted_message: DecryptedMessage,
credential: Credential,
Expand Down Expand Up @@ -402,32 +405,38 @@ impl ProcessedMessage {
/// Content of a processed message.
///
/// See the content variants' documentation for more information.
/// [`StagedCommit`] and [`QueuedProposal`] can be inspected for authorization purposes.
/// [`StagedCommit`] and [`QueuedProposal`] can be inspected for authorization
/// purposes.
#[derive(Debug)]
pub enum ProcessedMessageContent {
/// An application message.
///
/// The [`ApplicationMessage`] contains a vector of bytes that can be used right-away.
/// The [`ApplicationMessage`] contains a vector of bytes that can be used
/// right-away.
ApplicationMessage(ApplicationMessage),
/// A standalone proposal.
///
/// The [`QueuedProposal`] can be inspected for authorization purposes by the application.
/// If the proposal is deemed to be allowed, it should be added to the group's proposal
/// queue using [`MlsGroup::store_pending_proposal()`](crate::group::mls_group::MlsGroup::store_pending_proposal()).
/// The [`QueuedProposal`] can be inspected for authorization purposes by
/// the application. If the proposal is deemed to be allowed, it should
/// be added to the group's proposal queue using
/// [`MlsGroup::store_pending_proposal()`](crate::group::mls_group::MlsGroup::store_pending_proposal()).
ProposalMessage(Box<QueuedProposal>),
/// An [external join proposal](crate::prelude::JoinProposal) sent by a
/// [NewMemberProposal](crate::prelude::Sender::NewMemberProposal) sender which is outside the group.
/// [NewMemberProposal](crate::prelude::Sender::NewMemberProposal) sender
/// which is outside the group.
///
/// Since this originates from a party outside the group, the [`QueuedProposal`] SHOULD be
/// inspected for authorization purposes by the application. If the proposal is deemed to be
/// allowed, it should be added to the group's proposal queue using
/// Since this originates from a party outside the group, the
/// [`QueuedProposal`] SHOULD be inspected for authorization purposes by
/// the application. If the proposal is deemed to be allowed, it should
/// be added to the group's proposal queue using
/// [`MlsGroup::store_pending_proposal()`](crate::group::mls_group::MlsGroup::store_pending_proposal()).
ExternalJoinProposalMessage(Box<QueuedProposal>),
/// A Commit message.
///
/// The [`StagedCommit`] can be inspected for authorization purposes by the application.
/// If the type of the commit and the proposals it covers are deemed to be allowed,
/// the commit should be merged into the group's state using
/// The [`StagedCommit`] can be inspected for authorization purposes by the
/// application. If the type of the commit and the proposals it covers
/// are deemed to be allowed, the commit should be merged into the
/// group's state using
/// [`MlsGroup::merge_staged_commit()`](crate::group::mls_group::MlsGroup::merge_staged_commit()).
StagedCommitMessage(Box<StagedCommit>),
}
Expand Down
20 changes: 12 additions & 8 deletions openmls/src/group/core_group/kat_welcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
//! * Decrypt the encrypted group info
//! * Verify the signature on the decrypted group info using `signer_pub`
//! * Verify the `confirmation_tag` in the decrypted group info:
//! * Initialize a key schedule epoch using the decrypted `joiner_secret` and no PSKs
//! * Recompute a candidate `confirmation_tag` value using the `confirmation_key`
//! from the key schedule epoch and the `confirmed_transcript_hash` from the
//! decrypted GroupContext
//! * Initialize a key schedule epoch using the decrypted `joiner_secret` and
//! no PSKs
//! * Recompute a candidate `confirmation_tag` value using the
//! `confirmation_key` from the key schedule epoch and the
//! `confirmed_transcript_hash` from the decrypted GroupContext
use openmls_rust_crypto::OpenMlsRustCrypto;
use openmls_traits::{crypto::OpenMlsCrypto, key_store::OpenMlsKeyStore, OpenMlsCryptoProvider};
Expand Down Expand Up @@ -187,12 +188,12 @@ pub async fn run_test_vector(test_vector: WelcomeTestVector) -> Result<(), &'sta
// Verification:
// * Decrypt the Welcome message:
// * Identify the entry in `welcome.secrets` corresponding to `key_package`
let encrypted_group_secrets = CoreGroup::find_key_package_from_welcome_secrets(
let encrypted_group_secrets = CoreGroup::find_group_secrets_from_key_package(
key_package_bundle
.key_package()
.hash_ref(backend.crypto())
.unwrap(),
welcome.secrets(),
welcome.secrets().to_vec(),
)
.unwrap();
println!("{encrypted_group_secrets:?}");
Expand Down Expand Up @@ -254,8 +255,11 @@ pub async fn run_test_vector(test_vector: WelcomeTestVector) -> Result<(), &'sta

// * Verify the confirmation_tag in the decrypted group info:
//
// * Initialize a key schedule epoch using the decrypted joiner_secret and no PSKs
// * Recompute a candidate confirmation_tag value using the confirmation_key from the key schedule epoch and the confirmed_transcript_hash from the decrypted GroupContext
// * Initialize a key schedule epoch using the decrypted joiner_secret and no
// PSKs
// * Recompute a candidate confirmation_tag value using the confirmation_key
// from the key schedule epoch and the confirmed_transcript_hash from the
// decrypted GroupContext
let group_context = GroupContext::from(group_info.clone());

let serialized_group_context = group_context.tls_serialize_detached().unwrap();
Expand Down
Loading

0 comments on commit 3b98d53

Please sign in to comment.