1use std::{
25 convert::Infallible,
26 fmt::Debug,
27 io::{Read, Write},
28 marker::PhantomData,
29};
30
31use serde::{Deserialize, Serialize};
32
33#[cfg(feature = "extensions-draft")]
35mod app_data_dict_extension;
36mod application_id_extension;
37mod codec;
38mod external_pub_extension;
39mod external_sender_extension;
40mod last_resort;
41mod ratchet_tree_extension;
42mod required_capabilities;
43use errors::*;
44
45pub mod errors;
47
48#[cfg(feature = "extensions-draft")]
50pub use app_data_dict_extension::{AppDataDictionary, AppDataDictionaryExtension};
51pub use application_id_extension::ApplicationIdExtension;
52pub use external_pub_extension::ExternalPubExtension;
53pub use external_sender_extension::{
54 ExternalSender, ExternalSendersExtension, SenderExtensionIndex,
55};
56pub use last_resort::LastResortExtension;
57pub use ratchet_tree_extension::RatchetTreeExtension;
58pub use required_capabilities::RequiredCapabilitiesExtension;
59
60use tls_codec::{
61 Deserialize as TlsDeserializeTrait, DeserializeBytes, Error, Serialize as TlsSerializeTrait,
62 Size, TlsDeserialize, TlsSerialize, TlsSize,
63};
64
65use crate::{
66 group::GroupContext, key_packages::KeyPackage, messages::group_info::GroupInfo,
67 treesync::LeafNode,
68};
69
70#[cfg(test)]
71mod tests;
72
73#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
89#[cfg_attr(
90 feature = "0-8-1-storage-format",
91 derive(serde::Serialize, serde::Deserialize)
92)]
93#[cfg_attr(
94 not(feature = "0-8-1-storage-format"),
95 derive(
96 openmls_serialization_helpers::Serialize,
97 openmls_serialization_helpers::Deserialize,
98 )
99)]
100pub enum ExtensionType {
101 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 0)]
102 ApplicationId,
105
106 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 1)]
107 RatchetTree,
110
111 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 2)]
112 RequiredCapabilities,
115
116 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 3)]
117 ExternalPub,
120
121 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 4)]
122 ExternalSenders,
125
126 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 5)]
127 LastResort,
130
131 #[cfg(feature = "extensions-draft")]
132 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 8)]
133 AppDataDictionary,
135
136 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 7)]
137 Grease(u16),
139
140 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 6)]
141 Unknown(u16),
143}
144
145impl ExtensionType {
146 pub(crate) fn is_default(self) -> bool {
148 match self {
149 ExtensionType::ApplicationId
150 | ExtensionType::RatchetTree
151 | ExtensionType::RequiredCapabilities
152 | ExtensionType::ExternalPub
153 | ExtensionType::ExternalSenders => true,
154 ExtensionType::LastResort | ExtensionType::Grease(_) | ExtensionType::Unknown(_) => {
155 false
156 }
157 #[cfg(feature = "extensions-draft")]
158 ExtensionType::AppDataDictionary => false,
159 }
160 }
161
162 pub(crate) fn is_valid_in_leaf_node(self) -> bool {
167 match self {
168 ExtensionType::Grease(_)
169 | ExtensionType::LastResort
170 | ExtensionType::RatchetTree
171 | ExtensionType::RequiredCapabilities
172 | ExtensionType::ExternalPub
173 | ExtensionType::ExternalSenders => false,
174 ExtensionType::Unknown(_) | ExtensionType::ApplicationId => true,
175 #[cfg(feature = "extensions-draft")]
176 ExtensionType::AppDataDictionary => true,
177 }
178 }
179 pub(crate) fn is_valid_in_group_info(self) -> Option<bool> {
180 match self {
181 ExtensionType::Grease(_)
182 | ExtensionType::LastResort
183 | ExtensionType::RequiredCapabilities
184 | ExtensionType::ExternalSenders
185 | ExtensionType::ApplicationId => Some(false),
186 ExtensionType::RatchetTree | ExtensionType::ExternalPub => Some(true),
187 ExtensionType::Unknown(_) => None,
188 #[cfg(feature = "extensions-draft")]
189 ExtensionType::AppDataDictionary => Some(true),
190 }
191 }
192
193 pub(crate) fn is_valid_in_key_package(self) -> bool {
194 match self {
195 ExtensionType::Grease(_)
196 | ExtensionType::RatchetTree
197 | ExtensionType::RequiredCapabilities
198 | ExtensionType::ExternalPub
199 | ExtensionType::ExternalSenders
200 | ExtensionType::ApplicationId => false,
201 ExtensionType::Unknown(_) | ExtensionType::LastResort => true,
202 #[cfg(feature = "extensions-draft")]
203 ExtensionType::AppDataDictionary => true,
204 }
205 }
206
207 pub(crate) fn is_valid_in_group_context(self) -> bool {
208 match self {
209 ExtensionType::RequiredCapabilities
210 | ExtensionType::ExternalSenders
211 | ExtensionType::Unknown(_) => true,
212 #[cfg(feature = "extensions-draft")]
213 ExtensionType::AppDataDictionary => true,
214 _ => false,
215 }
216 }
217
218 pub fn is_grease(&self) -> bool {
223 matches!(self, ExtensionType::Grease(_))
224 }
225}
226
227impl Size for ExtensionType {
228 fn tls_serialized_len(&self) -> usize {
229 2
230 }
231}
232
233impl TlsDeserializeTrait for ExtensionType {
234 fn tls_deserialize<R: Read>(bytes: &mut R) -> Result<Self, Error>
235 where
236 Self: Sized,
237 {
238 let mut extension_type = [0u8; 2];
239 bytes.read_exact(&mut extension_type)?;
240
241 Ok(ExtensionType::from(u16::from_be_bytes(extension_type)))
242 }
243}
244
245impl DeserializeBytes for ExtensionType {
246 fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
247 where
248 Self: Sized,
249 {
250 let mut bytes_ref = bytes;
251 let extension_type = ExtensionType::tls_deserialize(&mut bytes_ref)?;
252 Ok((extension_type, bytes_ref))
253 }
254}
255
256impl TlsSerializeTrait for ExtensionType {
257 fn tls_serialize<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
258 writer.write_all(&u16::from(*self).to_be_bytes())?;
259
260 Ok(2)
261 }
262}
263
264impl From<u16> for ExtensionType {
265 fn from(a: u16) -> Self {
266 match a {
267 1 => ExtensionType::ApplicationId,
268 2 => ExtensionType::RatchetTree,
269 3 => ExtensionType::RequiredCapabilities,
270 4 => ExtensionType::ExternalPub,
271 5 => ExtensionType::ExternalSenders,
272 #[cfg(feature = "extensions-draft")]
273 6 => ExtensionType::AppDataDictionary,
274 10 => ExtensionType::LastResort,
275 unknown if crate::grease::is_grease_value(unknown) => ExtensionType::Grease(unknown),
276 unknown => ExtensionType::Unknown(unknown),
277 }
278 }
279}
280
281impl From<ExtensionType> for u16 {
282 fn from(value: ExtensionType) -> Self {
283 match value {
284 ExtensionType::ApplicationId => 1,
285 ExtensionType::RatchetTree => 2,
286 ExtensionType::RequiredCapabilities => 3,
287 ExtensionType::ExternalPub => 4,
288 ExtensionType::ExternalSenders => 5,
289 #[cfg(feature = "extensions-draft")]
290 ExtensionType::AppDataDictionary => 6,
291 ExtensionType::LastResort => 10,
292 ExtensionType::Grease(value) => value,
293 ExtensionType::Unknown(unknown) => unknown,
294 }
295 }
296}
297
298#[derive(Debug, Clone, PartialEq, Eq)]
313#[cfg_attr(
314 feature = "0-8-1-storage-format",
315 derive(serde::Serialize, serde::Deserialize)
316)]
317#[cfg_attr(
318 not(feature = "0-8-1-storage-format"),
319 derive(
320 openmls_serialization_helpers::Serialize,
321 openmls_serialization_helpers::Deserialize,
322 )
323)]
324pub enum Extension {
325 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 0)]
326 ApplicationId(ApplicationIdExtension),
328
329 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 1)]
330 RatchetTree(RatchetTreeExtension),
332
333 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 2)]
334 RequiredCapabilities(RequiredCapabilitiesExtension),
336
337 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 3)]
338 ExternalPub(ExternalPubExtension),
340
341 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 4)]
342 ExternalSenders(ExternalSendersExtension),
344
345 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 7)]
346 #[cfg(feature = "extensions-draft")]
348 AppDataDictionary(AppDataDictionaryExtension),
349
350 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 5)]
351 LastResort(LastResortExtension),
353
354 #[cfg_attr(not(feature = "0-8-1-storage-format"), storage_tag = 6)]
355 Unknown(u16, UnknownExtension),
357}
358
359#[derive(
361 PartialEq, Eq, Clone, Debug, Serialize, Deserialize, TlsSize, TlsSerialize, TlsDeserialize,
362)]
363pub struct UnknownExtension(pub Vec<u8>);
364
365#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
367pub struct Extensions<T> {
368 unique: Vec<Extension>,
369 #[serde(skip)]
370 _object: core::marker::PhantomData<T>,
371}
372
373#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, TlsSize, TlsSerialize, TlsDeserialize)]
374pub struct AnyObject;
376
377impl<T> Default for Extensions<T> {
378 fn default() -> Self {
379 Self {
380 unique: vec![],
381 _object: PhantomData,
382 }
383 }
384}
385
386impl<T> Size for Extensions<T> {
387 fn tls_serialized_len(&self) -> usize {
388 Vec::tls_serialized_len(&self.unique)
389 }
390}
391
392impl<T> TlsSerializeTrait for Extensions<T> {
393 fn tls_serialize<W: Write>(&self, writer: &mut W) -> Result<usize, Error> {
394 self.unique.tls_serialize(writer)
395 }
396}
397
398impl<T: ExtensionValidator> TlsDeserializeTrait for Extensions<T>
399where
400 InvalidExtensionError: From<T::Error>,
401{
402 fn tls_deserialize<R: Read>(bytes: &mut R) -> Result<Self, Error>
403 where
404 Self: Sized,
405 {
406 let candidate: Vec<Extension> = Vec::tls_deserialize(bytes)?;
407 Extensions::<T>::try_from(candidate)
408 .map_err(|_| Error::DecodingError("Found duplicate extensions".into()))
409 }
410}
411
412impl<T: ExtensionValidator> DeserializeBytes for Extensions<T>
413where
414 InvalidExtensionError: From<T::Error>,
415{
416 fn tls_deserialize_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), Error>
417 where
418 Self: Sized,
419 {
420 let mut bytes_ref = bytes;
421 let extensions = Extensions::<T>::tls_deserialize(&mut bytes_ref)?;
422 Ok((extensions, bytes_ref))
423 }
424}
425
426impl<T: ExtensionValidator> Extensions<T> {
427 pub fn empty() -> Self {
429 Self {
430 unique: vec![],
431 _object: PhantomData,
432 }
433 }
434
435 pub fn iter(&self) -> impl Iterator<Item = &Extension> {
437 self.unique.iter()
438 }
439
440 pub fn remove(&mut self, extension_type: ExtensionType) -> Option<Extension> {
445 if let Some(pos) = self
446 .unique
447 .iter()
448 .position(|ext| ext.extension_type() == extension_type)
449 {
450 Some(self.unique.remove(pos))
451 } else {
452 None
453 }
454 }
455
456 pub fn contains(&self, extension_type: ExtensionType) -> bool {
459 self.unique
460 .iter()
461 .any(|ext| ext.extension_type() == extension_type)
462 }
463}
464
465impl<T> Extensions<T>
466where
467 T: ExtensionValidator,
468 InvalidExtensionError: From<T::Error>,
469{
470 pub fn single(extension: Extension) -> Result<Self, InvalidExtensionError> {
472 T::validate_extension_type(&extension)?;
473 Ok(Self {
474 unique: vec![extension],
475 _object: PhantomData,
476 })
477 }
478
479 pub fn from_vec(extensions: Vec<Extension>) -> Result<Self, InvalidExtensionError> {
484 extensions.try_into()
485 }
486
487 pub fn validate<'a>(
489 extensions: impl Iterator<Item = &'a Extension>,
490 ) -> Result<(), InvalidExtensionError> {
491 for ext in extensions {
492 T::validate_extension_type(ext)?;
493 }
494 Ok(())
495 }
496
497 pub fn add(&mut self, extension: Extension) -> Result<(), InvalidExtensionError> {
502 T::validate_extension_type(&extension)?;
503 if self.contains(extension.extension_type()) {
504 return Err(InvalidExtensionError::Duplicate);
505 }
506
507 self.unique.push(extension);
508
509 Ok(())
510 }
511
512 pub fn add_or_replace(
516 &mut self,
517 extension: Extension,
518 ) -> Result<Option<Extension>, InvalidExtensionError> {
519 T::validate_extension_type(&extension)?;
520 let replaced = self.remove(extension.extension_type());
521 self.unique.push(extension);
522 Ok(replaced)
523 }
524}
525
526impl Extensions<AnyObject> {
527 #[cfg(feature = "unchecked-conversions")]
533 pub fn into_unchecked<T>(self) -> Extensions<T> {
534 Extensions {
535 unique: self.unique,
536 _object: PhantomData,
537 }
538 }
539}
540
541pub trait ExtensionValidator {
543 type Error;
545
546 fn validate_extension_type(ext: &Extension) -> Result<(), Self::Error>;
548}
549
550impl ExtensionValidator for AnyObject {
551 type Error = Infallible;
552
553 fn validate_extension_type(_ext: &Extension) -> Result<(), Infallible> {
554 Ok(())
555 }
556}
557
558impl<T: ExtensionValidator> TryFrom<Vec<Extension>> for Extensions<T>
559where
560 InvalidExtensionError: From<T::Error>,
561{
562 type Error = InvalidExtensionError;
563
564 fn try_from(candidate: Vec<Extension>) -> Result<Self, Self::Error> {
565 let mut unique: Vec<Extension> = Vec::new();
566 for extension in candidate.into_iter() {
567 T::validate_extension_type(&extension)?;
568
569 if unique
570 .iter()
571 .any(|ext| ext.extension_type() == extension.extension_type())
572 {
573 return Err(InvalidExtensionError::Duplicate);
574 } else {
575 unique.push(extension);
576 }
577 }
578
579 Ok(Self {
580 unique,
581 _object: PhantomData,
582 })
583 }
584}
585
586impl ExtensionValidator for GroupInfo {
588 type Error = ExtensionTypeNotValidInGroupInfoError;
589
590 fn validate_extension_type(
591 ext: &Extension,
592 ) -> Result<(), ExtensionTypeNotValidInGroupInfoError> {
593 if ext.extension_type().is_valid_in_group_info() == Some(true)
594 || ext.extension_type().is_valid_in_group_info().is_none()
595 {
596 Ok(())
597 } else {
598 Err(ExtensionTypeNotValidInGroupInfoError(ext.extension_type()))
599 }
600 }
601}
602
603impl ExtensionValidator for GroupContext {
605 type Error = ExtensionTypeNotValidInGroupContextError;
606
607 fn validate_extension_type(
608 ext: &Extension,
609 ) -> Result<(), ExtensionTypeNotValidInGroupContextError> {
610 if ext.extension_type().is_valid_in_group_context() {
611 Ok(())
612 } else {
613 Err(ExtensionTypeNotValidInGroupContextError(
614 ext.extension_type(),
615 ))
616 }
617 }
618}
619
620impl ExtensionValidator for KeyPackage {
622 type Error = ExtensionTypeNotValidInKeyPackageError;
623
624 fn validate_extension_type(
625 ext: &Extension,
626 ) -> Result<(), ExtensionTypeNotValidInKeyPackageError> {
627 if ext.extension_type().is_valid_in_key_package() {
628 Ok(())
629 } else {
630 Err(ExtensionTypeNotValidInKeyPackageError(ext.extension_type()))
631 }
632 }
633}
634
635impl ExtensionValidator for LeafNode {
637 type Error = ExtensionTypeNotValidInLeafNodeError;
638
639 fn validate_extension_type(
640 ext: &Extension,
641 ) -> Result<(), ExtensionTypeNotValidInLeafNodeError> {
642 if ext.extension_type().is_valid_in_leaf_node() {
643 Ok(())
644 } else {
645 Err(ExtensionTypeNotValidInLeafNodeError(ext.extension_type()))
646 }
647 }
648}
649
650impl<T> Extensions<T> {
651 fn find_by_type(&self, extension_type: ExtensionType) -> Option<&Extension> {
652 self.unique
653 .iter()
654 .find(|ext| ext.extension_type() == extension_type)
655 }
656
657 pub fn application_id(&self) -> Option<&ApplicationIdExtension> {
659 self.find_by_type(ExtensionType::ApplicationId)
660 .and_then(|e| match e {
661 Extension::ApplicationId(e) => Some(e),
662 _ => None,
663 })
664 }
665
666 pub fn ratchet_tree(&self) -> Option<&RatchetTreeExtension> {
668 self.find_by_type(ExtensionType::RatchetTree)
669 .and_then(|e| match e {
670 Extension::RatchetTree(e) => Some(e),
671 _ => None,
672 })
673 }
674
675 pub fn required_capabilities(&self) -> Option<&RequiredCapabilitiesExtension> {
678 self.find_by_type(ExtensionType::RequiredCapabilities)
679 .and_then(|e| match e {
680 Extension::RequiredCapabilities(e) => Some(e),
681 _ => None,
682 })
683 }
684
685 pub fn external_pub(&self) -> Option<&ExternalPubExtension> {
687 self.find_by_type(ExtensionType::ExternalPub)
688 .and_then(|e| match e {
689 Extension::ExternalPub(e) => Some(e),
690 _ => None,
691 })
692 }
693
694 pub fn external_senders(&self) -> Option<&ExternalSendersExtension> {
696 self.find_by_type(ExtensionType::ExternalSenders)
697 .and_then(|e| match e {
698 Extension::ExternalSenders(e) => Some(e),
699 _ => None,
700 })
701 }
702
703 #[cfg(feature = "extensions-draft")]
704 pub fn app_data_dictionary(&self) -> Option<&AppDataDictionaryExtension> {
706 self.find_by_type(ExtensionType::AppDataDictionary)
707 .and_then(|e| match e {
708 Extension::AppDataDictionary(e) => Some(e),
709 _ => None,
710 })
711 }
712
713 pub fn unknown(&self, extension_type_id: u16) -> Option<&UnknownExtension> {
715 let extension_type: ExtensionType = extension_type_id.into();
716
717 match extension_type {
718 ExtensionType::Unknown(_) => self.find_by_type(extension_type).and_then(|e| match e {
719 Extension::Unknown(_, e) => Some(e),
720 _ => None,
721 }),
722 _ => None,
723 }
724 }
725}
726
727impl Extension {
728 pub fn as_application_id_extension(&self) -> Result<&ApplicationIdExtension, ExtensionError> {
732 match self {
733 Self::ApplicationId(e) => Ok(e),
734 _ => Err(ExtensionError::InvalidExtensionType(
735 "This is not an ApplicationIdExtension".into(),
736 )),
737 }
738 }
739 #[cfg(feature = "extensions-draft")]
740 pub fn as_app_data_dictionary_extension(
744 &self,
745 ) -> Result<&AppDataDictionaryExtension, ExtensionError> {
746 match self {
747 Self::AppDataDictionary(e) => Ok(e),
748 _ => Err(ExtensionError::InvalidExtensionType(
749 "This is not an AppDataDictionaryExtension".into(),
750 )),
751 }
752 }
753
754 pub fn as_ratchet_tree_extension(&self) -> Result<&RatchetTreeExtension, ExtensionError> {
758 match self {
759 Self::RatchetTree(rte) => Ok(rte),
760 _ => Err(ExtensionError::InvalidExtensionType(
761 "This is not a RatchetTreeExtension".into(),
762 )),
763 }
764 }
765
766 pub fn as_required_capabilities_extension(
770 &self,
771 ) -> Result<&RequiredCapabilitiesExtension, ExtensionError> {
772 match self {
773 Self::RequiredCapabilities(e) => Ok(e),
774 _ => Err(ExtensionError::InvalidExtensionType(
775 "This is not a RequiredCapabilitiesExtension".into(),
776 )),
777 }
778 }
779
780 pub fn as_external_pub_extension(&self) -> Result<&ExternalPubExtension, ExtensionError> {
784 match self {
785 Self::ExternalPub(e) => Ok(e),
786 _ => Err(ExtensionError::InvalidExtensionType(
787 "This is not an ExternalPubExtension".into(),
788 )),
789 }
790 }
791
792 pub fn as_external_senders_extension(
796 &self,
797 ) -> Result<&ExternalSendersExtension, ExtensionError> {
798 match self {
799 Self::ExternalSenders(e) => Ok(e),
800 _ => Err(ExtensionError::InvalidExtensionType(
801 "This is not an ExternalSendersExtension".into(),
802 )),
803 }
804 }
805
806 #[inline]
808 pub const fn extension_type(&self) -> ExtensionType {
809 match self {
810 Extension::ApplicationId(_) => ExtensionType::ApplicationId,
811 Extension::RatchetTree(_) => ExtensionType::RatchetTree,
812 Extension::RequiredCapabilities(_) => ExtensionType::RequiredCapabilities,
813 Extension::ExternalPub(_) => ExtensionType::ExternalPub,
814 Extension::ExternalSenders(_) => ExtensionType::ExternalSenders,
815 #[cfg(feature = "extensions-draft")]
816 Extension::AppDataDictionary(_) => ExtensionType::AppDataDictionary,
817 Extension::LastResort(_) => ExtensionType::LastResort,
818 Extension::Unknown(kind, _) => ExtensionType::Unknown(*kind),
819 }
820 }
821}
822
823macro_rules! impl_from_extensions_validator {
824 ($validator:ty, $error:ty) => {
825 impl From<Extensions<$validator>> for Extensions<AnyObject> {
826 fn from(value: Extensions<$validator>) -> Self {
827 Extensions {
828 unique: value.unique,
829 _object: PhantomData,
830 }
831 }
832 }
833
834 impl TryFrom<Extensions<AnyObject>> for Extensions<$validator> {
835 type Error = $error;
836
837 fn try_from(value: Extensions<AnyObject>) -> Result<Self, $error> {
838 value
839 .unique
840 .iter()
841 .try_for_each(<$validator as ExtensionValidator>::validate_extension_type)?;
842
843 Ok(Extensions {
844 unique: value.unique,
845 _object: PhantomData,
846 })
847 }
848 }
849 };
850}
851
852impl_from_extensions_validator!(GroupContext, ExtensionTypeNotValidInGroupContextError);
853impl_from_extensions_validator!(LeafNode, ExtensionTypeNotValidInLeafNodeError);
854impl_from_extensions_validator!(KeyPackage, ExtensionTypeNotValidInKeyPackageError);
855
856#[cfg(any(feature = "test-utils", test))]
857impl Extensions<AnyObject> {
858 pub(crate) fn coerce<T: ExtensionValidator>(self) -> Extensions<T> {
860 Extensions {
861 unique: self.unique,
862 _object: PhantomData,
863 }
864 }
865}
866#[cfg(test)]
867mod test {
868 use itertools::Itertools;
869 use tls_codec::{Deserialize, Serialize, VLBytes};
870
871 use crate::{ciphersuite::HpkePublicKey, extensions::*};
872
873 #[test]
874 fn add() {
875 let mut extensions: Extensions<AnyObject> = Extensions::default();
876 extensions
877 .add(Extension::RequiredCapabilities(
878 RequiredCapabilitiesExtension::default(),
879 ))
880 .unwrap();
881 assert!(extensions
882 .add(Extension::RequiredCapabilities(
883 RequiredCapabilitiesExtension::default()
884 ))
885 .is_err());
886 }
887
888 #[test]
889 fn add_try_from() {
890 let ext_x = Extension::ApplicationId(ApplicationIdExtension::new(b"Test"));
893 let ext_y = Extension::RequiredCapabilities(RequiredCapabilitiesExtension::default());
894
895 let tests = [
896 (vec![], true),
897 (vec![ext_x.clone()], true),
898 (vec![ext_x.clone(), ext_x.clone()], false),
899 (vec![ext_x.clone(), ext_x.clone(), ext_x.clone()], false),
900 (vec![ext_y.clone()], true),
901 (vec![ext_y.clone(), ext_y.clone()], false),
902 (vec![ext_y.clone(), ext_y.clone(), ext_y.clone()], false),
903 (vec![ext_x.clone(), ext_y.clone()], true),
904 (vec![ext_y.clone(), ext_x.clone()], true),
905 (vec![ext_x.clone(), ext_x.clone(), ext_y.clone()], false),
906 (vec![ext_y.clone(), ext_y.clone(), ext_x.clone()], false),
907 (vec![ext_x.clone(), ext_y.clone(), ext_y.clone()], false),
908 (vec![ext_y.clone(), ext_x.clone(), ext_x.clone()], false),
909 (vec![ext_x.clone(), ext_y.clone(), ext_x.clone()], false),
910 (vec![ext_y.clone(), ext_x, ext_y], false),
911 ];
912
913 for (test, should_work) in tests.into_iter() {
914 {
916 let mut extensions: Extensions<AnyObject> = Extensions::default();
917
918 let mut works = true;
919 for ext in test.iter() {
920 match extensions.add(ext.clone()) {
921 Ok(_) => {}
922 Err(InvalidExtensionError::Duplicate) => {
923 works = false;
924 }
925 _ => panic!("This should have never happened."),
926 }
927 }
928
929 println!("{:?}, {:?}", test.clone(), should_work);
930 assert_eq!(works, should_work);
931 }
932
933 if should_work {
935 assert!(Extensions::<AnyObject>::try_from(test).is_ok());
936 } else {
937 assert!(Extensions::<AnyObject>::try_from(test).is_err());
938 }
939 }
940 }
941
942 #[test]
943 fn ensure_ordering() {
944 let ext_x = Extension::ApplicationId(ApplicationIdExtension::new(b"Test"));
948 let ext_y = Extension::ExternalPub(ExternalPubExtension::new(HpkePublicKey::new(vec![])));
949 let ext_z = Extension::RequiredCapabilities(RequiredCapabilitiesExtension::default());
950
951 for candidate in [ext_x, ext_y, ext_z]
952 .into_iter()
953 .permutations(3)
954 .collect::<Vec<_>>()
955 {
956 let candidate: Extensions<AnyObject> = Extensions::try_from(candidate).unwrap();
957 let bytes = candidate.tls_serialize_detached().unwrap();
958 let got = Extensions::tls_deserialize(&mut bytes.as_slice()).unwrap();
959 assert_eq!(candidate, got);
960 }
961 }
962
963 #[test]
964 fn that_unknown_extensions_are_de_serialized_correctly() {
965 let extension_types = [0x0000u16, 0x0A0A, 0x7A7A, 0xF100, 0xFFFF];
966 let extension_datas = [vec![], vec![0], vec![1, 2, 3]];
967
968 for extension_type in extension_types.into_iter() {
969 for extension_data in extension_datas.iter() {
970 let test = {
972 let mut buf = extension_type.to_be_bytes().to_vec();
973 buf.append(
974 &mut VLBytes::new(extension_data.clone())
975 .tls_serialize_detached()
976 .unwrap(),
977 );
978 buf
979 };
980
981 let got = Extension::tls_deserialize_exact(&test).unwrap();
983
984 match got {
985 Extension::Unknown(got_extension_type, ref got_extension_data) => {
986 assert_eq!(extension_type, got_extension_type);
987 assert_eq!(extension_data, &got_extension_data.0);
988 }
989 other => panic!("Expected `Extension::Unknown`, got {other:?}"),
990 }
991
992 let got_serialized = got.tls_serialize_detached().unwrap();
994 assert_eq!(test, got_serialized);
995 }
996 }
997 }
998}