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 futures::StreamExt;
11use futures::{channel::mpsc::Sender, pin_mut, SinkExt};
12use libsignal_core::curve::CurveError;
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::linking::{
26 LinkAccountAttributes, LinkCapabilities, LinkRequest, LinkResponse,
27};
28use crate::utils::BASE64_RELAXED;
29use crate::websocket::registration::DeviceActivationRequest;
30use crate::{
31 account_manager::encrypt_device_name,
32 pre_keys::PreKeysStore,
33 push_service::{HttpAuth, PushService, ServiceIds},
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("invalid device ID: {0}")]
85 InvalidDeviceId(#[from] libsignal_core::InvalidDeviceId),
86 #[error("ProvisioningCipher in encrypt-only mode")]
87 EncryptOnlyProvisioningCipher,
88 #[error("invalid profile key bytes")]
89 InvalidProfileKey(TryFromSliceError),
90}
91
92impl ProvisioningError {
93 pub fn invalid_public_key(e: impl Into<InvalidKeyError>) -> Self {
94 ProvisioningError::InvalidPublicKey(e.into())
95 }
96
97 pub fn invalid_private_key(e: impl Into<InvalidKeyError>) -> Self {
98 ProvisioningError::InvalidPrivateKey(e.into())
99 }
100}
101
102#[derive(Debug, thiserror::Error)]
103pub enum InvalidKeyError {
104 #[error("curve error: {0}")]
105 Curve(#[from] CurveError),
106 #[error("base64 decoding error: {0}")]
107 Base64(#[from] base64::DecodeError),
108 #[error("protocol error: {0}")]
109 Protocol(#[from] libsignal_protocol::SignalProtocolError),
110}
111
112pub fn generate_registration_id<R: rand::Rng + rand::CryptoRng>(
113 csprng: &mut R,
114) -> u32 {
115 csprng.random_range(1..16380)
116}
117
118#[derive(Debug, Deserialize)]
119#[serde(rename_all = "camelCase")]
120pub struct ConfirmCodeResponse {
121 pub uuid: Uuid,
122 pub storage_capable: bool,
123}
124
125#[derive(Debug)]
126pub enum SecondaryDeviceProvisioning {
127 Url(Url),
128 NewDeviceRegistration(NewDeviceRegistration),
129}
130
131#[derive(derive_more::Debug)]
132pub struct NewDeviceRegistration {
133 pub phone_number: phonenumber::PhoneNumber,
134 pub device_id: DeviceId,
135 pub registration_id: u32,
136 pub pni_registration_id: u32,
137 pub service_ids: ServiceIds,
138 #[debug(ignore)]
139 pub aci_private_key: PrivateKey,
140 pub aci_public_key: IdentityKey,
141 #[debug(ignore)]
142 pub pni_private_key: PrivateKey,
143 pub pni_public_key: IdentityKey,
144 #[debug(ignore)]
145 pub profile_key: ProfileKey,
146}
147
148pub async fn link_device<
149 R: rand::Rng + rand::CryptoRng,
150 Aci: PreKeysStore,
151 Pni: PreKeysStore,
152>(
153 aci_store: &mut Aci,
154 pni_store: &mut Pni,
155 csprng: &mut R,
156 mut push_service: PushService,
157 password: &str,
158 device_name: &str,
159 mut tx: Sender<SecondaryDeviceProvisioning>,
160) -> Result<(), ProvisioningError> {
161 let ws = push_service
163 .ws(
164 "/v1/websocket/provisioning/",
165 "/v1/keepalive/provisioning",
166 &[],
167 None,
168 )
169 .await?;
170
171 let registration_id = csprng.random_range(1..256);
172 let pni_registration_id = csprng.random_range(1..256);
173
174 let provisioning_pipe = ProvisioningPipe::from_socket(ws, csprng);
175 let provision_stream = provisioning_pipe.stream();
176 pin_mut!(provision_stream);
177
178 if let ProvisioningStep::Url(url) = provision_stream
179 .next()
180 .await
181 .ok_or(ProvisioningError::MissingUrl)??
182 {
183 tx.send(SecondaryDeviceProvisioning::Url(url))
184 .await
185 .expect("failed to send provisioning Url in channel");
186 } else {
187 return Err(ProvisioningError::InvalidStep);
188 }
189
190 if let ProvisioningStep::Message(message) =
191 provision_stream
192 .next()
193 .await
194 .ok_or(ProvisioningError::MissingMessage)??
195 {
196 let aci_public_key = PublicKey::deserialize(
197 &message
198 .aci_identity_key_public
199 .ok_or(ProvisioningError::MissingPublicKey)?,
200 )
201 .map_err(ProvisioningError::invalid_public_key)?;
202 let aci_public_key = IdentityKey::new(aci_public_key);
203
204 let aci_private_key = PrivateKey::deserialize(
205 &message
206 .aci_identity_key_private
207 .ok_or(ProvisioningError::MissingPrivateKey)?,
208 )
209 .map_err(ProvisioningError::invalid_private_key)?;
210
211 let pni_public_key = PublicKey::deserialize(
212 &message
213 .pni_identity_key_public
214 .ok_or(ProvisioningError::MissingPublicKey)?,
215 )
216 .map_err(ProvisioningError::invalid_public_key)?;
217 let pni_public_key = IdentityKey::new(pni_public_key);
218
219 let pni_private_key = PrivateKey::deserialize(
220 &message
221 .pni_identity_key_private
222 .ok_or(ProvisioningError::MissingPrivateKey)?,
223 )
224 .map_err(ProvisioningError::invalid_private_key)?;
225
226 let profile_key = message
227 .profile_key
228 .ok_or(ProvisioningError::MissingProfileKey)?;
229
230 let phone_number = message
231 .number
232 .ok_or(ProvisioningError::MissingPhoneNumber)?;
233
234 let phone_number = phonenumber::parse(None, phone_number)
235 .map_err(ProvisioningError::InvalidPhoneNumber)?;
236
237 let provisioning_code = message
238 .provisioning_code
239 .ok_or(ProvisioningError::MissingProvisioningCode)?;
240
241 let aci_key_pair =
242 IdentityKeyPair::new(aci_public_key, aci_private_key);
243 let pni_key_pair =
244 IdentityKeyPair::new(pni_public_key, pni_private_key);
245
246 let (
247 _aci_pre_keys,
248 aci_signed_pre_key,
249 _aci_pq_pre_keys,
250 aci_pq_last_resort_pre_key,
251 ) = crate::pre_keys::replenish_pre_keys(
252 aci_store,
253 csprng,
254 &aci_key_pair,
255 true,
256 0,
257 0,
258 )
259 .await?;
260
261 let aci_pq_last_resort_pre_key =
262 aci_pq_last_resort_pre_key.expect("requested last resort key");
263 assert!(_aci_pre_keys.is_empty());
264 assert!(_aci_pq_pre_keys.is_empty());
265
266 let (
267 _pni_pre_keys,
268 pni_signed_pre_key,
269 _pni_pq_pre_keys,
270 pni_pq_last_resort_pre_key,
271 ) = crate::pre_keys::replenish_pre_keys(
272 pni_store,
273 csprng,
274 &pni_key_pair,
275 true,
276 0,
277 0,
278 )
279 .await?;
280
281 let pni_pq_last_resort_pre_key =
282 pni_pq_last_resort_pre_key.expect("requested last resort key");
283 assert!(_pni_pre_keys.is_empty());
284 assert!(_pni_pq_pre_keys.is_empty());
285
286 let encrypted_device_name = BASE64_RELAXED.encode(
287 encrypt_device_name(csprng, device_name, &aci_public_key)?
288 .encode_to_vec(),
289 );
290
291 let profile_key = ProfileKey::create(
292 profile_key
293 .as_slice()
294 .try_into()
295 .map_err(ProvisioningError::InvalidProfileKey)?,
296 );
297
298 let request = LinkRequest {
299 verification_code: provisioning_code,
300 account_attributes: LinkAccountAttributes {
301 registration_id,
302 pni_registration_id,
303 fetches_messages: true,
304 capabilities: LinkCapabilities::default(),
305 name: encrypted_device_name,
306 },
307 device_activation_request: DeviceActivationRequest {
308 aci_signed_pre_key: aci_signed_pre_key.try_into()?,
309 pni_signed_pre_key: pni_signed_pre_key.try_into()?,
310 aci_pq_last_resort_pre_key: aci_pq_last_resort_pre_key
311 .try_into()?,
312 pni_pq_last_resort_pre_key: pni_pq_last_resort_pre_key
313 .try_into()?,
314 },
315 };
316
317 let LinkResponse {
318 aci,
319 pni,
320 device_id,
321 } = push_service
322 .link_device(
323 &request,
324 HttpAuth {
325 username: phone_number.to_string(),
326 password: password.to_owned(),
327 },
328 )
329 .await?;
330
331 tx.send(SecondaryDeviceProvisioning::NewDeviceRegistration(
332 NewDeviceRegistration {
333 phone_number,
334 service_ids: ServiceIds { aci, pni },
335 device_id: device_id.try_into()?,
336 registration_id,
337 pni_registration_id,
338 aci_private_key,
339 aci_public_key,
340 pni_private_key,
341 pni_public_key,
342 profile_key,
343 },
344 ))
345 .await
346 .expect("failed to send provisioning message in rx channel");
347 } else {
348 return Err(ProvisioningError::InvalidStep);
349 }
350
351 Ok(())
352}