Skip to content
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

Add Simple Metadata Extension #12

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion openmls/src/extensions/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use crate::extensions::{
UnknownExtension,
};

use super::{last_resort::LastResortExtension, protected_metadata::ProtectedMetadata};
use super::{
last_resort::LastResortExtension, metadata::Metadata, protected_metadata::ProtectedMetadata,
};

fn vlbytes_len_len(length: usize) -> usize {
if length < 0x40 {
Expand Down Expand Up @@ -38,6 +40,7 @@ impl Size for Extension {
Extension::ExternalSenders(e) => e.tls_serialized_len(),
Extension::LastResort(e) => e.tls_serialized_len(),
Extension::ProtectedMetadata(e) => e.tls_serialized_len(),
Extension::Metadata(e) => e.tls_serialized_len(),
Extension::Unknown(_, e) => e.0.len(),
};

Expand Down Expand Up @@ -71,6 +74,7 @@ impl Serialize for Extension {
Extension::ExternalSenders(e) => e.tls_serialize(&mut extension_data),
Extension::LastResort(e) => e.tls_serialize(&mut extension_data),
Extension::ProtectedMetadata(e) => e.tls_serialize(&mut extension_data),
Extension::Metadata(e) => e.tls_serialize(&mut extension_data),
Extension::Unknown(_, e) => extension_data
.write_all(e.0.as_slice())
.map(|_| e.0.len())
Expand Down Expand Up @@ -123,6 +127,9 @@ impl Deserialize for Extension {
ExtensionType::ProtectedMetadata => Extension::ProtectedMetadata(
ProtectedMetadata::tls_deserialize(&mut extension_data)?,
),
ExtensionType::Metadata => {
Extension::Metadata(Metadata::tls_deserialize(&mut extension_data)?)
}
ExtensionType::Unknown(unknown) => {
Extension::Unknown(unknown, UnknownExtension(extension_data.to_vec()))
}
Expand Down
23 changes: 23 additions & 0 deletions openmls/src/extensions/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use super::{Deserialize, Serialize};
use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize};

/// Metadata is an extension that keeps arbitrary application-specific metadata, in the form of a
/// byte sequence. The application is responsible for specifying a format and parsing the contents.
#[derive(
PartialEq, Eq, Clone, Debug, Serialize, Deserialize, TlsDeserialize, TlsSerialize, TlsSize,
)]
pub struct Metadata {
metadata: Vec<u8>,
}

impl Metadata {
/// Create a new [`Metadata`] extension.
pub fn new(metadata: Vec<u8>) -> Self {
Self { metadata }
}

/// Get the metadata bytes.
pub fn metadata(&self) -> &Vec<u8> {
&self.metadata
}
}
26 changes: 23 additions & 3 deletions openmls/src/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod codec;
mod external_pub_extension;
mod external_sender_extension;
mod last_resort;
mod metadata;
mod protected_metadata;
mod ratchet_tree_extension;
mod required_capabilities;
Expand All @@ -50,6 +51,7 @@ pub use last_resort::LastResortExtension;
pub use ratchet_tree_extension::RatchetTreeExtension;
pub use required_capabilities::RequiredCapabilitiesExtension;

pub use metadata::Metadata;
pub use protected_metadata::ProtectedMetadata;

#[cfg(test)]
Expand Down Expand Up @@ -100,6 +102,9 @@ pub enum ExtensionType {
/// extension
ProtectedMetadata,

/// Metadata extension for policies and other metadata. GroupContext Extension.
Metadata,

/// A currently unknown extension type.
Unknown(u16),
}
Expand Down Expand Up @@ -139,7 +144,8 @@ impl From<u16> for ExtensionType {
4 => ExtensionType::ExternalPub,
5 => ExtensionType::ExternalSenders,
10 => ExtensionType::LastResort,
11 => ExtensionType::ProtectedMetadata,
0xf000 => ExtensionType::ProtectedMetadata,
0xf001 => ExtensionType::Metadata,
unknown => ExtensionType::Unknown(unknown),
}
}
Expand All @@ -154,7 +160,8 @@ impl From<ExtensionType> for u16 {
ExtensionType::ExternalPub => 4,
ExtensionType::ExternalSenders => 5,
ExtensionType::LastResort => 10,
ExtensionType::ProtectedMetadata => 11,
ExtensionType::ProtectedMetadata => 0xf000,
ExtensionType::Metadata => 0xf001,
ExtensionType::Unknown(unknown) => unknown,
}
}
Expand All @@ -172,6 +179,7 @@ impl ExtensionType {
| ExtensionType::ExternalSenders
| ExtensionType::LastResort
| ExtensionType::ProtectedMetadata
| ExtensionType::Metadata
)
}
}
Expand Down Expand Up @@ -213,6 +221,9 @@ pub enum Extension {
/// A [`ProtectedMetadata`] extension
ProtectedMetadata(ProtectedMetadata),

// A [`Metadata`] extension
Metadata(Metadata),

/// A currently unknown extension.
Unknown(u16, UnknownExtension),
}
Expand Down Expand Up @@ -400,6 +411,14 @@ impl Extensions {
_ => None,
})
}

pub fn metadata(&self) -> Option<&Metadata> {
self.find_by_type(ExtensionType::Metadata)
.and_then(|e| match e {
Extension::Metadata(e) => Some(e),
_ => None,
})
}
}

impl Extension {
Expand Down Expand Up @@ -490,6 +509,7 @@ impl Extension {
Extension::ExternalSenders(_) => ExtensionType::ExternalSenders,
Extension::LastResort(_) => ExtensionType::LastResort,
Extension::ProtectedMetadata(_) => ExtensionType::ProtectedMetadata,
Extension::Metadata(_) => ExtensionType::Metadata,
Extension::Unknown(kind, _) => ExtensionType::Unknown(*kind),
}
}
Expand Down Expand Up @@ -594,7 +614,7 @@ mod test {

#[test]
fn that_unknown_extensions_are_de_serialized_correctly() {
let extension_types = [0x0000u16, 0x0A0A, 0x7A7A, 0xF000, 0xFFFF];
let extension_types = [0x0000u16, 0x0A0A, 0x7A7A, 0xF100, 0xFFFF];
let extension_datas = [vec![], vec![0], vec![1, 2, 3]];

for extension_type in extension_types.into_iter() {
Expand Down
39 changes: 39 additions & 0 deletions openmls/src/extensions/test_extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,45 @@ fn required_capabilities() {
assert_eq!(extension_bytes, encoded);
}

#[apply(ciphersuites_and_providers)]
fn test_metadata(ciphersuite: Ciphersuite, provider: &impl OpenMlsProvider) {
// Create credentials and keys
//let (alice_credential_with_key, alice_signature_keys) =
let alice_credential_with_key_and_signer = tests::utils::generate_credential_with_key(
b"Alice".into(),
ciphersuite.signature_algorithm(),
provider,
);

// example metadata (opaque data -- test hex string is "1cedc0ffee")
let metadata = vec![0x1c, 0xed, 0xc0, 0xff, 0xee];
let ext = Extension::Metadata(Metadata::new(metadata.clone()));
let extensions = Extensions::from_vec(vec![ext]).expect("could not build extensions struct");

let config = MlsGroupConfig::builder()
.group_context_extensions(extensions)
.build();

// === Alice creates a group with the ratchet tree extension ===
let alice_group = MlsGroup::new(
provider,
&alice_credential_with_key_and_signer.signer,
&config,
alice_credential_with_key_and_signer
.credential_with_key
.clone(),
)
.expect("failed to build group");

let got_metadata = alice_group
.export_group_context()
.extensions()
.metadata()
.expect("failed to read group metadata");

assert_eq!(got_metadata.metadata(), &metadata);
}

#[apply(ciphersuites_and_providers)]
fn last_resort_extension(ciphersuite: Ciphersuite, provider: &impl OpenMlsProvider) {
let last_resort = Extension::LastResort(LastResortExtension::default());
Expand Down