| 1 | #pragma once |
| 2 | |
| 3 | /// @file |
| 4 | /// @brief Various event types used in E2EE. |
| 5 | |
| 6 | #if __has_include(<nlohmann/json_fwd.hpp>) |
| 7 | #include <nlohmann/json_fwd.hpp> |
| 8 | #else |
| 9 | #include <nlohmann/json.hpp> |
| 10 | #endif |
| 11 | |
| 12 | #include "mtx/events.hpp" |
| 13 | #include "mtx/events/common.hpp" |
| 14 | #include "variant" |
| 15 | |
| 16 | namespace mtx { |
| 17 | namespace events { |
| 18 | namespace msg { |
| 19 | |
| 20 | //! Display methods for Short Authentication Strings |
| 21 | enum class SASMethods |
| 22 | { |
| 23 | Decimal, //!< Display 3 times 4 digits |
| 24 | Emoji, //! Display 7 emoji |
| 25 | Unsupported |
| 26 | }; |
| 27 | |
| 28 | void |
| 29 | from_json(const nlohmann::json &obj, SASMethods &method); |
| 30 | |
| 31 | void |
| 32 | to_json(nlohmann::json &obj, const SASMethods &method); |
| 33 | |
| 34 | //! The different verification methods |
| 35 | enum class VerificationMethods |
| 36 | { |
| 37 | SASv1, //!< Short Authentication Strings |
| 38 | Unsupported //!< Unsupported method |
| 39 | }; |
| 40 | |
| 41 | void |
| 42 | from_json(const nlohmann::json &obj, VerificationMethods &method); |
| 43 | |
| 44 | void |
| 45 | to_json(nlohmann::json &obj, const VerificationMethods &method); |
| 46 | |
| 47 | //! Content of an individual message encrypted for a certain key. |
| 48 | struct OlmCipherContent |
| 49 | { |
| 50 | //! Ciphertext of the message. |
| 51 | std::string body; |
| 52 | /// @brief Olm message type. |
| 53 | /// |
| 54 | /// `0` for initial pre-key messages. |
| 55 | /// `1` for normal messages after the initial exchange. |
| 56 | uint8_t type; |
| 57 | |
| 58 | friend void from_json(const nlohmann::json &obj, OlmCipherContent &event); |
| 59 | |
| 60 | friend void to_json(nlohmann::json &obj, const OlmCipherContent &event); |
| 61 | }; |
| 62 | |
| 63 | //! Content of the `m.room.encrypted` Olm event. |
| 64 | struct OlmEncrypted |
| 65 | { |
| 66 | //! Algorithm used for encrypting this event. |
| 67 | std::string algorithm; |
| 68 | //! curve25519 key of the sender. |
| 69 | std::string sender_key; |
| 70 | |
| 71 | using RecipientKey = std::string; |
| 72 | //! Map of recipient curve25519 key to the encrypted message. |
| 73 | std::map<RecipientKey, OlmCipherContent> ciphertext; |
| 74 | |
| 75 | friend void from_json(const nlohmann::json &obj, OlmEncrypted &event); |
| 76 | |
| 77 | friend void to_json(nlohmann::json &obj, const OlmEncrypted &event); |
| 78 | }; |
| 79 | |
| 80 | //! Content of the `m.room.encrypted` event. |
| 81 | struct Encrypted |
| 82 | { |
| 83 | //! Used for one-on-one exchanges. |
| 84 | std::string algorithm; |
| 85 | //! The actual encrypted payload. |
| 86 | std::string ciphertext; |
| 87 | //! Sender's device id. |
| 88 | std::string device_id; |
| 89 | //! The curve25519 device key. |
| 90 | std::string sender_key; |
| 91 | //! Outbound group session id. |
| 92 | std::string session_id; |
| 93 | //! Relations like rich replies |
| 94 | common::Relations relations; |
| 95 | |
| 96 | friend void from_json(const nlohmann::json &obj, Encrypted &event); |
| 97 | |
| 98 | friend void to_json(nlohmann::json &obj, const Encrypted &event); |
| 99 | }; |
| 100 | |
| 101 | //! Content of the `m.dummy` event. |
| 102 | struct Dummy |
| 103 | { |
| 104 | friend void from_json(const nlohmann::json &obj, Dummy &event); |
| 105 | friend void to_json(nlohmann::json &obj, const Dummy &event); |
| 106 | }; |
| 107 | |
| 108 | //! Content of the `m.room_key` event. |
| 109 | struct RoomKey |
| 110 | { |
| 111 | /// @brief *Required.* The encryption algorithm the key in this event is to be used with. |
| 112 | /// |
| 113 | /// Must be 'm.megolm.v1.aes-sha2'. |
| 114 | std::string algorithm; |
| 115 | std::string room_id; //!< *Required.* The room where the key is used. |
| 116 | std::string session_id; //!< *Required.* The ID of the session that the key is for. |
| 117 | std::string session_key; //!< *Required.* The key to be exchanged. |
| 118 | |
| 119 | friend void from_json(const nlohmann::json &obj, RoomKey &event); |
| 120 | friend void to_json(nlohmann::json &obj, const RoomKey &event); |
| 121 | }; |
| 122 | |
| 123 | //! Content of the `m.forwarded_room_key` event. |
| 124 | struct ForwardedRoomKey |
| 125 | { |
| 126 | /// @brief *Required.* The encryption algorithm the key in this event is to be used with. |
| 127 | std::string algorithm; |
| 128 | std::string room_id; //!< *Required.* The room where the key is used. |
| 129 | std::string session_id; //!< *Required.* The ID of the session that the key is for. |
| 130 | std::string session_key; //!< *Required.* The key to be exchanged. |
| 131 | |
| 132 | //! *Required.* The Curve25519 key of the device which initiated the session originally. |
| 133 | std::string sender_key; |
| 134 | /// @brief *Required.* The Ed25519 key of the device which initiated the session originally. |
| 135 | /// |
| 136 | /// It is 'claimed' because the receiving device has no way to tell that the original |
| 137 | /// room_key actually came from a device which owns the private part of this key unless they |
| 138 | /// have done device verification. |
| 139 | std::string sender_claimed_ed25519_key; |
| 140 | /// @brief *Required.* Chain of Curve25519 keys. |
| 141 | /// |
| 142 | /// It starts out empty, but each time the key is forwarded to another device, the previous |
| 143 | /// sender in the chain is added to the end of the list. For example, if the key is |
| 144 | /// forwarded from A to B to C, this field is empty between A and B, and contains A's |
| 145 | /// Curve25519 key between B and C. |
| 146 | std::vector<std::string> forwarding_curve25519_key_chain; |
| 147 | |
| 148 | friend void from_json(const nlohmann::json &obj, ForwardedRoomKey &event); |
| 149 | friend void to_json(nlohmann::json &obj, const ForwardedRoomKey &event); |
| 150 | }; |
| 151 | |
| 152 | //! The type of key request. |
| 153 | enum class RequestAction |
| 154 | { |
| 155 | Request, //!< request |
| 156 | Cancellation, //!< request_cancellation |
| 157 | Unknown, //!< Unknown request action |
| 158 | }; |
| 159 | |
| 160 | void |
| 161 | from_json(const nlohmann::json &obj, RequestAction &action); |
| 162 | |
| 163 | void |
| 164 | to_json(nlohmann::json &obj, const RequestAction &action); |
| 165 | |
| 166 | //! A request to share a session key. |
| 167 | struct KeyRequest |
| 168 | { |
| 169 | //! The type of request. |
| 170 | RequestAction action; |
| 171 | |
| 172 | /// @brief The encryption algorithm of the session we want keys for. |
| 173 | /// |
| 174 | /// Always m.megolm.v1.aes-sha2. |
| 175 | std::string algorithm; |
| 176 | //! The room in which the session was created. |
| 177 | std::string room_id; |
| 178 | //! The curve25519 key of the session creator. |
| 179 | std::string sender_key; |
| 180 | //! The session_id of the outbound megolm session. |
| 181 | std::string session_id; |
| 182 | |
| 183 | //! A unique identifier for this request. |
| 184 | std::string request_id; |
| 185 | //! The device requesting the keys. |
| 186 | std::string requesting_device_id; |
| 187 | |
| 188 | friend void from_json(const nlohmann::json &obj, KeyRequest &event); |
| 189 | friend void to_json(nlohmann::json &obj, const KeyRequest &event); |
| 190 | }; |
| 191 | |
| 192 | //! Content of the `m.key.verification.request` event |
| 193 | struct KeyVerificationRequest |
| 194 | { |
| 195 | std::optional<std::string> body; |
| 196 | //! The device ID which is initiating the request. |
| 197 | std::string from_device; |
| 198 | //! The device ID to which the key verification request is meant,used only for to-device |
| 199 | //! verification |
| 200 | std::optional<std::string> to; |
| 201 | //! An opaque identifier for the verification request. Must be unique with respect to the |
| 202 | //! devices involved. |
| 203 | std::optional<std::string> transaction_id; |
| 204 | //! must be `key.verification.request`, this field will be needed only in room verification |
| 205 | std::optional<std::string> msgtype; |
| 206 | //! The verification methods supported by the sender. |
| 207 | std::vector<VerificationMethods> methods; |
| 208 | //! The POSIX timestamp in milliseconds for when the request was made. If the request is in |
| 209 | //! the future by more than 5 minutes or more than 10 minutes in the past, the message |
| 210 | //! should be ignored by the receiver. |
| 211 | std::optional<uint64_t> timestamp; |
| 212 | |
| 213 | friend void from_json(const nlohmann::json &obj, KeyVerificationRequest &event); |
| 214 | friend void to_json(nlohmann::json &obj, const KeyVerificationRequest &event); |
| 215 | }; |
| 216 | |
| 217 | //! Content of the `m.key.verification.start` event |
| 218 | struct KeyVerificationStart |
| 219 | { |
| 220 | //! The device ID which is initiating the process. |
| 221 | std::string from_device; |
| 222 | /// @brief An opaque identifier for the verification process. |
| 223 | /// |
| 224 | /// Must be unique with respect to the devices involved. Must be the same as the |
| 225 | /// transaction_id given in the `m.key.verification.request` if this process is originating |
| 226 | /// from a request. |
| 227 | /// @note Used in verification via to_device messaging |
| 228 | std::optional<std::string> transaction_id; |
| 229 | //! The verification method to use. Must be 'm.sas.v1' |
| 230 | VerificationMethods method = VerificationMethods::SASv1; |
| 231 | /// @brief Optional method to use to verify the other user's key with. |
| 232 | // |
| 233 | // Applicable when the method chosen only verifies one user's key. This field will never be |
| 234 | // present if the method verifies keys both ways. |
| 235 | /// @note This appears to be unused in SAS verification |
| 236 | std::optional<std::string> next_method; |
| 237 | /// @brief The key agreement protocols the sending device understands. |
| 238 | /// |
| 239 | /// Must include at least curve25519. |
| 240 | std::vector<std::string> key_agreement_protocols; |
| 241 | //! The hash methods the sending device understands. Must include at least sha256. |
| 242 | std::vector<std::string> hashes; |
| 243 | /// @brief The message authentication codes that the sending device understands. |
| 244 | /// |
| 245 | /// Must include at least hkdf-hmac-sha256. |
| 246 | std::vector<std::string> message_authentication_codes; |
| 247 | /// @brief The SAS methods the sending device (and the sending device's user) understands. |
| 248 | /// |
| 249 | /// Must include at least decimal. Optionally can include emoji. |
| 250 | /// |
| 251 | /// One of: |
| 252 | /// - `decimal` |
| 253 | /// - `emoji` |
| 254 | std::vector<SASMethods> short_authentication_string; |
| 255 | /// @brief This is used for relating this message with previously sent |
| 256 | /// `key.verification.request` |
| 257 | /// |
| 258 | /// @note Will be used only for room-verification msgs where this is used in place of |
| 259 | /// transaction_id. |
| 260 | common::Relations relations; |
| 261 | |
| 262 | friend void from_json(const nlohmann::json &obj, KeyVerificationStart &event); |
| 263 | friend void to_json(nlohmann::json &obj, const KeyVerificationStart &event); |
| 264 | }; |
| 265 | |
| 266 | //! Implements the `m.key.verification.ready` event |
| 267 | struct KeyVerificationReady |
| 268 | { |
| 269 | //! the deviceId of the device which send the `m.key.verification.request` |
| 270 | std::string from_device; |
| 271 | //! transactionId of the current flow |
| 272 | std::optional<std::string> transaction_id; |
| 273 | //! Sends the user the supported methods |
| 274 | std::vector<VerificationMethods> methods; |
| 275 | //! this is used for relating this message with previously sent |
| 276 | //! key.verification.request will be used only for room-verification msgs where this |
| 277 | //! is used in place of txnid |
| 278 | common::Relations relations; |
| 279 | |
| 280 | friend void from_json(const nlohmann::json &obj, KeyVerificationReady &event); |
| 281 | friend void to_json(nlohmann::json &obj, const KeyVerificationReady &event); |
| 282 | }; |
| 283 | |
| 284 | // ! Implements the `m.key.verification.done` event |
| 285 | struct KeyVerificationDone |
| 286 | { |
| 287 | //! transactionId of the current flow |
| 288 | std::optional<std::string> transaction_id; |
| 289 | //! this is used for relating this message with previously sent key.verification.request |
| 290 | //! will be used only for room-verification msgs where this is used in place of txnid |
| 291 | common::Relations relations; |
| 292 | |
| 293 | friend void from_json(const nlohmann::json &obj, KeyVerificationDone &event); |
| 294 | friend void to_json(nlohmann::json &obj, const KeyVerificationDone &event); |
| 295 | }; |
| 296 | |
| 297 | //! Implements the `m.key.verification.accept` event |
| 298 | struct KeyVerificationAccept |
| 299 | { |
| 300 | //! when the method chosen only verifies one user's key. This field will never be present |
| 301 | //! if the method verifies keys both ways. |
| 302 | std::optional<std::string> transaction_id; |
| 303 | //! The verification method to use. Must be 'm.sas.v1' |
| 304 | VerificationMethods method = VerificationMethods::SASv1; |
| 305 | //! The key agreement protocol the device is choosing to use, out of the options in the |
| 306 | //! m.key.verification.start message. |
| 307 | std::string key_agreement_protocol; |
| 308 | //! The hash method the device is choosing to use, out of the options in the |
| 309 | //! m.key.verification.start message. |
| 310 | std::string hash; |
| 311 | //! The message authentication code the device is choosing to use, out of the options in |
| 312 | //! the m.key.verification.start message. |
| 313 | std::string message_authentication_code; |
| 314 | //! The SAS methods both devices involed in the verification process understand. Must be |
| 315 | //! a subset of the options in the m.key.verification.start message. |
| 316 | //! One of: ["decimal", "emoji"] |
| 317 | std::vector<SASMethods> short_authentication_string; |
| 318 | //! The hash (encoded as unpadded base64) of the concatenation of the device's ephemeral |
| 319 | //! public key (encoded as unpadded base64) and the canonical JSON representation of the |
| 320 | //! m.key.verification.start message. |
| 321 | std::string commitment; |
| 322 | //! this is used for relating this message with previously sent key.verification.request |
| 323 | //! will be used only for room-verification msgs where this is used in place of txnid |
| 324 | common::Relations relations; |
| 325 | |
| 326 | friend void from_json(const nlohmann::json &obj, KeyVerificationAccept &event); |
| 327 | friend void to_json(nlohmann::json &obj, const KeyVerificationAccept &event); |
| 328 | }; |
| 329 | |
| 330 | //! implementation of the `m.key.verification.cancel` event |
| 331 | struct KeyVerificationCancel |
| 332 | { |
| 333 | //! The opaque identifier for the verification process/request. |
| 334 | std::optional<std::string> transaction_id; |
| 335 | //! A human readable description of the code. The client should only rely on this string |
| 336 | //! if it does not understand the code. |
| 337 | std::string reason; |
| 338 | //! The error code for why the process/request was cancelled by the user. Error codes |
| 339 | //! should use the Java package naming convention if not in the following list: |
| 340 | //! m.user: The user cancelled the verification. |
| 341 | //! m.timeout: The verification process timed out. Verification processes can define |
| 342 | //! their own timeout parameters. |
| 343 | //! m.unknown_transaction: The device does not know about the given transaction ID. |
| 344 | //! m.unknown_method: The device does not know how to handle the requested method. |
| 345 | //! This should be sent for m.key.verification.start messages and messages |
| 346 | //! defined by individual verification processes. |
| 347 | //! m.unexpected_message: The device received an unexpected message. Typically raised |
| 348 | //! when one of the parties is handling the verification out of order. |
| 349 | //! m.key_mismatch: The key was not verified. |
| 350 | //! m.user_mismatch: The expected user did not match the user verified. |
| 351 | //! m.invalid_message: The message received was invalid. |
| 352 | //! m.accepted: A m.key.verification.request was accepted by a different device. |
| 353 | //! The device receiving this error can ignore the verification request. |
| 354 | //! m.unknown_method: The devices are unable to agree on the key agreement, |
| 355 | //! hash, MAC, or SAS method. |
| 356 | //! m.mismatched_commitment: The hash commitment did not match. |
| 357 | //! m.mismatched_sas: The SAS did not match. |
| 358 | //! Clients should be careful to avoid error loops. For example, if a device sends an |
| 359 | //! incorrect message and the client returns m.invalid_message to which it gets an |
| 360 | //! unexpected response with m.unexpected_message, the client should not respond |
| 361 | //! again with m.unexpected_message to avoid the other device potentially sending |
| 362 | //! another error response. |
| 363 | std::string code; |
| 364 | //! this is used for relating this message with previously sent key.verification.request |
| 365 | //! will be used only for room-verification msgs where this is used in place of txnid |
| 366 | common::Relations relations; |
| 367 | |
| 368 | friend void from_json(const nlohmann::json &obj, KeyVerificationCancel &event); |
| 369 | friend void to_json(nlohmann::json &obj, const KeyVerificationCancel &event); |
| 370 | }; |
| 371 | |
| 372 | struct KeyVerificationKey |
| 373 | { |
| 374 | //! An opaque identifier for the verification process. Must be the same as the one |
| 375 | //! used for the m.key.verification.start message. |
| 376 | std::optional<std::string> transaction_id; |
| 377 | //! The device's ephemeral public key, encoded as unpadded base64. |
| 378 | std::string key; |
| 379 | //! this is used for relating this message with previously sent key.verification.request |
| 380 | //! will be used only for room-verification msgs where this is used in place of txnid |
| 381 | common::Relations relations; |
| 382 | |
| 383 | friend void from_json(const nlohmann::json &obj, KeyVerificationKey &event); |
| 384 | friend void to_json(nlohmann::json &obj, const KeyVerificationKey &event); |
| 385 | }; |
| 386 | |
| 387 | struct KeyVerificationMac |
| 388 | { |
| 389 | //! An opaque identifier for the verification process. Must be the same as the one |
| 390 | //! used for the m.key.verification.start message. |
| 391 | std::optional<std::string> transaction_id; |
| 392 | //! A map of the key ID to the MAC of the key, using the algorithm in the |
| 393 | //! verification process. The MAC is encoded as unpadded base64. |
| 394 | std::map<std::string, std::string> mac; |
| 395 | //! The MAC of the comma-separated, sorted, list of key IDs given in the mac |
| 396 | //! property, encoded as unpadded base64. |
| 397 | std::string keys; |
| 398 | //! this is used for relating this message with previously sent key.verification.request |
| 399 | //! will be used only for room-verification msgs where this is used in place of txnid |
| 400 | common::Relations relations; |
| 401 | |
| 402 | friend void from_json(const nlohmann::json &obj, KeyVerificationMac &event); |
| 403 | friend void to_json(nlohmann::json &obj, const KeyVerificationMac &event); |
| 404 | }; |
| 405 | |
| 406 | struct SecretRequest |
| 407 | { |
| 408 | //! The type of request. |
| 409 | RequestAction action; |
| 410 | |
| 411 | //! Required if action is request. The name of the secret that is being requested. |
| 412 | std::string name; |
| 413 | |
| 414 | //! A unique identifier for this request. |
| 415 | std::string request_id; |
| 416 | //! The device requesting the keys. |
| 417 | std::string requesting_device_id; |
| 418 | |
| 419 | friend void from_json(const nlohmann::json &obj, SecretRequest &event); |
| 420 | friend void to_json(nlohmann::json &obj, const SecretRequest &event); |
| 421 | }; |
| 422 | |
| 423 | struct SecretSend |
| 424 | { |
| 425 | //! Required. The contents of the secret. |
| 426 | std::string secret; |
| 427 | |
| 428 | //! A unique identifier for this request. |
| 429 | std::string request_id; |
| 430 | |
| 431 | friend void from_json(const nlohmann::json &obj, SecretSend &event); |
| 432 | friend void to_json(nlohmann::json &obj, const SecretSend &event); |
| 433 | }; |
| 434 | |
| 435 | } // namespace msg |
| 436 | } // namespace events |
| 437 | } // namespace mtx |
| 438 | |