Skip to main content

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