libsignal_protocol/messages/
signal_message.rs

1use crate::{
2    errors::InternalError,
3    keys::PublicKey,
4    messages::{CiphertextMessage, CiphertextType},
5    raw_ptr::Raw,
6    Context, ContextInner,
7};
8use failure::Error;
9use std::{convert::TryFrom, rc::Rc};
10
11// For rustdoc link resolution
12#[allow(unused_imports)]
13use crate::keys::IdentityKeyPair;
14
15/// A message with an arbitrary payload.
16#[derive(Debug, Clone)]
17pub struct SignalMessage {
18    pub(crate) raw: Raw<sys::signal_message>,
19    pub(crate) _ctx: Rc<ContextInner>,
20}
21
22impl SignalMessage {
23    /// Is this a legacy message?
24    pub fn is_legacy(msg: &[u8]) -> bool {
25        unsafe { sys::signal_message_is_legacy(msg.as_ptr(), msg.len()) != 0 }
26    }
27
28    /// Get the public half of the sender's [`IdentityKeyPair`].
29    pub fn sender_ratchet_key(&self) -> PublicKey {
30        unsafe {
31            let raw = sys::signal_message_get_sender_ratchet_key(
32                self.raw.as_const_ptr(),
33            );
34            PublicKey {
35                raw: Raw::copied_from(raw),
36            }
37        }
38    }
39
40    /// The message format version.
41    pub fn message_version(&self) -> u8 {
42        unsafe {
43            sys::signal_message_get_message_version(self.raw.as_const_ptr())
44        }
45    }
46
47    /// Get the signal message counter.
48    pub fn counter(&self) -> u32 {
49        unsafe { sys::signal_message_get_counter(self.raw.as_const_ptr()) }
50    }
51
52    /// The message body.
53    pub fn body(&self) -> &[u8] {
54        unsafe {
55            let buffer = sys::signal_message_get_body(self.raw.as_const_ptr());
56            assert!(!buffer.is_null());
57
58            let len = sys::signal_buffer_len(buffer);
59            let data = sys::signal_buffer_data(buffer);
60
61            std::slice::from_raw_parts(data, len)
62        }
63    }
64
65    /// Verify the MAC on the signal message.
66    pub fn verify_mac(
67        &self,
68        sender_identity_key: &PublicKey,
69        receiver_identity_key: &PublicKey,
70        mac: &[u8],
71        ctx: &Context,
72    ) -> Result<bool, InternalError> {
73        unsafe {
74            let code = sys::signal_message_verify_mac(
75                self.raw.as_ptr(),
76                sender_identity_key.raw.as_ptr(),
77                receiver_identity_key.raw.as_ptr(),
78                mac.as_ptr(),
79                mac.len(),
80                ctx.raw(),
81            );
82
83            match code {
84                0 => Ok(false),
85                1 => Ok(true),
86                other => Err(InternalError::from_error_code(other)
87                    .unwrap_or(InternalError::Unknown)),
88            }
89        }
90    }
91}
92
93impl TryFrom<CiphertextMessage> for SignalMessage {
94    type Error = Error;
95
96    fn try_from(other: CiphertextMessage) -> Result<Self, Self::Error> {
97        if other.get_type()? != CiphertextType::Signal {
98            Err(failure::err_msg("Expected a signal message"))
99        } else {
100            // safety: the `CiphertextType` check tells us this is actually a
101            // pointer to a `signal_message`
102            let raw = unsafe {
103                Raw::copied_from(other.raw.as_ptr() as *mut sys::signal_message)
104            };
105            Ok(SignalMessage {
106                raw,
107                _ctx: other._ctx,
108            })
109        }
110    }
111}
112
113impl From<SignalMessage> for CiphertextMessage {
114    fn from(other: SignalMessage) -> CiphertextMessage {
115        CiphertextMessage {
116            raw: other.raw.upcast(),
117            _ctx: other._ctx,
118        }
119    }
120}
121
122impl_is_a!(sys::signal_message => sys::ciphertext_message);