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_core::curve::CurveError;
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::DeviceActivationRequest;
27use crate::utils::BASE64_RELAXED;
28use crate::{
29    account_manager::encrypt_device_name,
30    pre_keys::PreKeysStore,
31    push_service::{
32        HttpAuth, LinkAccountAttributes, LinkCapabilities, LinkRequest,
33        LinkResponse, PushService, ServiceIds,
34    },
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(phonenumber::ParseError),
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(Derivative)]
133#[derivative(Debug)]
134pub struct NewDeviceRegistration {
135    pub phone_number: phonenumber::PhoneNumber,
136    pub device_id: DeviceId,
137    pub registration_id: u32,
138    pub pni_registration_id: u32,
139    pub service_ids: ServiceIds,
140    #[derivative(Debug = "ignore")]
141    pub aci_private_key: PrivateKey,
142    pub aci_public_key: IdentityKey,
143    #[derivative(Debug = "ignore")]
144    pub pni_private_key: PrivateKey,
145    pub pni_public_key: IdentityKey,
146    #[derivative(Debug = "ignore")]
147    pub profile_key: ProfileKey,
148}
149
150pub async fn link_device<
151    R: rand::Rng + rand::CryptoRng,
152    Aci: PreKeysStore,
153    Pni: PreKeysStore,
154>(
155    aci_store: &mut Aci,
156    pni_store: &mut Pni,
157    csprng: &mut R,
158    mut push_service: PushService,
159    password: &str,
160    device_name: &str,
161    mut tx: Sender<SecondaryDeviceProvisioning>,
162) -> Result<(), ProvisioningError> {
163    // open a websocket without authentication, to receive a tsurl://
164    let ws = push_service
165        .ws(
166            "/v1/websocket/provisioning/",
167            "/v1/keepalive/provisioning",
168            &[],
169            None,
170        )
171        .await?;
172
173    let registration_id = csprng.random_range(1..256);
174    let pni_registration_id = csprng.random_range(1..256);
175
176    let provisioning_pipe = ProvisioningPipe::from_socket(ws, csprng);
177    let provision_stream = provisioning_pipe.stream();
178    pin_mut!(provision_stream);
179
180    if let ProvisioningStep::Url(url) = provision_stream
181        .next()
182        .await
183        .ok_or(ProvisioningError::MissingUrl)??
184    {
185        tx.send(SecondaryDeviceProvisioning::Url(url))
186            .await
187            .expect("failed to send provisioning Url in channel");
188    } else {
189        return Err(ProvisioningError::InvalidStep);
190    }
191
192    if let ProvisioningStep::Message(message) =
193        provision_stream
194            .next()
195            .await
196            .ok_or(ProvisioningError::MissingMessage)??
197    {
198        let aci_public_key = PublicKey::deserialize(
199            &message
200                .aci_identity_key_public
201                .ok_or(ProvisioningError::MissingPublicKey)?,
202        )
203        .map_err(ProvisioningError::invalid_public_key)?;
204        let aci_public_key = IdentityKey::new(aci_public_key);
205
206        let aci_private_key = PrivateKey::deserialize(
207            &message
208                .aci_identity_key_private
209                .ok_or(ProvisioningError::MissingPrivateKey)?,
210        )
211        .map_err(ProvisioningError::invalid_private_key)?;
212
213        let pni_public_key = PublicKey::deserialize(
214            &message
215                .pni_identity_key_public
216                .ok_or(ProvisioningError::MissingPublicKey)?,
217        )
218        .map_err(ProvisioningError::invalid_public_key)?;
219        let pni_public_key = IdentityKey::new(pni_public_key);
220
221        let pni_private_key = PrivateKey::deserialize(
222            &message
223                .pni_identity_key_private
224                .ok_or(ProvisioningError::MissingPrivateKey)?,
225        )
226        .map_err(ProvisioningError::invalid_private_key)?;
227
228        let profile_key = message
229            .profile_key
230            .ok_or(ProvisioningError::MissingProfileKey)?;
231
232        let phone_number = message
233            .number
234            .ok_or(ProvisioningError::MissingPhoneNumber)?;
235
236        let phone_number = phonenumber::parse(None, phone_number)
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: device_id.try_into()?,
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}