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