matrix_sdk_crypto/types/cross_signing/
common.rs

1// Copyright 2021 Devin Ragotzy.
2// Copyright 2021 Timo Kösters.
3//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21
22use std::collections::BTreeMap;
23
24use as_variant::as_variant;
25use ruma::{
26    encryption::KeyUsage, serde::Raw, DeviceKeyAlgorithm, DeviceKeyId, OwnedDeviceKeyId,
27    OwnedUserId, UserId,
28};
29use serde::{Deserialize, Serialize};
30use serde_json::{value::to_raw_value, Value};
31use vodozemac::{Ed25519PublicKey, KeyError};
32
33use super::{SelfSigningPubkey, UserSigningPubkey};
34use crate::types::{Signatures, SigningKeys};
35
36/// A cross signing key.
37#[derive(Clone, Debug, Deserialize, Serialize)]
38pub struct CrossSigningKey {
39    /// The ID of the user the key belongs to.
40    pub user_id: OwnedUserId,
41
42    /// What the key is used for.
43    pub usage: Vec<KeyUsage>,
44
45    /// The public key.
46    ///
47    /// The object must have exactly one property.
48    pub keys: SigningKeys<OwnedDeviceKeyId>,
49
50    /// Signatures of the key.
51    ///
52    /// Only optional for master key.
53    #[serde(default, skip_serializing_if = "Signatures::is_empty")]
54    pub signatures: Signatures,
55
56    #[serde(flatten)]
57    other: BTreeMap<String, Value>,
58}
59
60impl CrossSigningKey {
61    /// Creates a new `CrossSigningKey` with the given user ID, usage, keys and
62    /// signatures.
63    pub fn new(
64        user_id: OwnedUserId,
65        usage: Vec<KeyUsage>,
66        keys: SigningKeys<OwnedDeviceKeyId>,
67        signatures: Signatures,
68    ) -> Self {
69        Self { user_id, usage, keys, signatures, other: BTreeMap::new() }
70    }
71
72    /// Serialize the cross signing key into a Raw version.
73    pub fn to_raw<T>(&self) -> Raw<T> {
74        Raw::from_json(to_raw_value(&self).expect("Couldn't serialize cross signing keys"))
75    }
76
77    /// Get the Ed25519 cross-signing key (and its ID).
78    ///
79    /// Structurally, a cross-signing key could contain more than one actual
80    /// key. However, the spec [forbids this][cross_signing_key_spec] (see
81    /// the `keys` field description), so we just get the first one.
82    ///
83    /// [cross_signing_key_spec]: https//spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3keysdevice_signingupload
84    pub fn get_first_key_and_id(&self) -> Option<(&DeviceKeyId, Ed25519PublicKey)> {
85        self.keys.iter().find_map(|(id, key)| Some((id.as_ref(), key.ed25519()?)))
86    }
87}
88
89/// An enum over the different key types a cross-signing key can have.
90///
91/// Currently cross signing keys support an ed25519 keypair. The keys transport
92/// format is a base64 encoded string, any unknown key type will be left as such
93/// a string.
94#[derive(Clone, Debug, PartialEq, Eq)]
95pub enum SigningKey {
96    /// The ed25519 cross-signing key.
97    Ed25519(Ed25519PublicKey),
98    /// An unknown cross-signing key.
99    Unknown(String),
100}
101
102impl SigningKey {
103    /// Convert the `SigningKey` into a base64 encoded string.
104    pub fn to_base64(&self) -> String {
105        match self {
106            SigningKey::Ed25519(k) => k.to_base64(),
107            SigningKey::Unknown(k) => k.to_owned(),
108        }
109    }
110
111    /// Get the Ed25519 key, if the cross-signing key is actually an Ed25519
112    /// key.
113    pub fn ed25519(&self) -> Option<Ed25519PublicKey> {
114        as_variant!(self, SigningKey::Ed25519).copied()
115    }
116
117    /// Try to create a `SigningKey` from an `DeviceKeyAlgorithm` and a string
118    /// containing the base64 encoded public key.
119    pub fn from_parts(algorithm: &DeviceKeyAlgorithm, key: String) -> Result<Self, KeyError> {
120        match algorithm {
121            DeviceKeyAlgorithm::Ed25519 => Ed25519PublicKey::from_base64(&key).map(|k| k.into()),
122            _ => Ok(Self::Unknown(key)),
123        }
124    }
125}
126
127impl From<Ed25519PublicKey> for SigningKey {
128    fn from(val: Ed25519PublicKey) -> Self {
129        SigningKey::Ed25519(val)
130    }
131}
132
133/// Enum over the cross signing sub-keys.
134pub(crate) enum CrossSigningSubKeys<'a> {
135    /// The self signing subkey.
136    SelfSigning(&'a SelfSigningPubkey),
137    /// The user signing subkey.
138    UserSigning(&'a UserSigningPubkey),
139}
140
141impl CrossSigningSubKeys<'_> {
142    /// Get the id of the user that owns this cross signing subkey.
143    pub fn user_id(&self) -> &UserId {
144        match self {
145            CrossSigningSubKeys::SelfSigning(key) => key.user_id(),
146            CrossSigningSubKeys::UserSigning(key) => key.user_id(),
147        }
148    }
149
150    /// Get the `CrossSigningKey` from an sub-keys enum
151    pub fn cross_signing_key(&self) -> &CrossSigningKey {
152        match self {
153            CrossSigningSubKeys::SelfSigning(key) => key.as_ref(),
154            CrossSigningSubKeys::UserSigning(key) => key.as_ref(),
155        }
156    }
157}
158
159impl<'a> From<&'a UserSigningPubkey> for CrossSigningSubKeys<'a> {
160    fn from(key: &'a UserSigningPubkey) -> Self {
161        CrossSigningSubKeys::UserSigning(key)
162    }
163}
164
165impl<'a> From<&'a SelfSigningPubkey> for CrossSigningSubKeys<'a> {
166    fn from(key: &'a SelfSigningPubkey) -> Self {
167        CrossSigningSubKeys::SelfSigning(key)
168    }
169}