libsignal_service/websocket/
keys.rs

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