Skip to main content

openmls/key_packages/
key_package_in.rs

1//! Incoming KeyPackages. This modules contains deserialization and validation
2//! of KeyPackages.
3
4use crate::{
5    ciphersuite::{signable::*, *},
6    credentials::*,
7    extensions::{AnyObject, Extensions},
8    treesync::node::leaf_node::{LeafNodeIn, VerifiableLeafNode},
9    versions::ProtocolVersion,
10};
11use openmls_traits::{crypto::OpenMlsCrypto, types::Ciphersuite};
12use serde::{Deserialize, Serialize};
13use tls_codec::{
14    Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
15};
16
17use super::{
18    errors::KeyPackageVerifyError, InitKey, KeyPackage, KeyPackageTbs, SIGNATURE_KEY_PACKAGE_LABEL,
19};
20
21#[cfg(any(feature = "test-utils", test))]
22use super::KeyPackageBundle;
23
24/// Intermediary struct for deserialization of a [`KeyPackageIn`].
25struct VerifiableKeyPackage {
26    payload: KeyPackageTbs,
27    signature: Signature,
28}
29
30impl VerifiableKeyPackage {
31    fn new(payload: KeyPackageTbs, signature: Signature) -> Self {
32        Self { payload, signature }
33    }
34}
35
36impl Verifiable for VerifiableKeyPackage {
37    type VerifiedStruct = KeyPackage;
38
39    fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
40        self.payload.tls_serialize_detached()
41    }
42
43    fn signature(&self) -> &Signature {
44        &self.signature
45    }
46
47    fn label(&self) -> &str {
48        SIGNATURE_KEY_PACKAGE_LABEL
49    }
50
51    fn verify(
52        self,
53        crypto: &impl OpenMlsCrypto,
54        pk: &OpenMlsSignaturePublicKey,
55    ) -> Result<Self::VerifiedStruct, SignatureError> {
56        self.verify_no_out(crypto, pk)?;
57
58        Ok(KeyPackage {
59            payload: self.payload,
60            signature: self.signature,
61            serialized_payload: None,
62        })
63    }
64}
65
66impl VerifiedStruct for KeyPackage {}
67
68/// The unsigned payload of a key package.
69///
70/// ```text
71/// struct {
72///     ProtocolVersion version;
73///     CipherSuite cipher_suite;
74///     HPKEPublicKey init_key;
75///     LeafNode leaf_node;
76///     Extension extensions<V>;
77/// } KeyPackageTBS;
78/// ```
79#[derive(
80    Debug,
81    Clone,
82    PartialEq,
83    TlsSize,
84    TlsSerialize,
85    TlsDeserialize,
86    TlsDeserializeBytes,
87    Serialize,
88    Deserialize,
89)]
90struct KeyPackageTbsIn {
91    protocol_version: ProtocolVersion,
92    ciphersuite: Ciphersuite,
93    init_key: InitKey,
94    leaf_node: LeafNodeIn,
95    extensions: Extensions<AnyObject>,
96}
97
98/// The key package struct.
99#[derive(
100    Debug,
101    PartialEq,
102    Clone,
103    Serialize,
104    Deserialize,
105    TlsSerialize,
106    TlsDeserialize,
107    TlsDeserializeBytes,
108    TlsSize,
109)]
110pub struct KeyPackageIn {
111    payload: KeyPackageTbsIn,
112    signature: Signature,
113}
114
115impl KeyPackageIn {
116    /// Returns a [`CredentialWithKey`] from the unverified payload
117    pub fn unverified_credential(&self) -> CredentialWithKey {
118        let credential = self.payload.leaf_node.credential().clone();
119        let signature_key = self.payload.leaf_node.signature_key().clone();
120        CredentialWithKey {
121            credential,
122            signature_key,
123        }
124    }
125
126    /// Verify that this key package is valid:
127    /// * verify that the signature on this key package is valid
128    /// * verify that the signature on the leaf node is valid
129    /// * verify that all extensions are supported by the leaf node
130    /// * make sure that the lifetime is valid
131    /// * make sure that the init key and the encryption key are different
132    /// * make sure that the protocol version is valid
133    ///
134    /// Returns a [`KeyPackage`] after having verified the signature or a
135    /// [`KeyPackageVerifyError`] otherwise.
136    pub fn validate(
137        self,
138        crypto: &impl OpenMlsCrypto,
139        protocol_version: ProtocolVersion,
140    ) -> Result<KeyPackage, KeyPackageVerifyError> {
141        // We first need to verify the LeafNode inside the KeyPackage
142        let leaf_node = self.payload.leaf_node.clone().into_verifiable_leaf_node();
143
144        let signature_key = &OpenMlsSignaturePublicKey::from_signature_key(
145            self.payload.leaf_node.signature_key().clone(),
146            self.payload.ciphersuite.signature_algorithm(),
147        );
148
149        // https://validation.openmls.tech/#valn0108
150        let leaf_node = match leaf_node {
151            VerifiableLeafNode::KeyPackage(leaf_node) => leaf_node
152                .verify(crypto, signature_key)
153                .map_err(|_| KeyPackageVerifyError::InvalidLeafNodeSignature)?,
154            _ => return Err(KeyPackageVerifyError::InvalidLeafNodeSourceType),
155        };
156
157        // Verify that the protocol version is valid
158        // https://validation.openmls.tech/#valn0201
159        if !self.version_is_supported(protocol_version) {
160            return Err(KeyPackageVerifyError::InvalidProtocolVersion);
161        }
162
163        // Verify that the encryption key and the init key are different
164        // https://validation.openmls.tech/#valn0204
165        if leaf_node.encryption_key().key() == self.payload.init_key.key() {
166            return Err(KeyPackageVerifyError::InitKeyEqualsEncryptionKey);
167        }
168
169        let key_package_tbs = KeyPackageTbs {
170            protocol_version: self.payload.protocol_version,
171            ciphersuite: self.payload.ciphersuite,
172            init_key: self.payload.init_key,
173            leaf_node,
174            extensions: self.payload.extensions.try_into()?,
175        };
176
177        // Verify the KeyPackage signature
178        // https://validation.openmls.tech/#valn0203
179        let key_package = VerifiableKeyPackage::new(key_package_tbs, self.signature)
180            .verify(crypto, signature_key)
181            .map_err(|_| KeyPackageVerifyError::InvalidSignature)?;
182
183        // Extension included in the extensions or leaf_node.extensions fields
184        // MUST be included in the leaf_node.capabilities field.
185        if !key_package
186            .payload
187            .leaf_node
188            .capabilities()
189            .contains_extensions(&key_package.payload.extensions)
190        {
191            return Err(KeyPackageVerifyError::UnsupportedExtension);
192        }
193
194        // Ensure validity of the life time extension in the leaf node.
195        if let Some(life_time) = key_package.payload.leaf_node.life_time() {
196            life_time.validate()?;
197        } else {
198            // This assumes that we only verify key packages with leaf nodes
199            // that were created for the key package.
200            return Err(KeyPackageVerifyError::MissingLifetime);
201        }
202
203        Ok(key_package)
204    }
205
206    /// Returns true if the protocol version is supported by this key package and
207    /// false otherwise.
208    pub(crate) fn version_is_supported(&self, protocol_version: ProtocolVersion) -> bool {
209        self.payload.protocol_version == protocol_version
210    }
211
212    /// Assume that the signature is valid and return the [`KeyPackage`].
213    ///
214    /// # Safety
215    ///
216    /// The caller must guarantee that the key package is verified.
217    #[cfg(feature = "unchecked-conversions")]
218    pub fn into_unchecked(self) -> KeyPackage {
219        let payload = KeyPackageTbs {
220            protocol_version: self.payload.protocol_version,
221            ciphersuite: self.payload.ciphersuite,
222            init_key: self.payload.init_key,
223            leaf_node: self.payload.leaf_node.into_unchecked(),
224            extensions: self.payload.extensions.into_unchecked(),
225        };
226        KeyPackage {
227            payload,
228            signature: self.signature,
229            serialized_payload: None,
230        }
231    }
232}
233
234#[cfg(any(feature = "test-utils", test))]
235impl From<KeyPackageTbsIn> for KeyPackageTbs {
236    fn from(value: KeyPackageTbsIn) -> Self {
237        KeyPackageTbs {
238            protocol_version: value.protocol_version,
239            ciphersuite: value.ciphersuite,
240            init_key: value.init_key,
241            leaf_node: value.leaf_node.into(),
242            extensions: value.extensions.coerce(),
243        }
244    }
245}
246
247impl From<KeyPackageTbs> for KeyPackageTbsIn {
248    fn from(value: KeyPackageTbs) -> Self {
249        Self {
250            protocol_version: value.protocol_version,
251            ciphersuite: value.ciphersuite,
252            init_key: value.init_key,
253            leaf_node: value.leaf_node.into(),
254            extensions: value.extensions.into(),
255        }
256    }
257}
258
259impl From<KeyPackage> for KeyPackageIn {
260    fn from(value: KeyPackage) -> Self {
261        Self {
262            payload: value.payload.into(),
263            signature: value.signature,
264        }
265    }
266}
267
268#[cfg(any(feature = "test-utils", test))]
269impl From<KeyPackageBundle> for KeyPackageIn {
270    fn from(value: KeyPackageBundle) -> Self {
271        Self {
272            payload: value.key_package.payload.into(),
273            signature: value.key_package.signature,
274        }
275    }
276}
277
278#[cfg(any(feature = "test-utils", test))]
279impl From<KeyPackageIn> for KeyPackage {
280    fn from(value: KeyPackageIn) -> Self {
281        Self {
282            payload: value.payload.into(),
283            signature: value.signature,
284            serialized_payload: None,
285        }
286    }
287}