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