matrix_sdk_crypto/types/cross_signing/
master.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 std::collections::btree_map::Iter;
16
17use ruma::{encryption::KeyUsage, DeviceKeyId, OwnedDeviceKeyId, UserId};
18use serde::{Deserialize, Serialize};
19use vodozemac::Ed25519PublicKey;
20
21use super::{CrossSigningKey, CrossSigningSubKeys, SigningKey};
22use crate::{
23    olm::VerifyJson,
24    types::{Signatures, SigningKeys},
25    SignatureError,
26};
27
28/// Wrapper for a cross signing key marking it as the master key.
29///
30/// Master keys are used to sign other cross signing keys, the self signing and
31/// user signing keys of an user will be signed by their master key.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33#[serde(try_from = "CrossSigningKey")]
34pub struct MasterPubkey(pub(super) CrossSigningKey);
35
36impl MasterPubkey {
37    /// Get the user id of the master key's owner.
38    pub fn user_id(&self) -> &UserId {
39        &self.0.user_id
40    }
41
42    /// Get the keys map of containing the master keys.
43    pub fn keys(&self) -> &SigningKeys<OwnedDeviceKeyId> {
44        &self.0.keys
45    }
46
47    /// Get the list of `KeyUsage` that is set for this key.
48    pub fn usage(&self) -> &[KeyUsage] {
49        &self.0.usage
50    }
51
52    /// Get the signatures map of this cross signing key.
53    pub fn signatures(&self) -> &Signatures {
54        &self.0.signatures
55    }
56
57    /// Get the master key with the given key id.
58    ///
59    /// # Arguments
60    ///
61    /// * `key_id` - The id of the key that should be fetched.
62    pub fn get_key(&self, key_id: &DeviceKeyId) -> Option<&SigningKey> {
63        self.0.keys.get(key_id)
64    }
65
66    /// Get the first available master key.
67    ///
68    /// There's usually only a single master key so this will usually fetch the
69    /// only key.
70    pub fn get_first_key(&self) -> Option<Ed25519PublicKey> {
71        self.0.get_first_key_and_id().map(|(_, k)| k)
72    }
73
74    /// Check if the given JSON is signed by this master key.
75    ///
76    /// This method should only be used if an object's signature needs to be
77    /// checked multiple times, and you'd like to avoid performing the
78    /// canonicalization step each time.
79    ///
80    /// **Note**: Use this method with caution, the `canonical_json` needs to be
81    /// correctly canonicalized and make sure that the object you are checking
82    /// the signature for is allowed to be signed by a master key.
83    pub(crate) fn has_signed_raw(
84        &self,
85        signatures: &Signatures,
86        canonical_json: &str,
87    ) -> Result<(), SignatureError> {
88        if let Some((key_id, key)) = self.0.get_first_key_and_id() {
89            key.verify_canonicalized_json(&self.0.user_id, key_id, signatures, canonical_json)
90        } else {
91            Err(SignatureError::UnsupportedAlgorithm)
92        }
93    }
94
95    /// Check if the given cross signing sub-key is signed by the master key.
96    ///
97    /// # Arguments
98    ///
99    /// * `subkey` - The subkey that should be checked for a valid signature.
100    ///
101    /// Returns an empty result if the signature check succeeded, otherwise a
102    /// SignatureError indicating why the check failed.
103    pub(crate) fn verify_subkey<'a>(
104        &self,
105        subkey: impl Into<CrossSigningSubKeys<'a>>,
106    ) -> Result<(), SignatureError> {
107        let subkey: CrossSigningSubKeys<'_> = subkey.into();
108
109        if self.0.user_id != subkey.user_id() {
110            return Err(SignatureError::UserIdMismatch);
111        }
112
113        if let Some((key_id, key)) = self.0.get_first_key_and_id() {
114            key.verify_json(&self.0.user_id, key_id, subkey.cross_signing_key())
115        } else {
116            Err(SignatureError::UnsupportedAlgorithm)
117        }
118    }
119}
120
121impl<'a> IntoIterator for &'a MasterPubkey {
122    type Item = (&'a OwnedDeviceKeyId, &'a SigningKey);
123    type IntoIter = Iter<'a, OwnedDeviceKeyId, SigningKey>;
124
125    fn into_iter(self) -> Self::IntoIter {
126        self.keys().iter()
127    }
128}
129
130impl AsRef<CrossSigningKey> for MasterPubkey {
131    fn as_ref(&self) -> &CrossSigningKey {
132        &self.0
133    }
134}
135
136impl AsMut<CrossSigningKey> for MasterPubkey {
137    fn as_mut(&mut self) -> &mut CrossSigningKey {
138        &mut self.0
139    }
140}
141
142impl TryFrom<CrossSigningKey> for MasterPubkey {
143    type Error = serde_json::Error;
144
145    fn try_from(key: CrossSigningKey) -> Result<Self, Self::Error> {
146        if key.usage.contains(&KeyUsage::Master) && key.usage.len() == 1 {
147            Ok(Self(key))
148        } else {
149            Err(serde::de::Error::custom(format!(
150                "Expected cross signing key usage {} was not found",
151                KeyUsage::Master
152            )))
153        }
154    }
155}