matrix_sdk_crypto/olm/signing/
pk_signing.rs

1// Copyright 2020 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use ruma::{encryption::KeyUsage, DeviceKeyAlgorithm, DeviceKeyId, OwnedUserId};
16use serde::{Deserialize, Serialize};
17use serde_json::{Error as JsonError, Value};
18use thiserror::Error;
19use vodozemac::{DecodeError, Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature, KeyError};
20use zeroize::Zeroize;
21
22use crate::{
23    error::SignatureError,
24    olm::utility::SignJson,
25    types::{
26        CrossSigningKey, DeviceKeys, MasterPubkey, SelfSigningPubkey, Signatures, SigningKeys,
27        UserSigningPubkey,
28    },
29    OtherUserIdentityData,
30};
31
32/// Error type reporting failures in the signing operations.
33#[derive(Debug, Error)]
34pub enum SigningError {
35    /// Error decoding the base64 encoded pickle data.
36    #[error(transparent)]
37    Decode(#[from] DecodeError),
38
39    /// Error decrypting the pickled signing seed
40    #[error("Error decrypting the pickled signing seed")]
41    Decryption(String),
42
43    /// Error deserializing the pickle data.
44    #[error(transparent)]
45    Json(#[from] JsonError),
46}
47
48#[derive(Serialize, Deserialize)]
49pub struct Signing {
50    inner: Ed25519SecretKey,
51    public_key: Ed25519PublicKey,
52}
53
54#[cfg(not(tarpaulin_include))]
55impl std::fmt::Debug for Signing {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        f.debug_struct("Signing").field("public_key", &self.public_key.to_base64()).finish()
58    }
59}
60
61impl PartialEq for Signing {
62    fn eq(&self, other: &Signing) -> bool {
63        self.public_key == other.public_key
64    }
65}
66
67impl SignJson for Signing {
68    fn sign_json(&self, value: Value) -> Result<Ed25519Signature, SignatureError> {
69        self.inner.sign_json(value)
70    }
71}
72
73#[derive(PartialEq, Debug)]
74pub struct MasterSigning {
75    inner: Signing,
76    public_key: MasterPubkey,
77}
78
79#[derive(Deserialize, Serialize)]
80#[allow(missing_debug_implementations)]
81pub struct PickledMasterSigning {
82    pickle: PickledSigning,
83    public_key: MasterPubkey,
84}
85
86#[derive(Deserialize, Serialize)]
87#[allow(missing_debug_implementations)]
88pub struct PickledUserSigning {
89    pickle: PickledSigning,
90    public_key: UserSigningPubkey,
91}
92
93#[derive(Deserialize, Serialize)]
94#[allow(missing_debug_implementations)]
95pub struct PickledSelfSigning {
96    pickle: PickledSigning,
97    public_key: SelfSigningPubkey,
98}
99
100impl MasterSigning {
101    pub fn new(user_id: OwnedUserId) -> Self {
102        let inner = Signing::new();
103        let public_key = inner
104            .cross_signing_key(user_id, KeyUsage::Master)
105            .try_into()
106            .expect("A freshly created master key can be converted into a MasterPubkey");
107        let mut key = Self { inner, public_key };
108        let mut cross_signing_key = key.public_key.as_ref().to_owned();
109
110        key.sign_subkey(&mut cross_signing_key);
111        key.public_key = cross_signing_key
112            .try_into()
113            .expect("A freshly signed master key can be converted into a MasterPubkey");
114
115        key
116    }
117
118    pub(crate) fn new_subkeys(&self) -> (UserSigning, SelfSigning) {
119        let user = Signing::new();
120        let mut public_key =
121            user.cross_signing_key(self.public_key.user_id().to_owned(), KeyUsage::UserSigning);
122
123        self.sign_subkey(&mut public_key);
124
125        let user = UserSigning {
126            inner: user,
127            public_key: public_key
128                .try_into()
129                .expect("We can always create a new random UserSigningPubkey"),
130        };
131
132        let self_signing = Signing::new();
133        let mut public_key = self_signing
134            .cross_signing_key(self.public_key.user_id().to_owned(), KeyUsage::SelfSigning);
135        self.sign_subkey(&mut public_key);
136
137        let self_signing = SelfSigning {
138            inner: self_signing,
139            public_key: public_key
140                .try_into()
141                .expect("We can always create a new random SelfSigningPubkey"),
142        };
143
144        (user, self_signing)
145    }
146
147    pub fn public_key(&self) -> &MasterPubkey {
148        &self.public_key
149    }
150
151    pub(crate) fn public_key_mut(&mut self) -> &mut MasterPubkey {
152        &mut self.public_key
153    }
154
155    pub fn pickle(&self) -> PickledMasterSigning {
156        let pickle = self.inner.pickle();
157        let public_key = self.public_key.clone();
158        PickledMasterSigning { pickle, public_key }
159    }
160
161    pub fn export_seed(&self) -> String {
162        self.inner.to_base64()
163    }
164
165    pub fn from_base64(user_id: OwnedUserId, key: &str) -> Result<Self, KeyError> {
166        let inner = Signing::from_base64(key)?;
167        let public_key = inner
168            .cross_signing_key(user_id, KeyUsage::Master)
169            .try_into()
170            .expect("A master key can always be imported from a base64 encoded value");
171
172        Ok(Self { inner, public_key })
173    }
174
175    pub fn from_pickle(pickle: PickledMasterSigning) -> Result<Self, SigningError> {
176        let inner = Signing::from_pickle(pickle.pickle)?;
177        let public_key = pickle.public_key;
178
179        Ok(Self { inner, public_key })
180    }
181
182    pub fn sign(&self, message: &str) -> Ed25519Signature {
183        self.inner.sign(message)
184    }
185
186    pub fn sign_subkey(&self, subkey: &mut CrossSigningKey) {
187        #[allow(clippy::needless_borrows_for_generic_args)]
188        // XXX: false positive, see https://github.com/rust-lang/rust-clippy/issues/12856
189        let json_subkey = serde_json::to_value(&subkey).expect("Can't serialize cross signing key");
190        let signature = self.inner.sign_json(json_subkey).expect("Can't sign cross signing keys");
191
192        subkey.signatures.add_signature(
193            self.public_key.user_id().to_owned(),
194            DeviceKeyId::from_parts(
195                DeviceKeyAlgorithm::Ed25519,
196                self.inner.public_key.to_base64().as_str().into(),
197            ),
198            signature,
199        );
200    }
201}
202
203impl UserSigning {
204    pub fn pickle(&self) -> PickledUserSigning {
205        let pickle = self.inner.pickle();
206        let public_key = self.public_key.clone();
207        PickledUserSigning { pickle, public_key }
208    }
209
210    pub fn public_key(&self) -> &UserSigningPubkey {
211        &self.public_key
212    }
213
214    pub fn export_seed(&self) -> String {
215        self.inner.to_base64()
216    }
217
218    pub fn from_base64(user_id: OwnedUserId, key: &str) -> Result<Self, KeyError> {
219        let inner = Signing::from_base64(key)?;
220        let public_key = inner
221            .cross_signing_key(user_id, KeyUsage::UserSigning)
222            .try_into()
223            .expect("A user-signing key can always be imported from a base64 encoded value");
224
225        Ok(Self { inner, public_key })
226    }
227
228    pub fn sign_user(
229        &self,
230        user: &OtherUserIdentityData,
231    ) -> Result<CrossSigningKey, SignatureError> {
232        let signatures = self.sign_user_helper(user)?;
233        let mut master_key = user.master_key().as_ref().clone();
234
235        master_key.signatures = signatures;
236
237        Ok(master_key)
238    }
239
240    pub fn sign_user_helper(
241        &self,
242        user: &OtherUserIdentityData,
243    ) -> Result<Signatures, SignatureError> {
244        let user_master: &CrossSigningKey = user.master_key().as_ref();
245        let signature = self.inner.sign_json(serde_json::to_value(user_master)?)?;
246
247        let mut signatures = Signatures::new();
248
249        signatures.add_signature(
250            self.public_key.user_id().to_owned(),
251            DeviceKeyId::from_parts(
252                DeviceKeyAlgorithm::Ed25519,
253                self.inner.public_key.to_base64().as_str().into(),
254            ),
255            signature,
256        );
257
258        Ok(signatures)
259    }
260
261    pub fn from_pickle(pickle: PickledUserSigning) -> Result<Self, SigningError> {
262        let inner = Signing::from_pickle(pickle.pickle)?;
263
264        Ok(Self { inner, public_key: pickle.public_key })
265    }
266}
267
268impl SelfSigning {
269    pub(crate) fn pickle(&self) -> PickledSelfSigning {
270        let pickle = self.inner.pickle();
271        let public_key = self.public_key.clone();
272        PickledSelfSigning { pickle, public_key }
273    }
274
275    pub fn public_key(&self) -> &SelfSigningPubkey {
276        &self.public_key
277    }
278
279    pub fn export_seed(&self) -> String {
280        self.inner.to_base64()
281    }
282
283    pub fn from_base64(user_id: OwnedUserId, key: &str) -> Result<Self, KeyError> {
284        let inner = Signing::from_base64(key)?;
285        let public_key = inner
286            .cross_signing_key(user_id, KeyUsage::SelfSigning)
287            .try_into()
288            .expect("A self-signing key can always be imported from a base64 encoded value");
289
290        Ok(Self { inner, public_key })
291    }
292
293    pub(crate) fn sign_device(&self, device_keys: &mut DeviceKeys) -> Result<(), SignatureError> {
294        #[allow(clippy::needless_borrows_for_generic_args)]
295        // XXX: false positive, see https://github.com/rust-lang/rust-clippy/issues/12856
296        let serialized = serde_json::to_value(&device_keys)?;
297        let signature = self.inner.sign_json(serialized)?;
298
299        device_keys.signatures.add_signature(
300            self.public_key.user_id().to_owned(),
301            DeviceKeyId::from_parts(
302                DeviceKeyAlgorithm::Ed25519,
303                self.inner.public_key.to_base64().as_str().into(),
304            ),
305            signature,
306        );
307
308        Ok(())
309    }
310
311    pub(crate) fn from_pickle(pickle: PickledSelfSigning) -> Result<Self, SigningError> {
312        let inner = Signing::from_pickle(pickle.pickle)?;
313
314        Ok(Self { inner, public_key: pickle.public_key })
315    }
316}
317
318#[derive(PartialEq, Debug)]
319pub struct SelfSigning {
320    inner: Signing,
321    public_key: SelfSigningPubkey,
322}
323
324#[derive(PartialEq, Debug)]
325pub struct UserSigning {
326    inner: Signing,
327    public_key: UserSigningPubkey,
328}
329
330#[derive(Serialize, Deserialize)]
331#[allow(missing_debug_implementations)]
332pub struct PickledSignings {
333    pub master_key: Option<PickledMasterSigning>,
334    pub user_signing_key: Option<PickledUserSigning>,
335    pub self_signing_key: Option<PickledSelfSigning>,
336}
337
338#[derive(Serialize, Deserialize)]
339pub struct PickledSigning(Ed25519SecretKey);
340
341impl Signing {
342    pub fn new() -> Self {
343        let secret_key = Ed25519SecretKey::new();
344        Self::new_helper(secret_key)
345    }
346
347    fn new_helper(secret_key: Ed25519SecretKey) -> Self {
348        let public_key = secret_key.public_key();
349
350        Signing { inner: secret_key, public_key }
351    }
352
353    pub fn from_base64(key: &str) -> Result<Self, KeyError> {
354        let key = Ed25519SecretKey::from_base64(key)?;
355        Ok(Self::new_helper(key))
356    }
357
358    pub fn from_pickle(pickle: PickledSigning) -> Result<Self, SigningError> {
359        Ok(Self::new_helper(pickle.0))
360    }
361
362    pub fn to_base64(&self) -> String {
363        self.inner.to_base64()
364    }
365
366    pub fn pickle(&self) -> PickledSigning {
367        let mut bytes = self.inner.to_bytes();
368        let ret = PickledSigning(Ed25519SecretKey::from_slice(&bytes));
369
370        bytes.zeroize();
371
372        ret
373    }
374
375    pub fn public_key(&self) -> Ed25519PublicKey {
376        self.public_key
377    }
378
379    pub fn cross_signing_key(&self, user_id: OwnedUserId, usage: KeyUsage) -> CrossSigningKey {
380        let keys = SigningKeys::from([(
381            DeviceKeyId::from_parts(
382                DeviceKeyAlgorithm::Ed25519,
383                self.public_key().to_base64().as_str().into(),
384            ),
385            self.inner.public_key().into(),
386        )]);
387
388        CrossSigningKey::new(user_id, vec![usage], keys, Default::default())
389    }
390
391    pub fn sign(&self, message: &str) -> Ed25519Signature {
392        self.inner.sign(message.as_bytes())
393    }
394}