Skip to main content

libsignal_service/websocket/
keys.rs

1use std::collections::HashMap;
2
3use libsignal_core::DeviceId;
4use libsignal_protocol::{
5    kem::{Key, Public},
6    IdentityKey, PreKeyBundle, PublicKey, SenderCertificate, ServiceId,
7    ServiceIdKind, SignalProtocolError,
8};
9use reqwest::Method;
10use serde::Deserialize;
11
12use crate::{
13    pre_keys::{
14        KyberPreKeyEntity, PreKeyEntity, PreKeyState, SignedPreKeyEntity,
15    },
16    push_service::response::SignalServiceResponse,
17    push_service::DEFAULT_DEVICE_ID,
18    sender::OutgoingPushMessage,
19    utils::{serde_base64, serde_device_id},
20    websocket::{self, registration::VerifyAccountResponse, SignalWebSocket},
21};
22
23use super::ServiceError;
24
25#[derive(Debug, Deserialize, Default)]
26#[serde(rename_all = "camelCase")]
27pub struct PreKeyStatus {
28    pub count: u32,
29    pub pq_count: u32,
30}
31
32#[derive(Debug, Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub struct PreKeyResponse {
35    #[serde(with = "serde_base64")]
36    pub identity_key: Vec<u8>,
37    pub devices: Vec<PreKeyResponseItem>,
38}
39
40#[derive(Debug, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct PreKeyResponseItem {
43    #[serde(with = "serde_device_id")]
44    pub device_id: DeviceId,
45    pub registration_id: u32,
46    pub signed_pre_key: SignedPreKeyEntity,
47    pub pre_key: Option<PreKeyEntity>,
48    pub pq_pre_key: KyberPreKeyEntity,
49}
50
51impl PreKeyResponseItem {
52    pub(crate) fn into_bundle(
53        self,
54        identity: IdentityKey,
55    ) -> Result<PreKeyBundle, ServiceError> {
56        let pre_key_bundle = PreKeyBundle::new(
57            self.registration_id,
58            self.device_id,
59            self.pre_key
60                .map(|pk| -> Result<_, SignalProtocolError> {
61                    Ok((
62                        pk.key_id.into(),
63                        PublicKey::deserialize(&pk.public_key)?,
64                    ))
65                })
66                .transpose()?,
67            // pre_key: Option<(u32, PublicKey)>,
68            self.signed_pre_key.key_id.into(),
69            PublicKey::deserialize(&self.signed_pre_key.public_key)?,
70            self.signed_pre_key.signature,
71            self.pq_pre_key.key_id.into(),
72            Key::<Public>::deserialize(&self.pq_pre_key.public_key)?,
73            self.pq_pre_key.signature,
74            identity,
75        )?;
76
77        Ok(pre_key_bundle)
78    }
79}
80
81#[derive(Debug, Deserialize)]
82#[serde(rename_all = "camelCase")]
83struct SenderCertificateJson {
84    #[serde(with = "serde_base64")]
85    certificate: Vec<u8>,
86}
87
88impl SignalWebSocket<websocket::Identified> {
89    pub async fn get_pre_key_status(
90        &mut self,
91        service_id_kind: ServiceIdKind,
92    ) -> Result<PreKeyStatus, ServiceError> {
93        self.http_request(
94            Method::GET,
95            format!("/v2/keys?identity={}", service_id_kind),
96        )?
97        .send()
98        .await?
99        .service_error_for_status()
100        .await?
101        .json()
102        .await
103    }
104
105    /// Checks for consistency of the repeated-use keys
106    ///
107    /// Supply the digest as follows:
108    /// `SHA256(identityKeyBytes || signedEcPreKeyId || signedEcPreKeyIdBytes || lastResortKeyId ||
109    /// lastResortKeyBytes)`
110    ///
111    /// The IDs are represented as 8-byte big endian ints.
112    ///
113    /// Retuns `Ok(true)` if the view is consistent, `Ok(false)` if the view is inconsistent.
114    pub async fn check_pre_keys(
115        &mut self,
116        service_id_kind: ServiceIdKind,
117        digest: &[u8; 32],
118    ) -> Result<bool, ServiceError> {
119        #[derive(serde::Serialize)]
120        #[serde(rename_all = "camelCase")]
121        struct CheckPreKeysRequest<'a> {
122            identity_type: String,
123            #[serde(with = "serde_base64")]
124            digest: &'a [u8; 32],
125        }
126
127        let req = CheckPreKeysRequest {
128            identity_type: service_id_kind.to_string(),
129            digest,
130        };
131
132        let res = self
133            .http_request(Method::POST, "/v2/keys/check")?
134            .send_json(&req)
135            .await?;
136
137        if res.status_code() == Some(reqwest::StatusCode::CONFLICT) {
138            return Ok(false);
139        }
140
141        res.service_error_for_status().await?;
142
143        Ok(true)
144    }
145
146    pub async fn register_pre_keys(
147        &mut self,
148        service_id_kind: ServiceIdKind,
149        pre_key_state: PreKeyState,
150    ) -> Result<(), ServiceError> {
151        self.http_request(
152            Method::PUT,
153            format!("/v2/keys?identity={}", service_id_kind),
154        )?
155        .send_json(&pre_key_state)
156        .await?
157        .service_error_for_status()
158        .await?;
159
160        Ok(())
161    }
162
163    pub async fn get_pre_key(
164        &mut self,
165        destination: &ServiceId,
166        device_id: DeviceId,
167    ) -> Result<PreKeyBundle, ServiceError> {
168        let path = format!(
169            "/v2/keys/{}/{}",
170            destination.service_id_string(),
171            device_id
172        );
173
174        let mut pre_key_response: PreKeyResponse = self
175            .http_request(Method::GET, path)?
176            .send()
177            .await?
178            .service_error_for_status()
179            .await?
180            .json()
181            .await?;
182
183        assert!(!pre_key_response.devices.is_empty());
184
185        let identity = IdentityKey::decode(&pre_key_response.identity_key)?;
186        let device = pre_key_response.devices.remove(0);
187        device.into_bundle(identity)
188    }
189
190    pub(crate) async fn get_pre_keys(
191        &mut self,
192        destination: &ServiceId,
193        device_id: DeviceId,
194    ) -> Result<Vec<PreKeyBundle>, ServiceError> {
195        let path = if device_id == *DEFAULT_DEVICE_ID {
196            format!("/v2/keys/{}/*", destination.service_id_string())
197        } else {
198            format!(
199                "/v2/keys/{}/{}",
200                destination.service_id_string(),
201                device_id
202            )
203        };
204        let pre_key_response: PreKeyResponse = self
205            .http_request(Method::GET, path)?
206            .send()
207            .await?
208            .service_error_for_status()
209            .await?
210            .json()
211            .await?;
212        let mut pre_keys = vec![];
213        let identity = IdentityKey::decode(&pre_key_response.identity_key)?;
214        for device in pre_key_response.devices {
215            pre_keys.push(device.into_bundle(identity)?);
216        }
217        Ok(pre_keys)
218    }
219
220    pub async fn get_sender_certificate(
221        &mut self,
222    ) -> Result<SenderCertificate, ServiceError> {
223        let cert: SenderCertificateJson = self
224            .http_request(Method::GET, "/v1/certificate/delivery")?
225            .send()
226            .await?
227            .service_error_for_status()
228            .await?
229            .json()
230            .await?;
231        Ok(SenderCertificate::deserialize(&cert.certificate)?)
232    }
233
234    pub async fn get_uuid_only_sender_certificate(
235        &mut self,
236    ) -> Result<SenderCertificate, ServiceError> {
237        let cert: SenderCertificateJson = self
238            .http_request(
239                Method::GET,
240                "/v1/certificate/delivery?includeE164=false",
241            )?
242            .send()
243            .await?
244            .service_error_for_status()
245            .await?
246            .json()
247            .await?;
248        Ok(SenderCertificate::deserialize(&cert.certificate)?)
249    }
250
251    pub async fn distribute_pni_keys(
252        &mut self,
253        pni_identity_key: &IdentityKey,
254        device_messages: Vec<OutgoingPushMessage>,
255        device_pni_signed_prekeys: HashMap<String, SignedPreKeyEntity>,
256        device_pni_last_resort_kyber_prekeys: HashMap<
257            String,
258            KyberPreKeyEntity,
259        >,
260        pni_registration_ids: HashMap<String, u32>,
261        signature_valid_on_each_signed_pre_key: bool,
262    ) -> Result<VerifyAccountResponse, ServiceError> {
263        #[derive(serde::Serialize, Debug)]
264        #[serde(rename_all = "camelCase")]
265        struct PniKeyDistributionRequest {
266            #[serde(with = "serde_base64")]
267            pni_identity_key: Vec<u8>,
268            device_messages: Vec<OutgoingPushMessage>,
269            device_pni_signed_prekeys: HashMap<String, SignedPreKeyEntity>,
270            #[serde(rename = "devicePniPqLastResortPrekeys")]
271            device_pni_last_resort_kyber_prekeys:
272                HashMap<String, KyberPreKeyEntity>,
273            pni_registration_ids: HashMap<String, u32>,
274            signature_valid_on_each_signed_pre_key: bool,
275        }
276        self.http_request(
277            Method::PUT,
278            "/v2/accounts/phone_number_identity_key_distribution",
279        )?
280        .send_json(&PniKeyDistributionRequest {
281            pni_identity_key: pni_identity_key.serialize().into(),
282            device_messages,
283            device_pni_signed_prekeys,
284            device_pni_last_resort_kyber_prekeys,
285            pni_registration_ids,
286            signature_valid_on_each_signed_pre_key,
287        })
288        .await?
289        .service_error_for_status()
290        .await?
291        .json()
292        .await
293    }
294}