1use std::collections::HashSet;
3
4use openmls_traits::{
5 crypto::OpenMlsCrypto,
6 random::OpenMlsRand,
7 signatures::Signer,
8 types::{Ciphersuite, VerifiableCiphersuite},
9};
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12use tls_codec::{
13 Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
14 VLBytes,
15};
16
17use super::encryption_keys::{EncryptionKey, EncryptionKeyPair};
18use crate::{
19 binary_tree::array_representation::LeafNodeIndex,
20 ciphersuite::{
21 signable::{Signable, SignedStruct, Verifiable, VerifiedStruct},
22 Signature, SignaturePublicKey,
23 },
24 credentials::{Credential, CredentialType, CredentialWithKey},
25 error::LibraryError,
26 extensions::{Extension, ExtensionType, Extensions, RequiredCapabilitiesExtension},
27 group::{GroupContext, GroupId},
28 key_packages::{KeyPackage, Lifetime},
29 prelude::KeyPackageBundle,
30 storage::OpenMlsProvider,
31 versions::ProtocolVersion,
32};
33
34use crate::treesync::errors::LeafNodeValidationError;
35
36mod capabilities;
37mod codec;
38
39pub use capabilities::*;
40
41pub(crate) struct NewLeafNodeParams {
42 pub(crate) ciphersuite: Ciphersuite,
43 pub(crate) credential_with_key: CredentialWithKey,
44 pub(crate) leaf_node_source: LeafNodeSource,
45 pub(crate) capabilities: Capabilities,
46 pub(crate) extensions: Extensions<LeafNode>,
47 pub(crate) tree_info_tbs: TreeInfoTbs,
48 pub(crate) constraints: LeafNodeConstraints,
51 pub(crate) capabilities_policy: CapabilitiesPolicy,
54}
55
56#[derive(Debug, PartialEq, Clone)]
59pub(crate) struct UpdateLeafNodeParams {
60 pub(crate) credential_with_key: CredentialWithKey,
61 pub(crate) capabilities: Capabilities,
62 pub(crate) extensions: Extensions<LeafNode>,
63 pub(crate) constraints: LeafNodeConstraints,
65 pub(crate) capabilities_policy: CapabilitiesPolicy,
68}
69
70impl UpdateLeafNodeParams {
71 #[cfg(test)]
72 pub(crate) fn derive(leaf_node: &LeafNode) -> Self {
73 Self {
74 credential_with_key: CredentialWithKey {
75 credential: leaf_node.payload.credential.clone(),
76 signature_key: leaf_node.payload.signature_key.clone(),
77 },
78 capabilities: leaf_node.payload.capabilities.clone(),
79 extensions: leaf_node.payload.extensions.clone(),
80 constraints: LeafNodeConstraints::default(),
83 capabilities_policy: CapabilitiesPolicy::Reject,
84 }
85 }
86}
87
88#[derive(Debug, Clone, Default, PartialEq)]
98pub(crate) struct LeafNodeConstraints {
99 required_capabilities: Vec<RequiredCapabilitiesExtension>,
102
103 group_context_extensions: HashSet<ExtensionType>,
106
107 credentials_in_use: HashSet<CredentialType>,
110
111 credentials_supported_by_all: HashSet<CredentialType>,
117}
118
119impl LeafNodeConstraints {
120 pub(crate) fn from_group_context_extensions(extensions: &Extensions<GroupContext>) -> Self {
123 Self::new(extensions, [])
124 }
125
126 pub(crate) fn new<'a>(
128 extensions: &Extensions<GroupContext>,
129 members: impl IntoIterator<Item = &'a LeafNode>,
130 ) -> Self {
131 let mut credentials_in_use = HashSet::new();
132 let mut credentials_supported_by_all = None;
133
134 for member in members {
135 credentials_in_use.insert(member.credential().credential_type());
136 let supported = member.capabilities().credentials();
137 credentials_supported_by_all
138 .get_or_insert_with(|| supported.iter().copied().collect::<HashSet<_>>())
139 .retain(|credential_type| supported.contains(credential_type));
140 }
141
142 let mut constraints = Self {
143 credentials_in_use,
144 credentials_supported_by_all: credentials_supported_by_all.unwrap_or_default(),
145 ..Self::default()
146 };
147 constraints.add_group_context_extensions(extensions);
148
149 constraints
150 }
151
152 pub(crate) fn add_group_context_extensions(&mut self, extensions: &Extensions<GroupContext>) {
154 if let Some(required_capabilities) = extensions.required_capabilities() {
155 self.required_capabilities
156 .push(required_capabilities.clone());
157 }
158 self.group_context_extensions
159 .extend(extensions.iter().map(Extension::extension_type));
160 }
161
162 fn check(
164 &self,
165 capabilities: &Capabilities,
166 credential_type: CredentialType,
167 ) -> Result<(), LeafNodeValidationError> {
168 for required_capabilities in &self.required_capabilities {
170 capabilities.supports_required_capabilities(required_capabilities)?;
171 }
172
173 if self.group_context_extensions.iter().any(|extension_type| {
176 !extension_type.is_default() && !capabilities.extensions().contains(extension_type)
177 }) {
178 return Err(LeafNodeValidationError::UnsupportedExtensions);
179 }
180
181 if !self.credentials_supported_by_all.is_empty()
183 && !self.credentials_supported_by_all.contains(&credential_type)
184 {
185 return Err(LeafNodeValidationError::LeafNodeCredentialNotSupportedByMember);
186 }
187 if self
188 .credentials_in_use
189 .iter()
190 .any(|in_use| !capabilities.contains_credential(*in_use))
191 {
192 return Err(LeafNodeValidationError::MemberCredentialNotSupportedByLeafNode);
193 }
194
195 Ok(())
196 }
197}
198
199#[derive(Debug, PartialEq, Clone, Default)]
201pub struct LeafNodeParameters {
202 credential_with_key: Option<CredentialWithKey>,
203 capabilities: Option<Capabilities>,
204 extensions: Option<Extensions<LeafNode>>,
205 capabilities_policy: Option<CapabilitiesPolicy>,
206}
207
208impl LeafNodeParameters {
209 pub fn builder() -> LeafNodeParametersBuilder {
211 LeafNodeParametersBuilder::default()
212 }
213
214 pub fn credential_with_key(&self) -> Option<&CredentialWithKey> {
216 self.credential_with_key.as_ref()
217 }
218
219 pub fn capabilities(&self) -> Option<&Capabilities> {
221 self.capabilities.as_ref()
222 }
223
224 pub fn extensions(&self) -> Option<&Extensions<LeafNode>> {
226 self.extensions.as_ref()
227 }
228
229 pub(crate) fn capabilities_policy(&self) -> Option<CapabilitiesPolicy> {
233 self.capabilities_policy
234 }
235
236 pub(crate) fn is_empty(&self) -> bool {
237 self.credential_with_key.is_none()
238 && self.capabilities.is_none()
239 && self.extensions.is_none()
240 }
241
242 pub(crate) fn set_credential_with_key(&mut self, credential_with_key: CredentialWithKey) {
243 self.credential_with_key = Some(credential_with_key);
244 }
245
246 #[cfg(feature = "virtual-clients-draft")]
247 pub(crate) fn set_extensions(&mut self, extensions: Extensions<LeafNode>) {
248 self.extensions = Some(extensions);
249 }
250}
251
252#[derive(Debug, Default)]
254pub struct LeafNodeParametersBuilder {
255 credential_with_key: Option<CredentialWithKey>,
256 capabilities: Option<Capabilities>,
257 extensions: Option<Extensions<LeafNode>>,
258 capabilities_policy: Option<CapabilitiesPolicy>,
259}
260
261impl LeafNodeParametersBuilder {
262 pub fn with_credential_with_key(mut self, credential_with_key: CredentialWithKey) -> Self {
264 self.credential_with_key = Some(credential_with_key);
265 self
266 }
267
268 pub fn with_capabilities(mut self, capabilities: Capabilities) -> Self {
270 self.capabilities = Some(capabilities);
271 self
272 }
273
274 pub fn with_extensions(mut self, extensions: Extensions<LeafNode>) -> Self {
278 self.extensions = Some(extensions);
279 self
280 }
281
282 pub fn with_capabilities_policy(mut self, policy: CapabilitiesPolicy) -> Self {
288 self.capabilities_policy = Some(policy);
289 self
290 }
291
292 pub fn build(self) -> LeafNodeParameters {
294 LeafNodeParameters {
295 credential_with_key: self.credential_with_key,
296 capabilities: self.capabilities,
297 extensions: self.extensions,
298 capabilities_policy: self.capabilities_policy,
299 }
300 }
301}
302
303#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TlsSerialize, TlsSize)]
331pub struct LeafNode {
332 payload: LeafNodePayload,
333 signature: Signature,
334}
335
336#[derive(Error, Debug, PartialEq, Clone)]
340pub enum LeafNodeBuildError {
341 #[error(transparent)]
343 LibraryError(#[from] LibraryError),
344 #[error(transparent)]
346 Validation(#[from] LeafNodeValidationError),
347}
348
349impl LeafNode {
350 pub(crate) fn new(
358 provider: &impl OpenMlsProvider,
359 signer: &impl Signer,
360 new_leaf_node_params: NewLeafNodeParams,
361 ) -> Result<(Self, EncryptionKeyPair), LeafNodeBuildError> {
362 let NewLeafNodeParams {
363 ciphersuite,
364 credential_with_key,
365 leaf_node_source,
366 capabilities,
367 extensions,
368 tree_info_tbs,
369 constraints,
370 capabilities_policy,
371 } = new_leaf_node_params;
372
373 let encryption_key_pair =
375 EncryptionKeyPair::random(provider.rand(), provider.crypto(), ciphersuite)?;
376
377 let leaf_node = Self::new_with_key(
378 ciphersuite,
379 encryption_key_pair.public_key().clone(),
380 credential_with_key,
381 leaf_node_source,
382 capabilities,
383 extensions,
384 tree_info_tbs,
385 &constraints,
386 capabilities_policy,
387 signer,
388 )?;
389
390 Ok((leaf_node, encryption_key_pair))
391 }
392
393 #[cfg(feature = "virtual-clients-draft")]
400 pub(crate) fn new_with_encryption_key_pair(
401 signer: &impl Signer,
402 new_leaf_node_params: NewLeafNodeParams,
403 encryption_key_pair: EncryptionKeyPair,
404 ) -> Result<(Self, EncryptionKeyPair), LeafNodeBuildError> {
405 let NewLeafNodeParams {
406 ciphersuite,
407 credential_with_key,
408 leaf_node_source,
409 capabilities,
410 extensions,
411 tree_info_tbs,
412 constraints,
413 capabilities_policy,
414 } = new_leaf_node_params;
415
416 let leaf_node = Self::new_with_key(
417 ciphersuite,
418 encryption_key_pair.public_key().clone(),
419 credential_with_key,
420 leaf_node_source,
421 capabilities,
422 extensions,
423 tree_info_tbs,
424 &constraints,
425 capabilities_policy,
426 signer,
427 )?;
428
429 Ok((leaf_node, encryption_key_pair))
430 }
431
432 pub(crate) fn new_placeholder() -> Self {
438 let payload = LeafNodePayload {
439 encryption_key: EncryptionKey::from(Vec::new()),
440 signature_key: Vec::new().into(),
441 credential: Credential::new(CredentialType::Basic, Vec::new()),
442 capabilities: Capabilities::empty(),
443 leaf_node_source: LeafNodeSource::Update,
444 extensions: Extensions::default(),
445 };
446
447 Self {
448 payload,
449 signature: Vec::new().into(),
450 }
451 }
452
453 #[allow(clippy::too_many_arguments)]
456 fn new_with_key(
457 ciphersuite: Ciphersuite,
458 encryption_key: EncryptionKey,
459 credential_with_key: CredentialWithKey,
460 leaf_node_source: LeafNodeSource,
461 capabilities: Capabilities,
462 extensions: Extensions<LeafNode>,
463 tree_info_tbs: TreeInfoTbs,
464 constraints: &LeafNodeConstraints,
465 capabilities_policy: CapabilitiesPolicy,
466 signer: &impl Signer,
467 ) -> Result<Self, LeafNodeBuildError> {
468 let leaf_node_tbs = LeafNodeTbs::new(
469 ciphersuite,
470 encryption_key,
471 credential_with_key,
472 capabilities,
473 leaf_node_source,
474 extensions,
475 tree_info_tbs,
476 constraints,
477 capabilities_policy,
478 )?;
479
480 leaf_node_tbs
481 .sign(signer)
482 .map_err(|_| LibraryError::custom("Signing failed").into())
483 }
484
485 #[allow(clippy::too_many_arguments)]
492 pub(in crate::treesync) fn new_with_parent_hash(
493 rand: &impl OpenMlsRand,
494 crypto: &impl OpenMlsCrypto,
495 ciphersuite: Ciphersuite,
496 parent_hash: &[u8],
497 leaf_node_params: UpdateLeafNodeParams,
498 group_id: GroupId,
499 leaf_index: LeafNodeIndex,
500 signer: &impl Signer,
501 #[cfg(feature = "virtual-clients-draft")] encryption_key_pair_override: Option<
502 EncryptionKeyPair,
503 >,
504 ) -> Result<(Self, EncryptionKeyPair), LeafNodeBuildError> {
505 #[cfg(feature = "virtual-clients-draft")]
506 let encryption_key_pair = match encryption_key_pair_override {
507 Some(kp) => kp,
508 None => EncryptionKeyPair::random(rand, crypto, ciphersuite)?,
509 };
510 #[cfg(not(feature = "virtual-clients-draft"))]
511 let encryption_key_pair = EncryptionKeyPair::random(rand, crypto, ciphersuite)?;
512
513 let leaf_node_tbs = LeafNodeTbs::new(
514 ciphersuite,
515 encryption_key_pair.public_key().clone(),
516 leaf_node_params.credential_with_key,
517 leaf_node_params.capabilities,
518 LeafNodeSource::Commit(parent_hash.into()),
519 leaf_node_params.extensions,
520 TreeInfoTbs::Commit(TreePosition {
521 group_id,
522 leaf_index,
523 }),
524 &leaf_node_params.constraints,
525 leaf_node_params.capabilities_policy,
526 )?;
527
528 let leaf_node = leaf_node_tbs
530 .sign(signer)
531 .map_err(|_| LibraryError::custom("Signing failed"))?;
532
533 Ok((leaf_node, encryption_key_pair))
534 }
535
536 #[cfg(all(test, feature = "generate-kats"))]
544 #[openmls_traits::maybe_async]
545 pub(crate) async fn generate_update<Provider: OpenMlsProvider>(
546 ciphersuite: Ciphersuite,
547 credential_with_key: CredentialWithKey,
548 capabilities: Capabilities,
549 extensions: Extensions<LeafNode>,
550 tree_info_tbs: TreeInfoTbs,
551 provider: &Provider,
552 signer: &impl Signer,
553 ) -> Result<Self, LeafNodeGenerationError<Provider::StorageError>> {
554 let new_leaf_node_params = NewLeafNodeParams {
558 ciphersuite,
559 credential_with_key,
560 leaf_node_source: LeafNodeSource::Update,
561 capabilities,
562 extensions,
563 tree_info_tbs,
564 constraints: LeafNodeConstraints::default(),
568 capabilities_policy: CapabilitiesPolicy::Reject,
569 };
570
571 let (leaf_node, encryption_key_pair) = Self::new(provider, signer, new_leaf_node_params)?;
572
573 encryption_key_pair
575 .write(provider.storage())
576 .await
577 .map_err(LeafNodeGenerationError::StorageError)?;
578
579 Ok(leaf_node)
580 }
581
582 #[allow(clippy::too_many_arguments)]
590 #[openmls_traits::maybe_async]
591 pub(crate) async fn update<Provider: OpenMlsProvider>(
592 &mut self,
593 ciphersuite: Ciphersuite,
594 provider: &Provider,
595 signer: &impl Signer,
596 group_id: GroupId,
597 leaf_index: LeafNodeIndex,
598 leaf_node_parmeters: LeafNodeParameters,
599 constraints: &LeafNodeConstraints,
600 ) -> Result<EncryptionKeyPair, LeafNodeUpdateError<Provider::StorageError>> {
601 let tree_info = TreeInfoTbs::Update(TreePosition::new(group_id, leaf_index));
602 let mut leaf_node_tbs = LeafNodeTbs::from(self.clone(), tree_info);
603
604 if let Some(credential_with_key) = leaf_node_parmeters.credential_with_key {
606 leaf_node_tbs.payload.credential = credential_with_key.credential;
607 leaf_node_tbs.payload.signature_key = credential_with_key.signature_key;
608 }
609
610 if let Some(extensions) = leaf_node_parmeters.extensions {
612 leaf_node_tbs.payload.extensions = extensions;
613 }
614
615 let (capabilities, capabilities_policy) = resolve_capabilities_for_existing_leaf(
617 leaf_node_parmeters.capabilities,
618 leaf_node_parmeters.capabilities_policy,
619 &leaf_node_tbs.payload.capabilities,
620 );
621 leaf_node_tbs.payload.capabilities = capabilities;
622
623 leaf_node_tbs.payload.leaf_node_source = LeafNodeSource::Update;
625
626 leaf_node_tbs.payload.enforce_capabilities(
631 ciphersuite,
632 ProtocolVersion::default(),
633 constraints,
634 capabilities_policy,
635 )?;
636
637 let encryption_key_pair =
639 EncryptionKeyPair::random(provider.rand(), provider.crypto(), ciphersuite)?;
640 leaf_node_tbs.payload.encryption_key = encryption_key_pair.public_key().clone();
641
642 encryption_key_pair
644 .write(provider.storage())
645 .await
646 .map_err(LeafNodeUpdateError::Storage)?;
647
648 let leaf_node = leaf_node_tbs.sign(signer)?;
650 self.payload = leaf_node.payload;
651 self.signature = leaf_node.signature;
652
653 Ok(encryption_key_pair)
654 }
655
656 pub fn encryption_key(&self) -> &EncryptionKey {
658 &self.payload.encryption_key
659 }
660
661 pub fn signature_key(&self) -> &SignaturePublicKey {
663 &self.payload.signature_key
664 }
665
666 pub fn credential(&self) -> &Credential {
668 &self.payload.credential
669 }
670
671 pub fn parent_hash(&self) -> Option<&[u8]> {
673 match &self.payload.leaf_node_source {
674 LeafNodeSource::Commit(ph) => Some(ph.as_slice()),
675 _ => None,
676 }
677 }
678
679 pub(crate) fn life_time(&self) -> Option<&Lifetime> {
682 if let LeafNodeSource::KeyPackage(life_time) = &self.payload.leaf_node_source {
683 Some(life_time)
684 } else {
685 None
686 }
687 }
688
689 pub fn signature(&self) -> &Signature {
691 &self.signature
692 }
693
694 pub fn capabilities(&self) -> &Capabilities {
696 &self.payload.capabilities
697 }
698
699 pub fn leaf_node_source(&self) -> &LeafNodeSource {
701 &self.payload.leaf_node_source
702 }
703
704 pub fn extensions(&self) -> &Extensions<LeafNode> {
706 &self.payload.extensions
707 }
708
709 #[cfg(feature = "virtual-clients-draft")]
711 pub(crate) fn vc_derivation_info(
712 &self,
713 ) -> Result<
714 Option<crate::components::vc_derivation_info::DerivationInfo>,
715 crate::components::vc_derivation_info::VirtualClientsError,
716 > {
717 use tls_codec::DeserializeBytes as _;
718
719 use crate::components::vc_derivation_info::{
720 DerivationInfo, VirtualClientsError, VC_COMPONENT_ID,
721 };
722
723 let Some(bytes) = self
724 .extensions()
725 .app_data_dictionary()
726 .and_then(|dict| dict.dictionary().get(&VC_COMPONENT_ID))
727 else {
728 return Ok(None);
729 };
730 DerivationInfo::tls_deserialize_exact_bytes(bytes)
731 .map(Some)
732 .map_err(|e| {
733 log::error!("vc: leaf derivation info deserialize failed: {e:?}");
734 VirtualClientsError::DerivationInfoMalformed
735 })
736 }
737
738 pub(crate) fn supports_extension(&self, extension_type: &ExtensionType) -> bool {
740 extension_type.is_default()
741 || self
742 .payload
743 .capabilities
744 .extensions
745 .contains(extension_type)
746 }
747
748 pub(crate) fn check_extension_support(
751 &self,
752 extensions: &[ExtensionType],
753 ) -> Result<(), LeafNodeValidationError> {
754 let mut required = extensions.iter().filter(|e| !e.is_default()).peekable();
755
756 if required.peek().is_none() {
758 return Ok(());
759 }
760
761 let supported: HashSet<ExtensionType> = self
762 .payload
763 .capabilities
764 .extensions
765 .iter()
766 .copied()
767 .collect();
768
769 if let Some(unsupported) = required.find(|e| !supported.contains(e)) {
770 log::error!(
771 "Leaf node does not support required extension {:?}\n
772 Supported extensions: {:?}",
773 unsupported,
774 self.payload.capabilities.extensions
775 );
776 return Err(LeafNodeValidationError::UnsupportedExtensions);
777 }
778
779 Ok(())
780 }
781
782 pub(crate) fn validate_locally(&self) -> Result<(), LeafNodeValidationError> {
787 self.payload.validate_locally()
788 }
789}
790
791#[derive(
817 Debug,
818 Clone,
819 PartialEq,
820 Eq,
821 Serialize,
822 Deserialize,
823 TlsSerialize,
824 TlsDeserialize,
825 TlsDeserializeBytes,
826 TlsSize,
827)]
828struct LeafNodePayload {
829 encryption_key: EncryptionKey,
830 signature_key: SignaturePublicKey,
831 credential: Credential,
832 capabilities: Capabilities,
833 leaf_node_source: LeafNodeSource,
834 extensions: Extensions<LeafNode>,
835}
836
837impl LeafNodePayload {
838 pub(crate) fn validate_locally(&self) -> Result<(), LeafNodeValidationError> {
847 let invalid_extension_types = self
856 .extensions
857 .iter()
858 .filter(|ext| !ext.extension_type().is_valid_in_leaf_node())
859 .collect::<Vec<_>>();
860 if !invalid_extension_types.is_empty() {
861 log::error!("Invalid extension used in leaf node: {invalid_extension_types:?}");
862 return Err(LeafNodeValidationError::UnsupportedExtensions);
863 }
864
865 if !self.capabilities.contains_extensions(&self.extensions) {
867 log::error!(
868 "Leaf node does not support all extensions it uses\n
869 Supported extensions: {:?}\n
870 Used extensions: {:?}",
871 self.capabilities.extensions(),
872 self.extensions
873 );
874 return Err(LeafNodeValidationError::ExtensionsNotInCapabilities);
875 }
876
877 if !self
880 .capabilities
881 .contains_credential(self.credential.credential_type())
882 {
883 return Err(LeafNodeValidationError::CredentialNotInCapabilities);
884 }
885
886 Ok(())
887 }
888
889 fn enforce_capabilities(
901 &mut self,
902 ciphersuite: Ciphersuite,
903 version: ProtocolVersion,
904 constraints: &LeafNodeConstraints,
905 policy: CapabilitiesPolicy,
906 ) -> Result<(), LeafNodeValidationError> {
907 if matches!(policy, CapabilitiesPolicy::Widen) {
908 self.capabilities.widen_for(
909 ciphersuite,
910 self.credential.credential_type(),
911 &self.extensions,
912 );
913 }
914 self.capabilities.ensure_version(version);
915
916 self.validate_locally()?;
917
918 if !self
919 .capabilities
920 .contains_ciphersuite(VerifiableCiphersuite::from(ciphersuite))
921 {
922 return Err(LeafNodeValidationError::CiphersuiteNotInCapabilities);
923 }
924
925 constraints.check(&self.capabilities, self.credential.credential_type())?;
926
927 Ok(())
928 }
929}
930
931#[derive(
933 Debug,
934 Clone,
935 PartialEq,
936 Eq,
937 Serialize,
938 Deserialize,
939 TlsSerialize,
940 TlsDeserialize,
941 TlsDeserializeBytes,
942 TlsSize,
943)]
944#[repr(u8)]
945pub enum LeafNodeSource {
946 #[tls_codec(discriminant = 1)]
948 KeyPackage(Lifetime),
949 Update,
951 Commit(ParentHash),
953}
954
955pub type ParentHash = VLBytes;
956
957#[derive(Debug, TlsSerialize, TlsSize)]
985pub struct LeafNodeTbs {
986 payload: LeafNodePayload,
987 tree_info_tbs: TreeInfoTbs,
988}
989
990impl LeafNodeTbs {
991 pub(crate) fn from(leaf_node: LeafNode, tree_info_tbs: TreeInfoTbs) -> Self {
994 Self {
995 payload: leaf_node.payload,
996 tree_info_tbs,
997 }
998 }
999
1000 #[allow(clippy::too_many_arguments)]
1008 pub(crate) fn new(
1009 ciphersuite: Ciphersuite,
1010 encryption_key: EncryptionKey,
1011 credential_with_key: CredentialWithKey,
1012 capabilities: Capabilities,
1013 leaf_node_source: LeafNodeSource,
1014 extensions: Extensions<LeafNode>,
1015 tree_info_tbs: TreeInfoTbs,
1016 constraints: &LeafNodeConstraints,
1017 capabilities_policy: CapabilitiesPolicy,
1018 ) -> Result<Self, LeafNodeValidationError> {
1019 let mut payload = LeafNodePayload {
1020 encryption_key,
1021 signature_key: credential_with_key.signature_key,
1022 credential: credential_with_key.credential,
1023 capabilities,
1024 leaf_node_source,
1025 extensions,
1026 };
1027
1028 payload.enforce_capabilities(
1029 ciphersuite,
1030 ProtocolVersion::default(),
1031 constraints,
1032 capabilities_policy,
1033 )?;
1034
1035 Ok(LeafNodeTbs {
1036 payload,
1037 tree_info_tbs,
1038 })
1039 }
1040}
1041
1042#[derive(Debug)]
1064pub(crate) enum TreeInfoTbs {
1065 KeyPackage,
1066 Update(TreePosition),
1067 Commit(TreePosition),
1068}
1069
1070#[derive(Debug, Clone, PartialEq, Eq, TlsSerialize, TlsSize)]
1071pub(crate) struct TreePosition {
1072 group_id: GroupId,
1073 leaf_index: LeafNodeIndex,
1074}
1075
1076impl TreePosition {
1077 pub(crate) fn new(group_id: GroupId, leaf_index: LeafNodeIndex) -> Self {
1078 Self {
1079 group_id,
1080 leaf_index,
1081 }
1082 }
1083
1084 #[cfg(feature = "test-utils")]
1085 pub(crate) fn into_parts(self) -> (GroupId, LeafNodeIndex) {
1086 (self.group_id, self.leaf_index)
1087 }
1088}
1089
1090const LEAF_NODE_SIGNATURE_LABEL: &str = "LeafNodeTBS";
1091
1092#[derive(
1093 Debug,
1094 Clone,
1095 PartialEq,
1096 Eq,
1097 Serialize,
1098 Deserialize,
1099 TlsSerialize,
1100 TlsDeserialize,
1101 TlsDeserializeBytes,
1102 TlsSize,
1103)]
1104pub struct LeafNodeIn {
1105 payload: LeafNodePayload,
1106 signature: Signature,
1107}
1108
1109impl LeafNodeIn {
1110 pub(crate) fn into_verifiable_leaf_node(self) -> VerifiableLeafNode {
1111 match self.payload.leaf_node_source {
1112 LeafNodeSource::KeyPackage(_) => {
1113 let verifiable = VerifiableKeyPackageLeafNode {
1114 payload: self.payload,
1115 signature: self.signature,
1116 };
1117 VerifiableLeafNode::KeyPackage(verifiable)
1118 }
1119 LeafNodeSource::Update => {
1120 let verifiable = VerifiableUpdateLeafNode {
1121 payload: self.payload,
1122 signature: self.signature,
1123 tree_position: None,
1124 };
1125 VerifiableLeafNode::Update(verifiable)
1126 }
1127 LeafNodeSource::Commit(_) => {
1128 let verifiable = VerifiableCommitLeafNode {
1129 payload: self.payload,
1130 signature: self.signature,
1131 tree_position: None,
1132 };
1133 VerifiableLeafNode::Commit(verifiable)
1134 }
1135 }
1136 }
1137
1138 pub fn encryption_key(&self) -> &EncryptionKey {
1140 &self.payload.encryption_key
1141 }
1142
1143 pub fn signature_key(&self) -> &SignaturePublicKey {
1145 &self.payload.signature_key
1146 }
1147
1148 pub fn credential(&self) -> &Credential {
1150 &self.payload.credential
1151 }
1152
1153 #[cfg(feature = "unchecked-conversions")]
1159 pub fn into_unchecked(self) -> LeafNode {
1160 LeafNode {
1161 payload: self.payload,
1162 signature: self.signature,
1163 }
1164 }
1165}
1166
1167impl From<LeafNode> for LeafNodeIn {
1168 fn from(leaf_node: LeafNode) -> Self {
1169 Self {
1170 payload: leaf_node.payload,
1171 signature: leaf_node.signature,
1172 }
1173 }
1174}
1175
1176#[cfg(any(feature = "test-utils", test))]
1177impl From<LeafNodeIn> for LeafNode {
1178 fn from(deserialized: LeafNodeIn) -> Self {
1179 Self {
1180 payload: deserialized.payload,
1181 signature: deserialized.signature,
1182 }
1183 }
1184}
1185
1186impl From<KeyPackage> for LeafNode {
1187 fn from(key_package: KeyPackage) -> Self {
1188 key_package.leaf_node().clone()
1189 }
1190}
1191
1192impl From<KeyPackageBundle> for LeafNode {
1193 fn from(key_package: KeyPackageBundle) -> Self {
1194 key_package.key_package().leaf_node().clone()
1195 }
1196}
1197
1198#[derive(Debug, Clone, PartialEq, Eq)]
1199pub(crate) enum VerifiableLeafNode {
1200 KeyPackage(VerifiableKeyPackageLeafNode),
1201 Update(VerifiableUpdateLeafNode),
1202 Commit(VerifiableCommitLeafNode),
1203}
1204
1205impl VerifiableLeafNode {
1206 pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
1207 match self {
1208 VerifiableLeafNode::KeyPackage(v) => v.signature_key(),
1209 VerifiableLeafNode::Update(v) => v.signature_key(),
1210 VerifiableLeafNode::Commit(v) => v.signature_key(),
1211 }
1212 }
1213}
1214
1215#[derive(Debug, Clone, PartialEq, Eq)]
1216pub(crate) struct VerifiableKeyPackageLeafNode {
1217 payload: LeafNodePayload,
1218 signature: Signature,
1219}
1220
1221impl VerifiableKeyPackageLeafNode {
1222 pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
1223 &self.payload.signature_key
1224 }
1225}
1226
1227impl Verifiable for VerifiableKeyPackageLeafNode {
1229 type VerifiedStruct = LeafNode;
1230
1231 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
1232 self.payload.tls_serialize_detached()
1233 }
1234
1235 fn signature(&self) -> &Signature {
1236 &self.signature
1237 }
1238
1239 fn label(&self) -> &str {
1240 LEAF_NODE_SIGNATURE_LABEL
1241 }
1242
1243 fn verify(
1244 self,
1245 crypto: &impl openmls_traits::crypto::OpenMlsCrypto,
1246 pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
1247 ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
1248 self.verify_no_out(crypto, pk)?;
1249 Ok(LeafNode {
1250 payload: self.payload,
1251 signature: self.signature,
1252 })
1253 }
1254}
1255
1256impl VerifiedStruct for LeafNode {}
1257
1258#[derive(Debug, Clone, PartialEq, Eq)]
1259pub(crate) struct VerifiableUpdateLeafNode {
1260 payload: LeafNodePayload,
1261 signature: Signature,
1262 tree_position: Option<TreePosition>,
1263}
1264
1265impl VerifiableUpdateLeafNode {
1266 pub(crate) fn add_tree_position(&mut self, tree_info: TreePosition) {
1267 self.tree_position = Some(tree_info);
1268 }
1269
1270 pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
1271 &self.payload.signature_key
1272 }
1273}
1274
1275impl Verifiable for VerifiableUpdateLeafNode {
1276 type VerifiedStruct = LeafNode;
1277
1278 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
1279 let tree_info_tbs = match &self.tree_position {
1280 Some(tree_position) => TreeInfoTbs::Commit(tree_position.clone()),
1281 None => return Err(tls_codec::Error::InvalidInput),
1282 };
1283 let leaf_node_tbs = LeafNodeTbs {
1284 payload: self.payload.clone(),
1285 tree_info_tbs,
1286 };
1287 leaf_node_tbs.tls_serialize_detached()
1288 }
1289
1290 fn signature(&self) -> &Signature {
1291 &self.signature
1292 }
1293
1294 fn label(&self) -> &str {
1295 LEAF_NODE_SIGNATURE_LABEL
1296 }
1297
1298 fn verify(
1299 self,
1300 crypto: &impl openmls_traits::crypto::OpenMlsCrypto,
1301 pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
1302 ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
1303 self.verify_no_out(crypto, pk)?;
1304 Ok(LeafNode {
1305 payload: self.payload,
1306 signature: self.signature,
1307 })
1308 }
1309}
1310
1311#[derive(Debug, Clone, PartialEq, Eq)]
1312pub(crate) struct VerifiableCommitLeafNode {
1313 payload: LeafNodePayload,
1314 signature: Signature,
1315 tree_position: Option<TreePosition>,
1316}
1317
1318impl VerifiableCommitLeafNode {
1319 pub(crate) fn add_tree_position(&mut self, tree_info: TreePosition) {
1320 self.tree_position = Some(tree_info);
1321 }
1322
1323 pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
1324 &self.payload.signature_key
1325 }
1326}
1327
1328impl Verifiable for VerifiableCommitLeafNode {
1329 type VerifiedStruct = LeafNode;
1330
1331 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
1332 let tree_info_tbs = match &self.tree_position {
1333 Some(tree_position) => TreeInfoTbs::Commit(tree_position.clone()),
1334 None => return Err(tls_codec::Error::InvalidInput),
1335 };
1336 let leaf_node_tbs = LeafNodeTbs {
1337 payload: self.payload.clone(),
1338 tree_info_tbs,
1339 };
1340
1341 leaf_node_tbs.tls_serialize_detached()
1342 }
1343
1344 fn signature(&self) -> &Signature {
1345 &self.signature
1346 }
1347
1348 fn label(&self) -> &str {
1349 LEAF_NODE_SIGNATURE_LABEL
1350 }
1351
1352 fn verify(
1353 self,
1354 crypto: &impl openmls_traits::crypto::OpenMlsCrypto,
1355 pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
1356 ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
1357 self.verify_no_out(crypto, pk)?;
1358 Ok(LeafNode {
1359 payload: self.payload,
1360 signature: self.signature,
1361 })
1362 }
1363}
1364
1365impl Signable for LeafNodeTbs {
1366 type SignedOutput = LeafNode;
1367
1368 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
1369 self.tls_serialize_detached()
1370 }
1371
1372 fn label(&self) -> &str {
1373 LEAF_NODE_SIGNATURE_LABEL
1374 }
1375}
1376
1377impl SignedStruct<LeafNodeTbs> for LeafNode {
1378 fn from_payload(tbs: LeafNodeTbs, signature: Signature, _serialized_payload: Vec<u8>) -> Self {
1379 Self {
1380 payload: tbs.payload,
1381 signature,
1382 }
1383 }
1384}
1385
1386#[cfg(all(test, feature = "generate-kats"))]
1387#[derive(Error, Debug, PartialEq, Clone)]
1388pub enum LeafNodeGenerationError<StorageError> {
1389 #[error(transparent)]
1391 LibraryError(#[from] LibraryError),
1392
1393 #[error(transparent)]
1395 Build(#[from] LeafNodeBuildError),
1396
1397 #[error("Error storing leaf private key.")]
1399 StorageError(StorageError),
1400}
1401
1402#[derive(Error, Debug, PartialEq, Clone)]
1404pub enum LeafNodeUpdateError<StorageError> {
1405 #[error(transparent)]
1407 LibraryError(#[from] LibraryError),
1408
1409 #[error("Error storing leaf private key.")]
1411 Storage(StorageError),
1412
1413 #[error(transparent)]
1415 Signature(#[from] crate::ciphersuite::signable::SignatureError),
1416
1417 #[error(transparent)]
1419 Validation(#[from] LeafNodeValidationError),
1420}