openmls/treesync/node/
leaf_node.rs

1//! This module contains the [`LeafNode`] struct and its implementation.
2use openmls_traits::{
3    crypto::OpenMlsCrypto, random::OpenMlsRand, signatures::Signer, types::Ciphersuite,
4};
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7use tls_codec::{
8    Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
9    VLBytes,
10};
11
12use super::encryption_keys::{EncryptionKey, EncryptionKeyPair};
13use crate::{
14    binary_tree::array_representation::LeafNodeIndex,
15    ciphersuite::{
16        signable::{Signable, SignedStruct, Verifiable, VerifiedStruct},
17        Signature, SignaturePublicKey,
18    },
19    credentials::{Credential, CredentialType, CredentialWithKey},
20    error::LibraryError,
21    extensions::{errors::InvalidExtensionError, ExtensionType, Extensions},
22    group::GroupId,
23    key_packages::{KeyPackage, Lifetime},
24    prelude::KeyPackageBundle,
25    storage::OpenMlsProvider,
26};
27
28use crate::treesync::errors::LeafNodeValidationError;
29
30mod capabilities;
31mod codec;
32
33pub use capabilities::*;
34
35pub(crate) struct NewLeafNodeParams {
36    pub(crate) ciphersuite: Ciphersuite,
37    pub(crate) credential_with_key: CredentialWithKey,
38    pub(crate) leaf_node_source: LeafNodeSource,
39    pub(crate) capabilities: Capabilities,
40    pub(crate) extensions: Extensions,
41    pub(crate) tree_info_tbs: TreeInfoTbs,
42}
43
44/// Set of LeafNode parameters that are used when regenerating a LeafNodes
45/// during an update operation.
46#[derive(Debug, PartialEq, Clone)]
47pub(crate) struct UpdateLeafNodeParams {
48    pub(crate) credential_with_key: CredentialWithKey,
49    pub(crate) capabilities: Capabilities,
50    pub(crate) extensions: Extensions,
51}
52
53impl UpdateLeafNodeParams {
54    #[cfg(test)]
55    pub(crate) fn derive(leaf_node: &LeafNode) -> Self {
56        Self {
57            credential_with_key: CredentialWithKey {
58                credential: leaf_node.payload.credential.clone(),
59                signature_key: leaf_node.payload.signature_key.clone(),
60            },
61            capabilities: leaf_node.payload.capabilities.clone(),
62            extensions: leaf_node.payload.extensions.clone(),
63        }
64    }
65}
66
67/// Parameters for a leaf node that can be chosen by the application.
68#[derive(Debug, PartialEq, Clone, Default)]
69pub struct LeafNodeParameters {
70    credential_with_key: Option<CredentialWithKey>,
71    capabilities: Option<Capabilities>,
72    extensions: Option<Extensions>,
73}
74
75impl LeafNodeParameters {
76    /// Create a new [`LeafNodeParametersBuilder`].
77    pub fn builder() -> LeafNodeParametersBuilder {
78        LeafNodeParametersBuilder::default()
79    }
80
81    /// Returns the credential with key.
82    pub fn credential_with_key(&self) -> Option<&CredentialWithKey> {
83        self.credential_with_key.as_ref()
84    }
85
86    /// Returns the capabilities.
87    pub fn capabilities(&self) -> Option<&Capabilities> {
88        self.capabilities.as_ref()
89    }
90
91    /// Returns the extensions.
92    pub fn extensions(&self) -> Option<&Extensions> {
93        self.extensions.as_ref()
94    }
95
96    pub(crate) fn is_empty(&self) -> bool {
97        self.credential_with_key.is_none()
98            && self.capabilities.is_none()
99            && self.extensions.is_none()
100    }
101
102    pub(crate) fn set_credential_with_key(&mut self, credential_with_key: CredentialWithKey) {
103        self.credential_with_key = Some(credential_with_key);
104    }
105}
106
107/// Builder for [`LeafNodeParameters`].
108#[derive(Debug, Default)]
109pub struct LeafNodeParametersBuilder {
110    credential_with_key: Option<CredentialWithKey>,
111    capabilities: Option<Capabilities>,
112    extensions: Option<Extensions>,
113}
114
115impl LeafNodeParametersBuilder {
116    /// Set the credential with key.
117    pub fn with_credential_with_key(mut self, credential_with_key: CredentialWithKey) -> Self {
118        self.credential_with_key = Some(credential_with_key);
119        self
120    }
121
122    /// Set the capabilities.
123    pub fn with_capabilities(mut self, capabilities: Capabilities) -> Self {
124        self.capabilities = Some(capabilities);
125        self
126    }
127
128    /// Set the extensions.
129    ///
130    /// Returns an error if one or more of the extensions is invalid in leaf nodes.
131    pub fn with_extensions(
132        mut self,
133        extensions: Extensions,
134    ) -> Result<Self, InvalidExtensionError> {
135        // https://validation.openmls.tech/#valn1601
136        extensions.validate_extension_types_for_leaf_node()?;
137
138        self.extensions = Some(extensions);
139        Ok(self)
140    }
141
142    /// Build the [`LeafNodeParameters`].
143    pub fn build(self) -> LeafNodeParameters {
144        LeafNodeParameters {
145            credential_with_key: self.credential_with_key,
146            capabilities: self.capabilities,
147            extensions: self.extensions,
148        }
149    }
150}
151
152/// This struct implements the MLS leaf node.
153///
154/// ```c
155/// // draft-ietf-mls-protocol-17
156/// struct {
157///     HPKEPublicKey encryption_key;
158///     SignaturePublicKey signature_key;
159///     Credential credential;
160///     Capabilities capabilities;
161///
162///     LeafNodeSource leaf_node_source;
163///     select (LeafNode.leaf_node_source) {
164///         case key_package:
165///             Lifetime lifetime;
166///
167///         case update:
168///             struct{};
169///
170///         case commit:
171///             opaque parent_hash<V>;
172///     };
173///
174///     Extension extensions<V>;
175///     /* SignWithLabel(., "LeafNodeTBS", LeafNodeTBS) */
176///     opaque signature<V>;
177/// } LeafNode;
178/// ```
179#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TlsSerialize, TlsSize)]
180pub struct LeafNode {
181    payload: LeafNodePayload,
182    signature: Signature,
183}
184
185impl LeafNode {
186    /// Create a new [`LeafNode`].
187    /// This first creates a `LeadNodeTbs` and returns the result of signing
188    /// it.
189    ///
190    /// This function generates a fresh HPKE key pair for the leaf node and
191    /// returns the HPKE key pair along with the new leaf node.
192    /// The caller is responsible for storing the private key.
193    pub(crate) fn new(
194        provider: &impl OpenMlsProvider,
195        signer: &impl Signer,
196        new_leaf_node_params: NewLeafNodeParams,
197    ) -> Result<(Self, EncryptionKeyPair), LibraryError> {
198        let NewLeafNodeParams {
199            ciphersuite,
200            credential_with_key,
201            leaf_node_source,
202            capabilities,
203            extensions,
204            tree_info_tbs,
205        } = new_leaf_node_params;
206
207        // Create a new encryption key pair.
208        let encryption_key_pair =
209            EncryptionKeyPair::random(provider.rand(), provider.crypto(), ciphersuite)?;
210
211        let leaf_node = Self::new_with_key(
212            encryption_key_pair.public_key().clone(),
213            credential_with_key,
214            leaf_node_source,
215            capabilities,
216            extensions,
217            tree_info_tbs,
218            signer,
219        )?;
220
221        Ok((leaf_node, encryption_key_pair))
222    }
223
224    /// Creates a new placeholder [`LeafNode`] that is used to build external
225    /// commits.
226    ///
227    /// Note: This is not a valid leaf node and it must be rekeyed and signed
228    /// before it can be used.
229    pub(crate) fn new_placeholder() -> Self {
230        let payload = LeafNodePayload {
231            encryption_key: EncryptionKey::from(Vec::new()),
232            signature_key: Vec::new().into(),
233            credential: Credential::new(CredentialType::Basic, Vec::new()),
234            capabilities: Capabilities::default(),
235            leaf_node_source: LeafNodeSource::Update,
236            extensions: Extensions::default(),
237        };
238
239        Self {
240            payload,
241            signature: Vec::new().into(),
242        }
243    }
244
245    /// Create a new leaf node with a given HPKE encryption key pair.
246    /// The key pair must be stored in the key store by the caller.
247    fn new_with_key(
248        encryption_key: EncryptionKey,
249        credential_with_key: CredentialWithKey,
250        leaf_node_source: LeafNodeSource,
251        capabilities: Capabilities,
252        extensions: Extensions,
253        tree_info_tbs: TreeInfoTbs,
254        signer: &impl Signer,
255    ) -> Result<Self, LibraryError> {
256        let leaf_node_tbs = LeafNodeTbs::new(
257            encryption_key,
258            credential_with_key,
259            capabilities,
260            leaf_node_source,
261            extensions,
262            tree_info_tbs,
263        );
264
265        leaf_node_tbs
266            .sign(signer)
267            .map_err(|_| LibraryError::custom("Signing failed"))
268    }
269
270    /// New [`LeafNode`] with a parent hash.
271    #[allow(clippy::too_many_arguments)]
272    pub(in crate::treesync) fn new_with_parent_hash(
273        rand: &impl OpenMlsRand,
274        crypto: &impl OpenMlsCrypto,
275        ciphersuite: Ciphersuite,
276        parent_hash: &[u8],
277        leaf_node_params: UpdateLeafNodeParams,
278        group_id: GroupId,
279        leaf_index: LeafNodeIndex,
280        signer: &impl Signer,
281    ) -> Result<(Self, EncryptionKeyPair), LibraryError> {
282        let encryption_key_pair = EncryptionKeyPair::random(rand, crypto, ciphersuite)?;
283
284        let leaf_node_tbs = LeafNodeTbs::new(
285            encryption_key_pair.public_key().clone(),
286            leaf_node_params.credential_with_key,
287            leaf_node_params.capabilities,
288            LeafNodeSource::Commit(parent_hash.into()),
289            leaf_node_params.extensions,
290            TreeInfoTbs::Commit(TreePosition {
291                group_id,
292                leaf_index,
293            }),
294        );
295
296        // Sign the leaf node
297        let leaf_node = leaf_node_tbs
298            .sign(signer)
299            .map_err(|_| LibraryError::custom("Signing failed"))?;
300
301        Ok((leaf_node, encryption_key_pair))
302    }
303
304    /// Generate a fresh leaf node.
305    ///
306    /// This includes generating a new encryption key pair that is stored in the
307    /// key store.
308    ///
309    /// This function can be used when generating an update. In most other cases
310    /// a leaf node should be generated as part of a new [`KeyPackage`].
311    #[cfg(test)]
312    pub(crate) fn generate_update<Provider: OpenMlsProvider>(
313        ciphersuite: Ciphersuite,
314        credential_with_key: CredentialWithKey,
315        capabilities: Capabilities,
316        extensions: Extensions,
317        tree_info_tbs: TreeInfoTbs,
318        provider: &Provider,
319        signer: &impl Signer,
320    ) -> Result<Self, LeafNodeGenerationError<Provider::StorageError>> {
321        // Note that this function is supposed to be used in the public API only
322        // because it is interacting with the key store.
323
324        let new_leaf_node_params = NewLeafNodeParams {
325            ciphersuite,
326            credential_with_key,
327            leaf_node_source: LeafNodeSource::Update,
328            capabilities,
329            extensions,
330            tree_info_tbs,
331        };
332
333        let (leaf_node, encryption_key_pair) = Self::new(provider, signer, new_leaf_node_params)?;
334
335        // Store the encryption key pair in the key store.
336        encryption_key_pair
337            .write(provider.storage())
338            .map_err(LeafNodeGenerationError::StorageError)?;
339
340        Ok(leaf_node)
341    }
342
343    /// Update a leaf node.
344    ///
345    /// This function generates a new encryption key pair that is stored in the
346    /// key store and also returned.
347    ///
348    /// This function can be used when generating an update. In most other cases
349    /// a leaf node should be generated as part of a new [`KeyPackage`].
350    pub(crate) fn update<Provider: OpenMlsProvider>(
351        &mut self,
352        ciphersuite: Ciphersuite,
353        provider: &Provider,
354        signer: &impl Signer,
355        group_id: GroupId,
356        leaf_index: LeafNodeIndex,
357        leaf_node_parmeters: LeafNodeParameters,
358    ) -> Result<EncryptionKeyPair, LeafNodeUpdateError<Provider::StorageError>> {
359        let tree_info = TreeInfoTbs::Update(TreePosition::new(group_id, leaf_index));
360        let mut leaf_node_tbs = LeafNodeTbs::from(self.clone(), tree_info);
361
362        // Update credential
363        if let Some(credential_with_key) = leaf_node_parmeters.credential_with_key {
364            leaf_node_tbs.payload.credential = credential_with_key.credential;
365            leaf_node_tbs.payload.signature_key = credential_with_key.signature_key;
366        }
367
368        // Update extensions
369        if let Some(extensions) = leaf_node_parmeters.extensions {
370            leaf_node_tbs.payload.extensions = extensions;
371        }
372
373        // Update capabilities
374        if let Some(capabilities) = leaf_node_parmeters.capabilities {
375            leaf_node_tbs.payload.capabilities = capabilities;
376        }
377
378        // Create a new encryption key pair
379        let encryption_key_pair =
380            EncryptionKeyPair::random(provider.rand(), provider.crypto(), ciphersuite)?;
381        leaf_node_tbs.payload.encryption_key = encryption_key_pair.public_key().clone();
382
383        // Store the encryption key pair in the key store.
384        encryption_key_pair
385            .write(provider.storage())
386            .map_err(LeafNodeUpdateError::Storage)?;
387
388        // Set the leaf node source to update
389        leaf_node_tbs.payload.leaf_node_source = LeafNodeSource::Update;
390
391        // Sign the leaf node
392        let leaf_node = leaf_node_tbs.sign(signer)?;
393        self.payload = leaf_node.payload;
394        self.signature = leaf_node.signature;
395
396        Ok(encryption_key_pair)
397    }
398
399    /// Returns the `encryption_key`.
400    pub fn encryption_key(&self) -> &EncryptionKey {
401        &self.payload.encryption_key
402    }
403
404    /// Returns the `signature_key` as byte slice.
405    pub fn signature_key(&self) -> &SignaturePublicKey {
406        &self.payload.signature_key
407    }
408
409    /// Returns the `credential`.
410    pub fn credential(&self) -> &Credential {
411        &self.payload.credential
412    }
413
414    /// Returns the `parent_hash` as byte slice or `None`.
415    pub fn parent_hash(&self) -> Option<&[u8]> {
416        match &self.payload.leaf_node_source {
417            LeafNodeSource::Commit(ph) => Some(ph.as_slice()),
418            _ => None,
419        }
420    }
421
422    /// Returns the [`Lifetime`] if present.
423    /// `None` otherwise.
424    pub(crate) fn life_time(&self) -> Option<&Lifetime> {
425        if let LeafNodeSource::KeyPackage(life_time) = &self.payload.leaf_node_source {
426            Some(life_time)
427        } else {
428            None
429        }
430    }
431
432    /// Returns a reference to the [`Signature`] of this leaf.
433    pub fn signature(&self) -> &Signature {
434        &self.signature
435    }
436
437    /// Return a reference to [`Capabilities`].
438    pub fn capabilities(&self) -> &Capabilities {
439        &self.payload.capabilities
440    }
441
442    /// Return a reference to the leaf node source.
443    pub fn leaf_node_source(&self) -> &LeafNodeSource {
444        &self.payload.leaf_node_source
445    }
446
447    /// Return a reference to the leaf node extensions.
448    pub fn extensions(&self) -> &Extensions {
449        &self.payload.extensions
450    }
451
452    /// Returns `true` if the [`ExtensionType`] is supported by this leaf node.
453    pub(crate) fn supports_extension(&self, extension_type: &ExtensionType) -> bool {
454        extension_type.is_default()
455            || self
456                .payload
457                .capabilities
458                .extensions
459                .contains(extension_type)
460    }
461
462    /// Check whether the this leaf node supports all the required extensions
463    /// in the provided list.
464    pub(crate) fn check_extension_support(
465        &self,
466        extensions: &[ExtensionType],
467    ) -> Result<(), LeafNodeValidationError> {
468        for required in extensions.iter() {
469            if !self.supports_extension(required) {
470                log::error!(
471                    "Leaf node does not support required extension {:?}\n
472                    Supported extensions: {:?}",
473                    required,
474                    self.payload.capabilities.extensions
475                );
476                return Err(LeafNodeValidationError::UnsupportedExtensions);
477            }
478        }
479        Ok(())
480    }
481
482    /// Perform all checks that can be done without further context:
483    /// - the used extensions are not known to be invalid in leaf nodes
484    /// - the types of the used extensions are covered by the capabilities
485    /// - the type of the credential is covered by the capabilities
486    pub(crate) fn validate_locally(&self) -> Result<(), LeafNodeValidationError> {
487        // Check that no extension is invalid when used in leaf nodes.
488        // https://validation.openmls.tech/#valn1601
489        // NOTE: This check is conducted manually for now, instead of using the method
490        // Extensions::validate_extension_types_for_leaf_node(),
491        // in order to collect the invalid extension types for the log message below.
492        // However, it could be better to instead return the list of invalid extension types
493        // as part of Extensions::validate_extension_types_for_leaf_node(),
494        // as part of the error message.
495        let invalid_extension_types = self
496            .extensions()
497            .iter()
498            .filter(|ext| ext.extension_type().is_valid_in_leaf_node() == Some(false))
499            .collect::<Vec<_>>();
500        if !invalid_extension_types.is_empty() {
501            log::error!("Invalid extension used in leaf node: {invalid_extension_types:?}");
502            return Err(LeafNodeValidationError::UnsupportedExtensions);
503        }
504
505        // Check that all extensions are contained in the capabilities.
506        if !self.capabilities().contains_extensions(self.extensions()) {
507            log::error!(
508                "Leaf node does not support all extensions it uses\n
509                Supported extensions: {:?}\n
510                Used extensions: {:?}",
511                self.payload.capabilities.extensions,
512                self.extensions()
513            );
514            return Err(LeafNodeValidationError::UnsupportedExtensions);
515        }
516
517        // Check that the capabilities contain the leaf node's credential type.
518        // (https://validation.openmls.tech/#valn0113)
519        if !self
520            .capabilities()
521            .contains_credential(self.credential().credential_type())
522        {
523            return Err(LeafNodeValidationError::UnsupportedCredentials);
524        }
525
526        Ok(())
527    }
528}
529
530/// The payload of a [`LeafNode`]
531///
532/// ```text
533/// struct {
534///     HPKEPublicKey encryption_key;
535///     SignaturePublicKey signature_key;
536///     Credential credential;
537///     Capabilities capabilities;
538///
539///     LeafNodeSource leaf_node_source;
540///     select (LeafNode.leaf_node_source) {
541///         case key_package:
542///             Lifetime lifetime;
543///
544///         case update:
545///             struct{};
546///
547///         case commit:
548///             opaque parent_hash<V>;
549///     };
550///
551///     Extension extensions<V>;
552///     ...
553/// } LeafNode;
554/// ```
555#[derive(
556    Debug,
557    Clone,
558    PartialEq,
559    Eq,
560    Serialize,
561    Deserialize,
562    TlsSerialize,
563    TlsDeserialize,
564    TlsDeserializeBytes,
565    TlsSize,
566)]
567struct LeafNodePayload {
568    encryption_key: EncryptionKey,
569    signature_key: SignaturePublicKey,
570    credential: Credential,
571    capabilities: Capabilities,
572    leaf_node_source: LeafNodeSource,
573    extensions: Extensions,
574}
575
576/// The source of the `LeafNode`.
577#[derive(
578    Debug,
579    Clone,
580    PartialEq,
581    Eq,
582    Serialize,
583    Deserialize,
584    TlsSerialize,
585    TlsDeserialize,
586    TlsDeserializeBytes,
587    TlsSize,
588)]
589#[repr(u8)]
590pub enum LeafNodeSource {
591    /// The leaf node was added to the group as part of a key package.
592    #[tls_codec(discriminant = 1)]
593    KeyPackage(Lifetime),
594    /// The leaf node was added through an Update proposal.
595    Update,
596    /// The leaf node was added via a Commit.
597    Commit(ParentHash),
598}
599
600pub type ParentHash = VLBytes;
601
602/// To-be-signed leaf node.
603///
604/// ```c
605/// // draft-ietf-mls-protocol-17
606/// struct {
607///     HPKEPublicKey encryption_key;
608///     SignaturePublicKey signature_key;
609///     Credential credential;
610///     Capabilities capabilities;
611///
612///     LeafNodeSource leaf_node_source;
613///     select (LeafNodeTBS.leaf_node_source) {
614///         case key_package:
615///             Lifetime lifetime;
616///
617///         case update:
618///             struct{};
619///
620///         case commit:
621///             opaque parent_hash<V>;
622///     };
623///
624///     Extension extensions<V>;
625///
626///     // ... continued in [`TreeInfo`] ...
627/// } LeafNodeTBS;
628/// ```
629#[derive(Debug, TlsSerialize, TlsSize)]
630pub struct LeafNodeTbs {
631    payload: LeafNodePayload,
632    tree_info_tbs: TreeInfoTbs,
633}
634
635impl LeafNodeTbs {
636    /// Build a [`LeafNodeTbs`] from a [`LeafNode`] and a [`TreeInfo`]
637    /// to update a leaf node.
638    pub(crate) fn from(leaf_node: LeafNode, tree_info_tbs: TreeInfoTbs) -> Self {
639        Self {
640            payload: leaf_node.payload,
641            tree_info_tbs,
642        }
643    }
644
645    /// Build a new [`LeafNodeTbs`] from a [`KeyPackage`] and [`Credential`].
646    /// To get the [`LeafNode`] call [`LeafNode::sign`].
647    pub(crate) fn new(
648        encryption_key: EncryptionKey,
649        credential_with_key: CredentialWithKey,
650        capabilities: Capabilities,
651        leaf_node_source: LeafNodeSource,
652        extensions: Extensions,
653        tree_info_tbs: TreeInfoTbs,
654    ) -> Self {
655        let payload = LeafNodePayload {
656            encryption_key,
657            signature_key: credential_with_key.signature_key,
658            credential: credential_with_key.credential,
659            capabilities,
660            leaf_node_source,
661            extensions,
662        };
663
664        LeafNodeTbs {
665            payload,
666            tree_info_tbs,
667        }
668    }
669}
670
671/// Helper struct that holds additional information required to sign a leaf node.
672///
673/// ```c
674/// // draft-ietf-mls-protocol-17
675/// struct {
676///     // ... continued from [`LeafNodeTbs`] ...
677///
678///     select (LeafNodeTBS.leaf_node_source) {
679///         case key_package:
680///             struct{};
681///
682///         case update:
683///             opaque group_id<V>;
684///             uint32 leaf_index;
685///
686///         case commit:
687///             opaque group_id<V>;
688///             uint32 leaf_index;
689///     };
690/// } LeafNodeTBS;
691/// ```
692#[derive(Debug)]
693pub(crate) enum TreeInfoTbs {
694    KeyPackage,
695    Update(TreePosition),
696    Commit(TreePosition),
697}
698
699#[derive(Debug, Clone, PartialEq, Eq, TlsSerialize, TlsSize)]
700pub(crate) struct TreePosition {
701    group_id: GroupId,
702    leaf_index: LeafNodeIndex,
703}
704
705impl TreePosition {
706    pub(crate) fn new(group_id: GroupId, leaf_index: LeafNodeIndex) -> Self {
707        Self {
708            group_id,
709            leaf_index,
710        }
711    }
712
713    #[cfg(feature = "test-utils")]
714    pub(crate) fn into_parts(self) -> (GroupId, LeafNodeIndex) {
715        (self.group_id, self.leaf_index)
716    }
717}
718
719const LEAF_NODE_SIGNATURE_LABEL: &str = "LeafNodeTBS";
720
721#[derive(
722    Debug,
723    Clone,
724    PartialEq,
725    Eq,
726    Serialize,
727    Deserialize,
728    TlsSerialize,
729    TlsDeserialize,
730    TlsDeserializeBytes,
731    TlsSize,
732)]
733pub struct LeafNodeIn {
734    payload: LeafNodePayload,
735    signature: Signature,
736}
737
738impl LeafNodeIn {
739    pub(crate) fn into_verifiable_leaf_node(self) -> VerifiableLeafNode {
740        match self.payload.leaf_node_source {
741            LeafNodeSource::KeyPackage(_) => {
742                let verifiable = VerifiableKeyPackageLeafNode {
743                    payload: self.payload,
744                    signature: self.signature,
745                };
746                VerifiableLeafNode::KeyPackage(verifiable)
747            }
748            LeafNodeSource::Update => {
749                let verifiable = VerifiableUpdateLeafNode {
750                    payload: self.payload,
751                    signature: self.signature,
752                    tree_position: None,
753                };
754                VerifiableLeafNode::Update(verifiable)
755            }
756            LeafNodeSource::Commit(_) => {
757                let verifiable = VerifiableCommitLeafNode {
758                    payload: self.payload,
759                    signature: self.signature,
760                    tree_position: None,
761                };
762                VerifiableLeafNode::Commit(verifiable)
763            }
764        }
765    }
766
767    /// Returns the `encryption_key` as byte slice.
768    pub fn encryption_key(&self) -> &EncryptionKey {
769        &self.payload.encryption_key
770    }
771
772    /// Returns the `signature_key` as byte slice.
773    pub fn signature_key(&self) -> &SignaturePublicKey {
774        &self.payload.signature_key
775    }
776
777    /// Returns the `signature_key` as byte slice.
778    pub fn credential(&self) -> &Credential {
779        &self.payload.credential
780    }
781}
782
783impl From<LeafNode> for LeafNodeIn {
784    fn from(leaf_node: LeafNode) -> Self {
785        Self {
786            payload: leaf_node.payload,
787            signature: leaf_node.signature,
788        }
789    }
790}
791
792#[cfg(any(feature = "test-utils", test))]
793impl From<LeafNodeIn> for LeafNode {
794    fn from(deserialized: LeafNodeIn) -> Self {
795        Self {
796            payload: deserialized.payload,
797            signature: deserialized.signature,
798        }
799    }
800}
801
802impl From<KeyPackage> for LeafNode {
803    fn from(key_package: KeyPackage) -> Self {
804        key_package.leaf_node().clone()
805    }
806}
807
808impl From<KeyPackageBundle> for LeafNode {
809    fn from(key_package: KeyPackageBundle) -> Self {
810        key_package.key_package().leaf_node().clone()
811    }
812}
813
814#[derive(Debug, Clone, PartialEq, Eq)]
815pub(crate) enum VerifiableLeafNode {
816    KeyPackage(VerifiableKeyPackageLeafNode),
817    Update(VerifiableUpdateLeafNode),
818    Commit(VerifiableCommitLeafNode),
819}
820
821impl VerifiableLeafNode {
822    pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
823        match self {
824            VerifiableLeafNode::KeyPackage(v) => v.signature_key(),
825            VerifiableLeafNode::Update(v) => v.signature_key(),
826            VerifiableLeafNode::Commit(v) => v.signature_key(),
827        }
828    }
829}
830
831#[derive(Debug, Clone, PartialEq, Eq)]
832pub(crate) struct VerifiableKeyPackageLeafNode {
833    payload: LeafNodePayload,
834    signature: Signature,
835}
836
837impl VerifiableKeyPackageLeafNode {
838    pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
839        &self.payload.signature_key
840    }
841}
842
843// https://validation.openmls.tech/#valn0102
844impl Verifiable for VerifiableKeyPackageLeafNode {
845    type VerifiedStruct = LeafNode;
846
847    fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
848        self.payload.tls_serialize_detached()
849    }
850
851    fn signature(&self) -> &Signature {
852        &self.signature
853    }
854
855    fn label(&self) -> &str {
856        LEAF_NODE_SIGNATURE_LABEL
857    }
858
859    fn verify(
860        self,
861        crypto: &impl openmls_traits::crypto::OpenMlsCrypto,
862        pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
863    ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
864        self.verify_no_out(crypto, pk)?;
865        Ok(LeafNode {
866            payload: self.payload,
867            signature: self.signature,
868        })
869    }
870}
871
872impl VerifiedStruct for LeafNode {}
873
874#[derive(Debug, Clone, PartialEq, Eq)]
875pub(crate) struct VerifiableUpdateLeafNode {
876    payload: LeafNodePayload,
877    signature: Signature,
878    tree_position: Option<TreePosition>,
879}
880
881impl VerifiableUpdateLeafNode {
882    pub(crate) fn add_tree_position(&mut self, tree_info: TreePosition) {
883        self.tree_position = Some(tree_info);
884    }
885
886    pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
887        &self.payload.signature_key
888    }
889}
890
891impl Verifiable for VerifiableUpdateLeafNode {
892    type VerifiedStruct = LeafNode;
893
894    fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
895        let tree_info_tbs = match &self.tree_position {
896            Some(tree_position) => TreeInfoTbs::Commit(tree_position.clone()),
897            None => return Err(tls_codec::Error::InvalidInput),
898        };
899        let leaf_node_tbs = LeafNodeTbs {
900            payload: self.payload.clone(),
901            tree_info_tbs,
902        };
903        leaf_node_tbs.tls_serialize_detached()
904    }
905
906    fn signature(&self) -> &Signature {
907        &self.signature
908    }
909
910    fn label(&self) -> &str {
911        LEAF_NODE_SIGNATURE_LABEL
912    }
913
914    fn verify(
915        self,
916        crypto: &impl openmls_traits::crypto::OpenMlsCrypto,
917        pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
918    ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
919        self.verify_no_out(crypto, pk)?;
920        Ok(LeafNode {
921            payload: self.payload,
922            signature: self.signature,
923        })
924    }
925}
926
927#[derive(Debug, Clone, PartialEq, Eq)]
928pub(crate) struct VerifiableCommitLeafNode {
929    payload: LeafNodePayload,
930    signature: Signature,
931    tree_position: Option<TreePosition>,
932}
933
934impl VerifiableCommitLeafNode {
935    pub(crate) fn add_tree_position(&mut self, tree_info: TreePosition) {
936        self.tree_position = Some(tree_info);
937    }
938
939    pub(crate) fn signature_key(&self) -> &SignaturePublicKey {
940        &self.payload.signature_key
941    }
942}
943
944impl Verifiable for VerifiableCommitLeafNode {
945    type VerifiedStruct = LeafNode;
946
947    fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
948        let tree_info_tbs = match &self.tree_position {
949            Some(tree_position) => TreeInfoTbs::Commit(tree_position.clone()),
950            None => return Err(tls_codec::Error::InvalidInput),
951        };
952        let leaf_node_tbs = LeafNodeTbs {
953            payload: self.payload.clone(),
954            tree_info_tbs,
955        };
956
957        leaf_node_tbs.tls_serialize_detached()
958    }
959
960    fn signature(&self) -> &Signature {
961        &self.signature
962    }
963
964    fn label(&self) -> &str {
965        LEAF_NODE_SIGNATURE_LABEL
966    }
967
968    fn verify(
969        self,
970        crypto: &impl openmls_traits::crypto::OpenMlsCrypto,
971        pk: &crate::ciphersuite::OpenMlsSignaturePublicKey,
972    ) -> Result<Self::VerifiedStruct, crate::ciphersuite::signable::SignatureError> {
973        self.verify_no_out(crypto, pk)?;
974        Ok(LeafNode {
975            payload: self.payload,
976            signature: self.signature,
977        })
978    }
979}
980
981impl Signable for LeafNodeTbs {
982    type SignedOutput = LeafNode;
983
984    fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
985        self.tls_serialize_detached()
986    }
987
988    fn label(&self) -> &str {
989        LEAF_NODE_SIGNATURE_LABEL
990    }
991}
992
993impl SignedStruct<LeafNodeTbs> for LeafNode {
994    fn from_payload(tbs: LeafNodeTbs, signature: Signature) -> Self {
995        Self {
996            payload: tbs.payload,
997            signature,
998        }
999    }
1000}
1001
1002#[cfg(test)]
1003#[derive(Error, Debug, PartialEq, Clone)]
1004pub enum LeafNodeGenerationError<StorageError> {
1005    /// See [`LibraryError`] for more details.
1006    #[error(transparent)]
1007    LibraryError(#[from] LibraryError),
1008
1009    /// Error storing leaf private key in storage.
1010    #[error("Error storing leaf private key.")]
1011    StorageError(StorageError),
1012}
1013
1014/// Leaf Node Update Error
1015#[derive(Error, Debug, PartialEq, Clone)]
1016pub enum LeafNodeUpdateError<StorageError> {
1017    /// See [`LibraryError`] for more details.
1018    #[error(transparent)]
1019    LibraryError(#[from] LibraryError),
1020
1021    /// Error storing leaf private key in storage.
1022    #[error("Error storing leaf private key.")]
1023    Storage(StorageError),
1024
1025    /// Signature error.
1026    #[error(transparent)]
1027    Signature(#[from] crate::ciphersuite::signable::SignatureError),
1028}