matrix_sdk_crypto/olm/signing/
pk_signing.rs1use 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#[derive(Debug, Error)]
34pub enum SigningError {
35 #[error(transparent)]
37 Decode(#[from] DecodeError),
38
39 #[error("Error decrypting the pickled signing seed")]
41 Decryption(String),
42
43 #[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 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 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}