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