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