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