1 //
2 // Copyright 2020 Signal Messenger, LLC.
3 // SPDX-License-Identifier: AGPL-3.0-only
4 //
5
6 use crate::{
7 Context, Direction, IdentityKeyStore, KeyPair, PreKeyBundle, PreKeySignalMessage, PreKeyStore,
8 ProtocolAddress, Result, SessionRecord, SessionStore, SignalProtocolError, SignedPreKeyStore,
9 };
10
11 use crate::ratchet;
12 use crate::ratchet::{AliceSignalProtocolParameters, BobSignalProtocolParameters};
13 use crate::state::PreKeyId;
14 use rand::{CryptoRng, Rng};
15
16 /*
17 These functions are on SessionBuilder in Java
18
19 However using SessionBuilder + SessionCipher at the same time causes
20 &mut sharing issues. And as SessionBuilder has no actual state beyond
21 its reference to the various data stores, instead the functions are
22 free standing.
23 */
24
process_prekey( message: &PreKeySignalMessage, remote_address: &ProtocolAddress, session_record: &mut SessionRecord, identity_store: &mut dyn IdentityKeyStore, pre_key_store: &mut dyn PreKeyStore, signed_prekey_store: &mut dyn SignedPreKeyStore, ctx: Context, ) -> Result<Option<PreKeyId>>25 pub async fn process_prekey(
26 message: &PreKeySignalMessage,
27 remote_address: &ProtocolAddress,
28 session_record: &mut SessionRecord,
29 identity_store: &mut dyn IdentityKeyStore,
30 pre_key_store: &mut dyn PreKeyStore,
31 signed_prekey_store: &mut dyn SignedPreKeyStore,
32 ctx: Context,
33 ) -> Result<Option<PreKeyId>> {
34 let their_identity_key = message.identity_key();
35
36 if !identity_store
37 .is_trusted_identity(
38 remote_address,
39 their_identity_key,
40 Direction::Receiving,
41 ctx,
42 )
43 .await?
44 {
45 return Err(SignalProtocolError::UntrustedIdentity(
46 remote_address.clone(),
47 ));
48 }
49
50 let unsigned_pre_key_id = process_prekey_v3(
51 message,
52 remote_address,
53 session_record,
54 signed_prekey_store,
55 pre_key_store,
56 identity_store,
57 ctx,
58 )
59 .await?;
60
61 identity_store
62 .save_identity(remote_address, their_identity_key, ctx)
63 .await?;
64
65 Ok(unsigned_pre_key_id)
66 }
67
process_prekey_v3( message: &PreKeySignalMessage, remote_address: &ProtocolAddress, session_record: &mut SessionRecord, signed_prekey_store: &mut dyn SignedPreKeyStore, pre_key_store: &mut dyn PreKeyStore, identity_store: &mut dyn IdentityKeyStore, ctx: Context, ) -> Result<Option<PreKeyId>>68 async fn process_prekey_v3(
69 message: &PreKeySignalMessage,
70 remote_address: &ProtocolAddress,
71 session_record: &mut SessionRecord,
72 signed_prekey_store: &mut dyn SignedPreKeyStore,
73 pre_key_store: &mut dyn PreKeyStore,
74 identity_store: &mut dyn IdentityKeyStore,
75 ctx: Context,
76 ) -> Result<Option<PreKeyId>> {
77 if session_record.has_session_state(
78 message.message_version() as u32,
79 &message.base_key().serialize(),
80 )? {
81 // We've already setup a session for this V3 message, letting bundled message fall through
82 return Ok(None);
83 }
84
85 let our_signed_pre_key_pair = signed_prekey_store
86 .get_signed_pre_key(message.signed_pre_key_id(), ctx)
87 .await?
88 .key_pair()?;
89
90 let our_one_time_pre_key_pair = if let Some(pre_key_id) = message.pre_key_id() {
91 log::info!("processing PreKey message from {}", remote_address);
92 Some(
93 pre_key_store
94 .get_pre_key(pre_key_id, ctx)
95 .await?
96 .key_pair()?,
97 )
98 } else {
99 log::warn!(
100 "processing PreKey message from {} which had no one-time prekey",
101 remote_address
102 );
103 None
104 };
105
106 let parameters = BobSignalProtocolParameters::new(
107 identity_store.get_identity_key_pair(ctx).await?,
108 our_signed_pre_key_pair, // signed pre key
109 our_one_time_pre_key_pair,
110 our_signed_pre_key_pair, // ratchet key
111 *message.identity_key(),
112 *message.base_key(),
113 );
114
115 session_record.archive_current_state()?;
116
117 let mut new_session = ratchet::initialize_bob_session(¶meters)?;
118
119 new_session.set_local_registration_id(identity_store.get_local_registration_id(ctx).await?)?;
120 new_session.set_remote_registration_id(message.registration_id())?;
121 new_session.set_alice_base_key(&message.base_key().serialize())?;
122
123 session_record.promote_state(new_session)?;
124
125 Ok(message.pre_key_id())
126 }
127
process_prekey_bundle<R: Rng + CryptoRng>( remote_address: &ProtocolAddress, session_store: &mut dyn SessionStore, identity_store: &mut dyn IdentityKeyStore, bundle: &PreKeyBundle, mut csprng: &mut R, ctx: Context, ) -> Result<()>128 pub async fn process_prekey_bundle<R: Rng + CryptoRng>(
129 remote_address: &ProtocolAddress,
130 session_store: &mut dyn SessionStore,
131 identity_store: &mut dyn IdentityKeyStore,
132 bundle: &PreKeyBundle,
133 mut csprng: &mut R,
134 ctx: Context,
135 ) -> Result<()> {
136 let their_identity_key = bundle.identity_key()?;
137
138 if !identity_store
139 .is_trusted_identity(remote_address, their_identity_key, Direction::Sending, ctx)
140 .await?
141 {
142 return Err(SignalProtocolError::UntrustedIdentity(
143 remote_address.clone(),
144 ));
145 }
146
147 if !their_identity_key.public_key().verify_signature(
148 &bundle.signed_pre_key_public()?.serialize(),
149 bundle.signed_pre_key_signature()?,
150 )? {
151 return Err(SignalProtocolError::SignatureValidationFailed);
152 }
153
154 let mut session_record = session_store
155 .load_session(remote_address, ctx)
156 .await?
157 .unwrap_or_else(SessionRecord::new_fresh);
158
159 let our_base_key_pair = KeyPair::generate(&mut csprng);
160 let their_signed_prekey = bundle.signed_pre_key_public()?;
161
162 let their_one_time_prekey = bundle.pre_key_public()?;
163 let their_one_time_prekey_id = bundle.pre_key_id()?;
164
165 let our_identity_key_pair = identity_store.get_identity_key_pair(ctx).await?;
166
167 let parameters = AliceSignalProtocolParameters::new(
168 our_identity_key_pair,
169 our_base_key_pair,
170 *their_identity_key,
171 their_signed_prekey,
172 their_one_time_prekey,
173 their_signed_prekey,
174 );
175
176 let mut session = ratchet::initialize_alice_session(¶meters, csprng)?;
177
178 log::info!(
179 "set_unacknowledged_pre_key_message for: {} with preKeyId: {}",
180 remote_address,
181 their_one_time_prekey_id.map_or_else(|| "<none>".to_string(), |id| id.to_string())
182 );
183
184 session.set_unacknowledged_pre_key_message(
185 their_one_time_prekey_id,
186 bundle.signed_pre_key_id()?,
187 &our_base_key_pair.public_key,
188 )?;
189
190 session.set_local_registration_id(identity_store.get_local_registration_id(ctx).await?)?;
191 session.set_remote_registration_id(bundle.registration_id()?)?;
192 session.set_alice_base_key(&our_base_key_pair.public_key.serialize())?;
193
194 identity_store
195 .save_identity(remote_address, their_identity_key, ctx)
196 .await?;
197
198 session_record.promote_state(session)?;
199
200 session_store
201 .store_session(remote_address, &session_record, ctx)
202 .await?;
203
204 Ok(())
205 }
206