1 /*
2 * store.c
3 * vim: expandtab:ts=4:sts=4:sw=4
4 *
5 * Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
6 *
7 * This file is part of Profanity.
8 *
9 * Profanity is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * Profanity is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Profanity. If not, see <https://www.gnu.org/licenses/>.
21 *
22 * In addition, as a special exception, the copyright holders give permission to
23 * link the code of portions of this program with the OpenSSL library under
24 * certain conditions as described in each individual source file, and
25 * distribute linked combinations including the two.
26 *
27 * You must obey the GNU General Public License in all respects for all of the
28 * code used other than OpenSSL. If you modify file(s) with this exception, you
29 * may extend this exception to your version of the file(s), but you are not
30 * obligated to do so. If you do not wish to do so, delete this exception
31 * statement from your version. If you delete this exception statement from all
32 * source files in the program, then also delete it here.
33 *
34 */
35 #include <glib.h>
36 #include <signal/signal_protocol.h>
37
38 #include "config.h"
39 #include "log.h"
40 #include "omemo/omemo.h"
41 #include "omemo/store.h"
42
43 static void _g_hash_table_free(GHashTable* hash_table);
44
45 GHashTable*
session_store_new(void)46 session_store_new(void)
47 {
48 return g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_g_hash_table_free);
49 }
50
51 GHashTable*
pre_key_store_new(void)52 pre_key_store_new(void)
53 {
54 return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
55 }
56
57 GHashTable*
signed_pre_key_store_new(void)58 signed_pre_key_store_new(void)
59 {
60 return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
61 }
62
63 void
identity_key_store_new(identity_key_store_t * identity_key_store)64 identity_key_store_new(identity_key_store_t* identity_key_store)
65 {
66 identity_key_store->trusted = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)signal_buffer_free);
67 identity_key_store->private = NULL;
68 identity_key_store->public = NULL;
69 }
70
71 #ifdef HAVE_LIBSIGNAL_LT_2_3_2
72 int
load_session(signal_buffer ** record,const signal_protocol_address * address,void * user_data)73 load_session(signal_buffer** record, const signal_protocol_address* address,
74 void* user_data)
75 #else
76 int
77 load_session(signal_buffer** record, signal_buffer** user_record,
78 const signal_protocol_address* address, void* user_data)
79 #endif
80 {
81 GHashTable* session_store = (GHashTable*)user_data;
82 GHashTable* device_store = NULL;
83
84 log_debug("[OMEMO][STORE] Looking for %s in session_store", address->name);
85 device_store = g_hash_table_lookup(session_store, address->name);
86 if (!device_store) {
87 *record = NULL;
88 log_info("[OMEMO][STORE] No device store for %s found", address->name);
89 return 0;
90 }
91
92 log_debug("[OMEMO][STORE] Looking for device %d of %s ", address->device_id, address->name);
93 signal_buffer* original = g_hash_table_lookup(device_store, GINT_TO_POINTER(address->device_id));
94 if (!original) {
95 *record = NULL;
96 log_warning("[OMEMO][STORE] No device (%d) store for %s found", address->device_id, address->name);
97 return 0;
98 }
99 *record = signal_buffer_copy(original);
100 return 1;
101 }
102
103 int
get_sub_device_sessions(signal_int_list ** sessions,const char * name,size_t name_len,void * user_data)104 get_sub_device_sessions(signal_int_list** sessions, const char* name,
105 size_t name_len, void* user_data)
106 {
107 GHashTable* session_store = (GHashTable*)user_data;
108 GHashTable* device_store = NULL;
109 GHashTableIter iter;
110 gpointer key, value;
111
112 device_store = g_hash_table_lookup(session_store, name);
113 if (!device_store) {
114 log_debug("[OMEMO][STORE] What?");
115 return SG_SUCCESS;
116 }
117
118 *sessions = signal_int_list_alloc();
119 g_hash_table_iter_init(&iter, device_store);
120 while (g_hash_table_iter_next(&iter, &key, &value)) {
121 signal_int_list_push_back(*sessions, GPOINTER_TO_INT(key));
122 }
123
124 return SG_SUCCESS;
125 }
126
127 #ifdef HAVE_LIBSIGNAL_LT_2_3_2
128 int
store_session(const signal_protocol_address * address,uint8_t * record,size_t record_len,void * user_data)129 store_session(const signal_protocol_address* address, uint8_t* record,
130 size_t record_len, void* user_data)
131 #else
132 int
133 store_session(const signal_protocol_address* address,
134 uint8_t* record, size_t record_len,
135 uint8_t* user_record, size_t user_record_len,
136 void* user_data)
137 #endif
138 {
139 GHashTable* session_store = (GHashTable*)user_data;
140 GHashTable* device_store = NULL;
141
142 log_debug("[OMEMO][STORE] Store session for %s (%d)", address->name, address->device_id);
143 device_store = g_hash_table_lookup(session_store, (void*)address->name);
144 if (!device_store) {
145 device_store = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
146 g_hash_table_insert(session_store, strdup(address->name), device_store);
147 }
148
149 signal_buffer* buffer = signal_buffer_create(record, record_len);
150 g_hash_table_insert(device_store, GINT_TO_POINTER(address->device_id), buffer);
151
152 char* record_b64 = g_base64_encode(record, record_len);
153 char* device_id = g_strdup_printf("%d", address->device_id);
154 g_key_file_set_string(omemo_sessions_keyfile(), address->name, device_id, record_b64);
155 free(device_id);
156 g_free(record_b64);
157
158 omemo_sessions_keyfile_save();
159
160 return SG_SUCCESS;
161 }
162
163 int
contains_session(const signal_protocol_address * address,void * user_data)164 contains_session(const signal_protocol_address* address, void* user_data)
165 {
166 GHashTable* session_store = (GHashTable*)user_data;
167 GHashTable* device_store = NULL;
168
169 device_store = g_hash_table_lookup(session_store, address->name);
170 if (!device_store) {
171 log_debug("[OMEMO][STORE] No Device");
172 return 0;
173 }
174
175 if (!g_hash_table_lookup(device_store, GINT_TO_POINTER(address->device_id))) {
176 log_debug("[OMEMO][STORE] No Session for %d ", address->device_id);
177 return 0;
178 }
179
180 return 1;
181 }
182
183 int
delete_session(const signal_protocol_address * address,void * user_data)184 delete_session(const signal_protocol_address* address, void* user_data)
185 {
186 GHashTable* session_store = (GHashTable*)user_data;
187 GHashTable* device_store = NULL;
188
189 device_store = g_hash_table_lookup(session_store, address->name);
190 if (!device_store) {
191 return SG_SUCCESS;
192 }
193
194 g_hash_table_remove(device_store, GINT_TO_POINTER(address->device_id));
195
196 char* device_id_str = g_strdup_printf("%d", address->device_id);
197 g_key_file_remove_key(omemo_sessions_keyfile(), address->name, device_id_str, NULL);
198 g_free(device_id_str);
199 omemo_sessions_keyfile_save();
200
201 return SG_SUCCESS;
202 }
203
204 int
delete_all_sessions(const char * name,size_t name_len,void * user_data)205 delete_all_sessions(const char* name, size_t name_len, void* user_data)
206 {
207 GHashTable* session_store = (GHashTable*)user_data;
208 GHashTable* device_store = NULL;
209
210 device_store = g_hash_table_lookup(session_store, name);
211 if (!device_store) {
212 log_debug("[OMEMO][STORE] No device => no delete");
213 return SG_SUCCESS;
214 }
215
216 guint len = g_hash_table_size(device_store);
217 g_hash_table_remove_all(device_store);
218 return len;
219 }
220
221 int
load_pre_key(signal_buffer ** record,uint32_t pre_key_id,void * user_data)222 load_pre_key(signal_buffer** record, uint32_t pre_key_id, void* user_data)
223 {
224 signal_buffer* original;
225 GHashTable* pre_key_store = (GHashTable*)user_data;
226
227 original = g_hash_table_lookup(pre_key_store, GINT_TO_POINTER(pre_key_id));
228 if (original == NULL) {
229 log_error("[OMEMO][STORE] SG_ERR_INVALID_KEY_ID");
230 return SG_ERR_INVALID_KEY_ID;
231 }
232
233 *record = signal_buffer_copy(original);
234 return SG_SUCCESS;
235 }
236
237 int
store_pre_key(uint32_t pre_key_id,uint8_t * record,size_t record_len,void * user_data)238 store_pre_key(uint32_t pre_key_id, uint8_t* record, size_t record_len,
239 void* user_data)
240 {
241 GHashTable* pre_key_store = (GHashTable*)user_data;
242
243 signal_buffer* buffer = signal_buffer_create(record, record_len);
244 g_hash_table_insert(pre_key_store, GINT_TO_POINTER(pre_key_id), buffer);
245
246 /* Long term storage */
247 char* pre_key_id_str = g_strdup_printf("%d", pre_key_id);
248 char* record_b64 = g_base64_encode(record, record_len);
249 g_key_file_set_string(omemo_identity_keyfile(), OMEMO_STORE_GROUP_PREKEYS, pre_key_id_str, record_b64);
250 g_free(pre_key_id_str);
251 g_free(record_b64);
252
253 omemo_identity_keyfile_save();
254
255 return SG_SUCCESS;
256 }
257
258 int
contains_pre_key(uint32_t pre_key_id,void * user_data)259 contains_pre_key(uint32_t pre_key_id, void* user_data)
260 {
261 GHashTable* pre_key_store = (GHashTable*)user_data;
262
263 return g_hash_table_lookup(pre_key_store, GINT_TO_POINTER(pre_key_id)) != NULL;
264 }
265
266 int
remove_pre_key(uint32_t pre_key_id,void * user_data)267 remove_pre_key(uint32_t pre_key_id, void* user_data)
268 {
269 GHashTable* pre_key_store = (GHashTable*)user_data;
270
271 int ret = g_hash_table_remove(pre_key_store, GINT_TO_POINTER(pre_key_id));
272
273 /* Long term storage */
274 char* pre_key_id_str = g_strdup_printf("%d", pre_key_id);
275 g_key_file_remove_key(omemo_identity_keyfile(), OMEMO_STORE_GROUP_PREKEYS, pre_key_id_str, NULL);
276 g_free(pre_key_id_str);
277
278 omemo_identity_keyfile_save();
279
280 if (ret > 0) {
281 return SG_SUCCESS;
282 } else {
283 log_error("[OMEMO][STORE] SG_ERR_INVALID_KEY_ID");
284 return SG_ERR_INVALID_KEY_ID;
285 }
286 }
287
288 int
load_signed_pre_key(signal_buffer ** record,uint32_t signed_pre_key_id,void * user_data)289 load_signed_pre_key(signal_buffer** record, uint32_t signed_pre_key_id,
290 void* user_data)
291 {
292 signal_buffer* original;
293 GHashTable* signed_pre_key_store = (GHashTable*)user_data;
294
295 original = g_hash_table_lookup(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id));
296 if (!original) {
297 log_error("[OMEMO][STORE] SG_ERR_INVALID_KEY_ID");
298 return SG_ERR_INVALID_KEY_ID;
299 }
300
301 *record = signal_buffer_copy(original);
302 return SG_SUCCESS;
303 }
304
305 int
store_signed_pre_key(uint32_t signed_pre_key_id,uint8_t * record,size_t record_len,void * user_data)306 store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t* record,
307 size_t record_len, void* user_data)
308 {
309 GHashTable* signed_pre_key_store = (GHashTable*)user_data;
310
311 signal_buffer* buffer = signal_buffer_create(record, record_len);
312 g_hash_table_insert(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id), buffer);
313
314 /* Long term storage */
315 char* signed_pre_key_id_str = g_strdup_printf("%d", signed_pre_key_id);
316 char* record_b64 = g_base64_encode(record, record_len);
317 g_key_file_set_string(omemo_identity_keyfile(), OMEMO_STORE_GROUP_SIGNED_PREKEYS, signed_pre_key_id_str, record_b64);
318 g_free(signed_pre_key_id_str);
319 g_free(record_b64);
320
321 omemo_identity_keyfile_save();
322
323 return SG_SUCCESS;
324 }
325
326 int
contains_signed_pre_key(uint32_t signed_pre_key_id,void * user_data)327 contains_signed_pre_key(uint32_t signed_pre_key_id, void* user_data)
328 {
329 GHashTable* signed_pre_key_store = (GHashTable*)user_data;
330
331 return g_hash_table_lookup(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id)) != NULL;
332 }
333
334 int
remove_signed_pre_key(uint32_t signed_pre_key_id,void * user_data)335 remove_signed_pre_key(uint32_t signed_pre_key_id, void* user_data)
336 {
337 GHashTable* signed_pre_key_store = (GHashTable*)user_data;
338
339 int ret = g_hash_table_remove(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id));
340
341 /* Long term storage */
342 char* signed_pre_key_id_str = g_strdup_printf("%d", signed_pre_key_id);
343 g_key_file_remove_key(omemo_identity_keyfile(), OMEMO_STORE_GROUP_PREKEYS, signed_pre_key_id_str, NULL);
344 g_free(signed_pre_key_id_str);
345
346 omemo_identity_keyfile_save();
347
348 return ret;
349 }
350
351 int
get_identity_key_pair(signal_buffer ** public_data,signal_buffer ** private_data,void * user_data)352 get_identity_key_pair(signal_buffer** public_data, signal_buffer** private_data,
353 void* user_data)
354 {
355 identity_key_store_t* identity_key_store = (identity_key_store_t*)user_data;
356
357 *public_data = signal_buffer_copy(identity_key_store->public);
358 *private_data = signal_buffer_copy(identity_key_store->private);
359
360 return SG_SUCCESS;
361 }
362
363 int
get_local_registration_id(void * user_data,uint32_t * registration_id)364 get_local_registration_id(void* user_data, uint32_t* registration_id)
365 {
366 identity_key_store_t* identity_key_store = (identity_key_store_t*)user_data;
367
368 *registration_id = identity_key_store->registration_id;
369
370 return SG_SUCCESS;
371 }
372
373 int
save_identity(const signal_protocol_address * address,uint8_t * key_data,size_t key_len,void * user_data)374 save_identity(const signal_protocol_address* address, uint8_t* key_data,
375 size_t key_len, void* user_data)
376 {
377 identity_key_store_t* identity_key_store = (identity_key_store_t*)user_data;
378
379 if (identity_key_store->recv) {
380 /* Do not trust identity automatically */
381 /* Instead we perform a real trust check */
382 identity_key_store->recv = false;
383 int trusted = is_trusted_identity(address, key_data, key_len, user_data);
384 identity_key_store->recv = true;
385 if (trusted == 0) {
386 log_debug("[OMEMO][STORE] trusted 0");
387 /* If not trusted we just don't save the identity */
388 return SG_SUCCESS;
389 }
390 }
391
392 signal_buffer* buffer = signal_buffer_create(key_data, key_len);
393
394 GHashTable* trusted = g_hash_table_lookup(identity_key_store->trusted, address->name);
395 if (!trusted) {
396 trusted = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
397 g_hash_table_insert(identity_key_store->trusted, strdup(address->name), trusted);
398 }
399 g_hash_table_insert(trusted, GINT_TO_POINTER(address->device_id), buffer);
400
401 /* Long term storage */
402 char* key_b64 = g_base64_encode(key_data, key_len);
403 char* device_id = g_strdup_printf("%d", address->device_id);
404 g_key_file_set_string(omemo_trust_keyfile(), address->name, device_id, key_b64);
405 g_free(device_id);
406 g_free(key_b64);
407
408 omemo_trust_keyfile_save();
409
410 return SG_SUCCESS;
411 }
412
413 int
is_trusted_identity(const signal_protocol_address * address,uint8_t * key_data,size_t key_len,void * user_data)414 is_trusted_identity(const signal_protocol_address* address, uint8_t* key_data,
415 size_t key_len, void* user_data)
416 {
417 int ret;
418 identity_key_store_t* identity_key_store = (identity_key_store_t*)user_data;
419 log_debug("[OMEMO][STORE] Checking trust %s (%d)", address->name, address->device_id);
420 GHashTable* trusted = g_hash_table_lookup(identity_key_store->trusted, address->name);
421 if (!trusted) {
422 if (identity_key_store->recv) {
423 log_debug("[OMEMO][STORE] identity_key_store->recv");
424 return 1;
425 } else {
426 log_debug("[OMEMO][STORE] !identity_key_store->recv");
427 return 0;
428 }
429 }
430
431 signal_buffer* buffer = signal_buffer_create(key_data, key_len);
432 signal_buffer* original = g_hash_table_lookup(trusted, GINT_TO_POINTER(address->device_id));
433
434 if(!original) {
435 log_debug("[OMEMO][STORE] original not found %s (%d)", address->name, address->device_id);
436 }
437 ret = original != NULL && signal_buffer_compare(buffer, original) == 0;
438
439 signal_buffer_free(buffer);
440
441 if (identity_key_store->recv) {
442 log_debug("[OMEMO][STORE] 1 identity_key_store->recv");
443 return 1;
444 } else {
445 log_debug("[OMEMO][STORE] Checking trust %s (%d): %d", address->name, address->device_id, ret);
446 return ret;
447 }
448 }
449
450 int
store_sender_key(const signal_protocol_sender_key_name * sender_key_name,uint8_t * record,size_t record_len,uint8_t * user_record,size_t user_record_len,void * user_data)451 store_sender_key(const signal_protocol_sender_key_name* sender_key_name,
452 uint8_t* record, size_t record_len, uint8_t* user_record,
453 size_t user_record_len, void* user_data)
454 {
455 return SG_SUCCESS;
456 }
457
458 int
load_sender_key(signal_buffer ** record,signal_buffer ** user_record,const signal_protocol_sender_key_name * sender_key_name,void * user_data)459 load_sender_key(signal_buffer** record, signal_buffer** user_record,
460 const signal_protocol_sender_key_name* sender_key_name,
461 void* user_data)
462 {
463 return SG_SUCCESS;
464 }
465
466 static void
_g_hash_table_free(GHashTable * hash_table)467 _g_hash_table_free(GHashTable* hash_table)
468 {
469 g_hash_table_remove_all(hash_table);
470 g_hash_table_unref(hash_table);
471 }
472