From 3e9b0a8e7f2d5fa82a2d1e676d8465fe5bfbbf30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Wed, 9 Sep 2020 15:03:19 +0200 Subject: [PATCH] crypto: Correctly store the ed25519 key map for inbound group sessions. --- .../src/olm/group_sessions/inbound.rs | 24 ++-- matrix_sdk_crypto/src/store/sqlite.rs | 130 +++++++++++++----- 2 files changed, 107 insertions(+), 47 deletions(-) diff --git a/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs b/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs index ce41675a..ad9edf77 100644 --- a/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs +++ b/matrix_sdk_crypto/src/olm/group_sessions/inbound.rs @@ -49,9 +49,10 @@ pub struct InboundGroupSession { inner: Arc>, session_id: Arc, pub(crate) sender_key: Arc, - pub(crate) signing_key: Arc, + pub(crate) signing_key: Arc>, pub(crate) room_id: Arc, forwarding_chains: Arc>>>, + imported: Arc, } impl InboundGroupSession { @@ -80,13 +81,17 @@ impl InboundGroupSession { let session = OlmInboundGroupSession::new(&session_key.0)?; let session_id = session.session_id(); + let mut keys: BTreeMap = BTreeMap::new(); + keys.insert(DeviceKeyAlgorithm::Ed25519, signing_key.to_owned()); + Ok(InboundGroupSession { inner: Arc::new(Mutex::new(session)), session_id: Arc::new(session_id), sender_key: Arc::new(sender_key.to_owned()), - signing_key: Arc::new(signing_key.to_owned()), + signing_key: Arc::new(keys), room_id: Arc::new(room_id.clone()), forwarding_chains: Arc::new(Mutex::new(None)), + imported: Arc::new(false), }) } @@ -102,9 +107,10 @@ impl InboundGroupSession { PickledInboundGroupSession { pickle: InboundGroupSessionPickle::from(pickle), sender_key: self.sender_key.to_string(), - signing_key: self.signing_key.to_string(), + signing_key: (&*self.signing_key).clone(), room_id: (&*self.room_id).clone(), forwarding_chains: self.forwarding_chains.lock().await.clone(), + imported: *self.imported, } } @@ -120,10 +126,6 @@ impl InboundGroupSession { let session_key = ExportedGroupSessionKey(self.inner.lock().await.export(message_index).ok()?); - let mut sender_claimed_keys: BTreeMap = BTreeMap::new(); - - sender_claimed_keys.insert(DeviceKeyAlgorithm::Ed25519, (&*self.signing_key).to_owned()); - Some(ExportedRoomKey { algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2, room_id: (&*self.room_id).clone(), @@ -136,7 +138,7 @@ impl InboundGroupSession { .as_ref() .cloned() .unwrap_or_default(), - sender_claimed_keys, + sender_claimed_keys: (&*self.signing_key).clone(), session_key, }) } @@ -166,6 +168,7 @@ impl InboundGroupSession { signing_key: Arc::new(pickle.signing_key), room_id: Arc::new(pickle.room_id), forwarding_chains: Arc::new(Mutex::new(pickle.forwarding_chains)), + imported: Arc::new(pickle.imported), }) } @@ -265,12 +268,15 @@ pub struct PickledInboundGroupSession { /// The public curve25519 key of the account that sent us the session pub sender_key: String, /// The public ed25519 key of the account that sent us the session. - pub signing_key: String, + pub signing_key: BTreeMap, /// The id of the room that the session is used in. pub room_id: RoomId, /// The list of claimed ed25519 that forwarded us this key. Will be None if /// we dirrectly received this session. pub forwarding_chains: Option>, + /// Flag remembering if the session was dirrectly sent to us by the sender + /// or if it was imported. + pub imported: bool, } /// The typed representation of a base64 encoded string of the GroupSession pickle. diff --git a/matrix_sdk_crypto/src/store/sqlite.rs b/matrix_sdk_crypto/src/store/sqlite.rs index d40ca12b..219ffb06 100644 --- a/matrix_sdk_crypto/src/store/sqlite.rs +++ b/matrix_sdk_crypto/src/store/sqlite.rs @@ -231,14 +231,16 @@ impl SqliteStore { .execute( r#" CREATE TABLE IF NOT EXISTS inbound_group_sessions ( - "session_id" TEXT NOT NULL PRIMARY KEY, + "id" INTEGER NOT NULL PRIMARY KEY, + "session_id" TEXT NOT NULL, "account_id" INTEGER NOT NULL, "sender_key" TEXT NOT NULL, - "signing_key" TEXT NOT NULL, "room_id" TEXT NOT NULL, "pickle" BLOB NOT NULL, + "imported" INTEGER NOT NULL, FOREIGN KEY ("account_id") REFERENCES "accounts" ("id") ON DELETE CASCADE + UNIQUE(account_id,session_id,sender_key) ); CREATE INDEX IF NOT EXISTS "olm_groups_sessions_account_id" ON "inbound_group_sessions" ("account_id"); @@ -246,6 +248,24 @@ impl SqliteStore { ) .await?; + connection + .execute( + r#" + CREATE TABLE IF NOT EXISTS group_session_claimed_keys ( + "id" INTEGER NOT NULL PRIMARY KEY, + "session_id" INTEGER NOT NULL, + "algorithm" TEXT NOT NULL, + "key" TEXT NOT NULL, + FOREIGN KEY ("session_id") REFERENCES "inbound_group_sessions" ("id") + ON DELETE CASCADE + UNIQUE(session_id, algorithm) + ); + + CREATE INDEX IF NOT EXISTS "group_session_claimed_keys_session_id" ON "inbound_group_sessions" ("session_id"); + "#, + ) + .await?; + connection .execute( r#" @@ -475,45 +495,55 @@ impl SqliteStore { let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?; let mut connection = self.connection.lock().await; - let mut rows: Vec<(String, String, String, String)> = query_as( - "SELECT pickle, sender_key, signing_key, room_id + let mut rows: Vec<(i64, String, String, String, bool)> = query_as( + "SELECT id, pickle, sender_key, room_id, imported FROM inbound_group_sessions WHERE account_id = ?", ) .bind(account_id) .fetch_all(&mut *connection) .await?; - let mut group_sessions = rows - .drain(..) - .map(|row| { - let pickle = row.0; - let sender_key = row.1; - let signing_key = row.2; - let room_id = row.3; + for row in rows.drain(..) { + let session_row_id = row.0; + let pickle = row.1; + let sender_key = row.2; + let room_id = row.3; + let imported = row.4; - let pickle = PickledInboundGroupSession { - pickle: InboundGroupSessionPickle::from(pickle), - sender_key, - signing_key, - room_id: RoomId::try_from(room_id)?, - // Fixme we need to store/restore these once we get support - // for key requesting/forwarding. - forwarding_chains: None, - }; + let key_rows: Vec<(String, String)> = query_as( + "SELECT algorithm, key FROM group_session_claimed_keys WHERE session_id = ?", + ) + .bind(session_row_id) + .fetch_all(&mut *connection) + .await?; - Ok(InboundGroupSession::from_pickle( + let claimed_keys: BTreeMap = key_rows + .into_iter() + .filter_map(|row| { + let algorithm = row.0.parse::().ok()?; + let key = row.1; + + Some((algorithm, key)) + }) + .collect(); + + let pickle = PickledInboundGroupSession { + pickle: InboundGroupSessionPickle::from(pickle), + sender_key, + signing_key: claimed_keys, + room_id: RoomId::try_from(room_id)?, + // Fixme we need to store/restore these once we get support + // for key requesting/forwarding. + forwarding_chains: None, + imported, + }; + + self.inbound_group_sessions + .add(InboundGroupSession::from_pickle( pickle, self.get_pickle_mode(), - )?) - }) - .collect::>>()?; - - group_sessions - .drain(..) - .map(|s| { - self.inbound_group_sessions.add(s); - }) - .for_each(drop); + )?); + } Ok(()) } @@ -1146,23 +1176,47 @@ impl CryptoStore for SqliteStore { // the key import feature. query( - "INSERT INTO inbound_group_sessions ( - session_id, account_id, sender_key, signing_key, - room_id, pickle + "REPLACE INTO inbound_group_sessions ( + session_id, account_id, sender_key, + room_id, pickle, imported ) VALUES (?1, ?2, ?3, ?4, ?5, ?6) - ON CONFLICT(session_id) DO UPDATE SET - pickle = excluded.pickle ", ) .bind(session_id) .bind(account_id) - .bind(pickle.sender_key) - .bind(pickle.signing_key) + .bind(&pickle.sender_key) .bind(pickle.room_id.as_str()) .bind(pickle.pickle.as_str()) + .bind(pickle.imported) .execute(&mut *connection) .await?; + let row: (i64,) = query_as( + "SELECT id FROM inbound_group_sessions + WHERE account_id = ? and session_id = ? and sender_key = ?", + ) + .bind(account_id) + .bind(session_id) + .bind(pickle.sender_key) + .fetch_one(&mut *connection) + .await?; + + let session_row_id = row.0; + + for (key_id, key) in pickle.signing_key { + query( + "INSERT OR IGNORE INTO group_session_claimed_keys ( + session_id, algorithm, key + ) VALUES (?1, ?2, ?3) + ", + ) + .bind(session_row_id) + .bind(serde_json::to_string(&key_id)?) + .bind(key) + .execute(&mut *connection) + .await?; + } + Ok(self.inbound_group_sessions.add(session)) }