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