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    /// Returns the ciphersuite this key package claims, before validation.
127    pub(crate) fn unverified_ciphersuite(&self) -> Ciphersuite {
128        self.payload.ciphersuite
129    }
130
131    /// Verify that this key package is valid:
132    /// * verify that the ciphersuite is supported by the crypto provider
133    /// * verify that the signature on this key package is valid
134    /// * verify that the signature on the leaf node is valid
135    /// * verify that all extensions are supported by the leaf node
136    /// * make sure that the lifetime is valid
137    /// * make sure that the init key and the encryption key are different
138    /// * make sure that the protocol version is valid
139    ///
140    /// Returns a [`KeyPackage`] after having verified the signature or a
141    /// [`KeyPackageVerifyError`] otherwise.
142    pub fn validate(
143        self,
144        crypto: &impl OpenMlsCrypto,
145        protocol_version: ProtocolVersion,
146    ) -> Result<KeyPackage, KeyPackageVerifyError> {
147        let ciphersuite = self.payload.ciphersuite;
148        crypto
149            .supports(ciphersuite)
150            .map_err(|_| KeyPackageVerifyError::UnsupportedCiphersuite(ciphersuite))?;
151
152        // We first need to verify the LeafNode inside the KeyPackage
153        let leaf_node = self.payload.leaf_node.clone().into_verifiable_leaf_node();
154
155        let signature_key = &OpenMlsSignaturePublicKey::from_signature_key(
156            self.payload.leaf_node.signature_key().clone(),
157            self.payload.ciphersuite.signature_algorithm(),
158        );
159
160        // https://validation.openmls.tech/#valn0108
161        let leaf_node = match leaf_node {
162            VerifiableLeafNode::KeyPackage(leaf_node) => leaf_node
163                .verify(crypto, signature_key)
164                .map_err(|_| KeyPackageVerifyError::InvalidLeafNodeSignature)?,
165            _ => return Err(KeyPackageVerifyError::InvalidLeafNodeSourceType),
166        };
167
168        // Verify that the protocol version is valid
169        // https://validation.openmls.tech/#valn0201
170        if !self.version_is_supported(protocol_version) {
171            return Err(KeyPackageVerifyError::InvalidProtocolVersion);
172        }
173
174        // Verify that the encryption key and the init key are different
175        // https://validation.openmls.tech/#valn0204
176        if leaf_node.encryption_key().key() == self.payload.init_key.key() {
177            return Err(KeyPackageVerifyError::InitKeyEqualsEncryptionKey);
178        }
179
180        let key_package_tbs = KeyPackageTbs {
181            protocol_version: self.payload.protocol_version,
182            ciphersuite: self.payload.ciphersuite,
183            init_key: self.payload.init_key,
184            leaf_node,
185            extensions: self.payload.extensions.try_into()?,
186        };
187
188        // Verify the KeyPackage signature
189        // https://validation.openmls.tech/#valn0203
190        let key_package = VerifiableKeyPackage::new(key_package_tbs, self.signature)
191            .verify(crypto, signature_key)
192            .map_err(|_| KeyPackageVerifyError::InvalidSignature)?;
193
194        // Extension included in the extensions or leaf_node.extensions fields
195        // MUST be included in the leaf_node.capabilities field.
196        if !key_package
197            .payload
198            .leaf_node
199            .capabilities()
200            .contains_extensions(&key_package.payload.extensions)
201        {
202            return Err(KeyPackageVerifyError::UnsupportedExtension);
203        }
204
205        // Ensure validity of the life time extension in the leaf node.
206        if let Some(life_time) = key_package.payload.leaf_node.life_time() {
207            life_time.validate()?;
208        } else {
209            // This assumes that we only verify key packages with leaf nodes
210            // that were created for the key package.
211            return Err(KeyPackageVerifyError::MissingLifetime);
212        }
213
214        Ok(key_package)
215    }
216
217    /// Returns true if the protocol version is supported by this key package and
218    /// false otherwise.
219    pub(crate) fn version_is_supported(&self, protocol_version: ProtocolVersion) -> bool {
220        self.payload.protocol_version == protocol_version
221    }
222
223    /// Assume that the signature is valid and return the [`KeyPackage`].
224    ///
225    /// # Safety
226    ///
227    /// The caller must guarantee that the key package is verified.
228    #[cfg(feature = "unchecked-conversions")]
229    pub fn into_unchecked(self) -> KeyPackage {
230        let payload = KeyPackageTbs {
231            protocol_version: self.payload.protocol_version,
232            ciphersuite: self.payload.ciphersuite,
233            init_key: self.payload.init_key,
234            leaf_node: self.payload.leaf_node.into_unchecked(),
235            extensions: self.payload.extensions.into_unchecked(),
236        };
237        KeyPackage {
238            payload,
239            signature: self.signature,
240            serialized_payload: None,
241        }
242    }
243}
244
245#[cfg(any(feature = "test-utils", test))]
246impl From<KeyPackageTbsIn> for KeyPackageTbs {
247    fn from(value: KeyPackageTbsIn) -> Self {
248        KeyPackageTbs {
249            protocol_version: value.protocol_version,
250            ciphersuite: value.ciphersuite,
251            init_key: value.init_key,
252            leaf_node: value.leaf_node.into(),
253            extensions: value.extensions.coerce(),
254        }
255    }
256}
257
258impl From<KeyPackageTbs> for KeyPackageTbsIn {
259    fn from(value: KeyPackageTbs) -> Self {
260        Self {
261            protocol_version: value.protocol_version,
262            ciphersuite: value.ciphersuite,
263            init_key: value.init_key,
264            leaf_node: value.leaf_node.into(),
265            extensions: value.extensions.into(),
266        }
267    }
268}
269
270impl From<KeyPackage> for KeyPackageIn {
271    fn from(value: KeyPackage) -> Self {
272        Self {
273            payload: value.payload.into(),
274            signature: value.signature,
275        }
276    }
277}
278
279#[cfg(any(feature = "test-utils", test))]
280impl From<KeyPackageBundle> for KeyPackageIn {
281    fn from(value: KeyPackageBundle) -> Self {
282        Self {
283            payload: value.key_package.payload.into(),
284            signature: value.key_package.signature,
285        }
286    }
287}
288
289#[cfg(any(feature = "test-utils", test))]
290impl From<KeyPackageIn> for KeyPackage {
291    fn from(value: KeyPackageIn) -> Self {
292        Self {
293            payload: value.payload.into(),
294            signature: value.signature,
295            serialized_payload: None,
296        }
297    }
298}