From c118378e7c7f2e4084fa3036e63591f0841fec3c Mon Sep 17 00:00:00 2001 From: "Jan Winkelmann (keks)" Date: Wed, 10 Jan 2024 14:45:55 +0100 Subject: [PATCH 1/5] Add first draft of mutable metadata extension This is similar to the ProtectedMetadata extension, with the exception that the payload is not signed. Whether and how the payload should be processed is up to the application. --- openmls/src/extensions/codec.rs | 10 +++++++++- openmls/src/extensions/mod.rs | 11 +++++++++++ openmls/src/extensions/mutable_metadata.rs | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 openmls/src/extensions/mutable_metadata.rs diff --git a/openmls/src/extensions/codec.rs b/openmls/src/extensions/codec.rs index 487083b104..b7c4ca0efb 100644 --- a/openmls/src/extensions/codec.rs +++ b/openmls/src/extensions/codec.rs @@ -8,7 +8,10 @@ use crate::extensions::{ UnknownExtension, }; -use super::{last_resort::LastResortExtension, protected_metadata::ProtectedMetadata}; +use super::{ + last_resort::LastResortExtension, mutable_metadata::MutableMetadata, + protected_metadata::ProtectedMetadata, +}; fn vlbytes_len_len(length: usize) -> usize { if length < 0x40 { @@ -38,6 +41,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::MutableMetadata(e) => e.tls_serialized_len(), Extension::Unknown(_, e) => e.0.len(), }; @@ -71,6 +75,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::MutableMetadata(e) => e.tls_serialize(&mut extension_data), Extension::Unknown(_, e) => extension_data .write_all(e.0.as_slice()) .map(|_| e.0.len()) @@ -123,6 +128,9 @@ impl Deserialize for Extension { ExtensionType::ProtectedMetadata => Extension::ProtectedMetadata( ProtectedMetadata::tls_deserialize(&mut extension_data)?, ), + ExtensionType::MutableMetadata => { + Extension::MutableMetadata(MutableMetadata::tls_deserialize(&mut extension_data)?) + } ExtensionType::Unknown(unknown) => { Extension::Unknown(unknown, UnknownExtension(extension_data.to_vec())) } diff --git a/openmls/src/extensions/mod.rs b/openmls/src/extensions/mod.rs index 69bd3bfedf..55aca593a1 100644 --- a/openmls/src/extensions/mod.rs +++ b/openmls/src/extensions/mod.rs @@ -32,6 +32,7 @@ mod codec; mod external_pub_extension; mod external_sender_extension; mod last_resort; +mod mutable_metadata; mod protected_metadata; mod ratchet_tree_extension; mod required_capabilities; @@ -52,6 +53,8 @@ pub use required_capabilities::RequiredCapabilitiesExtension; pub use protected_metadata::ProtectedMetadata; +use self::mutable_metadata::MutableMetadata; + #[cfg(test)] mod test_extensions; @@ -100,6 +103,8 @@ pub enum ExtensionType { /// extension ProtectedMetadata, + MutableMetadata, + /// A currently unknown extension type. Unknown(u16), } @@ -140,6 +145,7 @@ impl From for ExtensionType { 5 => ExtensionType::ExternalSenders, 10 => ExtensionType::LastResort, 11 => ExtensionType::ProtectedMetadata, + 0xf001 => ExtensionType::MutableMetadata, unknown => ExtensionType::Unknown(unknown), } } @@ -155,6 +161,7 @@ impl From for u16 { ExtensionType::ExternalSenders => 5, ExtensionType::LastResort => 10, ExtensionType::ProtectedMetadata => 11, + ExtensionType::MutableMetadata => 0xf001, ExtensionType::Unknown(unknown) => unknown, } } @@ -172,6 +179,7 @@ impl ExtensionType { | ExtensionType::ExternalSenders | ExtensionType::LastResort | ExtensionType::ProtectedMetadata + | ExtensionType::MutableMetadata ) } } @@ -213,6 +221,8 @@ pub enum Extension { /// A [`ProtectedMetadata`] extension ProtectedMetadata(ProtectedMetadata), + MutableMetadata(MutableMetadata), + /// A currently unknown extension. Unknown(u16, UnknownExtension), } @@ -490,6 +500,7 @@ impl Extension { Extension::ExternalSenders(_) => ExtensionType::ExternalSenders, Extension::LastResort(_) => ExtensionType::LastResort, Extension::ProtectedMetadata(_) => ExtensionType::ProtectedMetadata, + Extension::MutableMetadata(_) => ExtensionType::MutableMetadata, Extension::Unknown(kind, _) => ExtensionType::Unknown(*kind), } } diff --git a/openmls/src/extensions/mutable_metadata.rs b/openmls/src/extensions/mutable_metadata.rs new file mode 100644 index 0000000000..be24578682 --- /dev/null +++ b/openmls/src/extensions/mutable_metadata.rs @@ -0,0 +1,19 @@ +use super::{Deserialize, Serialize}; +use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize}; + +#[derive( + PartialEq, Eq, Clone, Debug, Serialize, Deserialize, TlsDeserialize, TlsSerialize, TlsSize, +)] +pub struct MutableMetadata { + metadata: Vec, +} + +impl MutableMetadata { + pub fn new(metadata: Vec) -> Self { + Self { metadata } + } + + pub fn metadata(&self) -> &Vec { + &self.metadata + } +} From 08bd8ce86415809d96339fc09fa01c276bbcf14a Mon Sep 17 00:00:00 2001 From: "Jan Winkelmann (keks)" Date: Wed, 10 Jan 2024 16:50:58 +0100 Subject: [PATCH 2/5] rename to Metadata, add test --- openmls/src/extensions/codec.rs | 11 +++--- .../{mutable_metadata.rs => metadata.rs} | 4 +- openmls/src/extensions/mod.rs | 24 ++++++++---- openmls/src/extensions/test_extensions.rs | 39 +++++++++++++++++++ 4 files changed, 62 insertions(+), 16 deletions(-) rename openmls/src/extensions/{mutable_metadata.rs => metadata.rs} (87%) diff --git a/openmls/src/extensions/codec.rs b/openmls/src/extensions/codec.rs index b7c4ca0efb..696ec5c364 100644 --- a/openmls/src/extensions/codec.rs +++ b/openmls/src/extensions/codec.rs @@ -9,8 +9,7 @@ use crate::extensions::{ }; use super::{ - last_resort::LastResortExtension, mutable_metadata::MutableMetadata, - protected_metadata::ProtectedMetadata, + last_resort::LastResortExtension, metadata::Metadata, protected_metadata::ProtectedMetadata, }; fn vlbytes_len_len(length: usize) -> usize { @@ -41,7 +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::MutableMetadata(e) => e.tls_serialized_len(), + Extension::Metadata(e) => e.tls_serialized_len(), Extension::Unknown(_, e) => e.0.len(), }; @@ -75,7 +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::MutableMetadata(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()) @@ -128,8 +127,8 @@ impl Deserialize for Extension { ExtensionType::ProtectedMetadata => Extension::ProtectedMetadata( ProtectedMetadata::tls_deserialize(&mut extension_data)?, ), - ExtensionType::MutableMetadata => { - Extension::MutableMetadata(MutableMetadata::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())) diff --git a/openmls/src/extensions/mutable_metadata.rs b/openmls/src/extensions/metadata.rs similarity index 87% rename from openmls/src/extensions/mutable_metadata.rs rename to openmls/src/extensions/metadata.rs index be24578682..31dd9e217b 100644 --- a/openmls/src/extensions/mutable_metadata.rs +++ b/openmls/src/extensions/metadata.rs @@ -4,11 +4,11 @@ use tls_codec::{TlsDeserialize, TlsSerialize, TlsSize}; #[derive( PartialEq, Eq, Clone, Debug, Serialize, Deserialize, TlsDeserialize, TlsSerialize, TlsSize, )] -pub struct MutableMetadata { +pub struct Metadata { metadata: Vec, } -impl MutableMetadata { +impl Metadata { pub fn new(metadata: Vec) -> Self { Self { metadata } } diff --git a/openmls/src/extensions/mod.rs b/openmls/src/extensions/mod.rs index 55aca593a1..118b3df0b8 100644 --- a/openmls/src/extensions/mod.rs +++ b/openmls/src/extensions/mod.rs @@ -32,7 +32,7 @@ mod codec; mod external_pub_extension; mod external_sender_extension; mod last_resort; -mod mutable_metadata; +mod metadata; mod protected_metadata; mod ratchet_tree_extension; mod required_capabilities; @@ -53,7 +53,7 @@ pub use required_capabilities::RequiredCapabilitiesExtension; pub use protected_metadata::ProtectedMetadata; -use self::mutable_metadata::MutableMetadata; +pub use metadata::Metadata; #[cfg(test)] mod test_extensions; @@ -103,7 +103,7 @@ pub enum ExtensionType { /// extension ProtectedMetadata, - MutableMetadata, + Metadata, /// A currently unknown extension type. Unknown(u16), @@ -145,7 +145,7 @@ impl From for ExtensionType { 5 => ExtensionType::ExternalSenders, 10 => ExtensionType::LastResort, 11 => ExtensionType::ProtectedMetadata, - 0xf001 => ExtensionType::MutableMetadata, + 0xf001 => ExtensionType::Metadata, unknown => ExtensionType::Unknown(unknown), } } @@ -161,7 +161,7 @@ impl From for u16 { ExtensionType::ExternalSenders => 5, ExtensionType::LastResort => 10, ExtensionType::ProtectedMetadata => 11, - ExtensionType::MutableMetadata => 0xf001, + ExtensionType::Metadata => 0xf001, ExtensionType::Unknown(unknown) => unknown, } } @@ -179,7 +179,7 @@ impl ExtensionType { | ExtensionType::ExternalSenders | ExtensionType::LastResort | ExtensionType::ProtectedMetadata - | ExtensionType::MutableMetadata + | ExtensionType::Metadata ) } } @@ -221,7 +221,7 @@ pub enum Extension { /// A [`ProtectedMetadata`] extension ProtectedMetadata(ProtectedMetadata), - MutableMetadata(MutableMetadata), + Metadata(Metadata), /// A currently unknown extension. Unknown(u16, UnknownExtension), @@ -410,6 +410,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 { @@ -500,7 +508,7 @@ impl Extension { Extension::ExternalSenders(_) => ExtensionType::ExternalSenders, Extension::LastResort(_) => ExtensionType::LastResort, Extension::ProtectedMetadata(_) => ExtensionType::ProtectedMetadata, - Extension::MutableMetadata(_) => ExtensionType::MutableMetadata, + Extension::Metadata(_) => ExtensionType::Metadata, Extension::Unknown(kind, _) => ExtensionType::Unknown(*kind), } } diff --git a/openmls/src/extensions/test_extensions.rs b/openmls/src/extensions/test_extensions.rs index 69b9d0bd4a..c48e1f7ba6 100644 --- a/openmls/src/extensions/test_extensions.rs +++ b/openmls/src/extensions/test_extensions.rs @@ -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()); From 7830b2203291e3b07634c10b7f66295b6e01a938 Mon Sep 17 00:00:00 2001 From: "Jan Winkelmann (keks)" Date: Thu, 11 Jan 2024 10:54:47 +0100 Subject: [PATCH 3/5] add comments --- openmls/src/extensions/metadata.rs | 4 ++++ openmls/src/extensions/mod.rs | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/openmls/src/extensions/metadata.rs b/openmls/src/extensions/metadata.rs index 31dd9e217b..f2e1ab53b8 100644 --- a/openmls/src/extensions/metadata.rs +++ b/openmls/src/extensions/metadata.rs @@ -1,6 +1,8 @@ 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, )] @@ -9,10 +11,12 @@ pub struct Metadata { } impl Metadata { + /// Create a new [`Metadata`] extension. pub fn new(metadata: Vec) -> Self { Self { metadata } } + /// Get the metadata bytes. pub fn metadata(&self) -> &Vec { &self.metadata } diff --git a/openmls/src/extensions/mod.rs b/openmls/src/extensions/mod.rs index 118b3df0b8..651df776c1 100644 --- a/openmls/src/extensions/mod.rs +++ b/openmls/src/extensions/mod.rs @@ -51,9 +51,8 @@ pub use last_resort::LastResortExtension; pub use ratchet_tree_extension::RatchetTreeExtension; pub use required_capabilities::RequiredCapabilitiesExtension; -pub use protected_metadata::ProtectedMetadata; - pub use metadata::Metadata; +pub use protected_metadata::ProtectedMetadata; #[cfg(test)] mod test_extensions; @@ -103,6 +102,7 @@ pub enum ExtensionType { /// extension ProtectedMetadata, + /// Metadata extension for policies and other metadata. GroupContext Extension. Metadata, /// A currently unknown extension type. @@ -221,6 +221,7 @@ pub enum Extension { /// A [`ProtectedMetadata`] extension ProtectedMetadata(ProtectedMetadata), + // A [`Metadata`] extension Metadata(Metadata), /// A currently unknown extension. From 6d9e78c6e5f3cfb0c3a63ed77b3ed87df9f92deb Mon Sep 17 00:00:00 2001 From: "Jan Winkelmann (keks)" Date: Thu, 11 Jan 2024 10:58:58 +0100 Subject: [PATCH 4/5] change ProtectedMetadata extension id to 0xf002 --- openmls/src/extensions/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmls/src/extensions/mod.rs b/openmls/src/extensions/mod.rs index 651df776c1..15e91ac44e 100644 --- a/openmls/src/extensions/mod.rs +++ b/openmls/src/extensions/mod.rs @@ -144,8 +144,8 @@ impl From for ExtensionType { 4 => ExtensionType::ExternalPub, 5 => ExtensionType::ExternalSenders, 10 => ExtensionType::LastResort, - 11 => ExtensionType::ProtectedMetadata, 0xf001 => ExtensionType::Metadata, + 0xf002 => ExtensionType::ProtectedMetadata, unknown => ExtensionType::Unknown(unknown), } } @@ -160,8 +160,8 @@ impl From for u16 { ExtensionType::ExternalPub => 4, ExtensionType::ExternalSenders => 5, ExtensionType::LastResort => 10, - ExtensionType::ProtectedMetadata => 11, ExtensionType::Metadata => 0xf001, + ExtensionType::ProtectedMetadata => 0xf002, ExtensionType::Unknown(unknown) => unknown, } } From c771d65935ab1938535f2eb8c80e89872711bb89 Mon Sep 17 00:00:00 2001 From: "Jan Winkelmann (keks)" Date: Wed, 17 Jan 2024 17:06:38 +0100 Subject: [PATCH 5/5] update test that assumed 0xf000 was an unknown extension --- openmls/src/extensions/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openmls/src/extensions/mod.rs b/openmls/src/extensions/mod.rs index 15e91ac44e..1123891033 100644 --- a/openmls/src/extensions/mod.rs +++ b/openmls/src/extensions/mod.rs @@ -144,8 +144,8 @@ impl From for ExtensionType { 4 => ExtensionType::ExternalPub, 5 => ExtensionType::ExternalSenders, 10 => ExtensionType::LastResort, + 0xf000 => ExtensionType::ProtectedMetadata, 0xf001 => ExtensionType::Metadata, - 0xf002 => ExtensionType::ProtectedMetadata, unknown => ExtensionType::Unknown(unknown), } } @@ -160,8 +160,8 @@ impl From for u16 { ExtensionType::ExternalPub => 4, ExtensionType::ExternalSenders => 5, ExtensionType::LastResort => 10, + ExtensionType::ProtectedMetadata => 0xf000, ExtensionType::Metadata => 0xf001, - ExtensionType::ProtectedMetadata => 0xf002, ExtensionType::Unknown(unknown) => unknown, } } @@ -614,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() {