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,
27    serde::{JsonCastable, Raw},
28    DeviceKeyAlgorithm, DeviceKeyId, OwnedDeviceKeyId, OwnedUserId, UserId,
29};
30use serde::{Deserialize, Serialize};
31use serde_json::{value::to_raw_value, Value};
32use vodozemac::{Ed25519PublicKey, KeyError};
33
34use super::{SelfSigningPubkey, UserSigningPubkey};
35use crate::types::{Signatures, SigningKeys};
36
37/// A cross signing key.
38#[derive(Clone, Debug, Deserialize, Serialize)]
39pub struct CrossSigningKey {
40    /// The ID of the user the key belongs to.
41    pub user_id: OwnedUserId,
42
43    /// What the key is used for.
44    pub usage: Vec<KeyUsage>,
45
46    /// The public key.
47    ///
48    /// The object must have exactly one property.
49    pub keys: SigningKeys<OwnedDeviceKeyId>,
50
51    /// Signatures of the key.
52    ///
53    /// Only optional for master key.
54    #[serde(default, skip_serializing_if = "Signatures::is_empty")]
55    pub signatures: Signatures,
56
57    #[serde(flatten)]
58    other: BTreeMap<String, Value>,
59}
60
61impl CrossSigningKey {
62    /// Creates a new `CrossSigningKey` with the given user ID, usage, keys and
63    /// signatures.
64    pub fn new(
65        user_id: OwnedUserId,
66        usage: Vec<KeyUsage>,
67        keys: SigningKeys<OwnedDeviceKeyId>,
68        signatures: Signatures,
69    ) -> Self {
70        Self { user_id, usage, keys, signatures, other: BTreeMap::new() }
71    }
72
73    /// Serialize the cross signing key into a Raw version.
74    pub fn to_raw<T>(&self) -> Raw<T> {
75        Raw::from_json(to_raw_value(&self).expect("Couldn't serialize cross signing keys"))
76    }
77
78    /// Get the Ed25519 cross-signing key (and its ID).
79    ///
80    /// Structurally, a cross-signing key could contain more than one actual
81    /// key. However, the spec [forbids this][cross_signing_key_spec] (see
82    /// the `keys` field description), so we just get the first one.
83    ///
84    /// [cross_signing_key_spec]: https//spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3keysdevice_signingupload
85    pub fn get_first_key_and_id(&self) -> Option<(&DeviceKeyId, Ed25519PublicKey)> {
86        self.keys.iter().find_map(|(id, key)| Some((id.as_ref(), key.ed25519()?)))
87    }
88}
89
90impl JsonCastable<CrossSigningKey> for ruma::encryption::CrossSigningKey {}
91
92/// An enum over the different key types a cross-signing key can have.
93///
94/// Currently cross signing keys support an ed25519 keypair. The keys transport
95/// format is a base64 encoded string, any unknown key type will be left as such
96/// a string.
97#[derive(Clone, Debug, PartialEq, Eq)]
98pub enum SigningKey {
99    /// The ed25519 cross-signing key.
100    Ed25519(Ed25519PublicKey),
101    /// An unknown cross-signing key.
102    Unknown(String),
103}
104
105impl SigningKey {
106    /// Convert the `SigningKey` into a base64 encoded string.
107    pub fn to_base64(&self) -> String {
108        match self {
109            SigningKey::Ed25519(k) => k.to_base64(),
110            SigningKey::Unknown(k) => k.to_owned(),
111        }
112    }
113
114    /// Get the Ed25519 key, if the cross-signing key is actually an Ed25519
115    /// key.
116    pub fn ed25519(&self) -> Option<Ed25519PublicKey> {
117        as_variant!(self, SigningKey::Ed25519).copied()
118    }
119
120    /// Try to create a `SigningKey` from an `DeviceKeyAlgorithm` and a string
121    /// containing the base64 encoded public key.
122    pub fn from_parts(algorithm: &DeviceKeyAlgorithm, key: String) -> Result<Self, KeyError> {
123        match algorithm {
124            DeviceKeyAlgorithm::Ed25519 => Ed25519PublicKey::from_base64(&key).map(|k| k.into()),
125            _ => Ok(Self::Unknown(key)),
126        }
127    }
128}
129
130impl From<Ed25519PublicKey> for SigningKey {
131    fn from(val: Ed25519PublicKey) -> Self {
132        SigningKey::Ed25519(val)
133    }
134}
135
136/// Enum over the cross signing sub-keys.
137pub(crate) enum CrossSigningSubKeys<'a> {
138    /// The self signing subkey.
139    SelfSigning(&'a SelfSigningPubkey),
140    /// The user signing subkey.
141    UserSigning(&'a UserSigningPubkey),
142}
143
144impl CrossSigningSubKeys<'_> {
145    /// Get the id of the user that owns this cross signing subkey.
146    pub fn user_id(&self) -> &UserId {
147        match self {
148            CrossSigningSubKeys::SelfSigning(key) => key.user_id(),
149            CrossSigningSubKeys::UserSigning(key) => key.user_id(),
150        }
151    }
152
153    /// Get the `CrossSigningKey` from an sub-keys enum
154    pub fn cross_signing_key(&self) -> &CrossSigningKey {
155        match self {
156            CrossSigningSubKeys::SelfSigning(key) => key.as_ref(),
157            CrossSigningSubKeys::UserSigning(key) => key.as_ref(),
158        }
159    }
160}
161
162impl<'a> From<&'a UserSigningPubkey> for CrossSigningSubKeys<'a> {
163    fn from(key: &'a UserSigningPubkey) -> Self {
164        CrossSigningSubKeys::UserSigning(key)
165    }
166}
167
168impl<'a> From<&'a SelfSigningPubkey> for CrossSigningSubKeys<'a> {
169    fn from(key: &'a SelfSigningPubkey) -> Self {
170        CrossSigningSubKeys::SelfSigning(key)
171    }
172}