matrix_sdk_crypto/olm/group_sessions/
sender_data.rs

1// Copyright 2024 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::{cmp::Ordering, fmt};
16
17use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId};
18use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize};
19use vodozemac::Ed25519PublicKey;
20
21use crate::types::{serialize_ed25519_key, DeviceKeys};
22
23/// Information about the sender of a megolm session where we know the
24/// cross-signing identity of the sender.
25#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
26pub struct KnownSenderData {
27    /// The user ID of the user who established this session.
28    pub user_id: OwnedUserId,
29
30    /// The device ID of the device that send the session.
31    /// This is an `Option` for backwards compatibility, but we should always
32    /// populate it on creation.
33    pub device_id: Option<OwnedDeviceId>,
34
35    /// The cross-signing key of the user who established this session.
36    #[serde(
37        serialize_with = "serialize_ed25519_key",
38        deserialize_with = "deserialize_sender_msk_base64_or_array"
39    )]
40    pub master_key: Box<Ed25519PublicKey>,
41}
42
43/// In an initial version the master key was serialized as an array of number,
44/// it is now exported in base64. This code adds backward compatibility.
45pub(crate) fn deserialize_sender_msk_base64_or_array<'de, D>(
46    de: D,
47) -> Result<Box<Ed25519PublicKey>, D::Error>
48where
49    D: Deserializer<'de>,
50{
51    struct KeyVisitor;
52
53    impl<'de> Visitor<'de> for KeyVisitor {
54        type Value = Box<Ed25519PublicKey>;
55
56        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
57            write!(formatter, "a base64 string or an array of 32 bytes")
58        }
59
60        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
61        where
62            E: de::Error,
63        {
64            let decoded = Ed25519PublicKey::from_base64(v)
65                .map_err(|_| de::Error::custom("Base64 decoding error"))?;
66            Ok(Box::new(decoded))
67        }
68
69        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
70        where
71            A: de::SeqAccess<'de>,
72        {
73            let mut buf = [0u8; Ed25519PublicKey::LENGTH];
74
75            for (i, item) in buf.iter_mut().enumerate() {
76                *item = seq.next_element()?.ok_or_else(|| de::Error::invalid_length(i, &self))?;
77            }
78
79            let key = Ed25519PublicKey::from_slice(&buf).map_err(|e| de::Error::custom(&e))?;
80
81            Ok(Box::new(key))
82        }
83
84        fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
85        where
86            E: de::Error,
87        {
88            if v.len() == Ed25519PublicKey::LENGTH {
89                let mut buf = [0u8; Ed25519PublicKey::LENGTH];
90                buf.copy_from_slice(v);
91
92                let key = Ed25519PublicKey::from_slice(&buf).map_err(|e| de::Error::custom(&e))?;
93                Ok(Box::new(key))
94            } else {
95                Err(de::Error::invalid_length(v.len(), &self))
96            }
97        }
98    }
99
100    de.deserialize_any(KeyVisitor)
101}
102
103/// Information on the device and user that sent the megolm session data to us
104///
105/// Sessions start off in `UnknownDevice` state, and progress into `DeviceInfo`
106/// state when we get the device info. Finally, if we can look up the sender
107/// using the device info, the session can be moved into
108/// `VerificationViolation`, `SenderUnverified`, or
109/// `SenderVerified` state, depending on the verification status of the user.
110/// If the user's verification state changes, the state may change accordingly.
111#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
112#[serde(from = "SenderDataReader")]
113pub enum SenderData {
114    /// We have not yet found the (signed) device info for the sending device,
115    /// or we did find a device but it does not own the session.
116    UnknownDevice {
117        /// Was this session created before we started collecting trust
118        /// information about sessions? If so, we may choose to display its
119        /// messages even though trust info is missing.
120        legacy_session: bool,
121
122        /// If true, we found the device but it was not the owner of the
123        /// session. If false, we could not find the device.
124        #[serde(skip_serializing_if = "std::ops::Not::not")]
125        #[serde(default)]
126        owner_check_failed: bool,
127    },
128
129    /// We have the signed device info for the sending device, but not yet the
130    /// cross-signing key that it was signed with.
131    DeviceInfo {
132        /// Information about the device that sent the to-device message
133        /// creating this session.
134        device_keys: DeviceKeys,
135
136        /// Was this session created before we started collecting trust
137        /// information about sessions? If so, we may choose to display its
138        /// messages even though trust info is missing.
139        legacy_session: bool,
140    },
141
142    /// We have found proof that this user, with this cross-signing key, sent
143    /// the to-device message that established this session, but we have not yet
144    /// verified the cross-signing key, and we had verified a previous
145    /// cross-signing key for this user.
146    VerificationViolation(KnownSenderData),
147
148    /// We have found proof that this user, with this cross-signing key, sent
149    /// the to-device message that established this session, but we have not yet
150    /// verified the cross-signing key.
151    SenderUnverified(KnownSenderData),
152
153    /// We have found proof that this user, with this cross-signing key, sent
154    /// the to-device message that established this session, and we have
155    /// verified the cross-signing key.
156    SenderVerified(KnownSenderData),
157}
158
159impl SenderData {
160    /// Create a [`SenderData`] which contains no device info.
161    pub fn unknown() -> Self {
162        Self::UnknownDevice { legacy_session: false, owner_check_failed: false }
163    }
164
165    /// Create a [`SenderData`] which contains device info.
166    pub fn device_info(device_keys: DeviceKeys) -> Self {
167        Self::DeviceInfo { device_keys, legacy_session: false }
168    }
169
170    /// Create a [`SenderData`] with a known but unverified sender, where the
171    /// sender was previously verified.
172    pub fn sender_verification_violation(
173        user_id: &UserId,
174        device_id: &DeviceId,
175        master_key: Ed25519PublicKey,
176    ) -> Self {
177        Self::VerificationViolation(KnownSenderData {
178            user_id: user_id.to_owned(),
179            device_id: Some(device_id.to_owned()),
180            master_key: Box::new(master_key),
181        })
182    }
183
184    /// Create a [`SenderData`] with a known but unverified sender.
185    pub fn sender_unverified(
186        user_id: &UserId,
187        device_id: &DeviceId,
188        master_key: Ed25519PublicKey,
189    ) -> Self {
190        Self::SenderUnverified(KnownSenderData {
191            user_id: user_id.to_owned(),
192            device_id: Some(device_id.to_owned()),
193            master_key: Box::new(master_key),
194        })
195    }
196
197    /// Create a [`SenderData`] with a verified sender.
198    pub fn sender_verified(
199        user_id: &UserId,
200        device_id: &DeviceId,
201        master_key: Ed25519PublicKey,
202    ) -> Self {
203        Self::SenderVerified(KnownSenderData {
204            user_id: user_id.to_owned(),
205            device_id: Some(device_id.to_owned()),
206            master_key: Box::new(master_key),
207        })
208    }
209
210    /// Create a [`SenderData`] which has the legacy flag set. Caution: messages
211    /// within sessions with this flag will be displayed in some contexts,
212    /// even when we are unable to verify the sender.
213    ///
214    /// The returned struct contains no device info.
215    pub fn legacy() -> Self {
216        Self::UnknownDevice { legacy_session: true, owner_check_failed: false }
217    }
218
219    /// Returns `Greater` if this `SenderData` represents a greater level of
220    /// trust than the supplied one, `Equal` if they have the same level, and
221    /// `Less` if the supplied one has a greater level of trust.
222    ///
223    /// So calling this method on a `SenderKnown` or `DeviceInfo` `SenderData`
224    /// would return `Greater` if passed an `UnknownDevice` as its
225    /// argument, and a `SenderKnown` with `master_key_verified == true`
226    /// would return `Greater` if passed a `SenderKnown` with
227    /// `master_key_verified == false`.
228    pub(crate) fn compare_trust_level(&self, other: &Self) -> Ordering {
229        self.trust_number().cmp(&other.trust_number())
230    }
231
232    /// Internal function to give a numeric value of how much trust this
233    /// `SenderData` represents. Used to make the implementation of
234    /// compare_trust_level simpler.
235    fn trust_number(&self) -> u8 {
236        match self {
237            SenderData::UnknownDevice { .. } => 0,
238            SenderData::DeviceInfo { .. } => 1,
239            SenderData::VerificationViolation(..) => 2,
240            SenderData::SenderUnverified(..) => 3,
241            SenderData::SenderVerified(..) => 4,
242        }
243    }
244
245    /// Return our type as a [`SenderDataType`].
246    pub fn to_type(&self) -> SenderDataType {
247        match self {
248            Self::UnknownDevice { .. } => SenderDataType::UnknownDevice,
249            Self::DeviceInfo { .. } => SenderDataType::DeviceInfo,
250            Self::VerificationViolation { .. } => SenderDataType::VerificationViolation,
251            Self::SenderUnverified { .. } => SenderDataType::SenderUnverified,
252            Self::SenderVerified { .. } => SenderDataType::SenderVerified,
253        }
254    }
255}
256
257/// Used when deserialising and the sender_data property is missing.
258/// If we are deserialising an InboundGroupSession session with missing
259/// sender_data, this must be a legacy session (i.e. it was created before we
260/// started tracking sender data). We set its legacy flag to true, so we can
261/// populate it with trust information if it is available later.
262impl Default for SenderData {
263    fn default() -> Self {
264        Self::legacy()
265    }
266}
267
268/// Deserialisation type, to handle conversion from older formats
269#[derive(Deserialize)]
270enum SenderDataReader {
271    UnknownDevice {
272        legacy_session: bool,
273        #[serde(default)]
274        owner_check_failed: bool,
275    },
276
277    DeviceInfo {
278        device_keys: DeviceKeys,
279        legacy_session: bool,
280    },
281
282    #[serde(alias = "SenderUnverifiedButPreviouslyVerified")]
283    VerificationViolation(KnownSenderData),
284
285    SenderUnverified(KnownSenderData),
286
287    SenderVerified(KnownSenderData),
288
289    // If we read this older variant, it gets changed to SenderUnverified or
290    // SenderVerified, depending on the master_key_verified flag.
291    SenderKnown {
292        user_id: OwnedUserId,
293        device_id: Option<OwnedDeviceId>,
294        master_key: Box<Ed25519PublicKey>,
295        master_key_verified: bool,
296    },
297}
298
299impl From<SenderDataReader> for SenderData {
300    fn from(data: SenderDataReader) -> Self {
301        match data {
302            SenderDataReader::UnknownDevice { legacy_session, owner_check_failed } => {
303                Self::UnknownDevice { legacy_session, owner_check_failed }
304            }
305            SenderDataReader::DeviceInfo { device_keys, legacy_session } => {
306                Self::DeviceInfo { device_keys, legacy_session }
307            }
308            SenderDataReader::VerificationViolation(data) => Self::VerificationViolation(data),
309            SenderDataReader::SenderUnverified(data) => Self::SenderUnverified(data),
310            SenderDataReader::SenderVerified(data) => Self::SenderVerified(data),
311            SenderDataReader::SenderKnown {
312                user_id,
313                device_id,
314                master_key,
315                master_key_verified,
316            } => {
317                let known_sender_data = KnownSenderData { user_id, device_id, master_key };
318                if master_key_verified {
319                    Self::SenderVerified(known_sender_data)
320                } else {
321                    Self::SenderUnverified(known_sender_data)
322                }
323            }
324        }
325    }
326}
327
328/// Used when serializing [`crate::olm::group_sessions::InboundGroupSession`]s.
329/// We want just the type of the session's [`SenderData`] to be queryable, so we
330/// store the type as a separate column/property in the database.
331#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
332pub enum SenderDataType {
333    /// The [`SenderData`] is of type `UnknownDevice`.
334    UnknownDevice = 1,
335    /// The [`SenderData`] is of type `DeviceInfo`.
336    DeviceInfo = 2,
337    /// The [`SenderData`] is of type `VerificationViolation`.
338    VerificationViolation = 3,
339    /// The [`SenderData`] is of type `SenderUnverified`.
340    SenderUnverified = 4,
341    /// The [`SenderData`] is of type `SenderVerified`.
342    SenderVerified = 5,
343}
344
345#[cfg(test)]
346mod tests {
347    use std::{cmp::Ordering, collections::BTreeMap};
348
349    use assert_matches2::assert_let;
350    use insta::assert_json_snapshot;
351    use ruma::{
352        device_id, owned_device_id, owned_user_id, user_id, DeviceKeyAlgorithm, DeviceKeyId,
353    };
354    use serde_json::json;
355    use vodozemac::{base64_decode, Curve25519PublicKey, Ed25519PublicKey};
356
357    use super::SenderData;
358    use crate::{
359        olm::{KnownSenderData, PickledInboundGroupSession},
360        types::{DeviceKey, DeviceKeys, EventEncryptionAlgorithm, Signatures},
361    };
362
363    #[test]
364    fn serializing_unknown_device_correctly_preserves_owner_check_failed_if_true() {
365        // Given an unknown device SenderData with failed owner check
366        let start = SenderData::UnknownDevice { legacy_session: false, owner_check_failed: true };
367
368        // When we round-trip it to JSON and back
369        let json = serde_json::to_string(&start).unwrap();
370        let end: SenderData = serde_json::from_str(&json).unwrap();
371
372        // Then the failed owner check flag is preserved
373        assert_let!(SenderData::UnknownDevice { owner_check_failed, .. } = &end);
374        assert!(owner_check_failed);
375
376        // And for good measure, everything is preserved
377        assert_eq!(start, end);
378    }
379
380    #[test]
381    fn serializing_unknown_device_without_failed_owner_check_excludes_it() {
382        // Given an unknown device SenderData with owner_check_failed==false
383        let start = SenderData::UnknownDevice { legacy_session: false, owner_check_failed: false };
384
385        // When we write it to JSON
386        let json = serde_json::to_string(&start).unwrap();
387
388        // Then the JSON does not mention `owner_check_failed`
389        assert!(!json.contains("owner_check_failed"), "JSON contains 'owner_check_failed'!");
390
391        // And for good measure, it round-trips fully
392        let end: SenderData = serde_json::from_str(&json).unwrap();
393        assert_eq!(start, end);
394    }
395
396    #[test]
397    fn deserializing_unknown_device_with_extra_retry_info_ignores_it() {
398        // Previously, SenderData contained `retry_details` but it is no longer needed -
399        // just check that we are able to deserialize even if it is present.
400        let json = r#"
401            {
402                "UnknownDevice":{
403                    "retry_details":{
404                        "retry_count":3,
405                        "next_retry_time_ms":10000
406                    },
407                    "legacy_session":false
408                }
409            }
410            "#;
411
412        let end: SenderData = serde_json::from_str(json).expect("Failed to parse!");
413        assert_let!(SenderData::UnknownDevice { .. } = end);
414    }
415
416    #[test]
417    fn deserializing_senderknown_without_device_id_defaults_to_none() {
418        let json = r#"
419            {
420                "SenderKnown":{
421                    "user_id":"@u:s.co",
422                    "master_key":[
423                        150,140,249,139,141,29,63,230,179,14,213,175,176,61,11,255,
424                        26,103,10,51,100,154,183,47,181,117,87,204,33,215,241,92
425                    ],
426                    "master_key_verified":true
427                }
428            }
429            "#;
430
431        let end: SenderData = serde_json::from_str(json).expect("Failed to parse!");
432        assert_let!(SenderData::SenderVerified { .. } = end);
433    }
434
435    #[test]
436    fn deserializing_sender_unverified_but_previously_verified_migrates_to_verification_violation()
437    {
438        let json = r#"
439            {
440                "SenderUnverifiedButPreviouslyVerified":{
441                    "user_id":"@u:s.co",
442                    "master_key":[
443                        150,140,249,139,141,29,63,230,179,14,213,175,176,61,11,255,
444                        26,103,10,51,100,154,183,47,181,117,87,204,33,215,241,92
445                    ],
446                    "master_key_verified":true
447                }
448            }
449            "#;
450
451        let end: SenderData = serde_json::from_str(json).expect("Failed to parse!");
452        assert_let!(SenderData::VerificationViolation(KnownSenderData { user_id, .. }) = end);
453        assert_eq!(user_id, owned_user_id!("@u:s.co"));
454    }
455
456    #[test]
457    fn deserializing_verification_violation() {
458        let json = r#"
459            {
460                "VerificationViolation":{
461                    "user_id":"@u:s.co",
462                    "master_key":[
463                        150,140,249,139,141,29,63,230,179,14,213,175,176,61,11,255,
464                        26,103,10,51,100,154,183,47,181,117,87,204,33,215,241,92
465                    ],
466                    "master_key_verified":true
467                }
468            }
469            "#;
470
471        let end: SenderData = serde_json::from_str(json).expect("Failed to parse!");
472        assert_let!(SenderData::VerificationViolation(KnownSenderData { user_id, .. }) = end);
473        assert_eq!(user_id, owned_user_id!("@u:s.co"));
474    }
475
476    #[test]
477    fn equal_sessions_have_same_trust_level() {
478        let unknown = SenderData::unknown();
479        let device_keys = SenderData::device_info(DeviceKeys::new(
480            owned_user_id!("@u:s.co"),
481            owned_device_id!("DEV"),
482            Vec::new(),
483            BTreeMap::new(),
484            Signatures::new(),
485        ));
486        let master_key =
487            Ed25519PublicKey::from_base64("2/5LWJMow5zhJqakV88SIc7q/1pa8fmkfgAzx72w9G4").unwrap();
488        let sender_unverified =
489            SenderData::sender_unverified(user_id!("@u:s.co"), device_id!("DEV"), master_key);
490        let sender_verified =
491            SenderData::sender_verified(user_id!("@u:s.co"), device_id!("DEV"), master_key);
492
493        assert_eq!(unknown.compare_trust_level(&unknown), Ordering::Equal);
494        assert_eq!(device_keys.compare_trust_level(&device_keys), Ordering::Equal);
495        assert_eq!(sender_unverified.compare_trust_level(&sender_unverified), Ordering::Equal);
496        assert_eq!(sender_verified.compare_trust_level(&sender_verified), Ordering::Equal);
497    }
498
499    #[test]
500    fn more_trust_data_makes_you_more_trusted() {
501        let unknown = SenderData::unknown();
502        let device_keys = SenderData::device_info(DeviceKeys::new(
503            owned_user_id!("@u:s.co"),
504            owned_device_id!("DEV"),
505            Vec::new(),
506            BTreeMap::new(),
507            Signatures::new(),
508        ));
509        let master_key =
510            Ed25519PublicKey::from_base64("2/5LWJMow5zhJqakV88SIc7q/1pa8fmkfgAzx72w9G4").unwrap();
511        let sender_verification_violation = SenderData::sender_verification_violation(
512            user_id!("@u:s.co"),
513            device_id!("DEV"),
514            master_key,
515        );
516        let sender_unverified =
517            SenderData::sender_unverified(user_id!("@u:s.co"), device_id!("DEV"), master_key);
518        let sender_verified =
519            SenderData::sender_verified(user_id!("@u:s.co"), device_id!("DEV"), master_key);
520
521        assert_eq!(unknown.compare_trust_level(&device_keys), Ordering::Less);
522        assert_eq!(unknown.compare_trust_level(&sender_verification_violation), Ordering::Less);
523        assert_eq!(unknown.compare_trust_level(&sender_unverified), Ordering::Less);
524        assert_eq!(unknown.compare_trust_level(&sender_verified), Ordering::Less);
525        assert_eq!(device_keys.compare_trust_level(&unknown), Ordering::Greater);
526        assert_eq!(sender_verification_violation.compare_trust_level(&unknown), Ordering::Greater);
527        assert_eq!(sender_unverified.compare_trust_level(&unknown), Ordering::Greater);
528        assert_eq!(sender_verified.compare_trust_level(&unknown), Ordering::Greater);
529
530        assert_eq!(device_keys.compare_trust_level(&sender_unverified), Ordering::Less);
531        assert_eq!(device_keys.compare_trust_level(&sender_verified), Ordering::Less);
532        assert_eq!(
533            sender_verification_violation.compare_trust_level(&device_keys),
534            Ordering::Greater
535        );
536        assert_eq!(sender_unverified.compare_trust_level(&device_keys), Ordering::Greater);
537        assert_eq!(sender_verified.compare_trust_level(&device_keys), Ordering::Greater);
538
539        assert_eq!(
540            sender_verification_violation.compare_trust_level(&sender_verified),
541            Ordering::Less
542        );
543        assert_eq!(
544            sender_verification_violation.compare_trust_level(&sender_unverified),
545            Ordering::Less
546        );
547        assert_eq!(sender_unverified.compare_trust_level(&sender_verified), Ordering::Less);
548        assert_eq!(sender_verified.compare_trust_level(&sender_unverified), Ordering::Greater);
549    }
550
551    #[test]
552    fn snapshot_sender_data() {
553        assert_json_snapshot!(SenderData::UnknownDevice {
554            legacy_session: false,
555            owner_check_failed: true,
556        });
557
558        assert_json_snapshot!(SenderData::UnknownDevice {
559            legacy_session: true,
560            owner_check_failed: false,
561        });
562
563        assert_json_snapshot!(SenderData::DeviceInfo {
564            device_keys: DeviceKeys::new(
565                owned_user_id!("@foo:bar.baz"),
566                owned_device_id!("DEV"),
567                vec![
568                    EventEncryptionAlgorithm::MegolmV1AesSha2,
569                    EventEncryptionAlgorithm::OlmV1Curve25519AesSha2
570                ],
571                BTreeMap::from_iter(vec![(
572                    DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, device_id!("ABCDEFGH")),
573                    DeviceKey::Curve25519(Curve25519PublicKey::from_bytes([0u8; 32])),
574                )]),
575                Default::default(),
576            ),
577            legacy_session: false,
578        });
579
580        assert_json_snapshot!(SenderData::VerificationViolation(KnownSenderData {
581            user_id: owned_user_id!("@foo:bar.baz"),
582            device_id: Some(owned_device_id!("DEV")),
583            master_key: Box::new(Ed25519PublicKey::from_slice(&[0u8; 32]).unwrap()),
584        }));
585
586        assert_json_snapshot!(SenderData::SenderUnverified(KnownSenderData {
587            user_id: owned_user_id!("@foo:bar.baz"),
588            device_id: None,
589            master_key: Box::new(Ed25519PublicKey::from_slice(&[1u8; 32]).unwrap()),
590        }));
591
592        assert_json_snapshot!(SenderData::SenderVerified(KnownSenderData {
593            user_id: owned_user_id!("@foo:bar.baz"),
594            device_id: None,
595            master_key: Box::new(Ed25519PublicKey::from_slice(&[1u8; 32]).unwrap()),
596        }));
597    }
598
599    #[test]
600    fn test_sender_known_data_migration() {
601        let old_format = json!(
602        {
603            "SenderVerified": {
604                "user_id": "@foo:bar.baz",
605                "device_id": null,
606                "master_key": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
607            }
608        });
609
610        let migrated: SenderData = serde_json::from_value(old_format).unwrap();
611
612        assert_let!(SenderData::SenderVerified(KnownSenderData { master_key, .. }) = migrated);
613
614        assert_eq!(
615            master_key.to_base64(),
616            Ed25519PublicKey::from_slice(&[0u8; 32]).unwrap().to_base64()
617        );
618    }
619
620    #[test]
621    fn test_sender_known_data_migration_with_efficient_bytes_array() {
622        // This is an serialized PickledInboundGroupSession as rmp_serde will generate.
623        //
624        // This export usse a more efficient serialization format for bytes. This was
625        // exported when the `KnownSenderData` master_key was serialized as an byte
626        // array instead of a base64 encoded string.
627        const SERIALIZED_B64: &str =
628            "iaZwaWNrbGWEr2luaXRpYWxfcmF0Y2hldIKlaW5uZXLcAIABYMzfSnBRzMlPKF1uKjYbzLtkzNJ4RcylzN0HzP\
629             9DzON1Tm05zO7M2MzFQsy9Acz9zPnMqDvM4syQzNrMzxF5KzbM4sy9zPUbBWfM7m4/zJzM18zDzMESKgfMkE7M\
630             yszIHszqWjYyQURbzKTMkx7M58zANsy+AGPM2A8tbcyFYczge8ykzMFdbVxJMMyAzN8azJEXGsy8zPJazMMaP8\
631             ziDszmWwfM+My2ajLMr8y+eczTRm9TFadjb3VudGVyAKtzaWduaW5nX2tlecQgefpCr6Duu7QUWzKIeMOFmxv/\
632             NjfcsYwZz8IN2ZOhdaS0c2lnbmluZ19rZXlfdmVyaWZpZWTDpmNvbmZpZ4GndmVyc2lvbqJWMapzZW5kZXJfa2\
633             V52StoMkIySDg2ajFpYmk2SW13ak9UUkhzbTVMamtyT2kyUGtiSXVUb0w0TWtFq3NpZ25pbmdfa2V5gadlZDI1\
634             NTE52StUWHJqNS9UYXpia3Yram1CZDl4UlB4NWNVaFFzNUNnblc1Q1pNRjgvNjZzq3NlbmRlcl9kYXRhgbBTZW\
635             5kZXJVbnZlcmlmaWVkg6d1c2VyX2lks0B2YWxvdTM1Om1hdHJpeC5vcmepZGV2aWNlX2lkqkZJQlNaRlJLUE2q\
636             bWFzdGVyX2tlecQgkOp9s4ClyQujYD7rRZA8xgE6kvYlqKSNnMrQNmSrcuGncm9vbV9pZL4hRWt5VEtGdkViYl\
637             B6SmxhaUhFOm1hdHJpeC5vcmeoaW1wb3J0ZWTCqWJhY2tlZF91cMKyaGlzdG9yeV92aXNpYmlsaXR5wKlhbGdv\
638             cml0aG20bS5tZWdvbG0udjEuYWVzLXNoYTI";
639
640        let input = base64_decode(SERIALIZED_B64).unwrap();
641        let sender_data: PickledInboundGroupSession = rmp_serde::from_slice(&input)
642            .expect("Should be able to deserialize serialized inbound group session");
643
644        assert_let!(
645            SenderData::SenderUnverified(KnownSenderData { master_key, .. }) =
646                sender_data.sender_data
647        );
648
649        assert_eq!(master_key.to_base64(), "kOp9s4ClyQujYD7rRZA8xgE6kvYlqKSNnMrQNmSrcuE");
650    }
651}