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