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