libsignal_service/provisioning/
mod.rs

1mod 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    // open a websocket without authentication, to receive a tsurl://
149    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}