libsignal_service/provisioning/
mod.rs1mod cipher;
2mod pipe;
3
4use std::array::TryFromSliceError;
5use std::convert::TryInto;
6
7pub use cipher::ProvisioningCipher;
8
9use base64::Engine;
10use derivative::Derivative;
11use futures::StreamExt;
12use futures::{channel::mpsc::Sender, pin_mut, SinkExt};
13use libsignal_protocol::{
14 DeviceId, IdentityKey, IdentityKeyPair, PrivateKey, PublicKey,
15};
16use prost::Message;
17use serde::Deserialize;
18use url::Url;
19use uuid::Uuid;
20use zkgroup::profiles::ProfileKey;
21
22use pipe::{ProvisioningPipe, ProvisioningStep};
23
24use crate::prelude::ServiceError;
25use crate::push_service::DeviceActivationRequest;
26use crate::utils::BASE64_RELAXED;
27use crate::{
28 account_manager::encrypt_device_name,
29 pre_keys::PreKeysStore,
30 push_service::{
31 HttpAuth, LinkAccountAttributes, LinkCapabilities, LinkRequest,
32 LinkResponse, PushService, ServiceIds,
33 },
34};
35
36pub use crate::proto::{
37 ProvisionEnvelope, ProvisionMessage, ProvisioningVersion,
38};
39
40#[derive(thiserror::Error, Debug)]
41pub enum ProvisioningError {
42 #[error("no provisioning URL received")]
43 MissingUrl,
44 #[error("bad version number (unsupported)")]
45 BadVersionNumber,
46 #[error("missing public key")]
47 MissingPublicKey,
48 #[error("missing private key")]
49 MissingPrivateKey,
50 #[error("invalid public key")]
51 InvalidPublicKey(InvalidKeyError),
52 #[error("invalid privat key")]
53 InvalidPrivateKey(InvalidKeyError),
54 #[error("missing UUID")]
55 MissingUuid,
56 #[error("no provisioning message received")]
57 MissingMessage,
58 #[error("missing profile key")]
59 MissingProfileKey,
60 #[error("missing phone number")]
61 MissingPhoneNumber,
62 #[error("invalid phone number: {0}")]
63 InvalidPhoneNumber(phonenumber::ParseError),
64 #[error("missing provisioning code")]
65 MissingProvisioningCode,
66 #[error("mismatched MAC")]
67 MismatchedMac,
68 #[error("AES CBC padding error: {0}")]
69 AesPaddingError(aes::cipher::block_padding::UnpadError),
70
71 #[error("invalid provisioning step received")]
72 InvalidStep,
73
74 #[error("Protobuf decoding error: {0}")]
75 DecodeError(#[from] prost::DecodeError),
76 #[error("Websocket error: {reason}")]
77 WsError { reason: String },
78 #[error("Websocket closing")]
79 WsClosing,
80 #[error("Service error: {0}")]
81 ServiceError(#[from] ServiceError),
82 #[error("libsignal-protocol error: {0}")]
83 ProtocolError(#[from] libsignal_protocol::SignalProtocolError),
84 #[error("ProvisioningCipher in encrypt-only mode")]
85 EncryptOnlyProvisioningCipher,
86 #[error("invalid profile key bytes")]
87 InvalidProfileKey(TryFromSliceError),
88}
89
90#[derive(Debug, thiserror::Error)]
91pub enum InvalidKeyError {
92 #[error("base64 decoding error: {0}")]
93 Base64(#[from] base64::DecodeError),
94 #[error("protocol error: {0}")]
95 Protocol(#[from] libsignal_protocol::SignalProtocolError),
96}
97
98pub fn generate_registration_id<R: rand::Rng + rand::CryptoRng>(
99 csprng: &mut R,
100) -> u32 {
101 csprng.gen_range(1..16380)
102}
103
104#[derive(Debug, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct ConfirmCodeResponse {
107 pub uuid: Uuid,
108 pub storage_capable: bool,
109}
110
111#[derive(Debug)]
112pub enum SecondaryDeviceProvisioning {
113 Url(Url),
114 NewDeviceRegistration(NewDeviceRegistration),
115}
116
117#[derive(Derivative)]
118#[derivative(Debug)]
119pub struct NewDeviceRegistration {
120 pub phone_number: phonenumber::PhoneNumber,
121 pub device_id: DeviceId,
122 pub registration_id: u32,
123 pub pni_registration_id: u32,
124 pub service_ids: ServiceIds,
125 #[derivative(Debug = "ignore")]
126 pub aci_private_key: PrivateKey,
127 pub aci_public_key: IdentityKey,
128 #[derivative(Debug = "ignore")]
129 pub pni_private_key: PrivateKey,
130 pub pni_public_key: IdentityKey,
131 #[derivative(Debug = "ignore")]
132 pub profile_key: ProfileKey,
133}
134
135pub async fn link_device<
136 R: rand::Rng + rand::CryptoRng,
137 Aci: PreKeysStore,
138 Pni: PreKeysStore,
139>(
140 aci_store: &mut Aci,
141 pni_store: &mut Pni,
142 csprng: &mut R,
143 mut push_service: PushService,
144 password: &str,
145 device_name: &str,
146 mut tx: Sender<SecondaryDeviceProvisioning>,
147) -> Result<(), ProvisioningError> {
148 let ws = push_service
150 .ws(
151 "/v1/websocket/provisioning/",
152 "/v1/keepalive/provisioning",
153 &[],
154 None,
155 )
156 .await?;
157
158 let registration_id = csprng.gen_range(1..256);
159 let pni_registration_id = csprng.gen_range(1..256);
160
161 let provisioning_pipe = ProvisioningPipe::from_socket(ws, csprng);
162 let provision_stream = provisioning_pipe.stream();
163 pin_mut!(provision_stream);
164
165 if let ProvisioningStep::Url(url) = provision_stream
166 .next()
167 .await
168 .ok_or(ProvisioningError::MissingUrl)??
169 {
170 tx.send(SecondaryDeviceProvisioning::Url(url))
171 .await
172 .expect("failed to send provisioning Url in channel");
173 } else {
174 return Err(ProvisioningError::InvalidStep);
175 }
176
177 if let ProvisioningStep::Message(message) =
178 provision_stream
179 .next()
180 .await
181 .ok_or(ProvisioningError::MissingMessage)??
182 {
183 let aci_public_key = PublicKey::deserialize(
184 &message
185 .aci_identity_key_public
186 .ok_or(ProvisioningError::MissingPublicKey)?,
187 )
188 .map_err(|e| ProvisioningError::InvalidPublicKey(e.into()))?;
189 let aci_public_key = IdentityKey::new(aci_public_key);
190
191 let aci_private_key = PrivateKey::deserialize(
192 &message
193 .aci_identity_key_private
194 .ok_or(ProvisioningError::MissingPrivateKey)?,
195 )
196 .map_err(|e| ProvisioningError::InvalidPrivateKey(e.into()))?;
197
198 let pni_public_key = PublicKey::deserialize(
199 &message
200 .pni_identity_key_public
201 .ok_or(ProvisioningError::MissingPublicKey)?,
202 )
203 .map_err(|e| ProvisioningError::InvalidPublicKey(e.into()))?;
204 let pni_public_key = IdentityKey::new(pni_public_key);
205
206 let pni_private_key = PrivateKey::deserialize(
207 &message
208 .pni_identity_key_private
209 .ok_or(ProvisioningError::MissingPrivateKey)?,
210 )
211 .map_err(|e| ProvisioningError::InvalidPrivateKey(e.into()))?;
212
213 let profile_key = message
214 .profile_key
215 .ok_or(ProvisioningError::MissingProfileKey)?;
216
217 let phone_number = message
218 .number
219 .ok_or(ProvisioningError::MissingPhoneNumber)?;
220
221 let phone_number = phonenumber::parse(None, phone_number)
222 .map_err(ProvisioningError::InvalidPhoneNumber)?;
223
224 let provisioning_code = message
225 .provisioning_code
226 .ok_or(ProvisioningError::MissingProvisioningCode)?;
227
228 let aci_key_pair =
229 IdentityKeyPair::new(aci_public_key, aci_private_key);
230 let pni_key_pair =
231 IdentityKeyPair::new(pni_public_key, pni_private_key);
232
233 let (
234 _aci_pre_keys,
235 aci_signed_pre_key,
236 _aci_pq_pre_keys,
237 aci_pq_last_resort_pre_key,
238 ) = crate::pre_keys::replenish_pre_keys(
239 aci_store,
240 csprng,
241 &aci_key_pair,
242 true,
243 0,
244 0,
245 )
246 .await?;
247
248 let aci_pq_last_resort_pre_key =
249 aci_pq_last_resort_pre_key.expect("requested last resort key");
250 assert!(_aci_pre_keys.is_empty());
251 assert!(_aci_pq_pre_keys.is_empty());
252
253 let (
254 _pni_pre_keys,
255 pni_signed_pre_key,
256 _pni_pq_pre_keys,
257 pni_pq_last_resort_pre_key,
258 ) = crate::pre_keys::replenish_pre_keys(
259 pni_store,
260 csprng,
261 &pni_key_pair,
262 true,
263 0,
264 0,
265 )
266 .await?;
267
268 let pni_pq_last_resort_pre_key =
269 pni_pq_last_resort_pre_key.expect("requested last resort key");
270 assert!(_pni_pre_keys.is_empty());
271 assert!(_pni_pq_pre_keys.is_empty());
272
273 let encrypted_device_name = BASE64_RELAXED.encode(
274 encrypt_device_name(csprng, device_name, &aci_public_key)?
275 .encode_to_vec(),
276 );
277
278 let profile_key = ProfileKey::create(
279 profile_key
280 .as_slice()
281 .try_into()
282 .map_err(ProvisioningError::InvalidProfileKey)?,
283 );
284
285 let request = LinkRequest {
286 verification_code: provisioning_code,
287 account_attributes: LinkAccountAttributes {
288 registration_id,
289 pni_registration_id,
290 fetches_messages: true,
291 capabilities: LinkCapabilities::default(),
292 name: encrypted_device_name,
293 },
294 device_activation_request: DeviceActivationRequest {
295 aci_signed_pre_key: aci_signed_pre_key.try_into()?,
296 pni_signed_pre_key: pni_signed_pre_key.try_into()?,
297 aci_pq_last_resort_pre_key: aci_pq_last_resort_pre_key
298 .try_into()?,
299 pni_pq_last_resort_pre_key: pni_pq_last_resort_pre_key
300 .try_into()?,
301 },
302 };
303
304 let LinkResponse {
305 aci,
306 pni,
307 device_id,
308 } = push_service
309 .link_device(
310 &request,
311 HttpAuth {
312 username: phone_number.to_string(),
313 password: password.to_owned(),
314 },
315 )
316 .await?;
317
318 tx.send(SecondaryDeviceProvisioning::NewDeviceRegistration(
319 NewDeviceRegistration {
320 phone_number,
321 service_ids: ServiceIds { aci, pni },
322 device_id: device_id.into(),
323 registration_id,
324 pni_registration_id,
325 aci_private_key,
326 aci_public_key,
327 pni_private_key,
328 pni_public_key,
329 profile_key,
330 },
331 ))
332 .await
333 .expect("failed to send provisioning message in rx channel");
334 } else {
335 return Err(ProvisioningError::InvalidStep);
336 }
337
338 Ok(())
339}